From c7f58c17f906467634a5b236d7b3c1df24057419 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Sat, 5 Aug 2023 18:09:21 +0200 Subject: [PATCH 01/45] Remove xcm on_runtime_upgrade pallet hook (#7235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * move migration stuffs * Apply suggestions from code review Co-authored-by: Bastian Köcher * Fix test * fix * lint * fix lint * rm extra space * fix lint * PR review * fixes * use saturating_accrue in fn * fix test --------- Co-authored-by: Bastian Köcher --- xcm/pallet-xcm/src/lib.rs | 6 ----- xcm/pallet-xcm/src/migration.rs | 43 +++++++++++++++------------------ xcm/pallet-xcm/src/tests.rs | 13 +++++----- 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 990871b5c483..d52d5ba24271 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -689,12 +689,6 @@ pub mod pallet { } weight_used } - fn on_runtime_upgrade() -> Weight { - // Start a migration (this happens before on_initialize so it'll happen later in this - // block, which should be good enough)... - CurrentMigration::::put(VersionMigrationStage::default()); - T::DbWeight::get().writes(1) - } } pub mod migrations { diff --git a/xcm/pallet-xcm/src/migration.rs b/xcm/pallet-xcm/src/migration.rs index 1f1dac1c9e81..08809f0d2f2e 100644 --- a/xcm/pallet-xcm/src/migration.rs +++ b/xcm/pallet-xcm/src/migration.rs @@ -25,6 +25,7 @@ const DEFAULT_PROOF_SIZE: u64 = 64 * 1024; pub mod v1 { use super::*; + use crate::{CurrentMigration, VersionMigrationStage}; /// Named with the 'VersionUnchecked'-prefix because although this implements some version /// checking, the version checking is not complete as it will begin failing after the upgrade is @@ -33,34 +34,30 @@ pub mod v1 { /// Use experimental [`VersionCheckedMigrateToV1`] instead. pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - ensure!(StorageVersion::get::>() == 0, "must upgrade linearly"); - - Ok(sp_std::vec::Vec::new()) - } - fn on_runtime_upgrade() -> Weight { - if StorageVersion::get::>() == 0 { - let mut weight = T::DbWeight::get().reads(1); + let mut weight = T::DbWeight::get().reads(1); + + if StorageVersion::get::>() != 0 { + log::warn!("skipping v1, should be removed"); + return weight + } - let translate = |pre: (u64, u64, u32)| -> Option<(u64, Weight, u32)> { - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - let translated = (pre.0, Weight::from_parts(pre.1, DEFAULT_PROOF_SIZE), pre.2); - log::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated); - Some(translated) - }; + weight.saturating_accrue(T::DbWeight::get().writes(1)); + CurrentMigration::::put(VersionMigrationStage::default()); - VersionNotifyTargets::::translate_values(translate); + let translate = |pre: (u64, u64, u32)| -> Option<(u64, Weight, u32)> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + let translated = (pre.0, Weight::from_parts(pre.1, DEFAULT_PROOF_SIZE), pre.2); + log::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated); + Some(translated) + }; - log::info!("v1 applied successfully"); - StorageVersion::new(1).put::>(); + VersionNotifyTargets::::translate_values(translate); - weight.saturating_add(T::DbWeight::get().writes(1)) - } else { - log::warn!("skipping v1, should be removed"); - T::DbWeight::get().reads(1) - } + log::info!("v1 applied successfully"); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + StorageVersion::new(1).put::>(); + weight } } diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 2ad13dced936..f42eb987876a 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -16,7 +16,8 @@ use crate::{ mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries, - QueryStatus, VersionDiscoveryQueue, VersionNotifiers, VersionNotifyTargets, + QueryStatus, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, + VersionNotifyTargets, }; use frame_support::{ assert_noop, assert_ok, @@ -897,7 +898,7 @@ fn subscription_side_works() { assert_eq!(take_sent_xcm(), vec![(remote.clone(), Xcm(vec![instr]))]); // A runtime upgrade which doesn't alter the version sends no notifications. - XcmPallet::on_runtime_upgrade(); + CurrentMigration::::put(VersionMigrationStage::default()); XcmPallet::on_initialize(1); assert_eq!(take_sent_xcm(), vec![]); @@ -905,7 +906,7 @@ fn subscription_side_works() { AdvertisedXcmVersion::set(2); // A runtime upgrade which alters the version does send notifications. - XcmPallet::on_runtime_upgrade(); + CurrentMigration::::put(VersionMigrationStage::default()); XcmPallet::on_initialize(2); let instr = QueryResponse { query_id: 0, @@ -932,7 +933,7 @@ fn subscription_side_upgrades_work_with_notify() { AdvertisedXcmVersion::set(3); // A runtime upgrade which alters the version does send notifications. - XcmPallet::on_runtime_upgrade(); + CurrentMigration::::put(VersionMigrationStage::default()); XcmPallet::on_initialize(1); let instr1 = QueryResponse { @@ -982,7 +983,7 @@ fn subscription_side_upgrades_work_without_notify() { VersionNotifyTargets::::insert(3, v3_location, (72, Weight::zero(), 2)); // A runtime upgrade which alters the version does send notifications. - XcmPallet::on_runtime_upgrade(); + CurrentMigration::::put(VersionMigrationStage::default()); XcmPallet::on_initialize(1); let mut contents = VersionNotifyTargets::::iter().collect::>(); @@ -1166,7 +1167,7 @@ fn subscription_side_upgrades_work_with_multistage_notify() { AdvertisedXcmVersion::set(3); // A runtime upgrade which alters the version does send notifications. - XcmPallet::on_runtime_upgrade(); + CurrentMigration::::put(VersionMigrationStage::default()); let mut maybe_migration = CurrentMigration::::take(); let mut counter = 0; while let Some(migration) = maybe_migration.take() { From 70d80aa7441de1494bd422024236d59fd25e7252 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 7 Aug 2023 09:13:36 -0700 Subject: [PATCH 02/45] Document non-uniqueness of SetTopic IDs (#7579) * Document non-uniqueness of SetTopic IDs * More comments on WithUniqueTopic --- xcm/src/v3/mod.rs | 4 ++++ xcm/xcm-builder/src/barriers.rs | 3 +++ xcm/xcm-builder/src/routing.rs | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/xcm/src/v3/mod.rs b/xcm/src/v3/mod.rs index b1d134ae082c..772ad48ac4b2 100644 --- a/xcm/src/v3/mod.rs +++ b/xcm/src/v3/mod.rs @@ -981,6 +981,10 @@ pub enum Instruction { /// Set the Topic Register. /// + /// The 32-byte array identifier in the parameter is not guaranteed to be + /// unique; if such a property is desired, it is up to the code author to + /// enforce uniqueness. + /// /// Safety: No concerns. /// /// Kind: *Instruction* diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 13c1caca5ff6..6996c7145528 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -207,6 +207,9 @@ impl< /// Sets the message ID to `t` using a `SetTopic(t)` in the last position if present. /// +/// Note that the message ID does not necessarily have to be unique; it is the +/// sender's responsibility to ensure uniqueness. +/// /// Requires some inner barrier to pass on the rest of the message. pub struct TrailingSetTopicAsId(PhantomData); impl ShouldExecute for TrailingSetTopicAsId { diff --git a/xcm/xcm-builder/src/routing.rs b/xcm/xcm-builder/src/routing.rs index c46e0ce78569..39e9eab410bf 100644 --- a/xcm/xcm-builder/src/routing.rs +++ b/xcm/xcm-builder/src/routing.rs @@ -25,6 +25,11 @@ use xcm::prelude::*; /// appends one to the message filled with a universally unique ID. This ID is returned from a /// successful `deliver`. /// +/// If the message does already end with a `SetTopic` instruction, then it is the responsibility +/// of the code author to ensure that the ID supplied to `SetTopic` is universally unique. Due to +/// this property, consumers of the topic ID must be aware that a user-supplied ID may not be +/// unique. +/// /// This is designed to be at the top-level of any routers, since it will always mutate the /// passed `message` reference into a `None`. Don't try to combine it within a tuple except as the /// last element. From a0f986f515bf59bc84a20a0696957e02b57a51d4 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Tue, 8 Aug 2023 09:51:40 -0400 Subject: [PATCH 03/45] PVF: Add missing crate descriptions (#7587) --- node/core/candidate-validation/Cargo.toml | 1 + node/core/pvf-checker/Cargo.toml | 1 + node/core/pvf/Cargo.toml | 1 + node/core/pvf/common/Cargo.toml | 1 + node/core/pvf/common/src/lib.rs | 2 +- node/core/pvf/execute-worker/Cargo.toml | 1 + node/core/pvf/execute-worker/src/lib.rs | 2 ++ node/core/pvf/prepare-worker/Cargo.toml | 1 + node/core/pvf/prepare-worker/src/lib.rs | 2 ++ node/core/pvf/src/lib.rs | 2 +- 10 files changed, 12 insertions(+), 2 deletions(-) diff --git a/node/core/candidate-validation/Cargo.toml b/node/core/candidate-validation/Cargo.toml index ba40fea8140b..0401c892d426 100644 --- a/node/core/candidate-validation/Cargo.toml +++ b/node/core/candidate-validation/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-candidate-validation" +description = "Polkadot crate that implements the Candidate Validation subsystem. Handles requests to validate candidates according to a PVF." version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/core/pvf-checker/Cargo.toml b/node/core/pvf-checker/Cargo.toml index ee7001524265..2b6b53be4072 100644 --- a/node/core/pvf-checker/Cargo.toml +++ b/node/core/pvf-checker/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-pvf-checker" +description = "Polkadot crate that implements the PVF pre-checking subsystem. Responsible for checking and voting for PVFs that are pending approval." version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/core/pvf/Cargo.toml b/node/core/pvf/Cargo.toml index d6e9ef576628..02a56ed9d2df 100644 --- a/node/core/pvf/Cargo.toml +++ b/node/core/pvf/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-pvf" +description = "Polkadot crate that implements the PVF validation host. Responsible for coordinating preparation and execution of PVFs." version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/core/pvf/common/Cargo.toml b/node/core/pvf/common/Cargo.toml index 3e674422f812..a091f8f75806 100644 --- a/node/core/pvf/common/Cargo.toml +++ b/node/core/pvf/common/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-pvf-common" +description = "Polkadot crate that contains functionality related to PVFs that is shared by the PVF host and the PVF workers." version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/core/pvf/common/src/lib.rs b/node/core/pvf/common/src/lib.rs index e5737a66aaec..7e0cab45b671 100644 --- a/node/core/pvf/common/src/lib.rs +++ b/node/core/pvf/common/src/lib.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Functionality that is shared by the host and the workers. +//! Contains functionality related to PVFs that is shared by the PVF host and the PVF workers. pub mod error; pub mod execute; diff --git a/node/core/pvf/execute-worker/Cargo.toml b/node/core/pvf/execute-worker/Cargo.toml index 1c9e2d1f2784..931ea6951a68 100644 --- a/node/core/pvf/execute-worker/Cargo.toml +++ b/node/core/pvf/execute-worker/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-pvf-execute-worker" +description = "Polkadot crate that contains the logic for executing PVFs. Used by the polkadot-execute-worker binary." version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/core/pvf/execute-worker/src/lib.rs b/node/core/pvf/execute-worker/src/lib.rs index d90cac2522fd..c6ee515f9093 100644 --- a/node/core/pvf/execute-worker/src/lib.rs +++ b/node/core/pvf/execute-worker/src/lib.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +//! Contains the logic for executing PVFs. Used by the polkadot-execute-worker binary. + pub use polkadot_node_core_pvf_common::executor_intf::Executor; // NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are diff --git a/node/core/pvf/prepare-worker/Cargo.toml b/node/core/pvf/prepare-worker/Cargo.toml index 2f18faac712c..9ee009de44bb 100644 --- a/node/core/pvf/prepare-worker/Cargo.toml +++ b/node/core/pvf/prepare-worker/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-node-core-pvf-prepare-worker" +description = "Polkadot crate that contains the logic for preparing PVFs. Used by the polkadot-prepare-worker binary." version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/core/pvf/prepare-worker/src/lib.rs b/node/core/pvf/prepare-worker/src/lib.rs index 228ad3d4668d..3f60163c6196 100644 --- a/node/core/pvf/prepare-worker/src/lib.rs +++ b/node/core/pvf/prepare-worker/src/lib.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +//! Contains the logic for preparing PVFs. Used by the polkadot-prepare-worker binary. + mod executor_intf; mod memory_stats; diff --git a/node/core/pvf/src/lib.rs b/node/core/pvf/src/lib.rs index 772c0b430c1b..2ed3f5242ded 100644 --- a/node/core/pvf/src/lib.rs +++ b/node/core/pvf/src/lib.rs @@ -16,7 +16,7 @@ #![warn(missing_docs)] -//! A crate that implements the PVF validation host. +//! The PVF validation host. Responsible for coordinating preparation and execution of PVFs. //! //! For more background, refer to the Implementer's Guide: [PVF //! Pre-checking](https://paritytech.github.io/polkadot/book/pvf-prechecking.html) and [Candidate From a1c8d720e05624d5f2ac43d89dcedd3d0d2e7342 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 9 Aug 2023 02:16:42 +1200 Subject: [PATCH 04/45] update weight file template (#7589) --- xcm/pallet-xcm-benchmarks/template.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/pallet-xcm-benchmarks/template.hbs b/xcm/pallet-xcm-benchmarks/template.hbs index a0ba5173258f..81cdf62812b6 100644 --- a/xcm/pallet-xcm-benchmarks/template.hbs +++ b/xcm/pallet-xcm-benchmarks/template.hbs @@ -5,7 +5,7 @@ //! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` //! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` -//! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} +//! WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} // Executed Command: {{#each args as |arg|}} From a3bde921bafcd7a790c59b2753aa90839afa6ee7 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 9 Aug 2023 18:28:48 +0200 Subject: [PATCH 05/45] Companion for #14412 (#7547) * Companion for 14412 * update lockfile for {"substrate"} * Trigger CI --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 652 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 452 insertions(+), 200 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86284315686c..2ef64180f1dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,6 +246,164 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-secret-scalar" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "ark-transcript", + "digest 0.10.7", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-transcript" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "digest 0.10.7", + "rand_core 0.6.4", + "sha3", +] + [[package]] name = "array-bytes" version = "6.1.0" @@ -396,6 +554,27 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bandersnatch_vrfs" +version = "0.0.1" +source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-serialize", + "ark-std", + "dleq_vrf", + "fflonk", + "merlin 3.0.0", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "ring 0.1.0", + "sha2 0.10.7", + "zeroize", +] + [[package]] name = "base-x" version = "0.2.8" @@ -438,7 +617,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "hash-db", "log", @@ -1012,6 +1191,20 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "common" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#0e948f3c28cbacecdd3020403c4841c0eb339213" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "fflonk", + "merlin 3.0.0", +] + [[package]] name = "common-path" version = "1.0.0" @@ -1685,6 +1878,22 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31ad93652f40969dead8d4bf897a41e9462095152eb21c56e5830537e41179dd" +[[package]] +name = "dleq_vrf" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=c86ebd4#c86ebd4114d3165d05f9ce28c1d9e8d7a9a4e801" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-secret-scalar", + "ark-serialize", + "ark-std", + "ark-transcript", + "arrayvec 0.7.4", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "dlmalloc" version = "0.2.4" @@ -1702,18 +1911,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6491709f76fb7ceb951244daf624d480198b427556084391d6e3c33d3ae74b9" +checksum = "029de870d175d11969524d91a3fb2cbf6d488b853bff99d41cf65e533ac7d9d2" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc5338a9f72ce29a81377d9039798fcc926fb471b2004666caf48e446dffbbf" +checksum = "cac43324656a1b05eb0186deb51f27d2d891c704c37f34de281ef6297ba193e5" dependencies = [ "common-path", "derive-syn-parse", @@ -1723,6 +1932,7 @@ dependencies = [ "regex", "syn 2.0.20", "termcolor", + "toml 0.7.3", "walkdir", ] @@ -2131,6 +2341,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "fflonk" +version = "0.1.0" +source = "git+https://github.com/w3f/fflonk#26a5045b24e169cffc1f9328ca83d71061145c40" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "merlin 3.0.0", +] + [[package]] name = "fiat-crypto" version = "0.1.20" @@ -2223,7 +2446,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", ] @@ -2246,7 +2469,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-support-procedural", @@ -2271,7 +2494,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "Inflector", "array-bytes", @@ -2319,7 +2542,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2330,7 +2553,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2347,7 +2570,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -2376,7 +2599,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-recursion", "futures", @@ -2397,7 +2620,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "aquamarine", "bitflags", @@ -2434,7 +2657,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "Inflector", "cfg-expr", @@ -2452,7 +2675,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2464,7 +2687,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro2", "quote", @@ -2474,7 +2697,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-executive", @@ -2501,7 +2724,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -2514,7 +2737,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "cfg-if", "frame-support", @@ -2533,7 +2756,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -2548,7 +2771,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "sp-api", @@ -2557,7 +2780,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "parity-scale-codec", @@ -2739,7 +2962,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "chrono", "frame-election-provider-support", @@ -4548,6 +4771,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "mick-jaeger" version = "0.1.8" @@ -4594,7 +4829,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "log", @@ -4613,7 +4848,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "anyhow", "jsonrpsee", @@ -5139,7 +5374,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5154,7 +5389,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -5170,7 +5405,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -5184,7 +5419,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5208,7 +5443,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5228,7 +5463,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -5247,7 +5482,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5262,7 +5497,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -5281,7 +5516,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -5305,7 +5540,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5323,7 +5558,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5342,7 +5577,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5359,7 +5594,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5376,7 +5611,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5394,7 +5629,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5417,7 +5652,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5430,7 +5665,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5449,7 +5684,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "docify", "frame-benchmarking", @@ -5468,7 +5703,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5491,7 +5726,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5507,7 +5742,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5527,7 +5762,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5544,7 +5779,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5561,7 +5796,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5580,7 +5815,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5597,7 +5832,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5613,7 +5848,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5629,7 +5864,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -5648,7 +5883,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5668,7 +5903,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -5679,7 +5914,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -5696,7 +5931,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5720,7 +5955,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5737,7 +5972,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5752,7 +5987,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5770,7 +6005,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5785,7 +6020,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5804,7 +6039,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5821,7 +6056,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -5842,7 +6077,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5858,12 +6093,11 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal 0.3.4", "log", "parity-scale-codec", "rand_chacha 0.2.2", @@ -5877,7 +6111,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5900,7 +6134,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5911,7 +6145,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "log", "sp-arithmetic", @@ -5920,7 +6154,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "sp-api", @@ -5929,7 +6163,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5946,7 +6180,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5961,7 +6195,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5979,7 +6213,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -5998,7 +6232,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-support", "frame-system", @@ -6014,7 +6248,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6030,7 +6264,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6042,7 +6276,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -6059,7 +6293,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -6074,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -6090,7 +6324,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -6105,7 +6339,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-benchmarking", "frame-support", @@ -6764,7 +6998,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "lru 0.11.0", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-jaeger", @@ -8762,6 +8996,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#0e948f3c28cbacecdd3020403c4841c0eb339213" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "common", + "fflonk", + "merlin 3.0.0", +] + [[package]] name = "ring" version = "0.16.20" @@ -9010,7 +9259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", - "ring", + "ring 0.16.20", "sct", "webpki", ] @@ -9022,7 +9271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", - "ring", + "ring 0.16.20", "rustls-webpki", "sct", ] @@ -9063,7 +9312,7 @@ version = "0.100.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] @@ -9111,7 +9360,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "log", "sp-core", @@ -9122,7 +9371,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "futures", @@ -9150,7 +9399,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "futures-timer", @@ -9173,7 +9422,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9188,7 +9437,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -9207,7 +9456,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -9218,7 +9467,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "chrono", @@ -9257,7 +9506,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "fnv", "futures", @@ -9283,7 +9532,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "hash-db", "kvdb", @@ -9309,7 +9558,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "futures", @@ -9334,7 +9583,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "fork-tree", @@ -9370,7 +9619,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "jsonrpsee", @@ -9392,7 +9641,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "async-channel", @@ -9426,7 +9675,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "jsonrpsee", @@ -9445,7 +9694,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9458,7 +9707,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ahash 0.8.2", "array-bytes", @@ -9499,7 +9748,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "finality-grandpa", "futures", @@ -9519,7 +9768,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "futures", @@ -9542,7 +9791,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -9564,7 +9813,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -9576,7 +9825,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "anyhow", "cfg-if", @@ -9593,7 +9842,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ansi_term", "futures", @@ -9609,7 +9858,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -9623,7 +9872,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "async-channel", @@ -9666,7 +9915,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-channel", "cid", @@ -9686,7 +9935,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "bitflags", @@ -9703,7 +9952,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ahash 0.8.2", "futures", @@ -9722,7 +9971,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "async-channel", @@ -9743,7 +9992,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "async-channel", @@ -9777,7 +10026,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "futures", @@ -9795,7 +10044,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "bytes", @@ -9829,7 +10078,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -9838,7 +10087,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "jsonrpsee", @@ -9869,7 +10118,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -9888,7 +10137,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "http", "jsonrpsee", @@ -9903,7 +10152,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "futures", @@ -9916,6 +10165,7 @@ dependencies = [ "sc-chain-spec", "sc-client-api", "sc-transaction-pool-api", + "sc-utils", "serde", "sp-api", "sp-blockchain", @@ -9929,7 +10179,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "directories", @@ -9993,7 +10243,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "log", "parity-scale-codec", @@ -10004,7 +10254,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "clap 4.2.5", "fs4", @@ -10018,7 +10268,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10037,7 +10287,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "libc", @@ -10056,7 +10306,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "chrono", "futures", @@ -10075,7 +10325,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ansi_term", "atty", @@ -10104,7 +10354,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10115,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "futures", @@ -10141,7 +10391,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "futures", @@ -10157,7 +10407,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-channel", "futures", @@ -10226,7 +10476,7 @@ dependencies = [ "arrayvec 0.5.2", "curve25519-dalek 2.1.3", "getrandom 0.1.16", - "merlin", + "merlin 2.0.1", "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", @@ -10252,7 +10502,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] @@ -10516,9 +10766,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.0" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ "digest 0.10.7", "keccak", @@ -10660,7 +10910,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek 4.0.0-rc.1", "rand_core 0.6.4", - "ring", + "ring 0.16.20", "rustc_version", "sha2 0.10.7", "subtle", @@ -10705,7 +10955,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "hash-db", "log", @@ -10726,7 +10976,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "Inflector", "blake2", @@ -10740,7 +10990,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "scale-info", @@ -10753,7 +11003,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "integer-sqrt", "num-traits", @@ -10767,7 +11017,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "scale-info", @@ -10780,7 +11030,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "sp-api", "sp-inherents", @@ -10791,7 +11041,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "log", @@ -10809,7 +11059,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "futures", @@ -10824,7 +11074,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "parity-scale-codec", @@ -10841,7 +11091,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "parity-scale-codec", @@ -10860,7 +11110,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "lazy_static", "parity-scale-codec", @@ -10879,7 +11129,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "finality-grandpa", "log", @@ -10897,7 +11147,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "scale-info", @@ -10909,9 +11159,11 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", + "arrayvec 0.7.4", + "bandersnatch_vrfs", "bitflags", "blake2", "bounded-collections", @@ -10925,7 +11177,7 @@ dependencies = [ "lazy_static", "libsecp256k1", "log", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", "paste", @@ -10954,7 +11206,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "blake2b_simd", "byteorder", @@ -10967,7 +11219,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "quote", "sp-core-hashing", @@ -10977,7 +11229,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -10986,7 +11238,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro2", "quote", @@ -10996,7 +11248,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "environmental", "parity-scale-codec", @@ -11007,7 +11259,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "serde_json", "sp-api", @@ -11018,7 +11270,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11032,7 +11284,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "bytes", "ed25519", @@ -11057,7 +11309,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "lazy_static", "sp-core", @@ -11068,7 +11320,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -11080,7 +11332,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "thiserror", "zstd 0.12.3+zstd.1.5.2", @@ -11089,7 +11341,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -11100,7 +11352,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -11118,7 +11370,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "scale-info", @@ -11132,7 +11384,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "sp-api", "sp-core", @@ -11142,7 +11394,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "backtrace", "lazy_static", @@ -11152,7 +11404,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "rustc-hash", "serde", @@ -11162,7 +11414,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "either", "hash256-std-hasher", @@ -11184,7 +11436,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -11202,7 +11454,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "Inflector", "proc-macro-crate", @@ -11214,7 +11466,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "scale-info", @@ -11229,7 +11481,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -11243,7 +11495,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "hash-db", "log", @@ -11264,7 +11516,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -11288,12 +11540,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11306,7 +11558,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "parity-scale-codec", @@ -11319,7 +11571,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "sp-std", @@ -11331,7 +11583,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "sp-api", "sp-runtime", @@ -11340,7 +11592,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "parity-scale-codec", @@ -11355,7 +11607,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ahash 0.8.2", "hash-db", @@ -11378,7 +11630,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11395,7 +11647,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -11406,7 +11658,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -11419,7 +11671,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "parity-scale-codec", "scale-info", @@ -11644,12 +11896,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -11668,7 +11920,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "hyper", "log", @@ -11680,7 +11932,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "jsonrpsee", @@ -11693,7 +11945,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11710,7 +11962,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "array-bytes", "async-trait", @@ -11736,7 +11988,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "futures", "substrate-test-utils-derive", @@ -11746,7 +11998,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11757,7 +12009,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "ansi_term", "build-helper", @@ -12627,7 +12879,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e966352d118a745678f720ae85e617d054dc8165" +source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" dependencies = [ "async-trait", "clap 4.2.5", @@ -13304,7 +13556,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] From fe3c92333b712a9a40315c38601c50bce0d794eb Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 10 Aug 2023 15:29:43 +1000 Subject: [PATCH 06/45] Remove unused code in runtime/polkadot/src/lib.rs (#7540) * remove SetStorageVersions runtime upgrade * remove unused imports --- runtime/polkadot/src/lib.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index 585e48dd5a4b..ac031671a4e6 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -1488,35 +1488,12 @@ pub type Migrations = migrations::Unreleased; #[allow(deprecated, missing_docs)] pub mod migrations { use super::*; - use frame_support::traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion}; /// Unreleased migrations. Add new ones here: pub type Unreleased = ( pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, ); - - /// Migrations that set `StorageVersion`s we missed to set. - pub struct SetStorageVersions; - - impl OnRuntimeUpgrade for SetStorageVersions { - fn on_runtime_upgrade() -> Weight { - // `Referenda` pallet was added on chain after the migration to version `1` was added. - // Thus, it never required the migration and we just missed to set the correct `StorageVersion`. - let storage_version = Referenda::on_chain_storage_version(); - if storage_version < 1 { - StorageVersion::new(1).put::(); - } - - // Was missed as part of: `runtime_common::session::migration::ClearOldSessionStorage`. - let storage_version = Historical::on_chain_storage_version(); - if storage_version < 1 { - StorageVersion::new(1).put::(); - } - - RocksDbWeight::get().reads_writes(2, 2) - } - } } /// Unchecked extrinsic type as expected by this runtime. From 95c77cc51fa1b95b31395524f33ec1f6011aef52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 10 Aug 2023 10:42:43 +0200 Subject: [PATCH 07/45] Companion for substrate#12970 (#6807) * Runtime companion changes * updates runtime configs * Fixes runtime-test runtime configs * Uses ElectionBounds and builder from own mod * updates new bounds mod * Fixes test-runtime mock * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 368 ++++++++++++++++---------------- runtime/kusama/src/lib.rs | 20 +- runtime/polkadot/src/lib.rs | 21 +- runtime/test-runtime/src/lib.rs | 17 +- runtime/westend/src/lib.rs | 19 +- 5 files changed, 225 insertions(+), 220 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ef64180f1dd..1ad880641445 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -617,7 +617,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "hash-db", "log", @@ -2446,7 +2446,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", ] @@ -2469,7 +2469,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-support-procedural", @@ -2494,7 +2494,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "Inflector", "array-bytes", @@ -2542,7 +2542,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2553,7 +2553,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2570,7 +2570,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -2599,7 +2599,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-recursion", "futures", @@ -2620,7 +2620,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "aquamarine", "bitflags", @@ -2657,7 +2657,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "Inflector", "cfg-expr", @@ -2675,7 +2675,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2687,7 +2687,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro2", "quote", @@ -2697,7 +2697,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-executive", @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -2737,7 +2737,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "cfg-if", "frame-support", @@ -2756,7 +2756,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -2771,7 +2771,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "sp-api", @@ -2780,7 +2780,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "parity-scale-codec", @@ -2962,7 +2962,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "chrono", "frame-election-provider-support", @@ -4829,7 +4829,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "log", @@ -4848,7 +4848,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "anyhow", "jsonrpsee", @@ -5374,7 +5374,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5389,7 +5389,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -5405,7 +5405,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -5419,7 +5419,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5443,7 +5443,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5463,7 +5463,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -5482,7 +5482,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5497,7 +5497,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -5516,7 +5516,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -5540,7 +5540,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5558,7 +5558,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5577,7 +5577,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5594,7 +5594,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5611,7 +5611,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5629,7 +5629,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5652,7 +5652,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5665,7 +5665,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5684,7 +5684,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "docify", "frame-benchmarking", @@ -5703,7 +5703,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5726,7 +5726,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5742,7 +5742,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5762,7 +5762,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5779,7 +5779,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5796,7 +5796,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5815,7 +5815,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5832,7 +5832,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5848,7 +5848,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5864,7 +5864,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -5883,7 +5883,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5903,7 +5903,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -5914,7 +5914,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -5931,7 +5931,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5955,7 +5955,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5972,7 +5972,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -5987,7 +5987,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6005,7 +6005,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6020,7 +6020,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6039,7 +6039,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6056,7 +6056,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -6077,7 +6077,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6093,7 +6093,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6111,7 +6111,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6134,7 +6134,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6145,7 +6145,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "log", "sp-arithmetic", @@ -6154,7 +6154,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "sp-api", @@ -6163,7 +6163,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6180,7 +6180,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6195,7 +6195,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6213,7 +6213,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6232,7 +6232,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-support", "frame-system", @@ -6248,7 +6248,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6264,7 +6264,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6276,7 +6276,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6293,7 +6293,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6324,7 +6324,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -6339,7 +6339,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-benchmarking", "frame-support", @@ -9360,7 +9360,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "log", "sp-core", @@ -9371,7 +9371,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "futures", @@ -9399,7 +9399,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "futures-timer", @@ -9422,7 +9422,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9437,7 +9437,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -9456,7 +9456,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -9467,7 +9467,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "chrono", @@ -9506,7 +9506,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "fnv", "futures", @@ -9532,7 +9532,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "hash-db", "kvdb", @@ -9558,7 +9558,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "futures", @@ -9583,7 +9583,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "fork-tree", @@ -9619,7 +9619,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "jsonrpsee", @@ -9641,7 +9641,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "async-channel", @@ -9675,7 +9675,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "jsonrpsee", @@ -9694,7 +9694,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9707,7 +9707,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ahash 0.8.2", "array-bytes", @@ -9748,7 +9748,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "finality-grandpa", "futures", @@ -9768,7 +9768,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "futures", @@ -9791,7 +9791,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -9813,7 +9813,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -9825,7 +9825,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "anyhow", "cfg-if", @@ -9842,7 +9842,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ansi_term", "futures", @@ -9858,7 +9858,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -9872,7 +9872,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "async-channel", @@ -9915,7 +9915,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-channel", "cid", @@ -9935,7 +9935,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "bitflags", @@ -9952,7 +9952,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ahash 0.8.2", "futures", @@ -9971,7 +9971,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "async-channel", @@ -9992,7 +9992,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "async-channel", @@ -10026,7 +10026,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "futures", @@ -10044,7 +10044,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "bytes", @@ -10078,7 +10078,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10087,7 +10087,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "jsonrpsee", @@ -10118,7 +10118,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10137,7 +10137,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "http", "jsonrpsee", @@ -10152,7 +10152,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "futures", @@ -10179,7 +10179,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "directories", @@ -10243,7 +10243,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "log", "parity-scale-codec", @@ -10254,7 +10254,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "clap 4.2.5", "fs4", @@ -10268,7 +10268,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10287,7 +10287,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "libc", @@ -10306,7 +10306,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "chrono", "futures", @@ -10325,7 +10325,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ansi_term", "atty", @@ -10354,7 +10354,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10365,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "futures", @@ -10391,7 +10391,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "futures", @@ -10407,7 +10407,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-channel", "futures", @@ -10955,7 +10955,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "hash-db", "log", @@ -10976,7 +10976,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "Inflector", "blake2", @@ -10990,7 +10990,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "scale-info", @@ -11003,7 +11003,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "integer-sqrt", "num-traits", @@ -11017,7 +11017,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "scale-info", @@ -11030,7 +11030,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "sp-api", "sp-inherents", @@ -11041,7 +11041,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "log", @@ -11059,7 +11059,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "futures", @@ -11074,7 +11074,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "parity-scale-codec", @@ -11091,7 +11091,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "parity-scale-codec", @@ -11110,7 +11110,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11129,7 +11129,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "finality-grandpa", "log", @@ -11147,7 +11147,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "scale-info", @@ -11159,7 +11159,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11206,7 +11206,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "blake2b_simd", "byteorder", @@ -11219,7 +11219,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "quote", "sp-core-hashing", @@ -11229,7 +11229,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11238,7 +11238,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro2", "quote", @@ -11248,7 +11248,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "environmental", "parity-scale-codec", @@ -11259,7 +11259,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "serde_json", "sp-api", @@ -11270,7 +11270,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11284,7 +11284,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "bytes", "ed25519", @@ -11309,7 +11309,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "lazy_static", "sp-core", @@ -11320,7 +11320,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -11332,7 +11332,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "thiserror", "zstd 0.12.3+zstd.1.5.2", @@ -11341,7 +11341,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -11352,7 +11352,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -11370,7 +11370,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "scale-info", @@ -11384,7 +11384,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "sp-api", "sp-core", @@ -11394,7 +11394,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "backtrace", "lazy_static", @@ -11404,7 +11404,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "rustc-hash", "serde", @@ -11414,7 +11414,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "either", "hash256-std-hasher", @@ -11436,7 +11436,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -11454,7 +11454,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "Inflector", "proc-macro-crate", @@ -11466,7 +11466,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "scale-info", @@ -11481,7 +11481,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -11495,7 +11495,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "hash-db", "log", @@ -11516,7 +11516,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -11540,12 +11540,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11558,7 +11558,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "parity-scale-codec", @@ -11571,7 +11571,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "sp-std", @@ -11583,7 +11583,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "sp-api", "sp-runtime", @@ -11592,7 +11592,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "parity-scale-codec", @@ -11607,7 +11607,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ahash 0.8.2", "hash-db", @@ -11630,7 +11630,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11647,7 +11647,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -11658,7 +11658,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -11671,7 +11671,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "parity-scale-codec", "scale-info", @@ -11896,12 +11896,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -11920,7 +11920,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "hyper", "log", @@ -11932,7 +11932,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "jsonrpsee", @@ -11945,7 +11945,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11962,7 +11962,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "array-bytes", "async-trait", @@ -11988,7 +11988,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "futures", "substrate-test-utils-derive", @@ -11998,7 +11998,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12009,7 +12009,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "ansi_term", "build-helper", @@ -12879,7 +12879,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#19eb56a3fc51140b269e339ecb7e9a4a378c26ff" +source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" dependencies = [ "async-trait", "clap 4.2.5", diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 335ef79fab58..0248b02e12f6 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -53,7 +53,8 @@ use runtime_parachains::{ use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; use frame_election_provider_support::{ - generate_solution_type, onchain, NposSolution, SequentialPhragmen, + bounds::ElectionBoundsBuilder, generate_solution_type, onchain, NposSolution, + SequentialPhragmen, }; use frame_support::{ construct_runtime, parameter_types, @@ -399,11 +400,12 @@ parameter_types! { // 1 hour session, 15 minutes unsigned phase, 8 offchain executions. pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 8; - /// We take the top 12500 nominators as electing voters.. pub const MaxElectingVoters: u32 = 12_500; - /// ... and all of the validators as electable targets. Whilst this is the case, we cannot and - /// shall not increase the size of the validator intentions. - pub const MaxElectableTargets: u16 = u16::MAX; + /// We take the top 12500 nominators as electing voters and all of the validators as electable + /// targets. Whilst this is the case, we cannot and shall not increase the size of the + /// validator intentions. + pub ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = + ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); pub NposSolutionPriority: TransactionPriority = Perbill::from_percent(90) * TransactionPriority::max_value(); /// Setup election pallet to support maximum winners upto 2000. This will mean Staking Pallet @@ -428,8 +430,7 @@ impl onchain::Config for OnChainSeqPhragmen { type DataProvider = Staking; type WeightInfo = weights::frame_election_provider_support::WeightInfo; type MaxWinners = MaxActiveValidators; - type VotersBound = MaxElectingVoters; - type TargetsBound = MaxElectableTargets; + type Bounds = ElectionBounds; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { @@ -495,9 +496,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig; type ForceOrigin = EitherOf, StakingAdmin>; type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; - type MaxElectingVoters = MaxElectingVoters; - type MaxElectableTargets = MaxElectableTargets; type MaxWinners = MaxActiveValidators; + type ElectionBounds = ElectionBounds; } parameter_types! { @@ -564,7 +564,6 @@ parameter_types! { } impl pallet_staking::Config for Runtime { - type MaxNominations = MaxNominations; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; @@ -586,6 +585,7 @@ impl pallet_staking::Config for Runtime { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type VoterList = VoterList; type TargetList = UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index ac031671a4e6..fbf896cdedc5 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -40,7 +40,9 @@ use runtime_parachains::{ use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; -use frame_election_provider_support::{generate_solution_type, onchain, SequentialPhragmen}; +use frame_election_provider_support::{ + bounds::ElectionBoundsBuilder, generate_solution_type, onchain, SequentialPhragmen, +}; use frame_support::{ construct_runtime, parameter_types, traits::{ @@ -393,11 +395,12 @@ parameter_types! { // 4 hour session, 1 hour unsigned phase, 32 offchain executions. pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 32; - /// We take the top 22500 nominators as electing voters.. pub const MaxElectingVoters: u32 = 22_500; - /// ... and all of the validators as electable targets. Whilst this is the case, we cannot and - /// shall not increase the size of the validator intentions. - pub const MaxElectableTargets: u16 = u16::MAX; + /// We take the top 22500 nominators as electing voters and all of the validators as electable + /// targets. Whilst this is the case, we cannot and shall not increase the size of the + /// validator intentions. + pub ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = + ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); /// Setup election pallet to support maximum winners upto 1200. This will mean Staking Pallet /// cannot have active validators higher than this count. pub const MaxActiveValidators: u32 = 1200; @@ -420,8 +423,7 @@ impl onchain::Config for OnChainSeqPhragmen { type DataProvider = Staking; type WeightInfo = weights::frame_election_provider_support::WeightInfo; type MaxWinners = MaxActiveValidators; - type VotersBound = MaxElectingVoters; - type TargetsBound = MaxElectableTargets; + type Bounds = ElectionBounds; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { @@ -487,9 +489,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig; type ForceOrigin = EitherOf, StakingAdmin>; type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; - type MaxElectingVoters = MaxElectingVoters; - type MaxElectableTargets = MaxElectableTargets; type MaxWinners = MaxActiveValidators; + type ElectionBounds = ElectionBounds; } parameter_types! { @@ -572,7 +573,6 @@ impl pallet_staking::EraPayout for EraPayout { } impl pallet_staking::Config for Runtime { - type MaxNominations = MaxNominations; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; @@ -594,6 +594,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; diff --git a/runtime/test-runtime/src/lib.rs b/runtime/test-runtime/src/lib.rs index 9e2f2a66455b..c9f3aa6cb203 100644 --- a/runtime/test-runtime/src/lib.rs +++ b/runtime/test-runtime/src/lib.rs @@ -36,7 +36,10 @@ use polkadot_runtime_parachains::{ use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; -use frame_election_provider_support::{onchain, SequentialPhragmen}; +use frame_election_provider_support::{ + bounds::{ElectionBounds, ElectionBoundsBuilder}, + onchain, SequentialPhragmen, +}; use frame_support::{ construct_runtime, parameter_types, traits::{Everything, KeyOwnerProofSystem, WithdrawReasons}, @@ -315,8 +318,8 @@ parameter_types! { pub storage OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxAuthorities: u32 = 100_000; pub const OnChainMaxWinners: u32 = u32::MAX; - pub const MaxElectingVoters: u32 = u32::MAX; - pub const MaxElectableTargets: u16 = u16::MAX; + // Unbounded number of election targets and voters. + pub ElectionBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build(); } pub struct OnChainSeqPhragmen; @@ -325,13 +328,14 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); + type Bounds = ElectionBoundsOnChain; type MaxWinners = OnChainMaxWinners; - type VotersBound = MaxElectingVoters; - type TargetsBound = MaxElectableTargets; } +/// Upper limit on the number of NPOS nominations. +const MAX_QUOTA_NOMINATIONS: u32 = 16; + impl pallet_staking::Config for Runtime { - type MaxNominations = frame_support::pallet_prelude::ConstU32<16>; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; @@ -355,6 +359,7 @@ impl pallet_staking::Config for Runtime { // to bags-list is a no-op, but the storage version will be updated. type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index dd4bcff32e39..4b4659442cff 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -22,7 +22,7 @@ use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; -use frame_election_provider_support::{onchain, SequentialPhragmen}; +use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, SequentialPhragmen}; use frame_support::{ construct_runtime, parameter_types, traits::{ @@ -371,11 +371,12 @@ parameter_types! { // 1 hour session, 15 minutes unsigned phase, 4 offchain executions. pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 4; - /// We take the top 22500 nominators as electing voters.. pub const MaxElectingVoters: u32 = 22_500; - /// ... and all of the validators as electable targets. Whilst this is the case, we cannot and - /// shall not increase the size of the validator intentions. - pub const MaxElectableTargets: u16 = u16::MAX; + /// We take the top 22500 nominators as electing voters and all of the validators as electable + /// targets. Whilst this is the case, we cannot and shall not increase the size of the + /// validator intentions. + pub ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = + ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); // Maximum winners that can be chosen as active validators pub const MaxActiveValidators: u32 = 1000; @@ -398,8 +399,7 @@ impl onchain::Config for OnChainSeqPhragmen { type DataProvider = Staking; type WeightInfo = weights::frame_election_provider_support::WeightInfo; type MaxWinners = MaxActiveValidators; - type VotersBound = MaxElectingVoters; - type TargetsBound = MaxElectableTargets; + type Bounds = ElectionBounds; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { @@ -465,9 +465,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig; type ForceOrigin = EnsureRoot; type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; - type MaxElectingVoters = MaxElectingVoters; - type MaxElectableTargets = MaxElectableTargets; type MaxWinners = MaxActiveValidators; + type ElectionBounds = ElectionBounds; } parameter_types! { @@ -508,7 +507,6 @@ parameter_types! { } impl pallet_staking::Config for Runtime { - type MaxNominations = MaxNominations; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; @@ -530,6 +528,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; From c2efce0d60d656cb13f5ade52bf3d866e17085fa Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Thu, 10 Aug 2023 13:17:24 +0200 Subject: [PATCH 08/45] Add counter for unapproved candidates (#7491) * Add counter for unapproved candidates * Update metrics * Split metrics * Remove depth metric * Print only the oldest unapproved candidates * Update logging condition * Fix logging condition * Update logging * Update node/core/approval-voting/src/lib.rs Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --- node/core/approval-voting/src/lib.rs | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/node/core/approval-voting/src/lib.rs b/node/core/approval-voting/src/lib.rs index a6a74da50480..05b92f459529 100644 --- a/node/core/approval-voting/src/lib.rs +++ b/node/core/approval-voting/src/lib.rs @@ -160,6 +160,7 @@ struct MetricsInner { time_db_transaction: prometheus::Histogram, time_recover_and_approve: prometheus::Histogram, candidate_signatures_requests_total: prometheus::Counter, + unapproved_candidates_in_unfinalized_chain: prometheus::Gauge, } /// Approval Voting metrics. @@ -246,6 +247,12 @@ impl Metrics { fn time_recover_and_approve(&self) -> Option { self.0.as_ref().map(|metrics| metrics.time_recover_and_approve.start_timer()) } + + fn on_unapproved_candidates_in_unfinalized_chain(&self, count: usize) { + if let Some(metrics) = &self.0 { + metrics.unapproved_candidates_in_unfinalized_chain.set(count as u64); + } + } } impl metrics::Metrics for Metrics { @@ -336,6 +343,13 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + unapproved_candidates_in_unfinalized_chain: prometheus::register( + prometheus::Gauge::new( + "polkadot_parachain_approval_unapproved_candidates_in_unfinalized_chain", + "Number of unapproved candidates in unfinalized chain", + )?, + registry, + )?, }; Ok(Metrics(Some(metrics))) @@ -1298,6 +1312,7 @@ async fn handle_from_overseer( lower_bound, wakeups, &mut approved_ancestor_span, + &metrics, ) .await { @@ -1423,9 +1438,11 @@ async fn handle_approved_ancestor( lower_bound: BlockNumber, wakeups: &Wakeups, span: &mut jaeger::Span, + metrics: &Metrics, ) -> SubsystemResult> { const MAX_TRACING_WINDOW: usize = 200; const ABNORMAL_DEPTH_THRESHOLD: usize = 5; + const LOGGING_DEPTH_THRESHOLD: usize = 10; let mut span = span .child("handle-approved-ancestor") .with_stage(jaeger::Stage::ApprovalChecking); @@ -1471,6 +1488,7 @@ async fn handle_approved_ancestor( } else { Vec::new() }; + let ancestry_len = ancestry.len(); let mut block_descriptions = Vec::new(); @@ -1534,6 +1552,17 @@ async fn handle_approved_ancestor( unapproved.len(), entry.candidates().len(), ); + if ancestry_len >= LOGGING_DEPTH_THRESHOLD && i > ancestry_len - LOGGING_DEPTH_THRESHOLD + { + gum::trace!( + target: LOG_TARGET, + ?block_hash, + "Unapproved candidates at depth {}: {:?}", + bits.len(), + unapproved + ) + } + metrics.on_unapproved_candidates_in_unfinalized_chain(unapproved.len()); entry_span.add_uint_tag("unapproved-candidates", unapproved.len() as u64); for candidate_hash in unapproved { match db.load_candidate_entry(&candidate_hash)? { From b420bad817e68e9b60f0956ba66f6520bfe92cae Mon Sep 17 00:00:00 2001 From: Chevdor Date: Fri, 11 Aug 2023 15:28:39 +0200 Subject: [PATCH 09/45] Publish RC container images (#7556) * WIP * Add missing checkout * Add debuggin * Fix VAR name * Bug fix * Rework jobs * Revert "Rework jobs" This reverts commit 2bfa79fd3ae633c17403b838f9a5025f0f7fc3f3. * Add cache * Add temp default for testing * Add missing checkout * Fix patch * Comment out the GPG check for now * Rename polkadot_injected_release into a more appropriate polkadot_injected_debian * Refactoring / renaming * Introduce a generic image for binary injection * Flag files to be deleted and changes to be done * WIP * Fix multi binaries images * Add test build scripts * Remove old file, add polkadot build-injected script * Fix doc * Fix tagging * Add build of the injected container * Fix for docker * Remove the need for TTY * Handling container publishing * Fix owner and registry * Fix vars * Fix repo * Fix var naming * Fix case when there is no tag * Fix case with no tag * Handle error * Fix spacings * Fix tags * Remove unnecessary grep that may fail * Add final check * Clean up and introduce GPG check * Add doc * Add doc * Update doc/docker.md Co-authored-by: Mira Ressel * type Co-authored-by: Mira Ressel * Fix used VAR * Improve doc * ci: Update .build-push-image jobs to use the new build-injected.sh * ci: fix path to build-injected.sh script * Rename the release artifacts folder to prevent confusion due to a similar folder in the gitlab CI * ci: check out polkadot repo in .build-push-image This seems far cleaner than copying the entire scripts/ folder into our job artifacts. * feat(build-injected.sh): make PROJECT_ROOT configurable This lets us avoid a dependency on git in our CI image. * ci: build injected images with buildah * ci: pass full image names to zombienet * Add missing ignore --------- Co-authored-by: Mira Ressel --- .github/workflows/check-licenses.yml | 2 +- .../workflows/release-40_publish-rc-image.yml | 132 ++++++++++++++++++ .../release-50_publish-docker-release.yml | 2 +- .../release-51_publish-docker-manual.yml | 2 +- .gitignore | 4 + .gitlab-ci.yml | 36 +++-- doc/docker.md | 86 +++++++----- scripts/ci/common/lib.sh | 70 ++++++++++ .../adder-collator/build-injected.sh | 13 ++ .../dockerfiles/adder-collator/test-build.sh | 23 +++ .../ci/dockerfiles/binary_injected.Dockerfile | 48 +++++++ scripts/ci/dockerfiles/build-injected.sh | 92 ++++++++++++ .../dockerfiles/collator_injected.Dockerfile | 49 ------- scripts/ci/dockerfiles/entrypoint.sh | 18 +++ .../ci/dockerfiles/malus/build-injected.sh | 14 ++ scripts/ci/dockerfiles/malus/test-build.sh | 19 +++ .../ci/dockerfiles/malus_injected.Dockerfile | 50 ------- scripts/ci/dockerfiles/polkadot/README.md | 2 + .../ci/dockerfiles/polkadot/build-injected.sh | 13 ++ scripts/ci/dockerfiles/polkadot/build.sh | 27 ---- .../dockerfiles/polkadot/docker-compose.yml | 13 +- .../polkadot_Dockerfile.README.md | 0 .../polkadot/polkadot_builder.Dockerfile | 2 +- .../polkadot_injected_debian.Dockerfile} | 2 +- scripts/ci/dockerfiles/polkadot/test-build.sh | 18 +++ .../polkadot_injected_debug.Dockerfile | 48 ------- .../ci/dockerfiles/staking-miner/README.md | 37 +++++ .../staking-miner/build-injected.sh | 13 ++ scripts/ci/dockerfiles/staking-miner/build.sh | 13 ++ .../staking-miner_builder.Dockerfile | 11 +- .../staking-miner_injected.Dockerfile | 43 ------ .../dockerfiles/staking-miner/test-build.sh | 18 +++ scripts/ci/gitlab/pipeline/build.yml | 4 - scripts/ci/gitlab/pipeline/publish.yml | 54 +++---- utils/staking-miner/README.md | 6 +- 35 files changed, 661 insertions(+), 323 deletions(-) create mode 100644 .github/workflows/release-40_publish-rc-image.yml create mode 100755 scripts/ci/dockerfiles/adder-collator/build-injected.sh create mode 100755 scripts/ci/dockerfiles/adder-collator/test-build.sh create mode 100644 scripts/ci/dockerfiles/binary_injected.Dockerfile create mode 100755 scripts/ci/dockerfiles/build-injected.sh delete mode 100644 scripts/ci/dockerfiles/collator_injected.Dockerfile create mode 100755 scripts/ci/dockerfiles/entrypoint.sh create mode 100755 scripts/ci/dockerfiles/malus/build-injected.sh create mode 100755 scripts/ci/dockerfiles/malus/test-build.sh delete mode 100644 scripts/ci/dockerfiles/malus_injected.Dockerfile create mode 100755 scripts/ci/dockerfiles/polkadot/build-injected.sh delete mode 100755 scripts/ci/dockerfiles/polkadot/build.sh rename scripts/ci/dockerfiles/{ => polkadot}/polkadot_Dockerfile.README.md (100%) rename scripts/ci/dockerfiles/{polkadot_injected_release.Dockerfile => polkadot/polkadot_injected_debian.Dockerfile} (95%) create mode 100755 scripts/ci/dockerfiles/polkadot/test-build.sh delete mode 100644 scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile create mode 100644 scripts/ci/dockerfiles/staking-miner/README.md create mode 100755 scripts/ci/dockerfiles/staking-miner/build-injected.sh create mode 100755 scripts/ci/dockerfiles/staking-miner/build.sh delete mode 100644 scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile create mode 100755 scripts/ci/dockerfiles/staking-miner/test-build.sh diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index a4c8d5d97424..522037b6827c 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout sources - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v3 - uses: actions/setup-node@v3.7.0 with: node-version: '18.x' diff --git a/.github/workflows/release-40_publish-rc-image.yml b/.github/workflows/release-40_publish-rc-image.yml new file mode 100644 index 000000000000..a821eaa033fd --- /dev/null +++ b/.github/workflows/release-40_publish-rc-image.yml @@ -0,0 +1,132 @@ +name: Release - Publish RC Container image +# see https://github.com/paritytech/release-engineering/issues/97#issuecomment-1651372277 + +on: + workflow_dispatch: + inputs: + release_id: + description: | + Release ID. + You can find it using the command: + curl -s \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/$OWNER/$REPO/releases | \ + jq '.[] | { name: .name, id: .id }' + required: true + type: string + registry: + description: "Container registry" + required: true + type: string + default: docker.io + owner: + description: Owner of the container image repo + required: true + type: string + default: parity + +env: + RELEASE_ID: ${{ inputs.release_id }} + ENGINE: docker + REGISTRY: ${{ inputs.registry }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCKER_OWNER: ${{ inputs.owner || github.repository_owner }} + REPO: ${{ github.repository }} + ARTIFACT_FOLDER: release-artifacts + +jobs: + fetch-artifacts: + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Fetch all artifacts + run: | + . ./scripts/ci/common/lib.sh + fetch_release_artifacts + + - name: Cache the artifacts + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + key: artifacts-${{ github.sha }} + path: | + ${ARTIFACT_FOLDER}/**/* + + build-container: + runs-on: ubuntu-latest + needs: fetch-artifacts + + strategy: + matrix: + binary: ["polkadot", "staking-miner"] + + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Get artifacts from cache + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + key: artifacts-${{ github.sha }} + path: | + ${ARTIFACT_FOLDER}/**/* + + - name: Check sha256 ${{ matrix.binary }} + working-directory: ${ARTIFACT_FOLDER} + run: | + . ../scripts/ci/common/lib.sh + + echo "Checking binary ${{ matrix.binary }}" + check_sha256 ${{ matrix.binary }} && echo "OK" || echo "ERR" + + - name: Check GPG ${{ matrix.binary }} + working-directory: ${ARTIFACT_FOLDER} + run: | + . ../scripts/ci/common/lib.sh + import_gpg_keys + check_gpg ${{ matrix.binary }} + + - name: Fetch commit and tag + id: fetch_refs + run: | + release=release-${{ inputs.release_id }} && \ + echo "release=${release}" >> $GITHUB_OUTPUT + + commit=$(git rev-parse --short HEAD) && \ + echo "commit=${commit}" >> $GITHUB_OUTPUT + + tag=$(git name-rev --tags --name-only $(git rev-parse HEAD)) && \ + [ "${tag}" != "undefined" ] && echo "tag=${tag}" >> $GITHUB_OUTPUT || \ + echo "No tag, doing without" + + - name: Build Injected Container image for ${{ matrix.binary }} + env: + BIN_FOLDER: ${ARTIFACT_FOLDER} + BINARY: ${{ matrix.binary }} + TAGS: ${{join(steps.fetch_refs.outputs.*, ',')}} + run: | + echo "Building container for ${{ matrix.binary }}" + ./scripts/ci/dockerfiles/build-injected.sh + + - name: Login to Dockerhub + uses: docker/login-action@v2 + with: + username: ${{ inputs.owner }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Push Container image for ${{ matrix.binary }} + id: docker_push + env: + BINARY: ${{ matrix.binary }} + run: | + $ENGINE images | grep ${BINARY} + $ENGINE push --all-tags ${REGISTRY}/${DOCKER_OWNER}/${BINARY} + + - name: Check version for the published image for ${{ matrix.binary }} + env: + BINARY: ${{ matrix.binary }} + RELEASE_TAG: ${{ steps.fetch_refs.outputs.release }} + run: | + echo "Checking tag ${RELEASE_TAG} for image ${REGISTRY}/${DOCKER_OWNER}/${BINARY}" + $ENGINE run -i ${REGISTRY}/${DOCKER_OWNER}/${BINARY}:${RELEASE_TAG} --version diff --git a/.github/workflows/release-50_publish-docker-release.yml b/.github/workflows/release-50_publish-docker-release.yml index a6bf19162a46..81e5caa718f3 100644 --- a/.github/workflows/release-50_publish-docker-release.yml +++ b/.github/workflows/release-50_publish-docker-release.yml @@ -30,7 +30,7 @@ jobs: uses: docker/build-push-action@v4 with: push: true - file: scripts/ci/dockerfiles/polkadot_injected_release.Dockerfile + file: scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile tags: | parity/polkadot:latest parity/polkadot:${{ github.event.release.tag_name }} diff --git a/.github/workflows/release-51_publish-docker-manual.yml b/.github/workflows/release-51_publish-docker-manual.yml index 0c973d33b71c..919769f8700d 100644 --- a/.github/workflows/release-51_publish-docker-manual.yml +++ b/.github/workflows/release-51_publish-docker-manual.yml @@ -37,7 +37,7 @@ jobs: uses: docker/build-push-action@v4 with: push: true - file: scripts/ci/dockerfiles/polkadot_injected_release.Dockerfile + file: scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile tags: | parity/polkadot:latest parity/polkadot:${{ github.event.inputs.version }} diff --git a/.gitignore b/.gitignore index 0c6913dac340..61ef9e91a55e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ polkadot.* !polkadot.service .DS_Store .env + +artifacts +release-artifacts +release.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5056012e588e..5a84bbfeba85 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -159,31 +159,39 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 .build-push-image: + variables: + CI_IMAGE: "${BUILDAH_IMAGE}" + + REGISTRY: "docker.io" + DOCKER_OWNER: "paritypr" + DOCKER_USER: "${PARITYPR_USER}" + DOCKER_PASS: "${PARITYPR_PASS}" + IMAGE: "${REGISTRY}/${DOCKER_OWNER}/${IMAGE_NAME}" + + ENGINE: "${BUILDAH_COMMAND}" + BUILDAH_FORMAT: "docker" + SKIP_IMAGE_VALIDATION: 1 + + PROJECT_ROOT: "." + BIN_FOLDER: "./artifacts" + VCS_REF: "${CI_COMMIT_SHA}" + before_script: - !reference [.common-before-script, before_script] - test -s ./artifacts/VERSION || exit 1 - test -s ./artifacts/EXTRATAG || exit 1 - - VERSION="$(cat ./artifacts/VERSION)" + - export VERSION="$(cat ./artifacts/VERSION)" - EXTRATAG="$(cat ./artifacts/EXTRATAG)" - echo "Polkadot version = ${VERSION} (EXTRATAG = ${EXTRATAG})" script: - test "$DOCKER_USER" -a "$DOCKER_PASS" || ( echo "no docker credentials provided"; exit 1 ) - - cd ./artifacts - - $BUILDAH_COMMAND build - --format=docker - --build-arg VCS_REF="${CI_COMMIT_SHA}" - --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" - --build-arg IMAGE_NAME="${IMAGE_NAME}" - --tag "$IMAGE_NAME:$VERSION" - --tag "$IMAGE_NAME:$EXTRATAG" - --file ${DOCKERFILE} . - # The job will success only on the protected branch + - TAGS="${VERSION},${EXTRATAG}" scripts/ci/dockerfiles/build-injected.sh - echo "$DOCKER_PASS" | - buildah login --username "$DOCKER_USER" --password-stdin docker.io + buildah login --username "$DOCKER_USER" --password-stdin "${REGISTRY}" - $BUILDAH_COMMAND info - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$VERSION" - - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$EXTRATAG" + - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE:$VERSION" + - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE:$EXTRATAG" after_script: - buildah logout --all diff --git a/doc/docker.md b/doc/docker.md index e8b7fa74732e..f20c2d001edd 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -1,43 +1,58 @@ -# Using Docker +# Using Containers + +The following commands should work no matter if you use Docker or Podman. In general, Podman is recommended. All commands are "engine neutral" so you can use the container engine of your choice while still being able to copy/paste the commands below. + +Let's start defining Podman as our engine: +``` +ENGINE=podman +``` + +If you prefer to stick with Docker, use: +``` +ENGINE=docker +``` ## The easiest way -The easiest/faster option to run Polkadot in Docker is to use the latest release images. These are small images that use the latest official release of the Polkadot binary, pulled from our package repository. +The easiest/faster option to run Polkadot in Docker is to use the latest release images. These are small images that use the latest official release of the Polkadot binary, pulled from our Debian package. -**_Following examples are running on westend chain and without SSL. They can be used to quick start and learn how Polkadot needs to be configured. Please find out how to secure your node, if you want to operate it on the internet. Do not expose RPC and WS ports, if they are not correctly configured._** +**_The following examples are running on westend chain and without SSL. They can be used to quick start and learn how Polkadot needs to be configured. Please find out how to secure your node, if you want to operate it on the internet. Do not expose RPC and WS ports, if they are not correctly configured._** Let's first check the version we have. The first time you run this command, the Polkadot docker image will be downloaded. This takes a bit of time and bandwidth, be patient: ```bash -docker run --rm -it parity/polkadot:latest --version +$ENGINE run --rm -it parity/polkadot:latest --version ``` You can also pass any argument/flag that Polkadot supports: ```bash -docker run --rm -it parity/polkadot:latest --chain westend --name "PolkaDocker" +$ENGINE run --rm -it parity/polkadot:latest --chain westend --name "PolkaDocker" ``` ## Examples -Once you are done experimenting and picking the best node name :) you can start Polkadot as daemon, exposes the Polkadot ports and mount a volume that will keep your blockchain data locally. Make sure that you set the ownership of your local directory to the Polkadot user that is used by the container. Set user id 1000 and group id 1000, by running `chown 1000.1000 /my/local/folder -R` if you use a bind mount. - -To start a Polkadot node on default rpc port 9933 and default p2p port 30333 use the following command. If you want to connect to rpc port 9933, then must add Polkadot startup parameter: `--rpc-external`. +Once you are done experimenting and picking the best node name :) you can start Polkadot as daemon, exposes the Polkadot ports and mount a volume that will keep your blockchain data locally. Make sure that you set the ownership of your local directory to the Polkadot user that is used by the container. -```bash -docker run -d -p 30333:30333 -p 9933:9933 -v /my/local/folder:/polkadot parity/polkadot:latest --chain westend --rpc-external --rpc-cors all -``` +Set user id 1000 and group id 1000, by running `chown 1000.1000 /my/local/folder -R` if you use a bind mount. -Additionally if you want to have custom node name you can add the `--name "YourName"` at the end +To start a Polkadot node on default rpc port 9933 and default p2p port 30333 use the following command. If you want to connect to rpc port 9933, then must add Polkadot startup parameter: `--rpc-external`. ```bash -docker run -d -p 30333:30333 -p 9933:9933 -v /my/local/folder:/polkadot parity/polkadot:latest --chain westend --rpc-external --rpc-cors all --name "PolkaDocker" +$ENGINE run -d -p 30333:30333 -p 9933:9933 \ + -v /my/local/folder:/polkadot \ + parity/polkadot:latest \ + --chain westend --rpc-external --rpc-cors all \ + --name "PolkaDocker ``` If you also want to expose the webservice port 9944 use the following command: ```bash -docker run -d -p 30333:30333 -p 9933:9933 -p 9944:9944 -v /my/local/folder:/polkadot parity/polkadot:latest --chain westend --ws-external --rpc-external --rpc-cors all --name "PolkaDocker" +$ENGINE run -d -p 30333:30333 -p 9933:9933 -p 9944:9944 \ + -v /my/local/folder:/polkadot \ + parity/polkadot:latest \ + --chain westend --ws-external --rpc-external --rpc-cors all --name "PolkaDocker" ``` ## Using Docker compose @@ -55,17 +70,19 @@ services: - 30333:30333 # p2p port - 9933:9933 # rpc port - 9944:9944 # ws port + - 9615:9615 # Prometheus port volumes: - /my/local/folder:/polkadot command: [ "--name", "PolkaDocker", "--ws-external", "--rpc-external", + "--prometheus-external", "--rpc-cors", "all" ] ``` -With following docker-compose.yml you can set up a node and use polkadot-js-apps as the front end on port 80. After starting the node use a browser and enter your Docker host IP in the URL field: __ +With following `docker-compose.yml` you can set up a node and use polkadot-js-apps as the front end on port 80. After starting the node use a browser and enter your Docker host IP in the URL field: __ ```bash version: '2' @@ -78,10 +95,12 @@ services: - 30333:30333 # p2p port - 9933:9933 # rpc port - 9944:9944 # ws port + - 9615:9615 # Prometheus port command: [ "--name", "PolkaDocker", "--ws-external", "--rpc-external", + "--prometheus-external", "--rpc-cors", "all" ] @@ -100,27 +119,30 @@ Chain syncing will utilize all available memory and CPU power your server has to If running on a low resource VPS, use `--memory` and `--cpus` to limit the resources used. E.g. To allow a maximum of 512MB memory and 50% of 1 CPU, use `--cpus=".5" --memory="512m"`. Read more about limiting a container's resources [here](https://docs.docker.com/config/containers/resource_constraints). -Start a shell session with the daemon: -```bash -docker exec -it $(docker ps -q) bash; -``` +## Build your own image -Check the current version: +There are 3 options to build a polkadot container image: +- using the builder image +- using the injected "Debian" image +- using the generic injected image -```bash -polkadot --version -``` +### Builder image -## Build your own image +To get up and running with the smallest footprint on your system, you may use an existing Polkadot Container image. -To get up and running with the smallest footprint on your system, you may use the Polkadot Docker image. -You can build it yourself (it takes a while...) in the shell session of the daemon: +You may also build a polkadot container image yourself (it takes a while...) using the container specs `scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile`. -```bash -cd scripts/ci/dockerfiles/polkadot -./build.sh -``` +### Debian injected + +The Debian injected image is how the official polkadot container image is produced. It relies on the Debian package that is published upon each release. The Debian injected image is usually available a few minutes after a new release is published. +It has the benefit of relying on the GPG signatures embedded in the Debian package. + +### Generic injected + +For simple testing purposes, the easiest option for polkadot and also random binaries, is to use the `binary_injected.Dockerfile` container spec. This option is less secure since the injected binary is not checked at all but it has the benefit to be simple. This option requires to already have a valid `polkadot` binary, compiled for Linux. + +This binary is then simply copied inside the `parity/base-bin` image. ## Reporting issues @@ -128,8 +150,8 @@ If you run into issues with Polkadot when using docker, please run the following (replace the tag with the appropriate one if you do not use latest): ```bash -docker run --rm -it parity/polkadot:latest --version +$ENGINE run --rm -it parity/polkadot:latest --version ``` This will show you the Polkadot version as well as the git commit ref that was used to build your container. -Just paste that in the issue you create. +You can now paste the version information in a [new issue](https://github.com/paritytech/polkadot/issues/new/choose). diff --git a/scripts/ci/common/lib.sh b/scripts/ci/common/lib.sh index 2e94feb150ce..00abe9a1d8d4 100755 --- a/scripts/ci/common/lib.sh +++ b/scripts/ci/common/lib.sh @@ -193,3 +193,73 @@ check_bootnode(){ echo " Bootnode appears unreachable" return 1 } + +# Assumes the ENV are set: +# - RELEASE_ID +# - GITHUB_TOKEN +# - REPO in the form paritytech/polkadot +fetch_release_artifacts() { + echo "Release ID : $RELEASE_ID" + echo "Repo : $REPO" + echo "ARTIFACT_FOLDER: $ARTIFACT_FOLDER" + + curl -L -s \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${REPO}/releases/$RELEASE_ID > release.json + + # Get Asset ids + ids=($(jq -r '.assets[].id' < release.json )) + count=$(jq '.assets|length' < release.json ) + + # Fetch artifacts + mkdir -p ${ARTIFACT_FOLDER} + pushd ${ARTIFACT_FOLDER} > /dev/null + + iter=1 + for id in "${ids[@]}" + do + echo " - $iter/$count: downloading asset id: $id..." + curl -s -OJ -L -H "Accept: application/octet-stream" \ + -H "Authorization: Token ${GITHUB_TOKEN}" \ + "https://api.github.com/repos/${REPO}/releases/assets/$id" + iter=$((iter + 1)) + done + + ls -al --color + popd > /dev/null +} + +# Check the checksum for a given binary +function check_sha256() { + echo "Checking SHA256 for $1" + shasum -qc $1.sha256 +} + +# Import GPG keys of the release team members +# This is done in parallel as it can take a while sometimes +function import_gpg_keys() { + GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"} + SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798" + WILL="2835EAF92072BC01D188AF2C4A092B93E97CE1E2" + EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" + MARA="533C920F40E73A21EEB7E9EBF27AEA7E7594C9CF" + MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" + + echo "Importing GPG keys from $GPG_KEYSERVER in parallel" + for key in $SEC $WILL $EGOR $MARA $MORGAN; do + ( + echo "Importing GPG key $key" + gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key + echo -e "5\ny\n" | gpg --no-tty --command-fd 0 --expert --edit-key $key trust; + ) & + done + wait +} + +# Check the GPG signature for a given binary +function check_gpg() { + echo "Checking GPG Signature for $1" + gpg --no-tty --verify -q $1.asc $1 +} diff --git a/scripts/ci/dockerfiles/adder-collator/build-injected.sh b/scripts/ci/dockerfiles/adder-collator/build-injected.sh new file mode 100755 index 000000000000..9a1857bc7ab4 --- /dev/null +++ b/scripts/ci/dockerfiles/adder-collator/build-injected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=adder-collator,undying-collator +export BIN_FOLDER=$1 + +$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/scripts/ci/dockerfiles/adder-collator/test-build.sh b/scripts/ci/dockerfiles/adder-collator/test-build.sh new file mode 100755 index 000000000000..171e0309f807 --- /dev/null +++ b/scripts/ci/dockerfiles/adder-collator/test-build.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +# TODO: Switch to /bin/bash when the image is built from parity/base-bin + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /usr/bin/bash \ + paritypr/colander:master -c \ + 'cp "$(which adder-collator)" /export' + +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /usr/bin/bash \ + paritypr/colander:master -c \ + 'cp "$(which undying-collator)" /export' + +./build-injected.sh $TMP diff --git a/scripts/ci/dockerfiles/binary_injected.Dockerfile b/scripts/ci/dockerfiles/binary_injected.Dockerfile new file mode 100644 index 000000000000..cee81a2eb8ae --- /dev/null +++ b/scripts/ci/dockerfiles/binary_injected.Dockerfile @@ -0,0 +1,48 @@ +FROM docker.io/parity/base-bin + +# This file allows building a Generic container image +# based on one or multiple pre-built Linux binaries. +# Some defaults are set to polkadot but all can be overriden. + +SHELL ["/bin/bash", "-c"] + +# metadata +ARG VCS_REF +ARG BUILD_DATE +ARG IMAGE_NAME + +# That can be a single one or a comma separated list +ARG BINARY=polkadot + +ARG BIN_FOLDER=. +ARG DOC_URL=https://github.com/paritytech/polkadot +ARG DESCRIPTION="Polkadot: a platform for web3" +ARG AUTHORS="devops-team@parity.io" +ARG VENDOR="Parity Technologies" + +LABEL io.parity.image.authors=${AUTHORS} \ + io.parity.image.vendor="${VENDOR}" \ + io.parity.image.revision="${VCS_REF}" \ + io.parity.image.title="${IMAGE_NAME}" \ + io.parity.image.created="${BUILD_DATE}" \ + io.parity.image.documentation="${DOC_URL}" \ + io.parity.image.description="${DESCRIPTION}" \ + io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/binary_injected.Dockerfile" + +USER root +WORKDIR /app + +# add polkadot binary to docker image +# sample for polkadot: COPY ./polkadot ./polkadot-*-worker /usr/local/bin/ +COPY entrypoint.sh . +COPY "bin/*" "/usr/local/bin/" +RUN chmod -R a+rx "/usr/local/bin" + +USER parity +ENV BINARY=${BINARY} + +# ENTRYPOINT +ENTRYPOINT ["/app/entrypoint.sh"] + +# We call the help by default +CMD ["--help"] diff --git a/scripts/ci/dockerfiles/build-injected.sh b/scripts/ci/dockerfiles/build-injected.sh new file mode 100755 index 000000000000..d0e7fee3646e --- /dev/null +++ b/scripts/ci/dockerfiles/build-injected.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +set -e + +# This script allows building a Container Image from a Linux +# binary that is injected into a base-image. + +ENGINE=${ENGINE:-podman} + +if [ "$ENGINE" == "podman" ]; then + PODMAN_FLAGS="--format docker" +else + PODMAN_FLAGS="" +fi + +CONTEXT=$(mktemp -d) +REGISTRY=${REGISTRY:-docker.io} + +# The following line ensure we know the project root +PROJECT_ROOT=${PROJECT_ROOT:-$(git rev-parse --show-toplevel)} +DOCKERFILE=${DOCKERFILE:-$PROJECT_ROOT/scripts/ci/dockerfiles/binary_injected.Dockerfile} +VERSION_TOML=$(grep "^version " $PROJECT_ROOT/Cargo.toml | grep -oE "([0-9\.]+-?[0-9]+)") + +#n The following VAR have default that can be overriden +DOCKER_OWNER=${DOCKER_OWNER:-parity} + +# We may get 1..n binaries, comma separated +BINARY=${BINARY:-polkadot} +IFS=',' read -r -a BINARIES <<< "$BINARY" + +VERSION=${VERSION:-$VERSION_TOML} +BIN_FOLDER=${BIN_FOLDER:-.} + +IMAGE=${IMAGE:-${REGISTRY}/${DOCKER_OWNER}/${BINARIES[0]}} +DESCRIPTION_DEFAULT="Injected Container image built for ${BINARY}" +DESCRIPTION=${DESCRIPTION:-$DESCRIPTION_DEFAULT} + +VCS_REF=${VCS_REF:-01234567} + +# Build the image +echo "Using engine: $ENGINE" +echo "Using Dockerfile: $DOCKERFILE" +echo "Using context: $CONTEXT" +echo "Building ${IMAGE}:latest container image for ${BINARY} v${VERSION} from ${BIN_FOLDER} hang on!" +echo "BIN_FOLDER=$BIN_FOLDER" +echo "CONTEXT=$CONTEXT" + +# We need all binaries and resources available in the Container build "CONTEXT" +mkdir -p $CONTEXT/bin +for bin in "${BINARIES[@]}" +do + echo "Copying $BIN_FOLDER/$bin to context: $CONTEXT/bin" + cp "$BIN_FOLDER/$bin" "$CONTEXT/bin" +done + +cp "$PROJECT_ROOT/scripts/ci/dockerfiles/entrypoint.sh" "$CONTEXT" + +echo "Building image: ${IMAGE}" + +TAGS=${TAGS[@]:-latest} +IFS=',' read -r -a TAG_ARRAY <<< "$TAGS" +TAG_ARGS=" " + +echo "The image ${IMAGE} will be tagged with ${TAG_ARRAY[*]}" +for tag in "${TAG_ARRAY[@]}"; do + TAG_ARGS+="--tag ${IMAGE}:${tag} " +done + +echo "$TAG_ARGS" + +# time \ +$ENGINE build \ + ${PODMAN_FLAGS} \ + --build-arg VCS_REF="${VCS_REF}" \ + --build-arg BUILD_DATE=$(date -u '+%Y-%m-%dT%H:%M:%SZ') \ + --build-arg IMAGE_NAME="${IMAGE}" \ + --build-arg BINARY="${BINARY}" \ + --build-arg BIN_FOLDER="${BIN_FOLDER}" \ + --build-arg DESCRIPTION="${DESCRIPTION}" \ + ${TAG_ARGS} \ + -f "${DOCKERFILE}" \ + ${CONTEXT} + +echo "Your Container image for ${IMAGE} is ready" +$ENGINE images + +if [[ -z "${SKIP_IMAGE_VALIDATION}" ]]; then + echo "Check the image ${IMAGE}:${TAG_ARRAY[0]}" + $ENGINE run --rm -i "${IMAGE}:${TAG_ARRAY[0]}" --version + + echo "Query binaries" + $ENGINE run --rm -i --entrypoint /bin/bash "${IMAGE}:${TAG_ARRAY[0]}" -c 'echo BINARY: $BINARY' +fi diff --git a/scripts/ci/dockerfiles/collator_injected.Dockerfile b/scripts/ci/dockerfiles/collator_injected.Dockerfile deleted file mode 100644 index 91b8cb0057bf..000000000000 --- a/scripts/ci/dockerfiles/collator_injected.Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -# this file copies from scripts/ci/dockerfiles/Dockerfile and changes only the binary name -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -LABEL io.parity.image.authors="devops-team@parity.io" \ - io.parity.image.vendor="Parity Technologies" \ - io.parity.image.title="${IMAGE_NAME}" \ - io.parity.image.description="Injected adder-collator Docker image" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/collator_injected.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ -# add user and link ~/.local/share/adder-collator to /data - useradd -m -u 1000 -U -s /bin/sh -d /adder-collator adder-collator && \ - mkdir -p /data /adder-collator/.local/share && \ - chown -R adder-collator:adder-collator /data && \ - ln -s /data /adder-collator/.local/share/polkadot - -# add adder-collator binary to docker image -COPY ./adder-collator /usr/local/bin -COPY ./undying-collator /usr/local/bin - -USER adder-collator - -# check if executable works in this container -RUN /usr/local/bin/adder-collator --version -RUN /usr/local/bin/undying-collator --version - -EXPOSE 30333 9933 9944 -VOLUME ["/adder-collator"] - -ENTRYPOINT ["/usr/local/bin/adder-collator"] diff --git a/scripts/ci/dockerfiles/entrypoint.sh b/scripts/ci/dockerfiles/entrypoint.sh new file mode 100755 index 000000000000..eaa815faf6a4 --- /dev/null +++ b/scripts/ci/dockerfiles/entrypoint.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Sanity check +if [ -z "$BINARY" ] +then + echo "BINARY ENV not defined, this should never be the case. Aborting..." + exit 1 +fi + +# If the user built the image with multiple binaries, +# we consider the first one to be the canonical one +# To start with another binary, the user can either: +# - use the --entrypoint option +# - pass the ENV BINARY with a single binary +IFS=',' read -r -a BINARIES <<< "$BINARY" +BIN0=${BINARIES[0]} +echo "Starting binary $BIN0" +$BIN0 $@ diff --git a/scripts/ci/dockerfiles/malus/build-injected.sh b/scripts/ci/dockerfiles/malus/build-injected.sh new file mode 100755 index 000000000000..99bd5fde1d5a --- /dev/null +++ b/scripts/ci/dockerfiles/malus/build-injected.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=malus,polkadot-execute-worker,polkadot-prepare-worker +export BIN_FOLDER=$1 +# export TAGS=... + +$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/scripts/ci/dockerfiles/malus/test-build.sh b/scripts/ci/dockerfiles/malus/test-build.sh new file mode 100755 index 000000000000..3114e9e2adf1 --- /dev/null +++ b/scripts/ci/dockerfiles/malus/test-build.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +export TAGS=latest,beta,7777,1.0.2-rc23 + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + --pull always \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + paritypr/malus:7217 -c \ + 'cp "$(which malus)" /export' + +echo "Checking binaries we got:" +ls -al $TMP + +./build-injected.sh $TMP diff --git a/scripts/ci/dockerfiles/malus_injected.Dockerfile b/scripts/ci/dockerfiles/malus_injected.Dockerfile deleted file mode 100644 index fa429b5f142a..000000000000 --- a/scripts/ci/dockerfiles/malus_injected.Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -FROM debian:bullseye-slim - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -LABEL io.parity.image.authors="devops-team@parity.io" \ - io.parity.image.vendor="Parity Technologies" \ - io.parity.image.title="${IMAGE_NAME}" \ - io.parity.image.description="Malus - the nemesis of polkadot" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/malus.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - ca-certificates \ - curl \ - libssl1.1 \ - tini && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ -# add user - groupadd --gid 10000 nonroot && \ - useradd --home-dir /home/nonroot \ - --create-home \ - --shell /bin/bash \ - --gid nonroot \ - --groups nonroot \ - --uid 10000 nonroot - - -# add malus binary to docker image -COPY ./malus ./polkadot-execute-worker ./polkadot-prepare-worker /usr/local/bin - -USER nonroot - -# check if executable works in this container -RUN /usr/local/bin/malus --version - -# Tini allows us to avoid several Docker edge cases, see https://github.com/krallin/tini. -ENTRYPOINT ["tini", "--", "/bin/bash"] diff --git a/scripts/ci/dockerfiles/polkadot/README.md b/scripts/ci/dockerfiles/polkadot/README.md index 9ddf324bb29c..e331d8984c2c 100644 --- a/scripts/ci/dockerfiles/polkadot/README.md +++ b/scripts/ci/dockerfiles/polkadot/README.md @@ -1,7 +1,9 @@ # Self built Docker image The Polkadot repo contains several options to build Docker images for Polkadot. + This folder contains a self-contained image that does not require a Linux pre-built binary. + Instead, building the image is possible on any host having docker installed and will build Polkadot inside Docker. That also means that no Rust toolchain is required on the host machine for the build to succeed. diff --git a/scripts/ci/dockerfiles/polkadot/build-injected.sh b/scripts/ci/dockerfiles/polkadot/build-injected.sh new file mode 100755 index 000000000000..22774c7b7122 --- /dev/null +++ b/scripts/ci/dockerfiles/polkadot/build-injected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=polkadot,polkadot-execute-worker,polkadot-prepare-worker +export BIN_FOLDER=$1 + +$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/scripts/ci/dockerfiles/polkadot/build.sh b/scripts/ci/dockerfiles/polkadot/build.sh deleted file mode 100755 index d00c9108bd8c..000000000000 --- a/scripts/ci/dockerfiles/polkadot/build.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -set -e - -pushd . - -# The following line ensure we run from the project root -PROJECT_ROOT=`git rev-parse --show-toplevel` -cd $PROJECT_ROOT - -# Find the current version from Cargo.toml -VERSION=`grep "^version" ./cli/Cargo.toml | egrep -o "([0-9\.]+-?[0-9]+)"` -GITUSER=parity -GITREPO=polkadot - -# Build the image -echo "Building ${GITUSER}/${GITREPO}:latest docker image, hang on!" -time docker build \ - -f ./scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile \ - -t ${GITUSER}/${GITREPO}:latest \ - -t ${GITUSER}/${GITREPO}:v${VERSION} \ - . - -# Show the list of available images for this repo -echo "Your Docker image for $GITUSER/$GITREPO is ready" -docker images | grep ${GITREPO} - -popd diff --git a/scripts/ci/dockerfiles/polkadot/docker-compose.yml b/scripts/ci/dockerfiles/polkadot/docker-compose.yml index 978191af88c1..524b1164796a 100644 --- a/scripts/ci/dockerfiles/polkadot/docker-compose.yml +++ b/scripts/ci/dockerfiles/polkadot/docker-compose.yml @@ -1,23 +1,22 @@ version: '3' services: polkadot: + image: parity/polkadot:latest + ports: - "127.0.0.1:30333:30333/tcp" - "127.0.0.1:9933:9933/tcp" - image: parity/polkadot:latest + - "127.0.0.1:9944:9944/tcp" + - "127.0.0.1:9615:9615/tcp" + volumes: - "polkadot-data:/data" + command: | --unsafe-rpc-external --unsafe-ws-external --rpc-cors all --prometheus-external - ports: - - "30333:30333" - - "9933:9933" - - "9944:9944" - - "9615:9615" - volumes: polkadot-data: diff --git a/scripts/ci/dockerfiles/polkadot_Dockerfile.README.md b/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md similarity index 100% rename from scripts/ci/dockerfiles/polkadot_Dockerfile.README.md rename to scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md diff --git a/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile b/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile index 6e31298432f7..f263c836bbfe 100644 --- a/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile +++ b/scripts/ci/dockerfiles/polkadot/polkadot_builder.Dockerfile @@ -7,7 +7,7 @@ COPY . /polkadot RUN cargo build --locked --release # This is the 2nd stage: a very small image where we copy the Polkadot binary." -FROM docker.io/library/ubuntu:20.04 +FROM docker.io/parity/base-bin:latest LABEL description="Multistage Docker image for Polkadot: a platform for web3" \ io.parity.image.type="builder" \ diff --git a/scripts/ci/dockerfiles/polkadot_injected_release.Dockerfile b/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile similarity index 95% rename from scripts/ci/dockerfiles/polkadot_injected_release.Dockerfile rename to scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile index 74b5c7f48f88..e2c72dcfe2e9 100644 --- a/scripts/ci/dockerfiles/polkadot_injected_release.Dockerfile +++ b/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile @@ -11,7 +11,7 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ io.parity.image.title="parity/polkadot" \ io.parity.image.description="Polkadot: a platform for web3. This is the official Parity image with an injected binary." \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/polkadot_injected_release.Dockerfile" \ + io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile" \ io.parity.image.revision="${VCS_REF}" \ io.parity.image.created="${BUILD_DATE}" \ io.parity.image.documentation="https://github.com/paritytech/polkadot/" diff --git a/scripts/ci/dockerfiles/polkadot/test-build.sh b/scripts/ci/dockerfiles/polkadot/test-build.sh new file mode 100755 index 000000000000..d2d904561cb5 --- /dev/null +++ b/scripts/ci/dockerfiles/polkadot/test-build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +# You need to build an injected image first + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + parity/polkadot -c \ + 'cp "$(which polkadot)" /export' + +echo "Checking binaries we got:" +tree $TMP + +./build-injected.sh $TMP diff --git a/scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile b/scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile deleted file mode 100644 index aebbbdcf1b7f..000000000000 --- a/scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME - -LABEL io.parity.image.authors="devops-team@parity.io" \ - io.parity.image.vendor="Parity Technologies" \ - io.parity.image.title="${IMAGE_NAME}" \ - io.parity.image.description="Polkadot: a platform for web3" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ -# add user and link ~/.local/share/polkadot to /data - useradd -m -u 1000 -U -s /bin/sh -d /polkadot polkadot && \ - mkdir -p /data /polkadot/.local/share && \ - chown -R polkadot:polkadot /data && \ - ln -s /data /polkadot/.local/share/polkadot - -# add polkadot binary to docker image -COPY ./polkadot ./polkadot-execute-worker ./polkadot-prepare-worker /usr/local/bin - -USER polkadot - -# check if executable works in this container -RUN /usr/local/bin/polkadot --version -RUN /usr/local/bin/polkadot-execute-worker --version -RUN /usr/local/bin/polkadot-prepare-worker --version - -EXPOSE 30333 9933 9944 -VOLUME ["/polkadot"] - -ENTRYPOINT ["/usr/local/bin/polkadot"] diff --git a/scripts/ci/dockerfiles/staking-miner/README.md b/scripts/ci/dockerfiles/staking-miner/README.md new file mode 100644 index 000000000000..3610e1130316 --- /dev/null +++ b/scripts/ci/dockerfiles/staking-miner/README.md @@ -0,0 +1,37 @@ +# staking-miner container image + +## Build using the Builder + +``` +./build.sh +``` + +## Build the injected Image + +You first need a valid Linux binary to inject. Let's assume this binary is located in `BIN_FOLDER`. + +``` +./build-injected.sh "$BIN_FOLDER" +``` + +## Test + +Here is how to test the image. We can generate a valid seed but the staking-miner will quickly notice that our +account is not funded and "does not exist". + +You may pass any ENV supported by the binary and must provide at least a few such as `SEED` and `URI`: +``` +ENV SEED="" +ENV URI="wss://rpc.polkadot.io:443" +ENV RUST_LOG="info" +``` + +``` +export SEED=$(subkey generate -n polkadot --output-type json | jq -r .secretSeed) +podman run --rm -it \ + -e URI="wss://rpc.polkadot.io:443" \ + -e RUST_LOG="info" \ + -e SEED \ + localhost/parity/staking-miner \ + dry-run seq-phragmen +``` diff --git a/scripts/ci/dockerfiles/staking-miner/build-injected.sh b/scripts/ci/dockerfiles/staking-miner/build-injected.sh new file mode 100755 index 000000000000..536636df6a91 --- /dev/null +++ b/scripts/ci/dockerfiles/staking-miner/build-injected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_staking-miner_binary +# This script replace the former dedicated staking-miner "injected" Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=staking-miner +export BIN_FOLDER=$1 + +$PROJECT_ROOT/scripts/ci/dockerfiles/build-injected.sh diff --git a/scripts/ci/dockerfiles/staking-miner/build.sh b/scripts/ci/dockerfiles/staking-miner/build.sh new file mode 100755 index 000000000000..67c82afcd2ce --- /dev/null +++ b/scripts/ci/dockerfiles/staking-miner/build.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_staking-miner_binary +# This script replace the former dedicated staking-miner "injected" Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` +ENGINE=podman + +echo "Building the staking-miner using the Builder image" +echo "PROJECT_ROOT=$PROJECT_ROOT" +$ENGINE build -t staking-miner -f staking-miner_builder.Dockerfile "$PROJECT_ROOT" diff --git a/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile b/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile index a1932095fd4c..0ae77f36c79d 100644 --- a/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile +++ b/scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile @@ -4,17 +4,17 @@ FROM paritytech/ci-linux:production as builder ARG VCS_REF ARG BUILD_DATE ARG IMAGE_NAME="staking-miner" -ARG PROFILE=release +ARG PROFILE=production LABEL description="This is the build stage. Here we create the binary." WORKDIR /app COPY . /app -RUN cargo build --locked --$PROFILE --package staking-miner +RUN cargo build --locked --profile $PROFILE --package staking-miner # ===== SECOND STAGE ====== -FROM docker.io/library/ubuntu:20.04 +FROM docker.io/parity/base-bin:latest LABEL description="This is the 2nd stage: a very small image where we copy the binary." LABEL io.parity.image.authors="devops-team@parity.io" \ io.parity.image.vendor="Parity Technologies" \ @@ -28,13 +28,10 @@ LABEL io.parity.image.authors="devops-team@parity.io" \ ARG PROFILE=release COPY --from=builder /app/target/$PROFILE/staking-miner /usr/local/bin -RUN useradd -u 1000 -U -s /bin/sh miner && \ - rm -rf /usr/bin /usr/sbin - # show backtraces ENV RUST_BACKTRACE 1 -USER miner +USER parity ENV SEED="" ENV URI="wss://rpc.polkadot.io" diff --git a/scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile b/scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile deleted file mode 100644 index 4901ab4a3736..000000000000 --- a/scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -FROM docker.io/library/ubuntu:20.04 - -# metadata -ARG VCS_REF -ARG BUILD_DATE -ARG IMAGE_NAME="staking-miner" - -LABEL io.parity.image.authors="devops-team@parity.io" \ - io.parity.image.vendor="Parity Technologies" \ - io.parity.image.title="${IMAGE_NAME}" \ - io.parity.image.description="${IMAGE_NAME} for substrate based chains" \ - io.parity.image.source="https://github.com/paritytech/polkadot/blob/${VCS_REF}/scripts/ci/dockerfiles/${IMAGE_NAME}/${IMAGE_NAME}_injected.Dockerfile" \ - io.parity.image.revision="${VCS_REF}" \ - io.parity.image.created="${BUILD_DATE}" \ - io.parity.image.documentation="https://github.com/paritytech/polkadot/" - -# show backtraces -ENV RUST_BACKTRACE 1 - -# install tools and dependencies -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libssl1.1 \ - ca-certificates && \ -# apt cleanup - apt-get autoremove -y && \ - apt-get clean && \ - find /var/lib/apt/lists/ -type f -not -name lock -delete; \ - useradd -u 1000 -U -s /bin/sh miner - -# add binary to docker image -COPY ./staking-miner /usr/local/bin - -USER miner - -ENV SEED="" -ENV URI="wss://rpc.polkadot.io" -ENV RUST_LOG="info" - -# check if the binary works in this container -RUN /usr/local/bin/staking-miner --version - -ENTRYPOINT [ "/usr/local/bin/staking-miner" ] diff --git a/scripts/ci/dockerfiles/staking-miner/test-build.sh b/scripts/ci/dockerfiles/staking-miner/test-build.sh new file mode 100755 index 000000000000..0ce74e2df296 --- /dev/null +++ b/scripts/ci/dockerfiles/staking-miner/test-build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +TMP=$(mktemp -d) +ENGINE=${ENGINE:-podman} + +# You need to build an injected image first + +# Fetch some binaries +$ENGINE run --user root --rm -i \ + -v "$TMP:/export" \ + --entrypoint /bin/bash \ + parity/staking-miner -c \ + 'cp "$(which staking-miner)" /export' + +echo "Checking binaries we got:" +tree $TMP + +./build-injected.sh $TMP diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index dafca393cd4f..845ac7970108 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -39,7 +39,6 @@ build-linux-stable: - echo -n ${CI_JOB_ID} > ./artifacts/BUILD_LINUX_JOB_ID - RELEASE_VERSION=$(./artifacts/polkadot -V | awk '{print $2}'| awk -F "-" '{print $1}') - echo -n "v${RELEASE_VERSION}" > ./artifacts/BUILD_RELEASE_VERSION - - cp -r scripts/* ./artifacts build-test-collators: stage: build @@ -64,7 +63,6 @@ build-test-collators: - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - echo "adder-collator version = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - echo "undying-collator version = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - - cp -r ./scripts/* ./artifacts build-malus: stage: build @@ -88,7 +86,6 @@ build-malus: - echo -n "${CI_COMMIT_REF_NAME}" > ./artifacts/VERSION - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - echo "polkadot-test-malus = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - - cp -r ./scripts/* ./artifacts build-staking-miner: stage: build @@ -110,7 +107,6 @@ build-staking-miner: - echo -n "${CI_COMMIT_REF_NAME}" > ./artifacts/VERSION - echo -n "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" > ./artifacts/EXTRATAG - echo "staking-miner = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - - cp -r ./scripts/* ./artifacts build-rustdoc: stage: build diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index d9a0dff95767..c224094125e3 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -19,20 +19,16 @@ publish-polkadot-debug-image: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 variables: - CI_IMAGE: ${BUILDAH_IMAGE} - GIT_STRATEGY: none - DOCKER_USER: ${PARITYPR_USER} - DOCKER_PASS: ${PARITYPR_PASS} - # scripts/ci/dockerfiles/polkadot_injected_debug.Dockerfile - DOCKERFILE: ci/dockerfiles/polkadot_injected_debug.Dockerfile - IMAGE_NAME: docker.io/paritypr/polkadot-debug + IMAGE_NAME: "polkadot-debug" + BINARY: "polkadot,polkadot-execute-worker,polkadot-prepare-worker" needs: - job: build-linux-stable artifacts: true after_script: + - !reference [.build-push-image, after_script] # pass artifacts to the zombienet-tests job # https://docs.gitlab.com/ee/ci/multi_project_pipelines.html#with-variable-inheritance - - echo "PARACHAINS_IMAGE_NAME=${IMAGE_NAME}" > ./artifacts/parachains.env + - echo "PARACHAINS_IMAGE_NAME=${IMAGE}" > ./artifacts/parachains.env - echo "PARACHAINS_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/parachains.env artifacts: reports: @@ -48,20 +44,15 @@ publish-test-collators-image: - .build-push-image - .zombienet-refs variables: - CI_IMAGE: ${BUILDAH_IMAGE} - GIT_STRATEGY: none - DOCKER_USER: ${PARITYPR_USER} - DOCKER_PASS: ${PARITYPR_PASS} - # scripts/ci/dockerfiles/collator_injected.Dockerfile - DOCKERFILE: ci/dockerfiles/collator_injected.Dockerfile - IMAGE_NAME: docker.io/paritypr/colander + IMAGE_NAME: "colander" + BINARY: "adder-collator,undying-collator" needs: - job: build-test-collators artifacts: true after_script: - - buildah logout --all + - !reference [.build-push-image, after_script] # pass artifacts to the zombienet-tests job - - echo "COLLATOR_IMAGE_NAME=${IMAGE_NAME}" > ./artifacts/collator.env + - echo "COLLATOR_IMAGE_NAME=${IMAGE}" > ./artifacts/collator.env - echo "COLLATOR_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/collator.env artifacts: reports: @@ -76,20 +67,15 @@ publish-malus-image: - .build-push-image - .zombienet-refs variables: - CI_IMAGE: ${BUILDAH_IMAGE} - GIT_STRATEGY: none - DOCKER_USER: ${PARITYPR_USER} - DOCKER_PASS: ${PARITYPR_PASS} - # scripts/ci/dockerfiles/malus_injected.Dockerfile - DOCKERFILE: ci/dockerfiles/malus_injected.Dockerfile - IMAGE_NAME: docker.io/paritypr/malus + IMAGE_NAME: "malus" + BINARY: "malus,polkadot-execute-worker,polkadot-prepare-worker" needs: - job: build-malus artifacts: true after_script: - - buildah logout "$IMAGE_NAME" + - !reference [.build-push-image, after_script] # pass artifacts to the zombienet-tests job - - echo "MALUS_IMAGE_NAME=${IMAGE_NAME}" > ./artifacts/malus.env + - echo "MALUS_IMAGE_NAME=${IMAGE}" > ./artifacts/malus.env - echo "MALUS_IMAGE_TAG=$(cat ./artifacts/EXTRATAG)" >> ./artifacts/malus.env artifacts: reports: @@ -103,13 +89,11 @@ publish-staking-miner-image: - .build-push-image - .publish-refs variables: - CI_IMAGE: ${BUILDAH_IMAGE} - # scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile - DOCKERFILE: ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile - IMAGE_NAME: docker.io/paritytech/staking-miner - GIT_STRATEGY: none - DOCKER_USER: ${Docker_Hub_User_Parity} - DOCKER_PASS: ${Docker_Hub_Pass_Parity} + IMAGE_NAME: "staking-miner" + BINARY: "staking-miner" + DOCKER_OWNER: "paritytech" + DOCKER_USER: "${Docker_Hub_User_Parity}" + DOCKER_PASS: "${Docker_Hub_Pass_Parity}" needs: - job: build-staking-miner artifacts: true @@ -122,11 +106,11 @@ publish-polkadot-image-description: DOCKER_PASSWORD: ${Docker_Hub_Pass_Parity} DOCKERHUB_REPOSITORY: parity/polkadot SHORT_DESCRIPTION: "Polkadot Official Docker Image" - README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/dockerfiles/polkadot_Dockerfile.README.md + README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md rules: - if: $CI_COMMIT_REF_NAME == "master" changes: - - scripts/ci/dockerfiles/polkadot_Dockerfile.README.md + - scripts/ci/dockerfiles/polkadot/polkadot_Dockerfile.README.md - if: $CI_PIPELINE_SOURCE == "schedule" when: never script: diff --git a/utils/staking-miner/README.md b/utils/staking-miner/README.md index 4148677ee7ca..b7f70de573b0 100644 --- a/utils/staking-miner/README.md +++ b/utils/staking-miner/README.md @@ -28,8 +28,9 @@ There are 2 options to build a staking-miner Docker image: ### Building the injected image First build the binary as documented [above](#building). -You may then inject the binary into a Docker base image from the root of the Polkadot repository: +You may then inject the binary into a Docker base image: `parity/base-bin` (running the command from the root of the Polkadot repository): ``` +TODO: UPDATE THAT docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-miner_injected.Dockerfile target/release ``` @@ -39,6 +40,7 @@ Unlike the injected image that requires a Linux pre-built binary, this option do The trade-off however is that it takes a little longer to build and this option is less ideal for CI tasks. You may build the multi-stage image the root of the Polkadot repository with: ``` +TODO: UPDATE THAT docker build -t staking-miner -f scripts/ci/dockerfiles/staking-miner/staking-miner_builder.Dockerfile . ``` @@ -51,7 +53,7 @@ While it won't prevent a malicious actor to read your `SEED` if they gain access # The following line starts with an extra space on purpose: SEED=0x1234... -docker run --rm -it \ +docker run --rm -i \ --name staking-miner \ --read-only \ -e RUST_LOG=info \ From 8f05479e4bd61341af69f0721e617f01cbad8bb2 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 11 Aug 2023 18:30:58 +0300 Subject: [PATCH 10/45] companion for 14754: cli: move no-beefy flag to sc-cli (#7600) * cli: move no-beefy flag to substrate sc-cli config * bump substrate ref --------- Signed-off-by: Adrian Catangiu --- Cargo.lock | 368 +++++++++--------- cli/src/cli.rs | 5 - cli/src/command.rs | 11 +- node/service/src/lib.rs | 3 +- node/test/service/src/lib.rs | 2 +- .../adder/collator/src/main.rs | 4 +- .../undying/collator/src/main.rs | 4 +- 7 files changed, 195 insertions(+), 202 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ad880641445..862063ac72e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -617,7 +617,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "hash-db", "log", @@ -2446,7 +2446,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", ] @@ -2469,7 +2469,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-support-procedural", @@ -2494,7 +2494,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "Inflector", "array-bytes", @@ -2542,7 +2542,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2553,7 +2553,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2570,7 +2570,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -2599,7 +2599,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-recursion", "futures", @@ -2620,7 +2620,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "aquamarine", "bitflags", @@ -2657,7 +2657,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "Inflector", "cfg-expr", @@ -2675,7 +2675,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2687,7 +2687,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro2", "quote", @@ -2697,7 +2697,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-executive", @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -2737,7 +2737,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "cfg-if", "frame-support", @@ -2756,7 +2756,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -2771,7 +2771,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "sp-api", @@ -2780,7 +2780,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "parity-scale-codec", @@ -2962,7 +2962,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "chrono", "frame-election-provider-support", @@ -4829,7 +4829,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "log", @@ -4848,7 +4848,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "anyhow", "jsonrpsee", @@ -5374,7 +5374,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5389,7 +5389,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -5405,7 +5405,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -5419,7 +5419,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5443,7 +5443,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5463,7 +5463,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -5482,7 +5482,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5497,7 +5497,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -5516,7 +5516,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -5540,7 +5540,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5558,7 +5558,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5577,7 +5577,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5594,7 +5594,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5611,7 +5611,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5629,7 +5629,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5652,7 +5652,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5665,7 +5665,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5684,7 +5684,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "docify", "frame-benchmarking", @@ -5703,7 +5703,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5726,7 +5726,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5742,7 +5742,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5762,7 +5762,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5779,7 +5779,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5796,7 +5796,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5815,7 +5815,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5832,7 +5832,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5848,7 +5848,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5864,7 +5864,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -5883,7 +5883,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5903,7 +5903,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -5914,7 +5914,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -5931,7 +5931,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5955,7 +5955,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5972,7 +5972,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -5987,7 +5987,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6005,7 +6005,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6020,7 +6020,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6039,7 +6039,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6056,7 +6056,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -6077,7 +6077,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6093,7 +6093,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6111,7 +6111,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6134,7 +6134,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6145,7 +6145,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "log", "sp-arithmetic", @@ -6154,7 +6154,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "sp-api", @@ -6163,7 +6163,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6180,7 +6180,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6195,7 +6195,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6213,7 +6213,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6232,7 +6232,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-support", "frame-system", @@ -6248,7 +6248,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6264,7 +6264,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6276,7 +6276,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6293,7 +6293,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6324,7 +6324,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -6339,7 +6339,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-benchmarking", "frame-support", @@ -9360,7 +9360,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "log", "sp-core", @@ -9371,7 +9371,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "futures", @@ -9399,7 +9399,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "futures-timer", @@ -9422,7 +9422,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9437,7 +9437,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -9456,7 +9456,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -9467,7 +9467,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "chrono", @@ -9506,7 +9506,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "fnv", "futures", @@ -9532,7 +9532,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "hash-db", "kvdb", @@ -9558,7 +9558,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "futures", @@ -9583,7 +9583,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "fork-tree", @@ -9619,7 +9619,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "jsonrpsee", @@ -9641,7 +9641,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "async-channel", @@ -9675,7 +9675,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "jsonrpsee", @@ -9694,7 +9694,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9707,7 +9707,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ahash 0.8.2", "array-bytes", @@ -9748,7 +9748,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "finality-grandpa", "futures", @@ -9768,7 +9768,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "futures", @@ -9791,7 +9791,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -9813,7 +9813,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -9825,7 +9825,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "anyhow", "cfg-if", @@ -9842,7 +9842,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ansi_term", "futures", @@ -9858,7 +9858,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -9872,7 +9872,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "async-channel", @@ -9915,7 +9915,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-channel", "cid", @@ -9935,7 +9935,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "bitflags", @@ -9952,7 +9952,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ahash 0.8.2", "futures", @@ -9971,7 +9971,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "async-channel", @@ -9992,7 +9992,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "async-channel", @@ -10026,7 +10026,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "futures", @@ -10044,7 +10044,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "bytes", @@ -10078,7 +10078,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10087,7 +10087,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "jsonrpsee", @@ -10118,7 +10118,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10137,7 +10137,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "http", "jsonrpsee", @@ -10152,7 +10152,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "futures", @@ -10179,7 +10179,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "directories", @@ -10243,7 +10243,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "log", "parity-scale-codec", @@ -10254,7 +10254,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "clap 4.2.5", "fs4", @@ -10268,7 +10268,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10287,7 +10287,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "libc", @@ -10306,7 +10306,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "chrono", "futures", @@ -10325,7 +10325,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ansi_term", "atty", @@ -10354,7 +10354,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10365,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "futures", @@ -10391,7 +10391,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "futures", @@ -10407,7 +10407,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-channel", "futures", @@ -10955,7 +10955,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "hash-db", "log", @@ -10976,7 +10976,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "Inflector", "blake2", @@ -10990,7 +10990,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "scale-info", @@ -11003,7 +11003,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "integer-sqrt", "num-traits", @@ -11017,7 +11017,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "scale-info", @@ -11030,7 +11030,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "sp-api", "sp-inherents", @@ -11041,7 +11041,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "log", @@ -11059,7 +11059,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "futures", @@ -11074,7 +11074,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "parity-scale-codec", @@ -11091,7 +11091,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "parity-scale-codec", @@ -11110,7 +11110,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11129,7 +11129,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "finality-grandpa", "log", @@ -11147,7 +11147,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "scale-info", @@ -11159,7 +11159,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11206,7 +11206,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "blake2b_simd", "byteorder", @@ -11219,7 +11219,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "quote", "sp-core-hashing", @@ -11229,7 +11229,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11238,7 +11238,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro2", "quote", @@ -11248,7 +11248,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "environmental", "parity-scale-codec", @@ -11259,7 +11259,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "serde_json", "sp-api", @@ -11270,7 +11270,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11284,7 +11284,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "bytes", "ed25519", @@ -11309,7 +11309,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "lazy_static", "sp-core", @@ -11320,7 +11320,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -11332,7 +11332,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "thiserror", "zstd 0.12.3+zstd.1.5.2", @@ -11341,7 +11341,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -11352,7 +11352,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -11370,7 +11370,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "scale-info", @@ -11384,7 +11384,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "sp-api", "sp-core", @@ -11394,7 +11394,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "backtrace", "lazy_static", @@ -11404,7 +11404,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "rustc-hash", "serde", @@ -11414,7 +11414,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "either", "hash256-std-hasher", @@ -11436,7 +11436,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -11454,7 +11454,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "Inflector", "proc-macro-crate", @@ -11466,7 +11466,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "scale-info", @@ -11481,7 +11481,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -11495,7 +11495,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "hash-db", "log", @@ -11516,7 +11516,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -11540,12 +11540,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11558,7 +11558,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "parity-scale-codec", @@ -11571,7 +11571,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "sp-std", @@ -11583,7 +11583,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "sp-api", "sp-runtime", @@ -11592,7 +11592,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "parity-scale-codec", @@ -11607,7 +11607,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ahash 0.8.2", "hash-db", @@ -11630,7 +11630,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11647,7 +11647,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -11658,7 +11658,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -11671,7 +11671,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "parity-scale-codec", "scale-info", @@ -11896,12 +11896,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -11920,7 +11920,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "hyper", "log", @@ -11932,7 +11932,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "jsonrpsee", @@ -11945,7 +11945,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11962,7 +11962,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "array-bytes", "async-trait", @@ -11988,7 +11988,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "futures", "substrate-test-utils-derive", @@ -11998,7 +11998,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12009,7 +12009,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "ansi_term", "build-helper", @@ -12879,7 +12879,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#57d2e53b6afefc079cec3b507710970ccd4a5aae" +source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" dependencies = [ "async-trait", "clap 4.2.5", diff --git a/cli/src/cli.rs b/cli/src/cli.rs index b7d884750762..e78213cf11c8 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -99,11 +99,6 @@ pub struct RunCmd { #[arg(long = "grandpa-pause", num_args = 2)] pub grandpa_pause: Vec, - /// Disable the BEEFY gadget - /// (currently enabled by default on Rococo, Wococo and Versi). - #[arg(long)] - pub no_beefy: bool, - /// Add the destination address to the jaeger agent. /// /// Must be valid socket address, of format `IP:Port` diff --git a/cli/src/command.rs b/cli/src/command.rs index ee71bb0840dc..c8e8673c6d70 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -235,15 +235,11 @@ fn run_node_inner( where F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), { - let runner = cli + let mut runner = cli .create_runner_with_logger_hook::(&cli.run.base, logger_hook) .map_err(Error::from)?; let chain_spec = &runner.config().chain_spec; - // By default, enable BEEFY on test networks. - let enable_beefy = (chain_spec.is_rococo() || chain_spec.is_wococo() || chain_spec.is_versi()) && - !cli.run.no_beefy; - set_default_ss58_version(chain_spec); let grandpa_pause = if cli.run.grandpa_pause.is_empty() { @@ -259,6 +255,10 @@ where info!(" KUSAMA FOUNDATION "); info!("----------------------------"); } + // BEEFY allowed only on test networks. + if !(chain_spec.is_rococo() || chain_spec.is_wococo() || chain_spec.is_versi()) { + runner.config_mut().disable_beefy = true; + } let jaeger_agent = if let Some(ref jaeger_agent) = cli.run.jaeger_agent { Some( @@ -289,7 +289,6 @@ where service::NewFullParams { is_collator: service::IsCollator::No, grandpa_pause, - enable_beefy, jaeger_agent, telemetry_worker_handle: None, node_version, diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 457b5488ea14..fa8cb8ec77f7 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -629,7 +629,6 @@ where pub struct NewFullParams { pub is_collator: IsCollator, pub grandpa_pause: Option<(u32, u32)>, - pub enable_beefy: bool, pub jaeger_agent: Option, pub telemetry_worker_handle: Option, /// The version of the node. TESTING ONLY: `None` can be passed to skip the node/worker version @@ -711,7 +710,6 @@ pub fn new_full( NewFullParams { is_collator, grandpa_pause, - enable_beefy, jaeger_agent, telemetry_worker_handle, node_version, @@ -746,6 +744,7 @@ pub fn new_full( Some(backoff) }; + let enable_beefy = !config.disable_beefy; // If not on a known test network, warn the user that BEEFY is still experimental. if enable_beefy && !config.chain_spec.is_rococo() && diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index 99ccacb78f7e..a2c1b1941003 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -81,7 +81,6 @@ pub fn new_full( polkadot_service::NewFullParams { is_collator, grandpa_pause: None, - enable_beefy: true, jaeger_agent: None, telemetry_worker_handle: None, node_version: None, @@ -188,6 +187,7 @@ pub fn node_config( offchain_worker: Default::default(), force_authoring: false, disable_grandpa: false, + disable_beefy: false, dev_key_seed: Some(key_seed), tracing_targets: None, tracing_receiver: Default::default(), diff --git a/parachain/test-parachains/adder/collator/src/main.rs b/parachain/test-parachains/adder/collator/src/main.rs index d4bfc50c8db7..8d8a13767178 100644 --- a/parachain/test-parachains/adder/collator/src/main.rs +++ b/parachain/test-parachains/adder/collator/src/main.rs @@ -53,15 +53,15 @@ fn main() -> Result<()> { ) })?; - runner.run_node_until_exit(|config| async move { + runner.run_node_until_exit(|mut config| async move { let collator = Collator::new(); + config.disable_beefy = true; let full_node = polkadot_service::build_full( config, polkadot_service::NewFullParams { is_collator: polkadot_service::IsCollator::Yes(collator.collator_key()), grandpa_pause: None, - enable_beefy: false, jaeger_agent: None, telemetry_worker_handle: None, diff --git a/parachain/test-parachains/undying/collator/src/main.rs b/parachain/test-parachains/undying/collator/src/main.rs index 3b6b4259aaec..da8205ba1893 100644 --- a/parachain/test-parachains/undying/collator/src/main.rs +++ b/parachain/test-parachains/undying/collator/src/main.rs @@ -53,15 +53,15 @@ fn main() -> Result<()> { ) })?; - runner.run_node_until_exit(|config| async move { + runner.run_node_until_exit(|mut config| async move { let collator = Collator::new(cli.run.pov_size, cli.run.pvf_complexity); + config.disable_beefy = true; let full_node = polkadot_service::build_full( config, polkadot_service::NewFullParams { is_collator: polkadot_service::IsCollator::Yes(collator.collator_key()), grandpa_pause: None, - enable_beefy: false, jaeger_agent: None, telemetry_worker_handle: None, From 9417f1656c7523890a88665a6e89eaeb4be090be Mon Sep 17 00:00:00 2001 From: jserrat <35823283+Jpserrat@users.noreply.github.com> Date: Mon, 14 Aug 2023 06:48:15 -0300 Subject: [PATCH 11/45] pvf: use test-utils feature to export test only (#7538) * pvf: use test-utils feature to export test only * adding comment to test-utils feature * make prepare-worker and execute-worker as optional dependencies and add comments to test-utils * remove doc hidden from pvf testing * add prepare worker and execute worker entrypoints to test-utils feature * pvf: add sp_tracing as optional dependency of test-utils * add test-utils for polkadot and malus * add test-utils feature to prepare and execute workers script * remove required features from prepare and executing * Try to trigger CI again to fix broken jobs --------- Co-authored-by: Marcin S --- Cargo.lock | 3 +++ Cargo.toml | 3 +-- node/core/pvf/Cargo.toml | 13 ++++++++++--- node/core/pvf/common/Cargo.toml | 7 ++++++- node/core/pvf/common/src/lib.rs | 4 ++-- node/core/pvf/common/src/pvf.rs | 6 +++--- node/core/pvf/src/lib.rs | 6 ++++-- node/core/pvf/src/testing.rs | 1 - node/core/pvf/tests/it/worker_common.rs | 6 ++++-- node/malus/Cargo.toml | 2 +- parachain/test-parachains/adder/collator/Cargo.toml | 11 +++++++++-- .../test-parachains/undying/collator/Cargo.toml | 11 +++++++++-- 12 files changed, 52 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 862063ac72e4..85b0bf1cfa57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7238,6 +7238,7 @@ dependencies = [ "parity-scale-codec", "pin-project", "polkadot-core-primitives", + "polkadot-node-core-pvf", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", @@ -12253,6 +12254,7 @@ dependencies = [ "sp-keyring", "substrate-test-utils", "test-parachain-adder", + "test-parachain-adder-collator", "tokio", ] @@ -12301,6 +12303,7 @@ dependencies = [ "sp-keyring", "substrate-test-utils", "test-parachain-undying", + "test-parachain-undying-collator", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 0a6fc1b97891..44cf027e35b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ polkadot-node-core-pvf-prepare-worker = { path = "node/core/pvf/prepare-worker" polkadot-overseer = { path = "node/overseer" } # Needed for worker binaries. -polkadot-node-core-pvf-common = { path = "node/core/pvf/common" } +polkadot-node-core-pvf-common = { path = "node/core/pvf/common", features = ["test-utils"] } polkadot-node-core-pvf-execute-worker = { path = "node/core/pvf/execute-worker" } [dev-dependencies] @@ -227,7 +227,6 @@ fast-runtime = [ "polkadot-cli/fast-runtime" ] runtime-metrics = [ "polkadot-cli/runtime-metrics" ] pyroscope = ["polkadot-cli/pyroscope"] jemalloc-allocator = ["polkadot-node-core-pvf-prepare-worker/jemalloc-allocator", "polkadot-overseer/jemalloc-allocator"] - # Enables timeout-based tests supposed to be run only in CI environment as they may be flaky # when run locally depending on system load ci-only-tests = ["polkadot-node-core-pvf/ci-only-tests"] diff --git a/node/core/pvf/Cargo.toml b/node/core/pvf/Cargo.toml index 02a56ed9d2df..b55df45b0203 100644 --- a/node/core/pvf/Cargo.toml +++ b/node/core/pvf/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true [[bin]] name = "puppet_worker" path = "bin/puppet_worker.rs" +required-features = ["test-utils"] [dependencies] always-assert = "0.1" @@ -27,8 +28,6 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ polkadot-parachain = { path = "../../../parachain" } polkadot-core-primitives = { path = "../../../core-primitives" } polkadot-node-core-pvf-common = { path = "common" } -polkadot-node-core-pvf-execute-worker = { path = "execute-worker" } -polkadot-node-core-pvf-prepare-worker = { path = "prepare-worker" } polkadot-node-metrics = { path = "../../metrics" } polkadot-node-primitives = { path = "../../primitives" } polkadot-primitives = { path = "../../../primitives" } @@ -36,7 +35,9 @@ polkadot-primitives = { path = "../../../primitives" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-wasm-interface = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-maybe-compressed-blob = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } +polkadot-node-core-pvf-prepare-worker = { path = "prepare-worker", optional = true } +polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = true } [build-dependencies] substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -44,9 +45,15 @@ substrate-build-script-utils = { git = "https://github.com/paritytech/substrate" [dev-dependencies] assert_matches = "1.4.0" hex-literal = "0.3.4" +polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } +# For the puppet worker, depend on ourselves with the test-utils feature. +polkadot-node-core-pvf = { path = ".", features = ["test-utils"] } adder = { package = "test-parachain-adder", path = "../../../parachain/test-parachains/adder" } halt = { package = "test-parachain-halt", path = "../../../parachain/test-parachains/halt" } [features] ci-only-tests = [] +# This feature is used to export test code to other crates without putting it in the production build. +# This is also used by the `puppet_worker` binary. +test-utils = ["polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-pvf-execute-worker", "sp-tracing"] diff --git a/node/core/pvf/common/Cargo.toml b/node/core/pvf/common/Cargo.toml index a091f8f75806..dfb490455b3d 100644 --- a/node/core/pvf/common/Cargo.toml +++ b/node/core/pvf/common/Cargo.toml @@ -25,7 +25,7 @@ sc-executor-wasmtime = { git = "https://github.com/paritytech/substrate", branch sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } [target.'cfg(target_os = "linux")'.dependencies] landlock = "0.2.0" @@ -33,3 +33,8 @@ landlock = "0.2.0" [dev-dependencies] assert_matches = "1.4.0" tempfile = "3.3.0" + +[features] +# This feature is used to export test code to other crates without putting it in the production build. +# Also used for building the puppet worker. +test-utils = ["sp-tracing"] diff --git a/node/core/pvf/common/src/lib.rs b/node/core/pvf/common/src/lib.rs index 7e0cab45b671..8ff9757a07a0 100644 --- a/node/core/pvf/common/src/lib.rs +++ b/node/core/pvf/common/src/lib.rs @@ -26,7 +26,7 @@ pub mod worker; pub use cpu_time::ProcessTime; // Used by `decl_worker_main!`. -#[doc(hidden)] +#[cfg(feature = "test-utils")] pub use sp_tracing; const LOG_TARGET: &str = "parachain::pvf-common"; @@ -34,7 +34,7 @@ const LOG_TARGET: &str = "parachain::pvf-common"; use std::mem; use tokio::io::{self, AsyncRead, AsyncReadExt as _, AsyncWrite, AsyncWriteExt as _}; -#[doc(hidden)] +#[cfg(feature = "test-utils")] pub mod tests { use std::time::Duration; diff --git a/node/core/pvf/common/src/pvf.rs b/node/core/pvf/common/src/pvf.rs index ab0007352d1d..e31264713a57 100644 --- a/node/core/pvf/common/src/pvf.rs +++ b/node/core/pvf/common/src/pvf.rs @@ -84,7 +84,7 @@ impl PvfPrepData { } /// Creates a structure for tests. - #[doc(hidden)] + #[cfg(feature = "test-utils")] pub fn from_discriminator_and_timeout(num: u32, timeout: Duration) -> Self { let descriminator_buf = num.to_le_bytes().to_vec(); Self::from_code( @@ -96,13 +96,13 @@ impl PvfPrepData { } /// Creates a structure for tests. - #[doc(hidden)] + #[cfg(feature = "test-utils")] pub fn from_discriminator(num: u32) -> Self { Self::from_discriminator_and_timeout(num, crate::tests::TEST_PREPARATION_TIMEOUT) } /// Creates a structure for tests. - #[doc(hidden)] + #[cfg(feature = "test-utils")] pub fn from_discriminator_precheck(num: u32) -> Self { let mut pvf = Self::from_discriminator_and_timeout(num, crate::tests::TEST_PREPARATION_TIMEOUT); diff --git a/node/core/pvf/src/lib.rs b/node/core/pvf/src/lib.rs index 2ed3f5242ded..eb6ab39ac500 100644 --- a/node/core/pvf/src/lib.rs +++ b/node/core/pvf/src/lib.rs @@ -97,11 +97,11 @@ mod prepare; mod priority; mod worker_intf; -#[doc(hidden)] +#[cfg(feature = "test-utils")] pub mod testing; // Used by `decl_puppet_worker_main!`. -#[doc(hidden)] +#[cfg(feature = "test-utils")] pub use sp_tracing; pub use error::{InvalidCandidate, ValidationError}; @@ -118,7 +118,9 @@ pub use polkadot_node_core_pvf_common::{ }; // Re-export worker entrypoints. +#[cfg(feature = "test-utils")] pub use polkadot_node_core_pvf_execute_worker::worker_entrypoint as execute_worker_entrypoint; +#[cfg(feature = "test-utils")] pub use polkadot_node_core_pvf_prepare_worker::worker_entrypoint as prepare_worker_entrypoint; /// The log target for this crate. diff --git a/node/core/pvf/src/testing.rs b/node/core/pvf/src/testing.rs index 3cd1ce304ab8..980a28c01566 100644 --- a/node/core/pvf/src/testing.rs +++ b/node/core/pvf/src/testing.rs @@ -19,7 +19,6 @@ //! N.B. This is not guarded with some feature flag. Overexposing items here may affect the final //! artifact even for production builds. -#[doc(hidden)] pub use crate::worker_intf::{spawn_with_program_path, SpawnErr}; use polkadot_primitives::ExecutorParams; diff --git a/node/core/pvf/tests/it/worker_common.rs b/node/core/pvf/tests/it/worker_common.rs index 439ac8538c95..a3bf552e894a 100644 --- a/node/core/pvf/tests/it/worker_common.rs +++ b/node/core/pvf/tests/it/worker_common.rs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use crate::PUPPET_EXE; -use polkadot_node_core_pvf::testing::{spawn_with_program_path, SpawnErr}; use std::time::Duration; +use polkadot_node_core_pvf::testing::{spawn_with_program_path, SpawnErr}; + +use crate::PUPPET_EXE; + // Test spawning a program that immediately exits with a failure code. #[tokio::test] async fn spawn_immediate_exit() { diff --git a/node/malus/Cargo.toml b/node/malus/Cargo.toml index 08656ea9f3da..0c9988159516 100644 --- a/node/malus/Cargo.toml +++ b/node/malus/Cargo.toml @@ -48,7 +48,7 @@ erasure = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } rand = "0.8.5" # Required for worker binaries to build. -polkadot-node-core-pvf-common = { path = "../core/pvf/common" } +polkadot-node-core-pvf-common = { path = "../core/pvf/common", features = ["test-utils"] } polkadot-node-core-pvf-execute-worker = { path = "../core/pvf/execute-worker" } polkadot-node-core-pvf-prepare-worker = { path = "../core/pvf/prepare-worker" } diff --git a/parachain/test-parachains/adder/collator/Cargo.toml b/parachain/test-parachains/adder/collator/Cargo.toml index fec95a5718a1..08dcbcaa644e 100644 --- a/parachain/test-parachains/adder/collator/Cargo.toml +++ b/parachain/test-parachains/adder/collator/Cargo.toml @@ -13,6 +13,7 @@ path = "src/main.rs" [[bin]] name = "adder_collator_puppet_worker" path = "bin/puppet_worker.rs" +required-features = ["test-utils"] [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -31,11 +32,10 @@ polkadot-node-subsystem = { path = "../../../../node/subsystem" } sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } - # This one is tricky. Even though it is not used directly by the collator, we still need it for the # `puppet_worker` binary, which is required for the integration test. However, this shouldn't be # a big problem since it is used transitively anyway. -polkadot-node-core-pvf = { path = "../../../../node/core/pvf" } +polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"], optional = true } [dev-dependencies] polkadot-parachain = { path = "../../.." } @@ -44,5 +44,12 @@ polkadot-test-service = { path = "../../../../node/test/service" } substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } +# For the puppet worker, depend on ourselves with the test-utils feature. +test-parachain-adder-collator = { path = ".", features = ["test-utils"] } tokio = { version = "1.24.2", features = ["macros"] } + +[features] +# This feature is used to export test code to other crates without putting it in the production build. +# This is also used by the `puppet_worker` binary. +test-utils = ["polkadot-node-core-pvf/test-utils"] diff --git a/parachain/test-parachains/undying/collator/Cargo.toml b/parachain/test-parachains/undying/collator/Cargo.toml index 4f1a34f977c8..5b5656efb4ac 100644 --- a/parachain/test-parachains/undying/collator/Cargo.toml +++ b/parachain/test-parachains/undying/collator/Cargo.toml @@ -13,6 +13,7 @@ path = "src/main.rs" [[bin]] name = "undying_collator_puppet_worker" path = "bin/puppet_worker.rs" +required-features = ["test-utils"] [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -31,18 +32,24 @@ polkadot-node-subsystem = { path = "../../../../node/subsystem" } sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } - # This one is tricky. Even though it is not used directly by the collator, we still need it for the # `puppet_worker` binary, which is required for the integration test. However, this shouldn't be # a big problem since it is used transitively anyway. -polkadot-node-core-pvf = { path = "../../../../node/core/pvf" } +polkadot-node-core-pvf = { path = "../../../../node/core/pvf", features = ["test-utils"], optional = true } [dev-dependencies] polkadot-parachain = { path = "../../.." } polkadot-test-service = { path = "../../../../node/test/service" } +# For the puppet worker, depend on ourselves with the test-utils feature. +test-parachain-undying-collator = { path = ".", features = ["test-utils"] } substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } tokio = { version = "1.24.2", features = ["macros"] } + +[features] +# This feature is used to export test code to other crates without putting it in the production build. +# This is also used by the `puppet_worker` binary. +test-utils = ["polkadot-node-core-pvf/test-utils"] From 3999688e2cd10dcb48db987b9550049160f9e25d Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 14 Aug 2023 12:00:24 +0200 Subject: [PATCH 12/45] RC container image fixes (#7607) * Remove ENV for the artifacts folder --- .github/workflows/release-40_publish-rc-image.yml | 12 ++++++------ scripts/ci/common/lib.sh | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release-40_publish-rc-image.yml b/.github/workflows/release-40_publish-rc-image.yml index a821eaa033fd..c46bf534b060 100644 --- a/.github/workflows/release-40_publish-rc-image.yml +++ b/.github/workflows/release-40_publish-rc-image.yml @@ -31,7 +31,6 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DOCKER_OWNER: ${{ inputs.owner || github.repository_owner }} REPO: ${{ github.repository }} - ARTIFACT_FOLDER: release-artifacts jobs: fetch-artifacts: @@ -51,7 +50,7 @@ jobs: with: key: artifacts-${{ github.sha }} path: | - ${ARTIFACT_FOLDER}/**/* + ./release-artifacts/**/* build-container: runs-on: ubuntu-latest @@ -69,11 +68,12 @@ jobs: uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: key: artifacts-${{ github.sha }} + fail-on-cache-miss: true path: | - ${ARTIFACT_FOLDER}/**/* + ./release-artifacts/**/* - name: Check sha256 ${{ matrix.binary }} - working-directory: ${ARTIFACT_FOLDER} + working-directory: ./release-artifacts run: | . ../scripts/ci/common/lib.sh @@ -81,7 +81,7 @@ jobs: check_sha256 ${{ matrix.binary }} && echo "OK" || echo "ERR" - name: Check GPG ${{ matrix.binary }} - working-directory: ${ARTIFACT_FOLDER} + working-directory: ./release-artifacts run: | . ../scripts/ci/common/lib.sh import_gpg_keys @@ -102,7 +102,7 @@ jobs: - name: Build Injected Container image for ${{ matrix.binary }} env: - BIN_FOLDER: ${ARTIFACT_FOLDER} + BIN_FOLDER: ./release-artifacts BINARY: ${{ matrix.binary }} TAGS: ${{join(steps.fetch_refs.outputs.*, ',')}} run: | diff --git a/scripts/ci/common/lib.sh b/scripts/ci/common/lib.sh index 00abe9a1d8d4..a04dc2ef1da0 100755 --- a/scripts/ci/common/lib.sh +++ b/scripts/ci/common/lib.sh @@ -201,7 +201,6 @@ check_bootnode(){ fetch_release_artifacts() { echo "Release ID : $RELEASE_ID" echo "Repo : $REPO" - echo "ARTIFACT_FOLDER: $ARTIFACT_FOLDER" curl -L -s \ -H "Accept: application/vnd.github+json" \ @@ -214,8 +213,8 @@ fetch_release_artifacts() { count=$(jq '.assets|length' < release.json ) # Fetch artifacts - mkdir -p ${ARTIFACT_FOLDER} - pushd ${ARTIFACT_FOLDER} > /dev/null + mkdir -p "./release-artifacts" + pushd "./release-artifacts" > /dev/null iter=1 for id in "${ids[@]}" @@ -227,6 +226,7 @@ fetch_release_artifacts() { iter=$((iter + 1)) done + pwd ls -al --color popd > /dev/null } From 7da410e5068689c4864054d5fcce78ce312aef08 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Mon, 14 Aug 2023 13:11:11 +0200 Subject: [PATCH 13/45] Fix the user used to login to Docker hub (#7610) --- .github/workflows/release-40_publish-rc-image.yml | 2 +- scripts/ci/common/lib.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-40_publish-rc-image.yml b/.github/workflows/release-40_publish-rc-image.yml index c46bf534b060..3d91c5b8c682 100644 --- a/.github/workflows/release-40_publish-rc-image.yml +++ b/.github/workflows/release-40_publish-rc-image.yml @@ -112,7 +112,7 @@ jobs: - name: Login to Dockerhub uses: docker/login-action@v2 with: - username: ${{ inputs.owner }} + username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Push Container image for ${{ matrix.binary }} diff --git a/scripts/ci/common/lib.sh b/scripts/ci/common/lib.sh index a04dc2ef1da0..e490ec22d5bf 100755 --- a/scripts/ci/common/lib.sh +++ b/scripts/ci/common/lib.sh @@ -206,7 +206,7 @@ fetch_release_artifacts() { -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/${REPO}/releases/$RELEASE_ID > release.json + https://api.github.com/repos/${REPO}/releases/${RELEASE_ID} > release.json # Get Asset ids ids=($(jq -r '.assets[].id' < release.json )) From c46d7426445ba64cf3ef3158e50e1c7665345a3f Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:52:52 +0300 Subject: [PATCH 14/45] Remove ParityDb migration tests (#7612) --- node/service/src/parachains_db/upgrade.rs | 119 ---------------------- 1 file changed, 119 deletions(-) diff --git a/node/service/src/parachains_db/upgrade.rs b/node/service/src/parachains_db/upgrade.rs index 6041a093ef9b..54ef97afd71c 100644 --- a/node/service/src/parachains_db/upgrade.rs +++ b/node/service/src/parachains_db/upgrade.rs @@ -278,17 +278,6 @@ pub(crate) fn paritydb_version_3_config(path: &Path) -> parity_db::Options { options } -/// Database configuration for version 0. This is useful just for testing. -#[cfg(test)] -pub(crate) fn paritydb_version_0_config(path: &Path) -> parity_db::Options { - let mut options = - parity_db::Options::with_columns(&path, super::columns::v1::NUM_COLUMNS as u8); - options.columns[super::columns::v3::COL_AVAILABILITY_META as usize].btree_index = true; - options.columns[super::columns::v3::COL_CHAIN_SELECTION_DATA as usize].btree_index = true; - - options -} - /// Migration from version 0 to version 1. /// Cases covered: /// - upgrading from v0.9.23 or earlier -> the `dispute coordinator column` was changed @@ -332,82 +321,6 @@ mod tests { *, }; - #[test] - fn test_paritydb_migrate_0_to_1() { - use parity_db::Db; - - let db_dir = tempfile::tempdir().unwrap(); - let path = db_dir.path(); - { - let db = Db::open_or_create(&paritydb_version_0_config(&path)).unwrap(); - - db.commit(vec![ - (COL_DISPUTE_COORDINATOR_DATA as u8, b"1234".to_vec(), Some(b"somevalue".to_vec())), - (COL_AVAILABILITY_META as u8, b"5678".to_vec(), Some(b"somevalue".to_vec())), - ]) - .unwrap(); - } - - try_upgrade_db(&path, DatabaseKind::ParityDB).unwrap(); - - let db = Db::open(&paritydb_version_1_config(&path)).unwrap(); - assert_eq!(db.get(COL_DISPUTE_COORDINATOR_DATA as u8, b"1234").unwrap(), None); - assert_eq!( - db.get(COL_AVAILABILITY_META as u8, b"5678").unwrap(), - Some("somevalue".as_bytes().to_vec()) - ); - } - - #[test] - fn test_paritydb_migrate_1_to_2() { - use parity_db::Db; - - let db_dir = tempfile::tempdir().unwrap(); - let path = db_dir.path(); - - // We need to properly set db version for upgrade to work. - fs::write(version_file_path(path), "1").expect("Failed to write DB version"); - - { - let db = Db::open_or_create(&paritydb_version_1_config(&path)).unwrap(); - - // Write some dummy data - db.commit(vec![( - COL_DISPUTE_COORDINATOR_DATA as u8, - b"1234".to_vec(), - Some(b"somevalue".to_vec()), - )]) - .unwrap(); - - assert_eq!(db.num_columns(), columns::v1::NUM_COLUMNS as u8); - } - - try_upgrade_db(&path, DatabaseKind::ParityDB).unwrap(); - - let db = Db::open(&paritydb_version_2_config(&path)).unwrap(); - - assert_eq!(db.num_columns(), columns::v2::NUM_COLUMNS as u8); - - assert_eq!( - db.get(COL_DISPUTE_COORDINATOR_DATA as u8, b"1234").unwrap(), - Some("somevalue".as_bytes().to_vec()) - ); - - // Test we can write the new column. - db.commit(vec![( - COL_SESSION_WINDOW_DATA as u8, - b"1337".to_vec(), - Some(b"0xdeadb00b".to_vec()), - )]) - .unwrap(); - - // Read back data from new column. - assert_eq!( - db.get(COL_SESSION_WINDOW_DATA as u8, b"1337").unwrap(), - Some("0xdeadb00b".as_bytes().to_vec()) - ); - } - #[test] fn test_rocksdb_migrate_1_to_2() { use kvdb::{DBKey, DBOp}; @@ -467,38 +380,6 @@ mod tests { ); } - #[test] - fn test_paritydb_migrate_2_to_3() { - use parity_db::Db; - - let db_dir = tempfile::tempdir().unwrap(); - let path = db_dir.path(); - let test_key = b"1337"; - - // We need to properly set db version for upgrade to work. - fs::write(version_file_path(path), "2").expect("Failed to write DB version"); - - { - let db = Db::open_or_create(&paritydb_version_2_config(&path)).unwrap(); - - // Write some dummy data - db.commit(vec![( - COL_SESSION_WINDOW_DATA as u8, - test_key.to_vec(), - Some(b"0xdeadb00b".to_vec()), - )]) - .unwrap(); - - assert_eq!(db.num_columns(), columns::v2::NUM_COLUMNS as u8); - } - - try_upgrade_db(&path, DatabaseKind::ParityDB).unwrap(); - - let db = Db::open(&paritydb_version_3_config(&path)).unwrap(); - - assert_eq!(db.num_columns(), columns::v3::NUM_COLUMNS as u8); - } - #[test] fn test_rocksdb_migrate_2_to_3() { use kvdb_rocksdb::{Database, DatabaseConfig}; From 247e4a73ffd930dd8de415a1a8645da5531a373d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 14 Aug 2023 16:29:29 +0200 Subject: [PATCH 15/45] Use same `fmt` and `clippy` configs as in Substrate (#7611) * Use same rustfmt.toml as Substrate Signed-off-by: Oliver Tale-Yazdi * format format file Signed-off-by: Oliver Tale-Yazdi * Format with new config Signed-off-by: Oliver Tale-Yazdi * Add Substrate Clippy config Signed-off-by: Oliver Tale-Yazdi * Print Clippy version in CI Otherwise its difficult to reproduce locally. Signed-off-by: Oliver Tale-Yazdi * Make fmt happy Signed-off-by: Oliver Tale-Yazdi * Update node/core/pvf/src/error.rs Co-authored-by: Tsvetomir Dimitrov * Update node/core/pvf/src/error.rs Co-authored-by: Tsvetomir Dimitrov --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Tsvetomir Dimitrov --- .cargo/config.toml | 1 + cli/src/cli.rs | 4 +- cli/src/command.rs | 4 +- core-primitives/src/lib.rs | 12 +- node/collation-generation/src/lib.rs | 22 ++-- node/collation-generation/src/tests.rs | 10 +- .../approval-voting/src/approval_checking.rs | 8 +- node/core/approval-voting/src/criteria.rs | 15 +-- node/core/approval-voting/src/import.rs | 28 ++--- node/core/approval-voting/src/lib.rs | 35 +++--- node/core/approval-voting/src/ops.rs | 7 +- node/core/av-store/src/lib.rs | 35 +++--- node/core/backing/src/lib.rs | 14 ++- node/core/backing/src/metrics.rs | 3 +- node/core/backing/src/tests.rs | 3 +- node/core/bitfield-signing/src/lib.rs | 4 +- node/core/candidate-validation/src/lib.rs | 33 +++--- node/core/chain-selection/src/lib.rs | 6 +- node/core/dispute-coordinator/src/db/v1.rs | 7 +- node/core/dispute-coordinator/src/import.rs | 8 +- .../dispute-coordinator/src/initialized.rs | 12 +- node/core/dispute-coordinator/src/lib.rs | 19 +-- .../src/participation/queues/mod.rs | 22 ++-- .../src/participation/queues/tests.rs | 4 +- .../src/participation/tests.rs | 3 +- .../src/scraping/candidates.rs | 6 +- .../dispute-coordinator/src/scraping/mod.rs | 15 +-- .../dispute-coordinator/src/scraping/tests.rs | 19 +-- node/core/dispute-coordinator/src/tests.rs | 62 ++++++---- node/core/parachains-inherent/src/lib.rs | 11 +- node/core/provisioner/src/disputes/mod.rs | 6 +- .../src/disputes/prioritized_selection/mod.rs | 45 ++++---- .../disputes/prioritized_selection/tests.rs | 19 +-- node/core/provisioner/src/error.rs | 3 +- node/core/provisioner/src/lib.rs | 33 +++--- node/core/provisioner/src/metrics.rs | 7 +- node/core/provisioner/src/tests.rs | 3 +- node/core/pvf-checker/src/lib.rs | 4 +- node/core/pvf-checker/src/tests.rs | 4 +- node/core/pvf/common/src/error.rs | 23 ++-- node/core/pvf/common/src/executor_intf.rs | 20 ++-- node/core/pvf/common/src/worker/mod.rs | 6 +- node/core/pvf/execute-worker/src/lib.rs | 3 +- node/core/pvf/prepare-worker/src/lib.rs | 17 +-- .../pvf/prepare-worker/src/memory_stats.rs | 4 +- node/core/pvf/src/artifacts.rs | 3 +- node/core/pvf/src/error.rs | 29 ++--- node/core/pvf/src/execute/queue.rs | 3 +- node/core/pvf/src/execute/worker_intf.rs | 8 +- node/core/pvf/src/host.rs | 19 +-- node/core/pvf/src/lib.rs | 30 ++--- node/core/pvf/src/metrics.rs | 3 +- node/core/pvf/src/prepare/pool.rs | 16 +-- node/core/pvf/src/prepare/queue.rs | 5 +- node/core/pvf/src/prepare/worker_intf.rs | 4 +- node/core/pvf/src/worker_intf.rs | 26 +++-- node/core/runtime-api/src/lib.rs | 11 +- node/core/runtime-api/src/tests.rs | 3 +- node/gum/src/lib.rs | 15 ++- node/jaeger/src/lib.rs | 3 +- node/jaeger/src/spans.rs | 4 +- node/malus/src/variants/common.rs | 22 ++-- .../src/variants/dispute_valid_candidates.rs | 11 +- .../src/variants/suggest_garbage_candidate.rs | 11 +- node/metrics/src/lib.rs | 3 +- node/network/approval-distribution/src/lib.rs | 36 +++--- .../src/requester/fetch_task/mod.rs | 3 +- .../src/requester/mod.rs | 17 ++- .../src/futures_undead.rs | 1 - node/network/availability-recovery/src/lib.rs | 49 ++++---- .../availability-recovery/src/tests.rs | 3 +- node/network/bridge/src/rx/mod.rs | 6 +- node/network/bridge/src/rx/tests.rs | 5 +- node/network/bridge/src/tx/mod.rs | 3 +- .../network/bridge/src/validator_discovery.rs | 7 +- .../src/collator_side/mod.rs | 15 +-- .../src/collator_side/tests.rs | 10 +- .../src/collator_side/validators_buffer.rs | 6 +- .../src/validator_side/tests.rs | 3 +- node/network/dispute-distribution/src/lib.rs | 8 +- .../src/receiver/batches/batch.rs | 4 +- .../src/receiver/batches/waiting_queue.rs | 4 +- .../dispute-distribution/src/receiver/mod.rs | 10 +- .../src/sender/send_task.rs | 11 +- node/network/gossip-support/src/lib.rs | 3 +- node/network/protocol/src/grid_topology.rs | 19 +-- node/network/protocol/src/lib.rs | 6 +- node/network/protocol/src/peer_set.rs | 3 +- .../src/request_response/incoming/mod.rs | 4 +- .../protocol/src/request_response/mod.rs | 6 +- .../network/statement-distribution/src/lib.rs | 49 ++++---- .../statement-distribution/src/tests.rs | 8 +- node/overseer/src/lib.rs | 34 +++--- node/primitives/src/disputes/message.rs | 4 +- node/primitives/src/disputes/status.rs | 11 +- node/primitives/src/lib.rs | 26 +++-- node/service/src/chain_spec.rs | 11 +- node/service/src/fake_runtime_api.rs | 3 +- node/service/src/lib.rs | 14 ++- node/service/src/relay_chain_selection.rs | 11 +- node/service/src/tests.rs | 26 ++--- node/subsystem-test-helpers/src/lib.rs | 3 +- node/subsystem-types/src/lib.rs | 4 +- node/subsystem-types/src/messages.rs | 109 ++++++++++-------- node/subsystem-types/src/runtime_client.rs | 7 +- node/subsystem-util/src/lib.rs | 9 +- node/subsystem-util/src/nesting_sender.rs | 21 ++-- node/subsystem-util/src/reputation.rs | 3 +- node/test/client/src/block_builder.rs | 19 +-- node/test/service/src/lib.rs | 12 +- parachain/src/primitives.rs | 17 +-- .../test-parachains/adder/collator/src/lib.rs | 8 +- .../adder/collator/tests/integration.rs | 3 +- .../undying/collator/src/lib.rs | 8 +- .../undying/collator/tests/integration.rs | 3 +- primitives/src/runtime_api.rs | 21 ++-- primitives/src/v5/metrics.rs | 10 +- primitives/src/v5/mod.rs | 79 +++++++------ primitives/test-helpers/src/lib.rs | 3 +- runtime/common/slot_range_helper/src/lib.rs | 8 +- runtime/common/src/assigned_slots.rs | 9 +- runtime/common/src/auctions.rs | 42 +++---- runtime/common/src/claims.rs | 21 ++-- runtime/common/src/crowdloan/migration.rs | 4 +- runtime/common/src/crowdloan/mod.rs | 67 ++++++----- runtime/common/src/integration_tests.rs | 9 +- runtime/common/src/paras_registrar.rs | 44 ++++--- runtime/common/src/paras_sudo_wrapper.rs | 8 +- runtime/common/src/purchase.rs | 23 ++-- runtime/common/src/slots/mod.rs | 33 +++--- runtime/common/src/traits.rs | 25 ++-- runtime/kusama/src/xcm_config.rs | 28 ++--- runtime/parachains/src/builder.rs | 16 +-- runtime/parachains/src/configuration.rs | 48 ++++---- .../src/configuration/migration/v7.rs | 21 ++-- runtime/parachains/src/disputes.rs | 7 +- runtime/parachains/src/disputes/migration.rs | 6 +- runtime/parachains/src/disputes/tests.rs | 6 +- runtime/parachains/src/hrmp.rs | 19 +-- runtime/parachains/src/inclusion/mod.rs | 27 ++--- runtime/parachains/src/initializer.rs | 12 +- runtime/parachains/src/origin.rs | 1 - runtime/parachains/src/paras/mod.rs | 91 ++++++++------- runtime/parachains/src/paras/tests.rs | 8 +- runtime/parachains/src/paras_inherent/mod.rs | 42 ++++--- .../parachains/src/paras_inherent/tests.rs | 51 +++++--- runtime/parachains/src/runtime_api_impl/v5.rs | 3 +- runtime/parachains/src/scheduler.rs | 94 ++++++++------- runtime/parachains/src/scheduler/tests.rs | 14 ++- runtime/parachains/src/shared.rs | 4 +- runtime/parachains/src/util.rs | 4 +- runtime/polkadot/src/governance/old.rs | 3 +- runtime/polkadot/src/xcm_config.rs | 23 ++-- runtime/rococo/src/xcm_config.rs | 12 +- runtime/test-runtime/src/lib.rs | 4 +- runtime/test-runtime/src/xcm_config.rs | 4 +- runtime/westend/src/lib.rs | 4 +- runtime/westend/src/xcm_config.rs | 4 +- rustfmt.toml | 12 +- scripts/ci/gitlab/pipeline/test.yml | 1 + statement-table/src/generic.rs | 17 +-- tests/common.rs | 3 +- utils/staking-miner/src/opts.rs | 26 +++-- utils/staking-miner/src/rpc.rs | 3 +- xcm/pallet-xcm-benchmarks/src/generic/mod.rs | 9 +- xcm/pallet-xcm/src/lib.rs | 108 +++++++++-------- xcm/src/double_encoded.rs | 8 +- xcm/src/lib.rs | 12 +- xcm/src/v2/junction.rs | 16 +-- xcm/src/v2/mod.rs | 78 ++++++------- xcm/src/v2/multiasset.rs | 76 ++++++------ xcm/src/v2/multilocation.rs | 29 ++--- xcm/src/v2/traits.rs | 31 ++--- xcm/src/v3/junction.rs | 39 ++++--- xcm/src/v3/junctions.rs | 18 +-- xcm/src/v3/mod.rs | 69 ++++++----- xcm/src/v3/multiasset.rs | 57 +++++---- xcm/src/v3/multilocation.rs | 14 ++- xcm/src/v3/traits.rs | 9 +- xcm/xcm-builder/src/asset_conversion.rs | 6 +- xcm/xcm-builder/src/currency_adapter.rs | 4 +- xcm/xcm-builder/src/fungibles_adapter.rs | 4 +- xcm/xcm-builder/src/location_conversion.rs | 7 +- xcm/xcm-builder/src/origin_aliases.rs | 3 +- xcm/xcm-builder/src/origin_conversion.rs | 18 +-- xcm/xcm-builder/src/tests/assets.rs | 3 +- .../tests/bridging/paid_remote_relay_relay.rs | 6 +- xcm/xcm-builder/src/tests/mock.rs | 4 +- xcm/xcm-builder/src/tests/querying.rs | 3 +- xcm/xcm-builder/src/universal_exports.rs | 8 +- xcm/xcm-builder/src/weight.rs | 5 +- xcm/xcm-builder/tests/scenarios.rs | 4 +- xcm/xcm-executor/src/assets.rs | 47 ++++---- xcm/xcm-executor/src/lib.rs | 22 ++-- xcm/xcm-executor/src/traits/asset_exchange.rs | 4 +- xcm/xcm-executor/src/traits/asset_lock.rs | 4 +- xcm/xcm-executor/src/traits/conversion.rs | 6 +- .../src/traits/filter_asset_location.rs | 3 +- xcm/xcm-executor/src/traits/on_response.rs | 12 +- xcm/xcm-executor/src/traits/should_execute.rs | 4 +- xcm/xcm-executor/src/traits/transact_asset.rs | 53 +++++---- xcm/xcm-executor/src/traits/weight.rs | 8 +- xcm/xcm-simulator/src/lib.rs | 26 ++--- 203 files changed, 1880 insertions(+), 1504 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 66b28b3485d8..4796a2c26965 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -29,4 +29,5 @@ rustflags = [ "-Aclippy::needless_option_as_deref", # false positives "-Aclippy::derivable_impls", # false positives "-Aclippy::stable_sort_primitive", # prefer stable sort + "-Aclippy::extra-unused-type-parameters", # stylistic ] diff --git a/cli/src/cli.rs b/cli/src/cli.rs index e78213cf11c8..c13340d91a04 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -130,8 +130,8 @@ pub struct RunCmd { pub overseer_channel_capacity_override: Option, /// Path to the directory where auxiliary worker binaries reside. If not specified, the main - /// binary's directory is searched first, then `/usr/lib/polkadot` is searched. TESTING ONLY: if - /// the path points to an executable rather then directory, that executable is used both as + /// binary's directory is searched first, then `/usr/lib/polkadot` is searched. TESTING ONLY: + /// if the path points to an executable rather then directory, that executable is used both as /// preparation and execution worker. #[arg(long, value_name = "PATH")] pub workers_path: Option, diff --git a/cli/src/command.rs b/cli/src/command.rs index c8e8673c6d70..c75f96ee2ebf 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -148,8 +148,8 @@ impl SubstrateCli for Cli { let chain_spec = Box::new(service::PolkadotChainSpec::from_json_file(path.clone())?) as Box; - // When `force_*` is given or the file name starts with the name of one of the known chains, - // we use the chain spec for the specific chain. + // When `force_*` is given or the file name starts with the name of one of the known + // chains, we use the chain spec for the specific chain. if self.run.force_rococo || chain_spec.is_rococo() || chain_spec.is_wococo() || diff --git a/core-primitives/src/lib.rs b/core-primitives/src/lib.rs index 5e06966ecfee..aa01cf8dfc45 100644 --- a/core-primitives/src/lib.rs +++ b/core-primitives/src/lib.rs @@ -91,10 +91,10 @@ impl sp_std::fmt::Debug for CandidateHash { pub type Nonce = u32; /// The balance of an account. -/// 128-bits (or 38 significant decimal figures) will allow for 10 m currency (`10^7`) at a resolution -/// to all for one second's worth of an annualised 50% reward be paid to a unit holder (`10^11` unit -/// denomination), or `10^18` total atomic units, to grow at 50%/year for 51 years (`10^9` multiplier) -/// for an eventual total of `10^27` units (27 significant decimal figures). +/// 128-bits (or 38 significant decimal figures) will allow for 10 m currency (`10^7`) at a +/// resolution to all for one second's worth of an annualised 50% reward be paid to a unit holder +/// (`10^11` unit denomination), or `10^18` total atomic units, to grow at 50%/year for 51 years +/// (`10^9` multiplier) for an eventual total of `10^27` units (27 significant decimal figures). /// We round denomination to `10^12` (12 SDF), and leave the other redundancy at the upper end so /// that 32 bits may be multiplied with a balance in 128 bits without worrying about overflow. pub type Balance = u128; @@ -121,8 +121,8 @@ pub type Remark = [u8; 32]; /// The size of the message is limited by the `config.max_downward_message_size` parameter. pub type DownwardMessage = sp_std::vec::Vec; -/// A wrapped version of `DownwardMessage`. The difference is that it has attached the block number when -/// the message was sent. +/// A wrapped version of `DownwardMessage`. The difference is that it has attached the block number +/// when the message was sent. #[derive(Encode, Decode, Clone, sp_runtime::RuntimeDebug, PartialEq, TypeInfo)] pub struct InboundDownwardMessage { /// The block number at which these messages were put into the downward message queue. diff --git a/node/collation-generation/src/lib.rs b/node/collation-generation/src/lib.rs index 02a0e8df8f61..8726ebf44c71 100644 --- a/node/collation-generation/src/lib.rs +++ b/node/collation-generation/src/lib.rs @@ -22,9 +22,11 @@ //! //! * If there is no collation generation config, ignore. //! * Otherwise, for each `activated` head in the update: -//! * Determine if the para is scheduled on any core by fetching the `availability_cores` Runtime API. +//! * Determine if the para is scheduled on any core by fetching the `availability_cores` Runtime +//! API. //! * Use the Runtime API subsystem to fetch the full validation data. -//! * Invoke the `collator`, and use its outputs to produce a [`CandidateReceipt`], signed with the configuration's `key`. +//! * Invoke the `collator`, and use its outputs to produce a [`CandidateReceipt`], signed with +//! the configuration's `key`. //! * Dispatch a [`CollatorProtocolMessage::DistributeCollation`]`(receipt, pov)`. #![deny(missing_docs)] @@ -77,8 +79,8 @@ impl CollationGenerationSubsystem { /// Conceptually, this is very simple: it just loops forever. /// /// - On incoming overseer messages, it starts or stops jobs as appropriate. - /// - On other incoming messages, if they can be converted into `Job::ToJob` and - /// include a hash, then they're forwarded to the appropriate individual job. + /// - On other incoming messages, if they can be converted into `Job::ToJob` and include a hash, + /// then they're forwarded to the appropriate individual job. /// - On outgoing messages from the jobs, it forwards them to the overseer. /// /// If `err_tx` is not `None`, errors are forwarded onto that channel as they occur. @@ -109,9 +111,10 @@ impl CollationGenerationSubsystem { } // handle an incoming message. return true if we should break afterwards. - // note: this doesn't strictly need to be a separate function; it's more an administrative function - // so that we don't clutter the run loop. It could in principle be inlined directly into there. - // it should hopefully therefore be ok that it's an async function mutably borrowing self. + // note: this doesn't strictly need to be a separate function; it's more an administrative + // function so that we don't clutter the run loop. It could in principle be inlined directly + // into there. it should hopefully therefore be ok that it's an async function mutably borrowing + // self. async fn handle_incoming( &mut self, incoming: SubsystemResult::Message>>, @@ -319,8 +322,9 @@ async fn handle_new_activations( // As long as `POV_BOMB_LIMIT` is at least `max_pov_size`, this ensures // that honest collators never produce a PoV which is uncompressed. // - // As such, honest collators never produce an uncompressed PoV which starts with - // a compression magic number, which would lead validators to reject the collation. + // As such, honest collators never produce an uncompressed PoV which starts + // with a compression magic number, which would lead validators to reject + // the collation. if encoded_size > validation_data.max_pov_size as usize { gum::debug!( target: LOG_TARGET, diff --git a/node/collation-generation/src/tests.rs b/node/collation-generation/src/tests.rs index b2534bcf36c1..1c98e1450941 100644 --- a/node/collation-generation/src/tests.rs +++ b/node/collation-generation/src/tests.rs @@ -203,9 +203,9 @@ mod handle_new_activations { .into_inner(); // the only activated hash should be from the 4 hash: - // each activated hash generates two scheduled cores: one with its value * 4, one with its value * 5 - // given that the test configuration has a `para_id` of 16, there's only one way to get that value: with the 4 - // hash. + // each activated hash generates two scheduled cores: one with its value * 4, one with its + // value * 5 given that the test configuration has a `para_id` of 16, there's only one way + // to get that value: with the 4 hash. assert_eq!(requested_validation_data, vec![[4; 32].into()]); } @@ -301,8 +301,8 @@ mod handle_new_activations { .into_inner(); // we expect a single message to be sent, containing a candidate receipt. - // we don't care too much about the `commitments_hash` right now, but let's ensure that we've calculated the - // correct descriptor + // we don't care too much about the `commitments_hash` right now, but let's ensure that + // we've calculated the correct descriptor let expect_pov_hash = test_collation_compressed().proof_of_validity.into_compressed().hash(); let expect_validation_data_hash = test_validation_data().hash(); diff --git a/node/core/approval-voting/src/approval_checking.rs b/node/core/approval-voting/src/approval_checking.rs index bfecdba73f88..f345b57029b5 100644 --- a/node/core/approval-voting/src/approval_checking.rs +++ b/node/core/approval-voting/src/approval_checking.rs @@ -42,8 +42,8 @@ pub enum RequiredTranches { /// assignments that are before the local time. maximum_broadcast: DelayTranche, /// The clock drift, in ticks, to apply to the local clock when determining whether - /// to broadcast an assignment or when to schedule a wakeup. The local clock should be treated - /// as though it is `clock_drift` ticks earlier. + /// to broadcast an assignment or when to schedule a wakeup. The local clock should be + /// treated as though it is `clock_drift` ticks earlier. clock_drift: Tick, }, /// An exact number of required tranches and a number of no-shows. This indicates that @@ -55,8 +55,8 @@ pub enum RequiredTranches { /// The amount of missing votes that should be tolerated. tolerated_missing: usize, /// When the next no-show would be, if any. This is used to schedule the next wakeup in the - /// event that there are some assignments that don't have corresponding approval votes. If this - /// is `None`, all assignments have approvals. + /// event that there are some assignments that don't have corresponding approval votes. If + /// this is `None`, all assignments have approvals. next_no_show: Option, /// The last tick at which a needed assignment was received. last_assignment_tick: Option, diff --git a/node/core/approval-voting/src/criteria.rs b/node/core/approval-voting/src/criteria.rs index 40a24e2dd937..0e1d18198c21 100644 --- a/node/core/approval-voting/src/criteria.rs +++ b/node/core/approval-voting/src/criteria.rs @@ -218,13 +218,14 @@ impl AssignmentCriteria for RealAssignmentCriteria { } /// Compute the assignments for a given block. Returns a map containing all assignments to cores in -/// the block. If more than one assignment targets the given core, only the earliest assignment is kept. +/// the block. If more than one assignment targets the given core, only the earliest assignment is +/// kept. /// -/// The `leaving_cores` parameter indicates all cores within the block where a candidate was included, -/// as well as the group index backing those. +/// The `leaving_cores` parameter indicates all cores within the block where a candidate was +/// included, as well as the group index backing those. /// -/// The current description of the protocol assigns every validator to check every core. But at different times. -/// The idea is that most assignments are never triggered and fall by the wayside. +/// The current description of the protocol assigns every validator to check every core. But at +/// different times. The idea is that most assignments are never triggered and fall by the wayside. /// /// This will not assign to anything the local validator was part of the backing group for. pub(crate) fn compute_assignments( @@ -463,8 +464,8 @@ pub(crate) enum InvalidAssignmentReason { /// * Sample is out of bounds /// * Validator is present in backing group. /// -/// This function does not check whether the core is actually a valid assignment or not. That should be done -/// outside the scope of this function. +/// This function does not check whether the core is actually a valid assignment or not. That should +/// be done outside the scope of this function. pub(crate) fn check_assignment_cert( claimed_core_index: CoreIndex, validator_index: ValidatorIndex, diff --git a/node/core/approval-voting/src/import.rs b/node/core/approval-voting/src/import.rs index e33caed49c5f..c504ba71b3c2 100644 --- a/node/core/approval-voting/src/import.rs +++ b/node/core/approval-voting/src/import.rs @@ -104,7 +104,8 @@ enum ImportedBlockInfoError { VrfInfoUnavailable, } -/// Computes information about the imported block. Returns an error if the info couldn't be extracted. +/// Computes information about the imported block. Returns an error if the info couldn't be +/// extracted. #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] async fn imported_block_info( ctx: &mut Context, @@ -181,20 +182,21 @@ async fn imported_block_info( // It's not obvious whether to use the hash or the parent hash for this, intuitively. We // want to use the block hash itself, and here's why: // - // First off, 'epoch' in BABE means 'session' in other places. 'epoch' is the terminology from - // the paper, which we fulfill using 'session's, which are a Substrate consensus concept. + // First off, 'epoch' in BABE means 'session' in other places. 'epoch' is the terminology + // from the paper, which we fulfill using 'session's, which are a Substrate consensus + // concept. // - // In BABE, the on-chain and off-chain view of the current epoch can differ at epoch boundaries - // because epochs change precisely at a slot. When a block triggers a new epoch, the state of - // its parent will still have the old epoch. Conversely, we have the invariant that every - // block in BABE has the epoch _it was authored in_ within its post-state. So we use the - // block, and not its parent. + // In BABE, the on-chain and off-chain view of the current epoch can differ at epoch + // boundaries because epochs change precisely at a slot. When a block triggers a new epoch, + // the state of its parent will still have the old epoch. Conversely, we have the invariant + // that every block in BABE has the epoch _it was authored in_ within its post-state. So we + // use the block, and not its parent. // - // It's worth nothing that Polkadot session changes, at least for the purposes of parachains, - // would function the same way, except for the fact that they're always delayed by one block. - // This gives us the opposite invariant for sessions - the parent block's post-state gives - // us the canonical information about the session index for any of its children, regardless - // of which slot number they might be produced at. + // It's worth nothing that Polkadot session changes, at least for the purposes of + // parachains, would function the same way, except for the fact that they're always delayed + // by one block. This gives us the opposite invariant for sessions - the parent block's + // post-state gives us the canonical information about the session index for any of its + // children, regardless of which slot number they might be produced at. ctx.send_message(RuntimeApiMessage::Request( block_hash, RuntimeApiRequest::CurrentBabeEpoch(s_tx), diff --git a/node/core/approval-voting/src/lib.rs b/node/core/approval-voting/src/lib.rs index 05b92f459529..7e29e64c400a 100644 --- a/node/core/approval-voting/src/lib.rs +++ b/node/core/approval-voting/src/lib.rs @@ -1232,8 +1232,8 @@ async fn handle_from_overseer( ); // Our first wakeup will just be the tranche of our assignment, - // if any. This will likely be superseded by incoming assignments - // and approvals which trigger rescheduling. + // if any. This will likely be superseded by incoming + // assignments and approvals which trigger rescheduling. actions.push(Action::ScheduleWakeup { block_hash: block_batch.block_hash, block_number: block_batch.block_number, @@ -1256,12 +1256,14 @@ async fn handle_from_overseer( crate::ops::canonicalize(db, block_number, block_hash) .map_err(|e| SubsystemError::with_origin("db", e))?; - // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans accordingly. + // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans + // accordingly. wakeups.prune_finalized_wakeups(block_number, &mut state.spans); - // // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans accordingly. - // let hash_set = wakeups.block_numbers.values().flatten().collect::>(); - // state.spans.retain(|hash, _| hash_set.contains(hash)); + // // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans + // accordingly. let hash_set = + // wakeups.block_numbers.values().flatten().collect::>(); state.spans. + // retain(|hash, _| hash_set.contains(hash)); Vec::new() }, @@ -1403,8 +1405,8 @@ async fn get_approval_signatures_for_candidate( tx_distribution, )); - // Because of the unbounded sending and the nature of the call (just fetching data from state), - // this should not block long: + // Because of the unbounded sending and the nature of the call (just fetching data from + // state), this should not block long: match rx_distribution.timeout(WAIT_FOR_SIGS_TIMEOUT).await { None => { gum::warn!( @@ -2117,9 +2119,10 @@ impl ApprovalStateTransition { } } -// Advance the approval state, either by importing an approval vote which is already checked to be valid and corresponding to an assigned -// validator on the candidate and block, or by noting that there are no further wakeups or tranches needed. This updates the block entry and candidate entry as -// necessary and schedules any further wakeups. +// Advance the approval state, either by importing an approval vote which is already checked to be +// valid and corresponding to an assigned validator on the candidate and block, or by noting that +// there are no further wakeups or tranches needed. This updates the block entry and candidate entry +// as necessary and schedules any further wakeups. async fn advance_approval_state( sender: &mut Sender, state: &State, @@ -2251,7 +2254,8 @@ where // 1. This is not a local approval, as we don't store anything new in the approval entry. // 2. The candidate is not newly approved, as we haven't altered the approval entry's // approved flag with `mark_approved` above. - // 3. The approver, if any, had already approved the candidate, as we haven't altered the bitfield. + // 3. The approver, if any, had already approved the candidate, as we haven't altered the + // bitfield. if transition.is_local_approval() || newly_approved || !already_approved_by.unwrap_or(true) { // In all other cases, we need to write the candidate entry. @@ -2279,7 +2283,8 @@ fn should_trigger_assignment( &approval_entry, RequiredTranches::All, ) - .is_approved(Tick::max_value()), // when all are required, we are just waiting for the first 1/3+ + // when all are required, we are just waiting for the first 1/3+ + .is_approved(Tick::max_value()), RequiredTranches::Pending { maximum_broadcast, clock_drift, .. } => { let drifted_tranche_now = tranche_now.saturating_sub(clock_drift as DelayTranche); @@ -2615,8 +2620,8 @@ async fn launch_approval( match val_rx.await { Err(_) => return ApprovalState::failed(validator_index, candidate_hash), Ok(Ok(ValidationResult::Valid(_, _))) => { - // Validation checked out. Issue an approval command. If the underlying service is unreachable, - // then there isn't anything we can do. + // Validation checked out. Issue an approval command. If the underlying service is + // unreachable, then there isn't anything we can do. gum::trace!(target: LOG_TARGET, ?candidate_hash, ?para_id, "Candidate Valid"); diff --git a/node/core/approval-voting/src/ops.rs b/node/core/approval-voting/src/ops.rs index 4d6dc5e7ad66..6f57b2f80e8a 100644 --- a/node/core/approval-voting/src/ops.rs +++ b/node/core/approval-voting/src/ops.rs @@ -161,7 +161,8 @@ pub fn canonicalize( } } - // Update all blocks-at-height keys, deleting all those which now have empty `block_assignments`. + // Update all blocks-at-height keys, deleting all those which now have empty + // `block_assignments`. for (h, at) in visited_heights.into_iter() { if at.is_empty() { overlay_db.delete_blocks_at_height(h); @@ -170,8 +171,8 @@ pub fn canonicalize( } } - // due to the fork pruning, this range actually might go too far above where our actual highest block is, - // if a relatively short fork is canonicalized. + // due to the fork pruning, this range actually might go too far above where our actual highest + // block is, if a relatively short fork is canonicalized. // TODO https://github.com/paritytech/polkadot/issues/3389 let new_range = StoredBlockRange(canon_number + 1, std::cmp::max(range.1, canon_number + 2)); diff --git a/node/core/av-store/src/lib.rs b/node/core/av-store/src/lib.rs index 675d41b79c06..ef7dcecac075 100644 --- a/node/core/av-store/src/lib.rs +++ b/node/core/av-store/src/lib.rs @@ -67,8 +67,8 @@ const META_PREFIX: &[u8; 4] = b"meta"; const UNFINALIZED_PREFIX: &[u8; 11] = b"unfinalized"; const PRUNE_BY_TIME_PREFIX: &[u8; 13] = b"prune_by_time"; -// We have some keys we want to map to empty values because existence of the key is enough. We use this because -// rocksdb doesn't support empty values. +// We have some keys we want to map to empty values because existence of the key is enough. We use +// this because rocksdb doesn't support empty values. const TOMBSTONE_VALUE: &[u8] = b" "; /// Unavailable blocks are kept for 1 hour. @@ -139,10 +139,11 @@ enum State { /// Candidate data was first observed at the given time but is not available in any block. #[codec(index = 0)] Unavailable(BETimestamp), - /// The candidate was first observed at the given time and was included in the given list of unfinalized blocks, which may be - /// empty. The timestamp here is not used for pruning. Either one of these blocks will be finalized or the state will regress to - /// `State::Unavailable`, in which case the same timestamp will be reused. Blocks are sorted ascending first by block number and - /// then hash. + /// The candidate was first observed at the given time and was included in the given list of + /// unfinalized blocks, which may be empty. The timestamp here is not used for pruning. Either + /// one of these blocks will be finalized or the state will regress to `State::Unavailable`, in + /// which case the same timestamp will be reused. Blocks are sorted ascending first by block + /// number and then hash. #[codec(index = 1)] Unfinalized(BETimestamp, Vec<(BEBlockNumber, Hash)>), /// Candidate data has appeared in a finalized block and did so at the given time. @@ -820,8 +821,8 @@ fn note_block_included( match load_meta(db, config, &candidate_hash)? { None => { - // This is alarming. We've observed a block being included without ever seeing it backed. - // Warn and ignore. + // This is alarming. We've observed a block being included without ever seeing it + // backed. Warn and ignore. gum::warn!( target: LOG_TARGET, ?candidate_hash, @@ -894,9 +895,9 @@ async fn process_block_finalized( let mut db_transaction = DBTransaction::new(); let (start_prefix, end_prefix) = finalized_block_range(finalized_number); - // We have to do some juggling here of the `iter` to make sure it doesn't cross the `.await` boundary - // as it is not `Send`. That is why we create the iterator once within this loop, drop it, - // do an asynchronous request, and then instantiate the exact same iterator again. + // We have to do some juggling here of the `iter` to make sure it doesn't cross the `.await` + // boundary as it is not `Send`. That is why we create the iterator once within this loop, + // drop it, do an asynchronous request, and then instantiate the exact same iterator again. let batch_num = { let mut iter = subsystem .db @@ -961,8 +962,9 @@ async fn process_block_finalized( update_blocks_at_finalized_height(&subsystem, &mut db_transaction, batch, batch_num, now)?; - // We need to write at the end of the loop so the prefix iterator doesn't pick up the same values again - // in the next iteration. Another unfortunate effect of having to re-initialize the iterator. + // We need to write at the end of the loop so the prefix iterator doesn't pick up the same + // values again in the next iteration. Another unfortunate effect of having to re-initialize + // the iterator. subsystem.db.write(db_transaction)?; } @@ -1215,7 +1217,8 @@ fn process_message( // We do not bubble up internal errors to caller subsystems, instead the // tx channel is dropped and that error is caught by the caller subsystem. // - // We bubble up the specific error here so `av-store` logs still tell what happend. + // We bubble up the specific error here so `av-store` logs still tell what + // happend. return Err(e.into()) }, } @@ -1298,8 +1301,8 @@ fn store_available_data( .with_candidate(candidate_hash) .with_pov(&available_data.pov); - // Important note: This check below is critical for consensus and the `backing` subsystem relies on it to - // ensure candidate validity. + // Important note: This check below is critical for consensus and the `backing` subsystem relies + // on it to ensure candidate validity. let chunks = erasure::obtain_chunks_v1(n_validators, &available_data)?; let branches = erasure::branches(chunks.as_ref()); diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index dc0863cfa0b3..0abfbfad7657 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -422,7 +422,8 @@ struct CandidateBackingJob { awaiting_validation: HashSet, /// Data needed for retrying in case of `ValidatedCandidateCommand::AttestNoPoV`. fallbacks: HashMap)>, - /// `Some(h)` if this job has already issued `Seconded` statement for some candidate with `h` hash. + /// `Some(h)` if this job has already issued `Seconded` statement for some candidate with `h` + /// hash. seconded: Option, /// The candidates that are includable, by hash. Each entry here indicates /// that we've sent the provisioner the backed candidate. @@ -562,9 +563,10 @@ async fn store_available_data( expected_erasure_root: Hash, ) -> Result<(), Error> { let (tx, rx) = oneshot::channel(); - // Important: the `av-store` subsystem will check if the erasure root of the `available_data` matches `expected_erasure_root` - // which was provided by the collator in the `CandidateReceipt`. This check is consensus critical and the `backing` subsystem - // relies on it for ensuring candidate validity. + // Important: the `av-store` subsystem will check if the erasure root of the `available_data` + // matches `expected_erasure_root` which was provided by the collator in the `CandidateReceipt`. + // This check is consensus critical and the `backing` subsystem relies on it for ensuring + // candidate validity. sender .send_message(AvailabilityStoreMessage::StoreAvailableData { candidate_hash, @@ -582,8 +584,8 @@ async fn store_available_data( // Make a `PoV` available. // -// This calls the AV store to write the available data to storage. The AV store also checks the erasure root matches -// the `expected_erasure_root`. +// This calls the AV store to write the available data to storage. The AV store also checks the +// erasure root matches the `expected_erasure_root`. // This returns `Err()` on erasure root mismatch or due to any AV store subsystem error. // // Otherwise, it returns either `Ok(())` diff --git a/node/core/backing/src/metrics.rs b/node/core/backing/src/metrics.rs index 8468ea005404..77f0e7f9d92a 100644 --- a/node/core/backing/src/metrics.rs +++ b/node/core/backing/src/metrics.rs @@ -54,7 +54,8 @@ impl Metrics { self.0.as_ref().map(|metrics| metrics.process_statement.start_timer()) } - /// Provide a timer for handling `CandidateBackingMessage::GetBackedCandidates` which observes on drop. + /// Provide a timer for handling `CandidateBackingMessage::GetBackedCandidates` which observes + /// on drop. pub fn time_get_backed_candidates( &self, ) -> Option { diff --git a/node/core/backing/src/tests.rs b/node/core/backing/src/tests.rs index 35c83297fa71..386cc9e2279e 100644 --- a/node/core/backing/src/tests.rs +++ b/node/core/backing/src/tests.rs @@ -84,7 +84,8 @@ impl Default for TestState { ]; let keystore = Arc::new(sc_keystore::LocalKeystore::in_memory()); - // Make sure `Alice` key is in the keystore, so this mocked node will be a parachain validator. + // Make sure `Alice` key is in the keystore, so this mocked node will be a parachain + // validator. Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, Some(&validators[0].to_seed())) .expect("Insert key into keystore"); diff --git a/node/core/bitfield-signing/src/lib.rs b/node/core/bitfield-signing/src/lib.rs index 1e4d556de7ca..f29e827e1090 100644 --- a/node/core/bitfield-signing/src/lib.rs +++ b/node/core/bitfield-signing/src/lib.rs @@ -137,8 +137,8 @@ async fn get_availability_cores( /// - get the list of core states from the runtime /// - for each core, concurrently determine chunk availability (see `get_core_availability`) -/// - return the bitfield if there were no errors at any point in this process -/// (otherwise, it's prone to false negatives) +/// - return the bitfield if there were no errors at any point in this process (otherwise, it's +/// prone to false negatives) async fn construct_availability_bitfield( relay_parent: Hash, span: &jaeger::Span, diff --git a/node/core/candidate-validation/src/lib.rs b/node/core/candidate-validation/src/lib.rs index 93a7e05c8724..f53f2a6aee06 100644 --- a/node/core/candidate-validation/src/lib.rs +++ b/node/core/candidate-validation/src/lib.rs @@ -67,15 +67,15 @@ mod tests; const LOG_TARGET: &'static str = "parachain::candidate-validation"; -/// The amount of time to wait before retrying after a retry-able backing validation error. We use a lower value for the -/// backing case, to fit within the lower backing timeout. +/// The amount of time to wait before retrying after a retry-able backing validation error. We use a +/// lower value for the backing case, to fit within the lower backing timeout. #[cfg(not(test))] const PVF_BACKING_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(500); #[cfg(test)] const PVF_BACKING_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(200); -/// The amount of time to wait before retrying after a retry-able approval validation error. We use a higher value for -/// the approval case since we have more time, and if we wait longer it is more likely that transient conditions will -/// resolve. +/// The amount of time to wait before retrying after a retry-able approval validation error. We use +/// a higher value for the approval case since we have more time, and if we wait longer it is more +/// likely that transient conditions will resolve. #[cfg(not(test))] const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_secs(3); #[cfg(test)] @@ -451,9 +451,9 @@ where const ASSUMPTIONS: &[OccupiedCoreAssumption] = &[ OccupiedCoreAssumption::Included, OccupiedCoreAssumption::TimedOut, - // `TimedOut` and `Free` both don't perform any speculation and therefore should be the same - // for our purposes here. In other words, if `TimedOut` matched then the `Free` must be - // matched as well. + // `TimedOut` and `Free` both don't perform any speculation and therefore should be the + // same for our purposes here. In other words, if `TimedOut` matched then the `Free` must + // be matched as well. ]; // Consider running these checks in parallel to reduce validation latency. @@ -482,9 +482,10 @@ where AssumptionCheckOutcome::Matches(validation_data, validation_code) => Ok(Some((validation_data, validation_code))), AssumptionCheckOutcome::DoesNotMatch => { - // If neither the assumption of the occupied core having the para included or the assumption - // of the occupied core timing out are valid, then the persisted_validation_data_hash in the descriptor - // is not based on the relay parent and is thus invalid. + // If neither the assumption of the occupied core having the para included or the + // assumption of the occupied core timing out are valid, then the + // persisted_validation_data_hash in the descriptor is not based on the relay parent and + // is thus invalid. Ok(None) }, AssumptionCheckOutcome::BadRequest => @@ -704,7 +705,8 @@ where "Invalid candidate (commitments hash)" ); - // If validation produced a new set of commitments, we treat the candidate as invalid. + // If validation produced a new set of commitments, we treat the candidate as + // invalid. Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch)) } else { Ok(ValidationResult::Valid(outputs, persisted_validation_data)) @@ -744,7 +746,8 @@ trait ValidationBackend { prep_timeout, PrepareJobKind::Compilation, ); - // We keep track of the total time that has passed and stop retrying if we are taking too long. + // We keep track of the total time that has passed and stop retrying if we are taking too + // long. let total_time_start = Instant::now(); let mut validation_result = @@ -780,8 +783,8 @@ trait ValidationBackend { _ => break, } - // If we got a possibly transient error, retry once after a brief delay, on the assumption - // that the conditions that caused this error may have resolved on their own. + // If we got a possibly transient error, retry once after a brief delay, on the + // assumption that the conditions that caused this error may have resolved on their own. { // Wait a brief delay before retrying. futures_timer::Delay::new(retry_delay).await; diff --git a/node/core/chain-selection/src/lib.rs b/node/core/chain-selection/src/lib.rs index 4b512347dae4..aa5bb9548ad2 100644 --- a/node/core/chain-selection/src/lib.rs +++ b/node/core/chain-selection/src/lib.rs @@ -44,13 +44,15 @@ mod tree; mod tests; const LOG_TARGET: &str = "parachain::chain-selection"; -/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS reboots. +/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS +/// reboots. type Timestamp = u64; // If a block isn't approved in 120 seconds, nodes will abandon it // and begin building on another chain. const STAGNANT_TIMEOUT: Timestamp = 120; -// Delay prunning of the stagnant keys in prune only mode by 25 hours to avoid interception with the finality +// Delay prunning of the stagnant keys in prune only mode by 25 hours to avoid interception with the +// finality const STAGNANT_PRUNE_DELAY: Timestamp = 25 * 60 * 60; // Maximum number of stagnant entries cleaned during one `STAGNANT_TIMEOUT` iteration const MAX_STAGNANT_ENTRIES: usize = 1000; diff --git a/node/core/dispute-coordinator/src/db/v1.rs b/node/core/dispute-coordinator/src/db/v1.rs index 2d14f5151003..f0f17d2325d6 100644 --- a/node/core/dispute-coordinator/src/db/v1.rs +++ b/node/core/dispute-coordinator/src/db/v1.rs @@ -52,8 +52,8 @@ const CLEANED_VOTES_WATERMARK_KEY: &[u8; 23] = b"cleaned-votes-watermark"; /// this should not be done at once, but rather in smaller batches so nodes won't get stalled by /// this. /// -/// 300 is with session duration of 1 hour and 30 parachains around <3_000_000 key purges in the worst -/// case. Which is already quite a lot, at the same time we have around 21_000 sessions on +/// 300 is with session duration of 1 hour and 30 parachains around <3_000_000 key purges in the +/// worst case. Which is already quite a lot, at the same time we have around 21_000 sessions on /// Kusama. This means at 300 purged sessions per session, cleaning everything up will take /// around 3 days. Depending on how severe disk usage becomes, we might want to bump the batch /// size, at the cost of risking issues at session boundaries (performance). @@ -346,7 +346,8 @@ pub(crate) fn note_earliest_session( if pruned_disputes.len() != 0 { overlay_db.write_recent_disputes(new_recent_disputes); - // Note: Deleting old candidate votes is handled in `write` based on the earliest session. + // Note: Deleting old candidate votes is handled in `write` based on the + // earliest session. } } }, diff --git a/node/core/dispute-coordinator/src/import.rs b/node/core/dispute-coordinator/src/import.rs index 912521834075..0da3723ebf22 100644 --- a/node/core/dispute-coordinator/src/import.rs +++ b/node/core/dispute-coordinator/src/import.rs @@ -19,12 +19,12 @@ //! This module encapsulates the actual logic for importing new votes and provides easy access of //! the current state for votes for a particular candidate. //! -//! In particular there is `CandidateVoteState` which tells what can be concluded for a particular set of -//! votes. E.g. whether a dispute is ongoing, whether it is confirmed, concluded, .. +//! In particular there is `CandidateVoteState` which tells what can be concluded for a particular +//! set of votes. E.g. whether a dispute is ongoing, whether it is confirmed, concluded, .. //! //! Then there is `ImportResult` which reveals information about what changed once additional votes -//! got imported on top of an existing `CandidateVoteState` and reveals "dynamic" information, like whether -//! due to the import a dispute was raised/got confirmed, ... +//! got imported on top of an existing `CandidateVoteState` and reveals "dynamic" information, like +//! whether due to the import a dispute was raised/got confirmed, ... use std::collections::{BTreeMap, HashMap, HashSet}; diff --git a/node/core/dispute-coordinator/src/initialized.rs b/node/core/dispute-coordinator/src/initialized.rs index 2a1d8fd4b83c..c1d02ef976cb 100644 --- a/node/core/dispute-coordinator/src/initialized.rs +++ b/node/core/dispute-coordinator/src/initialized.rs @@ -92,8 +92,8 @@ pub struct InitialData { pub(crate) struct Initialized { keystore: Arc, runtime_info: RuntimeInfo, - /// This is the highest `SessionIndex` seen via `ActiveLeavesUpdate`. It doesn't matter if it was - /// cached successfully or not. It is used to detect ancient disputes. + /// This is the highest `SessionIndex` seen via `ActiveLeavesUpdate`. It doesn't matter if it + /// was cached successfully or not. It is used to detect ancient disputes. highest_session_seen: SessionIndex, /// Will be set to `true` if an error occured during the last caching attempt gaps_in_cache: bool, @@ -308,8 +308,8 @@ impl Initialized { Ok(session_idx) if self.gaps_in_cache || session_idx > self.highest_session_seen => { - // Fetch the last `DISPUTE_WINDOW` number of sessions unless there are no gaps in - // cache and we are not missing too many `SessionInfo`s + // Fetch the last `DISPUTE_WINDOW` number of sessions unless there are no gaps + // in cache and we are not missing too many `SessionInfo`s let mut lower_bound = session_idx.saturating_sub(DISPUTE_WINDOW.get() - 1); if !self.gaps_in_cache && self.highest_session_seen > lower_bound { lower_bound = self.highest_session_seen + 1 @@ -1133,8 +1133,8 @@ impl Initialized { } // Participate in dispute if we did not cast a vote before and actually have keys to cast a - // local vote. Disputes should fall in one of the categories below, otherwise we will refrain - // from participation: + // local vote. Disputes should fall in one of the categories below, otherwise we will + // refrain from participation: // - `is_included` lands in prioritised queue // - `is_confirmed` | `is_backed` lands in best effort queue // We don't participate in disputes on finalized candidates. diff --git a/node/core/dispute-coordinator/src/lib.rs b/node/core/dispute-coordinator/src/lib.rs index 02bb6ef9ecda..a2c500e08e28 100644 --- a/node/core/dispute-coordinator/src/lib.rs +++ b/node/core/dispute-coordinator/src/lib.rs @@ -17,12 +17,13 @@ //! Implements the dispute coordinator subsystem. //! //! This is the central subsystem of the node-side components which participate in disputes. -//! This subsystem wraps a database which tracks all statements observed by all validators over some window of sessions. -//! Votes older than this session window are pruned. +//! This subsystem wraps a database which tracks all statements observed by all validators over some +//! window of sessions. Votes older than this session window are pruned. //! -//! This subsystem will be the point which produce dispute votes, either positive or negative, based on locally-observed -//! validation results as well as a sink for votes received by other subsystems. When importing a dispute vote from -//! another node, this will trigger dispute participation to recover and validate the block. +//! This subsystem will be the point which produce dispute votes, either positive or negative, based +//! on locally-observed validation results as well as a sink for votes received by other subsystems. +//! When importing a dispute vote from another node, this will trigger dispute participation to +//! recover and validate the block. use std::{num::NonZeroUsize, sync::Arc}; @@ -92,10 +93,10 @@ mod spam_slots; /// Handling of participation requests via `Participation`. /// -/// `Participation` provides an API (`Participation::queue_participation`) for queuing of dispute participations and will process those -/// participation requests, such that most important/urgent disputes will be resolved and processed -/// first and more importantly it will order requests in a way so disputes will get resolved, even -/// if there are lots of them. +/// `Participation` provides an API (`Participation::queue_participation`) for queuing of dispute +/// participations and will process those participation requests, such that most important/urgent +/// disputes will be resolved and processed first and more importantly it will order requests in a +/// way so disputes will get resolved, even if there are lots of them. pub(crate) mod participation; /// Pure processing of vote imports. diff --git a/node/core/dispute-coordinator/src/participation/queues/mod.rs b/node/core/dispute-coordinator/src/participation/queues/mod.rs index 4d8ee585ea29..8a4374999f88 100644 --- a/node/core/dispute-coordinator/src/participation/queues/mod.rs +++ b/node/core/dispute-coordinator/src/participation/queues/mod.rs @@ -294,8 +294,8 @@ impl Queues { return Self::pop_impl(&mut self.priority) } - // `pop_best_effort` and `pop_priority` do the same but on different `BTreeMap`s. This function has - // the extracted implementation + // `pop_best_effort` and `pop_priority` do the same but on different `BTreeMap`s. This function + // has the extracted implementation fn pop_impl( target: &mut BTreeMap, ) -> Option<(CandidateComparator, ParticipationRequest)> { @@ -331,9 +331,10 @@ impl Queues { #[derive(Copy, Clone)] #[cfg_attr(test, derive(Debug))] struct CandidateComparator { - /// Block number of the relay parent. It's wrapped in an `Option<>` because there are cases when - /// it can't be obtained. For example when the node is lagging behind and new leaves are received - /// with a slight delay. Candidates with unknown relay parent are treated with the lowest priority. + /// Block number of the relay parent. It's wrapped in an `Option<>` because there are cases + /// when it can't be obtained. For example when the node is lagging behind and new leaves are + /// received with a slight delay. Candidates with unknown relay parent are treated with the + /// lowest priority. /// /// The order enforced by `CandidateComparator` is important because we want to participate in /// the oldest disputes first. @@ -346,9 +347,10 @@ struct CandidateComparator { /// that is not stable. If a new fork appears after the fact, we would start ordering the same /// candidate differently, which would result in the same candidate getting queued twice. relay_parent_block_number: Option, - /// By adding the `CandidateHash`, we can guarantee a unique ordering across candidates with the - /// same relay parent block number. Candidates without `relay_parent_block_number` are ordered by - /// the `candidate_hash` (and treated with the lowest priority, as already mentioned). + /// By adding the `CandidateHash`, we can guarantee a unique ordering across candidates with + /// the same relay parent block number. Candidates without `relay_parent_block_number` are + /// ordered by the `candidate_hash` (and treated with the lowest priority, as already + /// mentioned). candidate_hash: CandidateHash, } @@ -364,11 +366,11 @@ impl CandidateComparator { /// Create a candidate comparator for a given candidate. /// /// Returns: - /// - `Ok(CandidateComparator{Some(relay_parent_block_number), candidate_hash})` when the + /// - `Ok(CandidateComparator{Some(relay_parent_block_number), candidate_hash})` when the /// relay parent can be obtained. This is the happy case. /// - `Ok(CandidateComparator{None, candidate_hash})` in case the candidate's relay parent /// can't be obtained. - /// - `FatalError` in case the chain API call fails with an unexpected error. + /// - `FatalError` in case the chain API call fails with an unexpected error. pub async fn new( sender: &mut impl overseer::DisputeCoordinatorSenderTrait, candidate: &CandidateReceipt, diff --git a/node/core/dispute-coordinator/src/participation/queues/tests.rs b/node/core/dispute-coordinator/src/participation/queues/tests.rs index 8293a935d11a..5e262d895e31 100644 --- a/node/core/dispute-coordinator/src/participation/queues/tests.rs +++ b/node/core/dispute-coordinator/src/participation/queues/tests.rs @@ -53,8 +53,8 @@ fn clone_request(request: &ParticipationRequest) -> ParticipationRequest { /// Check that dequeuing acknowledges order. /// /// Any priority item will be dequeued before any best effort items, priority and best effort with -/// known parent block number items will be processed in order. Best effort items without known parent -/// block number should be treated with lowest priority. +/// known parent block number items will be processed in order. Best effort items without known +/// parent block number should be treated with lowest priority. #[test] fn ordering_works_as_expected() { let metrics = Metrics::default(); diff --git a/node/core/dispute-coordinator/src/participation/tests.rs b/node/core/dispute-coordinator/src/participation/tests.rs index ab58db4e7628..32725a3ac658 100644 --- a/node/core/dispute-coordinator/src/participation/tests.rs +++ b/node/core/dispute-coordinator/src/participation/tests.rs @@ -305,7 +305,8 @@ fn reqs_get_queued_on_no_recent_block() { // Responds to messages from the test and verifies its behaviour let request_handler = async { - // If we receive `BlockNumber` request this implicitly proves that the participation is queued + // If we receive `BlockNumber` request this implicitly proves that the participation is + // queued assert_matches!( ctx_handle.recv().await, AllMessages::ChainApi(ChainApiMessage::BlockNumber(_, tx)) => { diff --git a/node/core/dispute-coordinator/src/scraping/candidates.rs b/node/core/dispute-coordinator/src/scraping/candidates.rs index 89323907a732..38956700545c 100644 --- a/node/core/dispute-coordinator/src/scraping/candidates.rs +++ b/node/core/dispute-coordinator/src/scraping/candidates.rs @@ -98,7 +98,8 @@ mod ref_counted_candidates_tests { /// Keeps track of scraped candidates. Supports `insert`, `remove_up_to_height` and `contains` /// operations. pub struct ScrapedCandidates { - /// Main data structure which keeps the candidates we know about. `contains` does lookups only here. + /// Main data structure which keeps the candidates we know about. `contains` does lookups only + /// here. candidates: RefCountedCandidates, /// Keeps track at which block number a candidate was inserted. Used in `remove_up_to_height`. /// Without this tracking we won't be able to remove all candidates before block X. @@ -117,7 +118,8 @@ impl ScrapedCandidates { self.candidates.contains(candidate_hash) } - // Removes all candidates up to a given height. The candidates at the block height are NOT removed. + // Removes all candidates up to a given height. The candidates at the block height are NOT + // removed. pub fn remove_up_to_height(&mut self, height: &BlockNumber) -> HashSet { let mut candidates_modified: HashSet = HashSet::new(); let not_stale = self.candidates_by_block_number.split_off(&height); diff --git a/node/core/dispute-coordinator/src/scraping/mod.rs b/node/core/dispute-coordinator/src/scraping/mod.rs index a1e385b5ff85..f93ad0abab91 100644 --- a/node/core/dispute-coordinator/src/scraping/mod.rs +++ b/node/core/dispute-coordinator/src/scraping/mod.rs @@ -120,7 +120,8 @@ impl Inclusions { ) { for candidate in candidates_modified { if let Some(blocks_including) = self.inclusions_inner.get_mut(&candidate) { - // Returns everything after the given key, including the key. This works because the blocks are sorted in ascending order. + // Returns everything after the given key, including the key. This works because the + // blocks are sorted in ascending order. *blocks_including = blocks_including.split_off(height); } } @@ -150,8 +151,8 @@ impl Inclusions { /// /// Concretely: /// -/// - Monitors for `CandidateIncluded` events to keep track of candidates that have been -/// included on chains. +/// - Monitors for `CandidateIncluded` events to keep track of candidates that have been included on +/// chains. /// - Monitors for `CandidateBacked` events to keep track of all backed candidates. /// - Calls `FetchOnChainVotes` for each block to gather potentially missed votes from chain. /// @@ -294,11 +295,11 @@ impl ChainScraper { /// Prune finalized candidates. /// - /// We keep each candidate for `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` blocks after finalization. - /// After that we treat it as low priority. + /// We keep each candidate for `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` blocks after + /// finalization. After that we treat it as low priority. pub fn process_finalized_block(&mut self, finalized_block_number: &BlockNumber) { - // `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION - 1` because `finalized_block_number`counts to the - // candidate lifetime. + // `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION - 1` because + // `finalized_block_number`counts to the candidate lifetime. match finalized_block_number.checked_sub(DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION - 1) { Some(key_to_prune) => { diff --git a/node/core/dispute-coordinator/src/scraping/tests.rs b/node/core/dispute-coordinator/src/scraping/tests.rs index 57e0731056b7..d938304a9e97 100644 --- a/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/node/core/dispute-coordinator/src/scraping/tests.rs @@ -183,7 +183,8 @@ fn get_backed_candidate_event(block_number: BlockNumber) -> Vec GroupIndex::from(0), )] } -/// Hash for a 'magic' candidate. This is meant to be a special candidate used to verify special cases. +/// Hash for a 'magic' candidate. This is meant to be a special candidate used to verify special +/// cases. fn get_magic_candidate_hash() -> Hash { BlakeTwo256::hash(&"abc".encode()) } @@ -425,7 +426,7 @@ fn scraper_requests_candidates_of_non_finalized_ancestors() { &chain, finalized_block_number, BLOCKS_TO_SKIP - - (finalized_block_number - DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION) as usize, // Expect the provider not to go past finalized block. + (finalized_block_number - DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION) as usize, /* Expect the provider not to go past finalized block. */ get_backed_and_included_candidate_events, ); join(process_active_leaves_update(ctx.sender(), &mut ordering, next_update), overseer_fut) @@ -468,7 +469,8 @@ fn scraper_prunes_finalized_candidates() { let candidate = make_candidate_receipt(get_block_number_hash(TEST_TARGET_BLOCK_NUMBER)); - // After `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` blocks the candidate should be removed + // After `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` blocks the candidate should be + // removed finalized_block_number = TEST_TARGET_BLOCK_NUMBER + DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION; process_finalized_block(&mut scraper, &finalized_block_number); @@ -518,8 +520,9 @@ fn scraper_handles_backed_but_not_included_candidate() { finalized_block_number += 1; process_finalized_block(&mut scraper, &finalized_block_number); - // `FIRST_TEST_BLOCK` is finalized, which is within `BACKED_CANDIDATE_LIFETIME_AFTER_FINALIZATION` window. - // The candidate should still be backed. + // `FIRST_TEST_BLOCK` is finalized, which is within + // `BACKED_CANDIDATE_LIFETIME_AFTER_FINALIZATION` window. The candidate should still be + // backed. let candidate = make_candidate_receipt(get_block_number_hash(TEST_TARGET_BLOCK_NUMBER)); assert!(!scraper.is_candidate_included(&candidate.hash())); assert!(scraper.is_candidate_backed(&candidate.hash())); @@ -576,7 +579,8 @@ fn scraper_handles_the_same_candidate_incuded_in_two_different_block_heights() { .await; // Finalize blocks to enforce pruning of scraped events. - // The magic candidate was added twice, so it shouldn't be removed if we finalize two more blocks. + // The magic candidate was added twice, so it shouldn't be removed if we finalize two more + // blocks. finalized_block_number = test_targets.first().expect("there are two block nums") + DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION; process_finalized_block(&mut scraper, &finalized_block_number); @@ -641,7 +645,8 @@ fn inclusions_per_candidate_properly_adds_and_prunes() { ]) ); - // After `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` blocks the earlier inclusion should be removed + // After `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` blocks the earlier inclusion should + // be removed finalized_block_number = TEST_TARGET_BLOCK_NUMBER + DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION; process_finalized_block(&mut scraper, &finalized_block_number); diff --git a/node/core/dispute-coordinator/src/tests.rs b/node/core/dispute-coordinator/src/tests.rs index f2590aea1511..d0cf494d2d4d 100644 --- a/node/core/dispute-coordinator/src/tests.rs +++ b/node/core/dispute-coordinator/src/tests.rs @@ -734,8 +734,9 @@ fn too_many_unconfirmed_statements_are_considered_spam() { .await; // Participation has to fail here, otherwise the dispute will be confirmed. However - // participation won't happen at all because the dispute is neither backed, not confirmed - // nor the candidate is included. Or in other words - we'll refrain from participation. + // participation won't happen at all because the dispute is neither backed, not + // confirmed nor the candidate is included. Or in other words - we'll refrain from + // participation. { let (tx, rx) = oneshot::channel(); @@ -2050,7 +2051,8 @@ fn concluded_supermajority_against_non_active_after_time() { ImportStatementsResult::ValidImport => {} ); - // Use a different expected commitments hash to ensure the candidate validation returns invalid. + // Use a different expected commitments hash to ensure the candidate validation returns + // invalid. participation_with_distribution( &mut virtual_overseer, &candidate_hash, @@ -2351,7 +2353,8 @@ fn resume_dispute_with_local_statement() { assert_eq!(messages.len(), 1, "A message should have gone out."); - // Assert that subsystem is not sending Participation messages because we issued a local statement + // Assert that subsystem is not sending Participation messages because we issued a local + // statement assert!(virtual_overseer.recv().timeout(TEST_TIMEOUT).await.is_none()); virtual_overseer.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; @@ -2445,7 +2448,8 @@ fn resume_dispute_without_local_statement_or_local_key() { Box::pin(async move { test_state.handle_resume_sync(&mut virtual_overseer, session).await; - // Assert that subsystem is not sending Participation messages because we issued a local statement + // Assert that subsystem is not sending Participation messages because we issued a + // local statement assert!(virtual_overseer.recv().timeout(TEST_TIMEOUT).await.is_none()); virtual_overseer.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; @@ -2751,7 +2755,8 @@ fn redundant_votes_ignored() { } #[test] -/// Make sure no disputes are recorded when there are no opposing votes, even if we reached supermajority. +/// Make sure no disputes are recorded when there are no opposing votes, even if we reached +/// supermajority. fn no_onesided_disputes() { test_harness(|mut test_state, mut virtual_overseer| { Box::pin(async move { @@ -3124,16 +3129,17 @@ fn participation_requests_reprioritized_for_newly_included() { candidate_receipt.descriptor.pov_hash = Hash::from( [repetition; 32], // Altering this receipt so its hash will be changed ); - // Set consecutive parents (starting from zero). They will order the candidates for participation. + // Set consecutive parents (starting from zero). They will order the candidates for + // participation. let parent_block_num: BlockNumber = repetition as BlockNumber - 1; candidate_receipt.descriptor.relay_parent = test_state.block_num_to_header.get(&parent_block_num).unwrap().clone(); receipts.push(candidate_receipt.clone()); } - // Mark all candidates as backed, so their participation requests make it to best effort. - // These calls must all occur before including the candidates due to test overseer - // oddities. + // Mark all candidates as backed, so their participation requests make it to best + // effort. These calls must all occur before including the candidates due to test + // overseer oddities. let mut candidate_events = Vec::new(); for r in receipts.iter() { candidate_events.push(make_candidate_backed_event(r.clone())) @@ -3172,7 +3178,8 @@ fn participation_requests_reprioritized_for_newly_included() { .await; // Handle corresponding messages to unblock import - // we need to handle `ApprovalVotingMessage::GetApprovalSignaturesForCandidate` for import + // we need to handle `ApprovalVotingMessage::GetApprovalSignaturesForCandidate` for + // import handle_approval_vote_request( &mut virtual_overseer, &candidate_hash, @@ -3180,8 +3187,9 @@ fn participation_requests_reprioritized_for_newly_included() { ) .await; - // We'll trigger participation for the first `MAX_PARALLEL_PARTICIPATIONS` candidates. - // The rest will be queued => we need to handle `ChainApiMessage::BlockNumber` for them. + // We'll trigger participation for the first `MAX_PARALLEL_PARTICIPATIONS` + // candidates. The rest will be queued => we need to handle + // `ChainApiMessage::BlockNumber` for them. if idx >= crate::participation::MAX_PARALLEL_PARTICIPATIONS { // We send the `idx` as parent block number, because it is used for ordering. // This way we get predictable ordering and participation. @@ -3201,11 +3209,13 @@ fn participation_requests_reprioritized_for_newly_included() { ) .await; - // NB: The checks below are a bit racy. In theory candidate 2 can be processed even before candidate 0 and this is okay. If any - // of the asserts in the two functions after this comment fail -> rework `participation_with_distribution` to expect a set of + // NB: The checks below are a bit racy. In theory candidate 2 can be processed even + // before candidate 0 and this is okay. If any of the asserts in the two functions after + // this comment fail -> rework `participation_with_distribution` to expect a set of // commitment hashes instead of just one. - // This is the candidate for which participation was started initially (`MAX_PARALLEL_PARTICIPATIONS` threshold was not yet hit) + // This is the candidate for which participation was started initially + // (`MAX_PARALLEL_PARTICIPATIONS` threshold was not yet hit) participation_with_distribution( &mut virtual_overseer, &receipts.get(0).expect("There is more than one candidate").hash(), @@ -3326,7 +3336,8 @@ fn informs_chain_selection_when_dispute_concluded_against() { ImportStatementsResult::ValidImport => {} ); - // Use a different expected commitments hash to ensure the candidate validation returns invalid. + // Use a different expected commitments hash to ensure the candidate validation returns + // invalid. participation_with_distribution( &mut virtual_overseer, &candidate_hash, @@ -3440,7 +3451,8 @@ fn session_info_is_requested_only_once() { test_state.handle_resume_sync(&mut virtual_overseer, session).await; - // This leaf activation shouldn't fetch `SessionInfo` because the session is already cached + // This leaf activation shouldn't fetch `SessionInfo` because the session is already + // cached test_state .activate_leaf_at_session( &mut virtual_overseer, @@ -3475,8 +3487,8 @@ fn session_info_is_requested_only_once() { }); } -// Big jump means the new session we see with a leaf update is at least a `DISPUTE_WINDOW` bigger than -// the already known one. In this case The whole `DISPUTE_WINDOW` should be fetched. +// Big jump means the new session we see with a leaf update is at least a `DISPUTE_WINDOW` bigger +// than the already known one. In this case The whole `DISPUTE_WINDOW` should be fetched. #[test] fn session_info_big_jump_works() { test_harness(|mut test_state, mut virtual_overseer| { @@ -3485,7 +3497,8 @@ fn session_info_big_jump_works() { test_state.handle_resume_sync(&mut virtual_overseer, session_on_startup).await; - // This leaf activation shouldn't fetch `SessionInfo` because the session is already cached + // This leaf activation shouldn't fetch `SessionInfo` because the session is already + // cached test_state .activate_leaf_at_session( &mut virtual_overseer, @@ -3525,8 +3538,8 @@ fn session_info_big_jump_works() { }); } -// Small jump means the new session we see with a leaf update is at less than last known one + `DISPUTE_WINDOW`. In this -// case fetching should start from last known one + 1. +// Small jump means the new session we see with a leaf update is at less than last known one + +// `DISPUTE_WINDOW`. In this case fetching should start from last known one + 1. #[test] fn session_info_small_jump_works() { test_harness(|mut test_state, mut virtual_overseer| { @@ -3535,7 +3548,8 @@ fn session_info_small_jump_works() { test_state.handle_resume_sync(&mut virtual_overseer, session_on_startup).await; - // This leaf activation shouldn't fetch `SessionInfo` because the session is already cached + // This leaf activation shouldn't fetch `SessionInfo` because the session is already + // cached test_state .activate_leaf_at_session( &mut virtual_overseer, diff --git a/node/core/parachains-inherent/src/lib.rs b/node/core/parachains-inherent/src/lib.rs index f27481ee5a7d..3063147fb136 100644 --- a/node/core/parachains-inherent/src/lib.rs +++ b/node/core/parachains-inherent/src/lib.rs @@ -16,11 +16,12 @@ //! The parachain inherent data provider //! -//! Parachain backing and approval is an off-chain process, but the parachain needs to progress on chain as well. To -//! make it progress on chain a block producer needs to forward information about the state of a parachain to the -//! runtime. This information is forwarded through an inherent to the runtime. Here we provide the -//! [`ParachainInherentDataProvider`] that requests the relevant data from the provisioner subsystem and creates the -//! the inherent data that the runtime will use to create an inherent. +//! Parachain backing and approval is an off-chain process, but the parachain needs to progress on +//! chain as well. To make it progress on chain a block producer needs to forward information about +//! the state of a parachain to the runtime. This information is forwarded through an inherent to +//! the runtime. Here we provide the [`ParachainInherentDataProvider`] that requests the relevant +//! data from the provisioner subsystem and creates the the inherent data that the runtime will use +//! to create an inherent. #![deny(unused_crate_dependencies, unused_results)] diff --git a/node/core/provisioner/src/disputes/mod.rs b/node/core/provisioner/src/disputes/mod.rs index fab70a054698..2d8f6fb6e93b 100644 --- a/node/core/provisioner/src/disputes/mod.rs +++ b/node/core/provisioner/src/disputes/mod.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! The disputes module is responsible for selecting dispute votes to be sent with the inherent data. +//! The disputes module is responsible for selecting dispute votes to be sent with the inherent +//! data. use crate::LOG_TARGET; use futures::channel::oneshot; @@ -22,7 +23,8 @@ use polkadot_node_primitives::CandidateVotes; use polkadot_node_subsystem::{messages::DisputeCoordinatorMessage, overseer}; use polkadot_primitives::{CandidateHash, SessionIndex}; -/// Request the relevant dispute statements for a set of disputes identified by `CandidateHash` and the `SessionIndex`. +/// Request the relevant dispute statements for a set of disputes identified by `CandidateHash` and +/// the `SessionIndex`. async fn request_votes( sender: &mut impl overseer::ProvisionerSenderTrait, disputes_to_query: Vec<(SessionIndex, CandidateHash)>, diff --git a/node/core/provisioner/src/disputes/prioritized_selection/mod.rs b/node/core/provisioner/src/disputes/prioritized_selection/mod.rs index 5c8aaad422f2..096b73d271a8 100644 --- a/node/core/provisioner/src/disputes/prioritized_selection/mod.rs +++ b/node/core/provisioner/src/disputes/prioritized_selection/mod.rs @@ -48,7 +48,8 @@ pub const MAX_DISPUTE_VOTES_FORWARDED_TO_RUNTIME: usize = 200; /// Controls how much dispute votes to be fetched from the `dispute-coordinator` per iteration in /// `fn vote_selection`. The purpose is to fetch the votes in batches until /// `MAX_DISPUTE_VOTES_FORWARDED_TO_RUNTIME` is reached. If all votes are fetched in single call -/// we might fetch votes which we never use. This will create unnecessary load on `dispute-coordinator`. +/// we might fetch votes which we never use. This will create unnecessary load on +/// `dispute-coordinator`. /// /// This value should be less than `MAX_DISPUTE_VOTES_FORWARDED_TO_RUNTIME`. Increase it in case /// `provisioner` sends too many `QueryCandidateVotes` messages to `dispite-coordinator`. @@ -68,22 +69,23 @@ const VOTES_SELECTION_BATCH_SIZE: usize = 11; /// * Offchain vs Onchain /// * Concluded onchain vs Unconcluded onchain /// -/// Provisioner fetches all disputes from `dispute-coordinator` and separates them in multiple partitions. -/// Please refer to `struct PartitionedDisputes` for details about the actual partitions. -/// Each partition has got a priority implicitly assigned to it and the disputes are selected based on this -/// priority (e.g. disputes in partition 1, then if there is space - disputes from partition 2 and so on). +/// Provisioner fetches all disputes from `dispute-coordinator` and separates them in multiple +/// partitions. Please refer to `struct PartitionedDisputes` for details about the actual +/// partitions. Each partition has got a priority implicitly assigned to it and the disputes are +/// selected based on this priority (e.g. disputes in partition 1, then if there is space - disputes +/// from partition 2 and so on). /// /// # Votes selection /// -/// Besides the prioritization described above the votes in each partition are filtered too. Provisioner -/// fetches all onchain votes and filters them out from all partitions. As a result the Runtime receives -/// only fresh votes (votes it didn't know about). +/// Besides the prioritization described above the votes in each partition are filtered too. +/// Provisioner fetches all onchain votes and filters them out from all partitions. As a result the +/// Runtime receives only fresh votes (votes it didn't know about). /// /// # How the onchain votes are fetched /// -/// The logic outlined above relies on `RuntimeApiRequest::Disputes` message from the Runtime. The user -/// check the Runtime version before calling `select_disputes`. If the function is used with old runtime -/// an error is logged and the logic will continue with empty onchain votes `HashMap`. +/// The logic outlined above relies on `RuntimeApiRequest::Disputes` message from the Runtime. The +/// user check the Runtime version before calling `select_disputes`. If the function is used with +/// old runtime an error is logged and the logic will continue with empty onchain votes `HashMap`. pub async fn select_disputes( sender: &mut Sender, metrics: &metrics::Metrics, @@ -110,7 +112,8 @@ where r }, Err(GetOnchainDisputesError::NotSupported(runtime_api_err, relay_parent)) => { - // Runtime version is checked before calling this method, so the error below should never happen! + // Runtime version is checked before calling this method, so the error below should + // never happen! gum::error!( target: LOG_TARGET, ?runtime_api_err, @@ -152,7 +155,8 @@ where gum::trace!(target: LOG_TARGET, ?leaf, "Filtering recent disputes"); // Filter out unconfirmed disputes. However if the dispute is already onchain - don't skip it. - // In this case we'd better push as much fresh votes as possible to bring it to conclusion faster. + // In this case we'd better push as much fresh votes as possible to bring it to conclusion + // faster. let recent_disputes = recent_disputes .into_iter() .filter(|d| d.2.is_confirmed_concluded() || onchain.contains_key(&(d.0, d.1))) @@ -178,9 +182,9 @@ where make_multi_dispute_statement_set(metrics, result) } -/// Selects dispute votes from `PartitionedDisputes` which should be sent to the runtime. Votes which -/// are already onchain are filtered out. Result should be sorted by `(SessionIndex, CandidateHash)` -/// which is enforced by the `BTreeMap`. This is a requirement from the runtime. +/// Selects dispute votes from `PartitionedDisputes` which should be sent to the runtime. Votes +/// which are already onchain are filtered out. Result should be sorted by `(SessionIndex, +/// CandidateHash)` which is enforced by the `BTreeMap`. This is a requirement from the runtime. async fn vote_selection( sender: &mut Sender, partitioned: PartitionedDisputes, @@ -237,9 +241,9 @@ where for (session_index, candidate_hash, selected_votes) in votes { let votes_len = selected_votes.valid.raw().len() + selected_votes.invalid.len(); if votes_len + total_votes_len > MAX_DISPUTE_VOTES_FORWARDED_TO_RUNTIME { - // we are done - no more votes can be added. Importantly, we don't add any votes for a dispute here - // if we can't fit them all. This gives us an important invariant, that backing votes for - // disputes make it into the provisioned vote set. + // we are done - no more votes can be added. Importantly, we don't add any votes for + // a dispute here if we can't fit them all. This gives us an important invariant, + // that backing votes for disputes make it into the provisioned vote set. gum::trace!( target: LOG_TARGET, ?request_votes_counter, @@ -483,7 +487,8 @@ fn make_multi_dispute_statement_set( .collect() } -/// Gets the on-chain disputes at a given block number and returns them as a `HashMap` so that searching in them is cheap. +/// Gets the on-chain disputes at a given block number and returns them as a `HashMap` so that +/// searching in them is cheap. pub async fn get_onchain_disputes( sender: &mut Sender, relay_parent: Hash, diff --git a/node/core/provisioner/src/disputes/prioritized_selection/tests.rs b/node/core/provisioner/src/disputes/prioritized_selection/tests.rs index 4ae67e3b7968..7798ebe51aaf 100644 --- a/node/core/provisioner/src/disputes/prioritized_selection/tests.rs +++ b/node/core/provisioner/src/disputes/prioritized_selection/tests.rs @@ -237,21 +237,22 @@ fn partitioning_happy_case() { ); } -// This test verifies the double voting behavior. Currently we don't care if a supermajority is achieved with or -// without the 'help' of a double vote (a validator voting for and against at the same time). This makes the test -// a bit pointless but anyway I'm leaving it here to make this decision explicit and have the test code ready in -// case this behavior needs to be further tested in the future. -// Link to the PR with the discussions: https://github.com/paritytech/polkadot/pull/5567 +// This test verifies the double voting behavior. Currently we don't care if a supermajority is +// achieved with or without the 'help' of a double vote (a validator voting for and against at the +// same time). This makes the test a bit pointless but anyway I'm leaving it here to make this +// decision explicit and have the test code ready in case this behavior needs to be further tested +// in the future. Link to the PR with the discussions: https://github.com/paritytech/polkadot/pull/5567 #[test] fn partitioning_doubled_onchain_vote() { let mut input = Vec::<(SessionIndex, CandidateHash, DisputeStatus)>::new(); let mut onchain = HashMap::<(u32, CandidateHash), DisputeState>::new(); - // Dispute A relies on a 'double onchain vote' to conclude. Validator with index 0 has voted both `for` and `against`. - // Despite that this dispute should be considered 'can conclude onchain'. + // Dispute A relies on a 'double onchain vote' to conclude. Validator with index 0 has voted + // both `for` and `against`. Despite that this dispute should be considered 'can conclude + // onchain'. let dispute_a = (3, CandidateHash(Hash::random()), DisputeStatus::Active); - // Dispute B has supermajority + 1 votes, so the doubled onchain vote doesn't affect it. It should be considered - // as 'can conclude onchain'. + // Dispute B has supermajority + 1 votes, so the doubled onchain vote doesn't affect it. It + // should be considered as 'can conclude onchain'. let dispute_b = (4, CandidateHash(Hash::random()), DisputeStatus::Active); input.push(dispute_a.clone()); input.push(dispute_b.clone()); diff --git a/node/core/provisioner/src/error.rs b/node/core/provisioner/src/error.rs index 0f1747995843..5645ed2762bc 100644 --- a/node/core/provisioner/src/error.rs +++ b/node/core/provisioner/src/error.rs @@ -81,7 +81,8 @@ pub enum Error { OverseerExited(SubsystemError), } -/// Used by `get_onchain_disputes` to represent errors related to fetching on-chain disputes from the Runtime +/// Used by `get_onchain_disputes` to represent errors related to fetching on-chain disputes from +/// the Runtime #[allow(dead_code)] // Remove when promoting to stable #[fatality::fatality] pub enum GetOnchainDisputesError { diff --git a/node/core/provisioner/src/lib.rs b/node/core/provisioner/src/lib.rs index 3ae297fee736..b5073763dfab 100644 --- a/node/core/provisioner/src/lib.rs +++ b/node/core/provisioner/src/lib.rs @@ -466,11 +466,11 @@ async fn send_inherent_data( /// - not more than one per validator /// - each 1 bit must correspond to an occupied core /// -/// If we have too many, an arbitrary selection policy is fine. For purposes of maximizing availability, -/// we pick the one with the greatest number of 1 bits. +/// If we have too many, an arbitrary selection policy is fine. For purposes of maximizing +/// availability, we pick the one with the greatest number of 1 bits. /// -/// Note: This does not enforce any sorting precondition on the output; the ordering there will be unrelated -/// to the sorting of the input. +/// Note: This does not enforce any sorting precondition on the output; the ordering there will be +/// unrelated to the sorting of the input. fn select_availability_bitfields( cores: &[CoreState], bitfields: &[SignedAvailabilityBitfield], @@ -532,7 +532,8 @@ fn select_availability_bitfields( selected.into_values().collect() } -/// Determine which cores are free, and then to the degree possible, pick a candidate appropriate to each free core. +/// Determine which cores are free, and then to the degree possible, pick a candidate appropriate to +/// each free core. async fn select_candidates( availability_cores: &[CoreState], bitfields: &[SignedAvailabilityBitfield], @@ -593,7 +594,8 @@ async fn select_candidates( let computed_validation_data_hash = validation_data.hash(); - // we arbitrarily pick the first of the backed candidates which match the appropriate selection criteria + // we arbitrarily pick the first of the backed candidates which match the appropriate + // selection criteria if let Some(candidate) = candidates.iter().find(|backed_candidate| { let descriptor = &backed_candidate.descriptor; descriptor.para_id == scheduled_core.para_id && @@ -628,12 +630,12 @@ async fn select_candidates( gum::trace!(target: LOG_TARGET, leaf_hash=?relay_parent, "Got {} backed candidates", candidates.len()); - // `selected_candidates` is generated in ascending order by core index, and `GetBackedCandidates` - // _should_ preserve that property, but let's just make sure. + // `selected_candidates` is generated in ascending order by core index, and + // `GetBackedCandidates` _should_ preserve that property, but let's just make sure. // - // We can't easily map from `BackedCandidate` to `core_idx`, but we know that every selected candidate - // maps to either 0 or 1 backed candidate, and the hashes correspond. Therefore, by checking them - // in order, we can ensure that the backed candidates are also in order. + // We can't easily map from `BackedCandidate` to `core_idx`, but we know that every selected + // candidate maps to either 0 or 1 backed candidate, and the hashes correspond. Therefore, by + // checking them in order, we can ensure that the backed candidates are also in order. let mut backed_idx = 0; for selected in selected_candidates { if selected == @@ -705,8 +707,9 @@ fn bitfields_indicate_availability( let validator_idx = bitfield.validator_index().0 as usize; match availability.get_mut(validator_idx) { None => { - // in principle, this function might return a `Result` so that we can more clearly express this error condition - // however, in practice, that would just push off an error-handling routine which would look a whole lot like this one. + // in principle, this function might return a `Result` so that we can + // more clearly express this error condition however, in practice, that would just + // push off an error-handling routine which would look a whole lot like this one. // simpler to just handle the error internally here. gum::warn!( target: LOG_TARGET, @@ -726,8 +729,8 @@ fn bitfields_indicate_availability( 3 * availability.count_ones() >= 2 * availability.len() } -// If we have to be absolutely precise here, this method gets the version of the `ParachainHost` api. -// For brevity we'll just call it 'runtime version'. +// If we have to be absolutely precise here, this method gets the version of the `ParachainHost` +// api. For brevity we'll just call it 'runtime version'. async fn has_required_runtime( sender: &mut impl overseer::ProvisionerSenderTrait, relay_parent: Hash, diff --git a/node/core/provisioner/src/metrics.rs b/node/core/provisioner/src/metrics.rs index c65d999d04a7..fabbd798cf02 100644 --- a/node/core/provisioner/src/metrics.rs +++ b/node/core/provisioner/src/metrics.rs @@ -28,9 +28,10 @@ struct MetricsInner { /// Bitfields array length in `ProvisionerInherentData` (the result for `RequestInherentData`) inherent_data_response_bitfields: prometheus::Histogram, - /// The following metrics track how many disputes/votes the runtime will have to process. These will count - /// all recent statements meaning every dispute from last sessions: 10 min on Rococo, 60 min on Kusama and - /// 4 hours on Polkadot. The metrics are updated only when the node authors a block, so values vary across nodes. + /// The following metrics track how many disputes/votes the runtime will have to process. These + /// will count all recent statements meaning every dispute from last sessions: 10 min on + /// Rococo, 60 min on Kusama and 4 hours on Polkadot. The metrics are updated only when the + /// node authors a block, so values vary across nodes. inherent_data_dispute_statement_sets: prometheus::Counter, inherent_data_dispute_statements: prometheus::CounterVec, diff --git a/node/core/provisioner/src/tests.rs b/node/core/provisioner/src/tests.rs index e8692df8543a..4a469a43c893 100644 --- a/node/core/provisioner/src/tests.rs +++ b/node/core/provisioner/src/tests.rs @@ -90,7 +90,8 @@ mod select_availability_bitfields { let cores = vec![occupied_core(0), occupied_core(1)]; // we pass in three bitfields with two validators - // this helps us check the postcondition that we get two bitfields back, for which the validators differ + // this helps us check the postcondition that we get two bitfields back, for which the + // validators differ let bitfields = vec![ signed_bitfield(&keystore, bitvec.clone(), ValidatorIndex(0)), signed_bitfield(&keystore, bitvec.clone(), ValidatorIndex(1)), diff --git a/node/core/pvf-checker/src/lib.rs b/node/core/pvf-checker/src/lib.rs index 222e85e36542..2946f3f78861 100644 --- a/node/core/pvf-checker/src/lib.rs +++ b/node/core/pvf-checker/src/lib.rs @@ -110,8 +110,8 @@ struct State { /// /// Here are some fun facts about these futures: /// - /// - Pre-checking can take quite some time, in the matter of tens of seconds, so the futures here - /// can soak for quite some time. + /// - Pre-checking can take quite some time, in the matter of tens of seconds, so the futures + /// here can soak for quite some time. /// - Pre-checking of one PVF can take drastically more time than pre-checking of another PVF. /// This leads to results coming out of order. /// diff --git a/node/core/pvf-checker/src/tests.rs b/node/core/pvf-checker/src/tests.rs index 46e760936144..b223b1b54c0b 100644 --- a/node/core/pvf-checker/src/tests.rs +++ b/node/core/pvf-checker/src/tests.rs @@ -110,8 +110,8 @@ impl TestState { Self { leaves, sessions, last_session_index } } - /// A convenience function to receive a message from the overseer and returning `None` if nothing - /// was received within a reasonable (for local tests anyway) timeout. + /// A convenience function to receive a message from the overseer and returning `None` if + /// nothing was received within a reasonable (for local tests anyway) timeout. async fn recv_timeout(&mut self, handle: &mut VirtualOverseer) -> Option { futures::select! { msg = handle.recv().fuse() => { diff --git a/node/core/pvf/common/src/error.rs b/node/core/pvf/common/src/error.rs index 64d17800ac10..6eb0d9b7df42 100644 --- a/node/core/pvf/common/src/error.rs +++ b/node/core/pvf/common/src/error.rs @@ -18,8 +18,8 @@ use crate::prepare::PrepareStats; use parity_scale_codec::{Decode, Encode}; use std::fmt; -/// Result of PVF preparation performed by the validation host. Contains stats about the preparation if -/// successful +/// Result of PVF preparation performed by the validation host. Contains stats about the preparation +/// if successful pub type PrepareResult = Result; /// An error that occurred during the prepare part of the PVF pipeline. @@ -35,13 +35,15 @@ pub enum PrepareError { Panic(String), /// Failed to prepare the PVF due to the time limit. TimedOut, - /// An IO error occurred. This state is reported by either the validation host or by the worker. + /// An IO error occurred. This state is reported by either the validation host or by the + /// worker. IoErr(String), - /// The temporary file for the artifact could not be created at the given cache path. This state is reported by the - /// validation host (not by the worker). + /// The temporary file for the artifact could not be created at the given cache path. This + /// state is reported by the validation host (not by the worker). CreateTmpFileErr(String), - /// The response from the worker is received, but the file cannot be renamed (moved) to the final destination - /// location. This state is reported by the validation host (not by the worker). + /// The response from the worker is received, but the file cannot be renamed (moved) to the + /// final destination location. This state is reported by the validation host (not by the + /// worker). RenameTmpFileErr(String), } @@ -81,15 +83,16 @@ impl fmt::Display for PrepareError { /// Some internal error occurred. /// -/// Should only ever be used for validation errors independent of the candidate and PVF, or for errors we ruled out -/// during pre-checking (so preparation errors are fine). +/// Should only ever be used for validation errors independent of the candidate and PVF, or for +/// errors we ruled out during pre-checking (so preparation errors are fine). #[derive(Debug, Clone, Encode, Decode)] pub enum InternalValidationError { /// Some communication error occurred with the host. HostCommunication(String), /// Could not find or open compiled artifact file. CouldNotOpenFile(String), - /// An error occurred in the CPU time monitor thread. Should be totally unrelated to validation. + /// An error occurred in the CPU time monitor thread. Should be totally unrelated to + /// validation. CpuTimeMonitorThread(String), /// Some non-deterministic preparation error occurred. NonDeterministicPrepareError(PrepareError), diff --git a/node/core/pvf/common/src/executor_intf.rs b/node/core/pvf/common/src/executor_intf.rs index ef74e5f2ca92..42ed4b79c761 100644 --- a/node/core/pvf/common/src/executor_intf.rs +++ b/node/core/pvf/common/src/executor_intf.rs @@ -35,10 +35,10 @@ use std::any::{Any, TypeId}; // left for the stack; this is, of course, overridable at link time when compiling the runtime) // plus the number of pages specified in the `extra_heap_pages` passed to the executor. // -// By default, rustc (or `lld` specifically) should allocate 1 MiB for the shadow stack, or 16 pages. -// The data section for runtimes are typically rather small and can fit in a single digit number of -// WASM pages, so let's say an extra 16 pages. Thus let's assume that 32 pages or 2 MiB are used for -// these needs by default. +// By default, rustc (or `lld` specifically) should allocate 1 MiB for the shadow stack, or 16 +// pages. The data section for runtimes are typically rather small and can fit in a single digit +// number of WASM pages, so let's say an extra 16 pages. Thus let's assume that 32 pages or 2 MiB +// are used for these needs by default. const DEFAULT_HEAP_PAGES_ESTIMATE: u32 = 32; const EXTRA_HEAP_PAGES: u32 = 2048; @@ -65,9 +65,9 @@ pub const DEFAULT_CONFIG: Config = Config { // // Here is how the values below were chosen. // - // At the moment of writing, the default native stack size limit is 1 MiB. Assuming a logical item - // (see the docs about the field and the instrumentation algorithm) is 8 bytes, 1 MiB can - // fit 2x 65536 logical items. + // At the moment of writing, the default native stack size limit is 1 MiB. Assuming a + // logical item (see the docs about the field and the instrumentation algorithm) is 8 bytes, + // 1 MiB can fit 2x 65536 logical items. // // Since reaching the native stack limit is undesirable, we halve the logical item limit and // also increase the native 256x. This hopefully should preclude wasm code from reaching @@ -113,7 +113,7 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Result sem.wasm_bulk_memory = true, // TODO: Not implemented yet; . ExecutorParam::PrecheckingMaxMemory(_) => (), - ExecutorParam::PvfPrepTimeout(_, _) | ExecutorParam::PvfExecTimeout(_, _) => (), // Not used here + ExecutorParam::PvfPrepTimeout(_, _) | ExecutorParam::PvfExecTimeout(_, _) => (), /* Not used here */ } } sem.deterministic_stack_limit = Some(stack_limit); @@ -135,8 +135,8 @@ impl Executor { Ok(Self { config }) } - /// Executes the given PVF in the form of a compiled artifact and returns the result of execution - /// upon success. + /// Executes the given PVF in the form of a compiled artifact and returns the result of + /// execution upon success. /// /// # Safety /// diff --git a/node/core/pvf/common/src/worker/mod.rs b/node/core/pvf/common/src/worker/mod.rs index 8dd99fc762d8..d9a0dff71b24 100644 --- a/node/core/pvf/common/src/worker/mod.rs +++ b/node/core/pvf/common/src/worker/mod.rs @@ -251,9 +251,9 @@ pub mod thread { Arc::new((Mutex::new(WaitOutcome::Pending), Condvar::new())) } - /// Runs a worker thread. Will first enable security features, and afterwards notify the threads waiting on the - /// condvar. Catches panics during execution and resumes the panics after triggering the condvar, so that the - /// waiting thread is notified on panics. + /// Runs a worker thread. Will first enable security features, and afterwards notify the threads + /// waiting on the condvar. Catches panics during execution and resumes the panics after + /// triggering the condvar, so that the waiting thread is notified on panics. /// /// # Returns /// diff --git a/node/core/pvf/execute-worker/src/lib.rs b/node/core/pvf/execute-worker/src/lib.rs index c6ee515f9093..6f632a0ae95e 100644 --- a/node/core/pvf/execute-worker/src/lib.rs +++ b/node/core/pvf/execute-worker/src/lib.rs @@ -239,7 +239,8 @@ pub fn worker_entrypoint( WaitOutcome::TimedOut => { match cpu_time_monitor_thread.join() { Ok(Some(cpu_time_elapsed)) => { - // Log if we exceed the timeout and the other thread hasn't finished. + // Log if we exceed the timeout and the other thread hasn't + // finished. gum::warn!( target: LOG_TARGET, %worker_pid, diff --git a/node/core/pvf/prepare-worker/src/lib.rs b/node/core/pvf/prepare-worker/src/lib.rs index 3f60163c6196..caa7d33df12a 100644 --- a/node/core/pvf/prepare-worker/src/lib.rs +++ b/node/core/pvf/prepare-worker/src/lib.rs @@ -190,8 +190,9 @@ pub fn worker_entrypoint( // If we are pre-checking, check for runtime construction errors. // - // As pre-checking is more strict than just preparation in terms of memory and - // time, it is okay to do extra checks here. This takes negligible time anyway. + // As pre-checking is more strict than just preparation in terms of memory + // and time, it is okay to do extra checks here. This takes negligible time + // anyway. if let PrepareJobKind::Prechecking = prepare_job_kind { result = result.and_then(|output| { runtime_construction_check(output.0.as_ref(), executor_params)?; @@ -253,10 +254,11 @@ pub fn worker_entrypoint( // Write the serialized artifact into a temp file. // - // PVF host only keeps artifacts statuses in its memory, successfully - // compiled code gets stored on the disk (and consequently deserialized - // by execute-workers). The prepare worker is only required to send `Ok` - // to the pool to indicate the success. + // PVF host only keeps artifacts statuses in its memory, + // successfully compiled code gets stored on the disk (and + // consequently deserialized by execute-workers). The prepare worker + // is only required to send `Ok` to the pool to indicate the + // success. gum::debug!( target: LOG_TARGET, @@ -275,7 +277,8 @@ pub fn worker_entrypoint( WaitOutcome::TimedOut => { match cpu_time_monitor_thread.join() { Ok(Some(cpu_time_elapsed)) => { - // Log if we exceed the timeout and the other thread hasn't finished. + // Log if we exceed the timeout and the other thread hasn't + // finished. gum::warn!( target: LOG_TARGET, %worker_pid, diff --git a/node/core/pvf/prepare-worker/src/memory_stats.rs b/node/core/pvf/prepare-worker/src/memory_stats.rs index e6dc8572c4a3..7904dfa9cb88 100644 --- a/node/core/pvf/prepare-worker/src/memory_stats.rs +++ b/node/core/pvf/prepare-worker/src/memory_stats.rs @@ -83,8 +83,8 @@ pub mod memory_tracker { /// /// # Errors /// - /// For simplicity, any errors are returned as a string. As this is not a critical component, errors - /// are used for informational purposes (logging) only. + /// For simplicity, any errors are returned as a string. As this is not a critical component, + /// errors are used for informational purposes (logging) only. pub fn memory_tracker_loop(condvar: thread::Cond) -> Result { // NOTE: This doesn't need to be too fine-grained since preparation currently takes 3-10s or // more. Apart from that, there is not really a science to this number. diff --git a/node/core/pvf/src/artifacts.rs b/node/core/pvf/src/artifacts.rs index 78d2f88941b8..a180af15db27 100644 --- a/node/core/pvf/src/artifacts.rs +++ b/node/core/pvf/src/artifacts.rs @@ -224,7 +224,8 @@ impl Artifacts { .is_none()); } - /// Remove and retrieve the artifacts from the table that are older than the supplied Time-To-Live. + /// Remove and retrieve the artifacts from the table that are older than the supplied + /// Time-To-Live. pub fn prune(&mut self, artifact_ttl: Duration) -> Vec { let now = SystemTime::now(); diff --git a/node/core/pvf/src/error.rs b/node/core/pvf/src/error.rs index 7372cd233c49..cb35ec9e9d9a 100644 --- a/node/core/pvf/src/error.rs +++ b/node/core/pvf/src/error.rs @@ -38,29 +38,30 @@ pub enum InvalidCandidate { /// The worker has died during validation of a candidate. That may fall in one of the following /// categories, which we cannot distinguish programmatically: /// - /// (a) Some sort of transient glitch caused the worker process to abort. An example would be that - /// the host machine ran out of free memory and the OOM killer started killing the processes, - /// and in order to save the parent it will "sacrifice child" first. + /// (a) Some sort of transient glitch caused the worker process to abort. An example would be + /// that the host machine ran out of free memory and the OOM killer started killing the + /// processes, and in order to save the parent it will "sacrifice child" first. /// /// (b) The candidate triggered a code path that has lead to the process death. For example, - /// the PVF found a way to consume unbounded amount of resources and then it either exceeded - /// an `rlimit` (if set) or, again, invited OOM killer. Another possibility is a bug in - /// wasmtime allowed the PVF to gain control over the execution worker. + /// the PVF found a way to consume unbounded amount of resources and then it either + /// exceeded an `rlimit` (if set) or, again, invited OOM killer. Another possibility is a + /// bug in wasmtime allowed the PVF to gain control over the execution worker. /// /// We attribute such an event to an *invalid candidate* in either case. /// /// The rationale for this is that a glitch may lead to unfair rejecting candidate by a single - /// validator. If the glitch is somewhat more persistent the validator will reject all candidate - /// thrown at it and hopefully the operator notices it by decreased reward performance of the - /// validator. On the other hand, if the worker died because of (b) we would have better chances - /// to stop the attack. + /// validator. If the glitch is somewhat more persistent the validator will reject all + /// candidate thrown at it and hopefully the operator notices it by decreased reward + /// performance of the validator. On the other hand, if the worker died because of (b) we would + /// have better chances to stop the attack. AmbiguousWorkerDeath, /// PVF execution (compilation is not included) took more time than was allotted. HardTimeout, - /// A panic occurred and we can't be sure whether the candidate is really invalid or some internal glitch occurred. - /// Whenever we are unsure, we can never treat an error as internal as we would abstain from voting. This is bad - /// because if the issue was due to the candidate, then all validators would abstain, stalling finality on the - /// chain. So we will first retry the candidate, and if the issue persists we are forced to vote invalid. + /// A panic occurred and we can't be sure whether the candidate is really invalid or some + /// internal glitch occurred. Whenever we are unsure, we can never treat an error as internal + /// as we would abstain from voting. This is bad because if the issue was due to the candidate, + /// then all validators would abstain, stalling finality on the chain. So we will first retry + /// the candidate, and if the issue persists we are forced to vote invalid. Panic(String), } diff --git a/node/core/pvf/src/execute/queue.rs b/node/core/pvf/src/execute/queue.rs index 33a1c6f89709..acb260e25693 100644 --- a/node/core/pvf/src/execute/queue.rs +++ b/node/core/pvf/src/execute/queue.rs @@ -419,7 +419,8 @@ fn spawn_extra_worker(queue: &mut Queue, job: ExecuteJob) { /// beforehand. In such a way, a race condition is avoided: during the worker being spawned, /// another job in the queue, with an incompatible execution environment, may become stale, and /// the queue would have to kill a newly started worker and spawn another one. -/// Nevertheless, if the worker finishes executing the job, it becomes idle and may be used to execute other jobs with a compatible execution environment. +/// Nevertheless, if the worker finishes executing the job, it becomes idle and may be used to +/// execute other jobs with a compatible execution environment. async fn spawn_worker_task( program_path: PathBuf, job: ExecuteJob, diff --git a/node/core/pvf/src/execute/worker_intf.rs b/node/core/pvf/src/execute/worker_intf.rs index 9d8b61d10447..948abd2261d7 100644 --- a/node/core/pvf/src/execute/worker_intf.rs +++ b/node/core/pvf/src/execute/worker_intf.rs @@ -74,8 +74,9 @@ pub enum Outcome { /// PVF execution completed successfully and the result is returned. The worker is ready for /// another job. Ok { result_descriptor: ValidationResult, duration: Duration, idle_worker: IdleWorker }, - /// The candidate validation failed. It may be for example because the wasm execution triggered a trap. - /// Errors related to the preparation process are not expected to be encountered by the execution workers. + /// The candidate validation failed. It may be for example because the wasm execution triggered + /// a trap. Errors related to the preparation process are not expected to be encountered by the + /// execution workers. InvalidCandidate { err: String, idle_worker: IdleWorker }, /// An internal error happened during the validation. Such an error is most likely related to /// some transient glitch. @@ -95,7 +96,8 @@ pub enum Outcome { /// Given the idle token of a worker and parameters of work, communicates with the worker and /// returns the outcome. /// -/// NOTE: Not returning the idle worker token in `Outcome` will trigger the child process being killed. +/// NOTE: Not returning the idle worker token in `Outcome` will trigger the child process being +/// killed. pub async fn start_work( worker: IdleWorker, artifact: ArtifactPathId, diff --git a/node/core/pvf/src/host.rs b/node/core/pvf/src/host.rs index a5772e34e16e..9f3b7e23fd89 100644 --- a/node/core/pvf/src/host.rs +++ b/node/core/pvf/src/host.rs @@ -455,8 +455,8 @@ async fn handle_precheck_pvf( ArtifactState::Preparing { waiting_for_response, num_failures: _ } => waiting_for_response.push(result_sender), ArtifactState::FailedToProcess { error, .. } => { - // Do not retry failed preparation if another pre-check request comes in. We do not retry pre-checking, - // anyway. + // Do not retry failed preparation if another pre-check request comes in. We do not + // retry pre-checking, anyway. let _ = result_sender.send(PrepareResult::Err(error.clone())); }, } @@ -470,8 +470,8 @@ async fn handle_precheck_pvf( /// Handles PVF execution. /// -/// This will try to prepare the PVF, if a prepared artifact does not already exist. If there is already a -/// preparation job, we coalesce the two preparation jobs. +/// This will try to prepare the PVF, if a prepared artifact does not already exist. If there is +/// already a preparation job, we coalesce the two preparation jobs. /// /// If the prepare job succeeded previously, we will enqueue an execute job right away. /// @@ -521,7 +521,8 @@ async fn handle_execute_pvf( "handle_execute_pvf: Re-queuing PVF preparation for prepared artifact with missing file." ); - // The artifact has been prepared previously but the file is missing, prepare it again. + // The artifact has been prepared previously but the file is missing, prepare it + // again. *state = ArtifactState::Preparing { waiting_for_response: Vec::new(), num_failures: 0, @@ -721,8 +722,8 @@ async fn handle_prepare_done( pending_requests { if result_tx.is_canceled() { - // Preparation could've taken quite a bit of time and the requester may be not interested - // in execution anymore, in which case we just skip the request. + // Preparation could've taken quite a bit of time and the requester may be not + // interested in execution anymore, in which case we just skip the request. continue } @@ -855,8 +856,8 @@ fn can_retry_prepare_after_failure( return false } - // Retry if the retry cooldown has elapsed and if we have already retried less than `NUM_PREPARE_RETRIES` times. IO - // errors may resolve themselves. + // Retry if the retry cooldown has elapsed and if we have already retried less than + // `NUM_PREPARE_RETRIES` times. IO errors may resolve themselves. SystemTime::now() >= last_time_failed + PREPARE_FAILURE_COOLDOWN && num_failures <= NUM_PREPARE_RETRIES } diff --git a/node/core/pvf/src/lib.rs b/node/core/pvf/src/lib.rs index eb6ab39ac500..1da0593835fb 100644 --- a/node/core/pvf/src/lib.rs +++ b/node/core/pvf/src/lib.rs @@ -32,26 +32,26 @@ //! (a) PVF pre-checking. This takes the `Pvf` code and tries to prepare it (verify and //! compile) in order to pre-check its validity. //! -//! (b) PVF execution. This accepts the PVF [`params`][`polkadot_parachain::primitives::ValidationParams`] -//! and the `Pvf` code, prepares (verifies and compiles) the code, and then executes PVF -//! with the `params`. +//! (b) PVF execution. This accepts the PVF +//! [`params`][`polkadot_parachain::primitives::ValidationParams`] and the `Pvf` code, prepares +//! (verifies and compiles) the code, and then executes PVF with the `params`. //! //! (c) Heads up. This request allows to signal that the given PVF may be needed soon and that it //! should be prepared for execution. //! -//! The preparation results are cached for some time after they either used or was signaled in heads up. -//! All requests that depends on preparation of the same PVF are bundled together and will be executed -//! as soon as the artifact is prepared. +//! The preparation results are cached for some time after they either used or was signaled in heads +//! up. All requests that depends on preparation of the same PVF are bundled together and will be +//! executed as soon as the artifact is prepared. //! //! # Priority //! -//! PVF execution requests can specify the [priority][`Priority`] with which the given request should -//! be handled. Different priority levels have different effects. This is discussed below. +//! PVF execution requests can specify the [priority][`Priority`] with which the given request +//! should be handled. Different priority levels have different effects. This is discussed below. //! //! Preparation started by a heads up signal always starts with the background priority. If there -//! is already a request for that PVF preparation under way the priority is inherited. If after heads -//! up, a new PVF execution request comes in with a higher priority, then the original task's priority -//! will be adjusted to match the new one if it's larger. +//! is already a request for that PVF preparation under way the priority is inherited. If after +//! heads up, a new PVF execution request comes in with a higher priority, then the original task's +//! priority will be adjusted to match the new one if it's larger. //! //! Priority can never go down, only up. //! @@ -63,11 +63,11 @@ //! dissimilar to actors. Each of such "processes" is a future task that contains an event loop that //! processes incoming messages, potentially delegating sub-tasks to other "processes". //! -//! Two of these processes are queues. The first one is for preparation jobs and the second one is for -//! execution. Both of the queues are backed by separate pools of workers of different kind. +//! Two of these processes are queues. The first one is for preparation jobs and the second one is +//! for execution. Both of the queues are backed by separate pools of workers of different kind. //! -//! Preparation workers handle preparation requests by prevalidating and instrumenting PVF wasm code, -//! and then passing it into the compiler, to prepare the artifact. +//! Preparation workers handle preparation requests by prevalidating and instrumenting PVF wasm +//! code, and then passing it into the compiler, to prepare the artifact. //! //! ## Artifacts //! diff --git a/node/core/pvf/src/metrics.rs b/node/core/pvf/src/metrics.rs index 62f8c6dc5157..3d792793498b 100644 --- a/node/core/pvf/src/metrics.rs +++ b/node/core/pvf/src/metrics.rs @@ -85,7 +85,8 @@ impl Metrics { #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] if let Some(tracker_stats) = memory_stats.memory_tracker_stats { - // We convert these stats from B to KB to match the unit of `ru_maxrss` from `getrusage`. + // We convert these stats from B to KB to match the unit of `ru_maxrss` from + // `getrusage`. let max_resident_kb = (tracker_stats.resident / 1024) as f64; let max_allocated_kb = (tracker_stats.allocated / 1024) as f64; diff --git a/node/core/pvf/src/prepare/pool.rs b/node/core/pvf/src/prepare/pool.rs index 1e8ccc7365bf..92aa4896c263 100644 --- a/node/core/pvf/src/prepare/pool.rs +++ b/node/core/pvf/src/prepare/pool.rs @@ -61,9 +61,9 @@ pub enum ToPool { /// Request the given worker to start working on the given code. /// - /// Once the job either succeeded or failed, a [`FromPool::Concluded`] message will be sent back. - /// It's also possible that the worker dies before handling the message in which case [`FromPool::Rip`] - /// will be sent back. + /// Once the job either succeeded or failed, a [`FromPool::Concluded`] message will be sent + /// back. It's also possible that the worker dies before handling the message in which case + /// [`FromPool::Rip`] will be sent back. /// /// In either case, the worker is considered busy and no further `StartWork` messages should be /// sent until either `Concluded` or `Rip` message is received. @@ -237,8 +237,8 @@ fn handle_to_pool( ); } else { // idle token is present after spawn and after a job is concluded; - // the precondition for `StartWork` is it should be sent only if all previous work - // items concluded; + // the precondition for `StartWork` is it should be sent only if all previous + // work items concluded; // thus idle token is Some; // qed. never!("unexpected absence of the idle token in prepare pool"); @@ -311,7 +311,8 @@ fn handle_mux( match outcome { Outcome::Concluded { worker: idle, result } => handle_concluded_no_rip(from_pool, spawned, worker, idle, result), - // Return `Concluded`, but do not kill the worker since the error was on the host side. + // Return `Concluded`, but do not kill the worker since the error was on the host + // side. Outcome::CreateTmpFileErr { worker: idle, err } => handle_concluded_no_rip( from_pool, spawned, @@ -319,7 +320,8 @@ fn handle_mux( idle, Err(PrepareError::CreateTmpFileErr(err)), ), - // Return `Concluded`, but do not kill the worker since the error was on the host side. + // Return `Concluded`, but do not kill the worker since the error was on the host + // side. Outcome::RenameTmpFileErr { worker: idle, result: _, err } => handle_concluded_no_rip( from_pool, diff --git a/node/core/pvf/src/prepare/queue.rs b/node/core/pvf/src/prepare/queue.rs index 5e19a4c7217a..c38012d74548 100644 --- a/node/core/pvf/src/prepare/queue.rs +++ b/node/core/pvf/src/prepare/queue.rs @@ -96,8 +96,9 @@ impl WorkerData { } } -/// A queue structured like this is prone to starving, however, we don't care that much since we expect -/// there is going to be a limited number of critical jobs and we don't really care if background starve. +/// A queue structured like this is prone to starving, however, we don't care that much since we +/// expect there is going to be a limited number of critical jobs and we don't really care if +/// background starve. #[derive(Default)] struct Unscheduled { normal: VecDeque, diff --git a/node/core/pvf/src/prepare/worker_intf.rs b/node/core/pvf/src/prepare/worker_intf.rs index d0d9a026dda7..5280ab6b42a2 100644 --- a/node/core/pvf/src/prepare/worker_intf.rs +++ b/node/core/pvf/src/prepare/worker_intf.rs @@ -247,8 +247,8 @@ where let outcome = f(tmp_file.clone(), stream).await; - // The function called above is expected to move `tmp_file` to a new location upon success. However, - // the function may as well fail and in that case we should remove the tmp file here. + // The function called above is expected to move `tmp_file` to a new location upon success. + // However, the function may as well fail and in that case we should remove the tmp file here. // // In any case, we try to remove the file here so that there are no leftovers. We only report // errors that are different from the `NotFound`. diff --git a/node/core/pvf/src/worker_intf.rs b/node/core/pvf/src/worker_intf.rs index ef5733ec0e6d..795ad4524443 100644 --- a/node/core/pvf/src/worker_intf.rs +++ b/node/core/pvf/src/worker_intf.rs @@ -196,13 +196,15 @@ pub enum SpawnErr { Handshake, } -/// This is a representation of a potentially running worker. Drop it and the process will be killed. +/// This is a representation of a potentially running worker. Drop it and the process will be +/// killed. /// /// A worker's handle is also a future that resolves when it's detected that the worker's process /// has been terminated. Since the worker is running in another process it is obviously not /// necessary to poll this future to make the worker run, it's only for termination detection. /// -/// This future relies on the fact that a child process's stdout `fd` is closed upon it's termination. +/// This future relies on the fact that a child process's stdout `fd` is closed upon it's +/// termination. #[pin_project] pub struct WorkerHandle { child: process::Child, @@ -240,15 +242,15 @@ impl WorkerHandle { child_id, stdout, program: program.as_ref().to_path_buf(), - // We don't expect the bytes to be ever read. But in case we do, we should not use a buffer - // of a small size, because otherwise if the child process does return any data we will end up - // issuing a syscall for each byte. We also prefer not to do allocate that on the stack, since - // each poll the buffer will be allocated and initialized (and that's due `poll_read` takes &mut [u8] - // and there are no guarantees that a `poll_read` won't ever read from there even though that's - // unlikely). + // We don't expect the bytes to be ever read. But in case we do, we should not use a + // buffer of a small size, because otherwise if the child process does return any data + // we will end up issuing a syscall for each byte. We also prefer not to do allocate + // that on the stack, since each poll the buffer will be allocated and initialized (and + // that's due `poll_read` takes &mut [u8] and there are no guarantees that a `poll_read` + // won't ever read from there even though that's unlikely). // - // OTOH, we also don't want to be super smart here and we could just afford to allocate a buffer - // for that here. + // OTOH, we also don't want to be super smart here and we could just afford to allocate + // a buffer for that here. drop_box: vec![0; 8192].into_boxed_slice(), }) } @@ -280,8 +282,8 @@ impl futures::Future for WorkerHandle { } }, Err(err) => { - // The implementation is guaranteed to not to return `WouldBlock` and Interrupted. This - // leaves us with legit errors which we suppose were due to termination. + // The implementation is guaranteed to not to return `WouldBlock` and Interrupted. + // This leaves us with legit errors which we suppose were due to termination. // Log the status code. gum::debug!( diff --git a/node/core/runtime-api/src/lib.rs b/node/core/runtime-api/src/lib.rs index 252bb21b0edb..0ee5ca24ceee 100644 --- a/node/core/runtime-api/src/lib.rs +++ b/node/core/runtime-api/src/lib.rs @@ -321,7 +321,8 @@ where return futures::pending!() } - // If there are active requests, this will always resolve to `Some(_)` when a request is finished. + // If there are active requests, this will always resolve to `Some(_)` when a request is + // finished. if let Some(Ok(Some(result))) = self.active_requests.next().await { self.store_cache(result); } @@ -343,10 +344,10 @@ where { loop { // Let's add some back pressure when the subsystem is running at `MAX_PARALLEL_REQUESTS`. - // This can never block forever, because `active_requests` is owned by this task and any mutations - // happen either in `poll_requests` or `spawn_request` - so if `is_busy` returns true, then - // even if all of the requests finish before us calling `poll_requests` the `active_requests` length - // remains invariant. + // This can never block forever, because `active_requests` is owned by this task and any + // mutations happen either in `poll_requests` or `spawn_request` - so if `is_busy` returns + // true, then even if all of the requests finish before us calling `poll_requests` the + // `active_requests` length remains invariant. if subsystem.is_busy() { // Since we are not using any internal waiting queues, we need to wait for exactly // one request to complete before we can read the next one from the overseer channel. diff --git a/node/core/runtime-api/src/tests.rs b/node/core/runtime-api/src/tests.rs index 27090a102ec2..33f5eef3869f 100644 --- a/node/core/runtime-api/src/tests.rs +++ b/node/core/runtime-api/src/tests.rs @@ -895,7 +895,8 @@ fn multiple_requests_in_parallel_are_working() { receivers.push(rx); } - // The backpressure from reaching `MAX_PARALLEL_REQUESTS` will make the test block, we need to drop the lock. + // The backpressure from reaching `MAX_PARALLEL_REQUESTS` will make the test block, we need + // to drop the lock. drop(lock); for _ in 0..MAX_PARALLEL_REQUESTS * 100 { diff --git a/node/gum/src/lib.rs b/node/gum/src/lib.rs index e989a15ae4e3..1cc4d8dec1cb 100644 --- a/node/gum/src/lib.rs +++ b/node/gum/src/lib.rs @@ -67,14 +67,13 @@ //! //! Here's the rundown on how fields work: //! -//! - Fields on spans and events are specified using the `syntax field_name = -//! field_value`. -//! - Local variables may be used as field values without an assignment, similar to -//! struct initializers. -//! - The `?` sigil is shorthand that specifies a field should be recorded using its -//! `fmt::Debug` implementation. -//! - The `%` sigil operates similarly, but indicates that the value should be -//! recorded using its `fmt::Display` implementation. +//! - Fields on spans and events are specified using the `syntax field_name = field_value`. +//! - Local variables may be used as field values without an assignment, similar to struct +//! initializers. +//! - The `?` sigil is shorthand that specifies a field should be recorded using its `fmt::Debug` +//! implementation. +//! - The `%` sigil operates similarly, but indicates that the value should be recorded using its +//! `fmt::Display` implementation. //! //! For full details, again see [the tracing //! docs](https://docs.rs/tracing/latest/tracing/index.html#recording-fields). diff --git a/node/jaeger/src/lib.rs b/node/jaeger/src/lib.rs index 99222589d4ab..7de458606816 100644 --- a/node/jaeger/src/lib.rs +++ b/node/jaeger/src/lib.rs @@ -132,7 +132,8 @@ impl Jaeger { match tokio::net::UdpSocket::bind("0.0.0.0:0").await { Ok(udp_socket) => loop { let buf = traces_out.next().await; - // UDP sending errors happen only either if the API is misused or in case of missing privilege. + // UDP sending errors happen only either if the API is misused or in case of + // missing privilege. if let Err(e) = udp_socket.send_to(&buf, jaeger_agent).await { log::debug!(target: "jaeger", "UDP send error: {}", e); } diff --git a/node/jaeger/src/spans.rs b/node/jaeger/src/spans.rs index be8bf9cd5ddc..4038d41344f2 100644 --- a/node/jaeger/src/spans.rs +++ b/node/jaeger/src/spans.rs @@ -110,8 +110,8 @@ impl PerLeafSpan { /// Creates a new instance. /// /// Takes the `leaf_span` that is created by the overseer per leaf and a name for a child span. - /// Both will be stored in this object, while the child span is implicitly accessible by using the - /// [`Deref`](std::ops::Deref) implementation. + /// Both will be stored in this object, while the child span is implicitly accessible by using + /// the [`Deref`](std::ops::Deref) implementation. pub fn new(leaf_span: Arc, name: &'static str) -> Self { let span = leaf_span.child(name); diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 4ea8b88b56a5..ab1dfbbb360a 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -125,8 +125,8 @@ where Self { fake_validation, fake_validation_error, distribution, spawner } } - /// Creates and sends the validation response for a given candidate. Queries the runtime to obtain the validation data for the - /// given candidate. + /// Creates and sends the validation response for a given candidate. Queries the runtime to + /// obtain the validation data for the given candidate. pub fn send_validation_response( &self, candidate_descriptor: CandidateDescriptor, @@ -203,7 +203,8 @@ where { type Message = CandidateValidationMessage; - // Capture all (approval and backing) candidate validation requests and depending on configuration fail them. + // Capture all (approval and backing) candidate validation requests and depending on + // configuration fail them. fn intercept_incoming( &self, subsystem_sender: &mut Sender, @@ -279,7 +280,8 @@ where }, FakeCandidateValidation::ApprovalInvalid | FakeCandidateValidation::BackingAndApprovalInvalid => { - // Set the validation result to invalid with probability `p` and trigger a dispute + // Set the validation result to invalid with probability `p` and trigger a + // dispute let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); match behave_maliciously { true => { @@ -294,7 +296,8 @@ where &validation_result, ); - // We're not even checking the candidate, this makes us appear faster than honest validators. + // We're not even checking the candidate, this makes us appear + // faster than honest validators. sender.send(Ok(validation_result)).unwrap(); None }, @@ -370,7 +373,8 @@ where ); None }, - // If the `PoV` is malicious, we behave normally with some probability `(1-p)` + // If the `PoV` is malicious, we behave normally with some probability + // `(1-p)` false => Some(FromOrchestra::Communication { msg: CandidateValidationMessage::ValidateFromChainState( candidate_receipt, @@ -383,7 +387,8 @@ where }, FakeCandidateValidation::BackingInvalid | FakeCandidateValidation::BackingAndApprovalInvalid => { - // Maliciously set the validation result to invalid for a valid candidate with probability `p` + // Maliciously set the validation result to invalid for a valid candidate + // with probability `p` let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); match behave_maliciously { true => { @@ -396,7 +401,8 @@ where "😈 Maliciously sending invalid validation result: {:?}.", &validation_result, ); - // We're not even checking the candidate, this makes us appear faster than honest validators. + // We're not even checking the candidate, this makes us appear + // faster than honest validators. response_sender.send(Ok(validation_result)).unwrap(); None }, diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index ab1fba478beb..9ea8449a1d0b 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -45,14 +45,15 @@ use std::sync::Arc; #[command(rename_all = "kebab-case")] #[allow(missing_docs)] pub struct DisputeAncestorOptions { - /// Malicious candidate validation subsystem configuration. When enabled, node PVF execution is skipped - /// during backing and/or approval and it's result can by specified by this option and `--fake-validation-error` - /// for invalid candidate outcomes. + /// Malicious candidate validation subsystem configuration. When enabled, node PVF execution is + /// skipped during backing and/or approval and it's result can by specified by this option and + /// `--fake-validation-error` for invalid candidate outcomes. #[arg(long, value_enum, ignore_case = true, default_value_t = FakeCandidateValidation::BackingAndApprovalInvalid)] pub fake_validation: FakeCandidateValidation, - /// Applies only when `--fake-validation` is configured to reject candidates as invalid. It allows - /// to specify the exact error to return from the malicious candidate validation subsystem. + /// Applies only when `--fake-validation` is configured to reject candidates as invalid. It + /// allows to specify the exact error to return from the malicious candidate validation + /// subsystem. #[arg(long, value_enum, ignore_case = true, default_value_t = FakeCandidateValidationError::InvalidOutputs)] pub fake_validation_error: FakeCandidateValidationError, diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 9fd8f6473bde..7d301c194b44 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -88,14 +88,15 @@ where "Received request to second candidate", ); - // Need to draw value from Bernoulli distribution with given probability of success defined by the clap parameter. - // Note that clap parameter must be f64 since this is expected by the Bernoulli::new() function. - // It must be converted from u8, due to the lack of support for the .range() call on u64 in the clap crate. + // Need to draw value from Bernoulli distribution with given probability of success + // defined by the clap parameter. Note that clap parameter must be f64 since this is + // expected by the Bernoulli::new() function. It must be converted from u8, due to + // the lack of support for the .range() call on u64 in the clap crate. let distribution = Bernoulli::new(self.percentage / 100.0) .expect("Invalid probability! Percentage must be in range [0..=100]."); - // Draw a random boolean from the Bernoulli distribution with probability of true equal to `p`. - // We use `rand::thread_rng` as the source of randomness. + // Draw a random boolean from the Bernoulli distribution with probability of true + // equal to `p`. We use `rand::thread_rng` as the source of randomness. let generate_malicious_candidate = distribution.sample(&mut rand::thread_rng()); if generate_malicious_candidate == true { diff --git a/node/metrics/src/lib.rs b/node/metrics/src/lib.rs index 69b3771d696a..9cb0f289a580 100644 --- a/node/metrics/src/lib.rs +++ b/node/metrics/src/lib.rs @@ -19,7 +19,8 @@ //! Collects a bunch of metrics providers and related features such as //! `Metronome` for usage with metrics collections. //! -//! This crate also reexports Prometheus metric types which are expected to be implemented by subsystems. +//! This crate also reexports Prometheus metric types which are expected to be implemented by +//! subsystems. #![deny(missing_docs)] #![deny(unused_imports)] diff --git a/node/network/approval-distribution/src/lib.rs b/node/network/approval-distribution/src/lib.rs index bc85f54177cb..803a56251495 100644 --- a/node/network/approval-distribution/src/lib.rs +++ b/node/network/approval-distribution/src/lib.rs @@ -102,11 +102,13 @@ impl RecentlyOutdated { // Aggression has 3 levels: // // * Aggression Level 0: The basic behaviors described above. -// * Aggression Level 1: The originator of a message sends to all peers. Other peers follow the rules above. -// * Aggression Level 2: All peers send all messages to all their row and column neighbors. -// This means that each validator will, on average, receive each message approximately `2*sqrt(n)` times. -// The aggression level of messages pertaining to a block increases when that block is unfinalized and -// is a child of the finalized block. +// * Aggression Level 1: The originator of a message sends to all peers. Other peers follow the +// rules above. +// * Aggression Level 2: All peers send all messages to all their row and column neighbors. This +// means that each validator will, on average, receive each message approximately `2*sqrt(n)` +// times. +// The aggression level of messages pertaining to a block increases when that block is unfinalized +// and is a child of the finalized block. // This means that only one block at a time has its messages propagated with aggression > 0. // // A note on aggression thresholds: changes in propagation apply only to blocks which are the @@ -120,7 +122,8 @@ impl RecentlyOutdated { struct AggressionConfig { /// Aggression level 1: all validators send all their own messages to all peers. l1_threshold: Option, - /// Aggression level 2: level 1 + all validators send all messages to all peers in the X and Y dimensions. + /// Aggression level 2: level 1 + all validators send all messages to all peers in the X and Y + /// dimensions. l2_threshold: Option, /// How often to re-send messages to all targeted recipients. /// This applies to all unfinalized blocks. @@ -167,11 +170,12 @@ struct State { blocks: HashMap, /// Our view updates to our peers can race with `NewBlocks` updates. We store messages received - /// against the directly mentioned blocks in our view in this map until `NewBlocks` is received. + /// against the directly mentioned blocks in our view in this map until `NewBlocks` is + /// received. /// - /// As long as the parent is already in the `blocks` map and `NewBlocks` messages aren't delayed - /// by more than a block length, this strategy will work well for mitigating the race. This is - /// also a race that occurs typically on local networks. + /// As long as the parent is already in the `blocks` map and `NewBlocks` messages aren't + /// delayed by more than a block length, this strategy will work well for mitigating the race. + /// This is also a race that occurs typically on local networks. pending_known: HashMap>, /// Peer data is partially stored here, and partially inline within the [`BlockEntry`]s @@ -947,7 +951,8 @@ impl State { } } - // Invariant: to our knowledge, none of the peers except for the `source` know about the assignment. + // Invariant: to our knowledge, none of the peers except for the `source` know about the + // assignment. metrics.on_assignment_imported(); let topology = self.topologies.get_topology(entry.session); @@ -1239,7 +1244,8 @@ impl State { } } - // Invariant: to our knowledge, none of the peers except for the `source` know about the approval. + // Invariant: to our knowledge, none of the peers except for the `source` know about the + // approval. metrics.on_approval_imported(); let required_routing = match entry.candidates.get_mut(candidate_index as usize) { @@ -1925,9 +1931,9 @@ const fn ensure_size_not_zero(size: usize) -> usize { } /// The maximum amount of assignments per batch is 33% of maximum allowed by protocol. -/// This is an arbitrary value. Bumping this up increases the maximum amount of approvals or assignments -/// we send in a single message to peers. Exceeding `MAX_NOTIFICATION_SIZE` will violate the protocol -/// configuration. +/// This is an arbitrary value. Bumping this up increases the maximum amount of approvals or +/// assignments we send in a single message to peers. Exceeding `MAX_NOTIFICATION_SIZE` will violate +/// the protocol configuration. pub const MAX_ASSIGNMENT_BATCH_SIZE: usize = ensure_size_not_zero( MAX_NOTIFICATION_SIZE as usize / std::mem::size_of::<(IndirectAssignmentCert, CandidateIndex)>() / diff --git a/node/network/availability-distribution/src/requester/fetch_task/mod.rs b/node/network/availability-distribution/src/requester/fetch_task/mod.rs index f87e1888bb10..191ee2acd973 100644 --- a/node/network/availability-distribution/src/requester/fetch_task/mod.rs +++ b/node/network/availability-distribution/src/requester/fetch_task/mod.rs @@ -315,7 +315,8 @@ impl RunningTask { continue }, }; - // We drop the span so that the span is not active whilst we validate and store the chunk. + // We drop the span so that the span is not active whilst we validate and store the + // chunk. drop(_chunk_recombine_span); let _chunk_validate_and_store_span = span .child("validate-and-store-chunk") diff --git a/node/network/availability-distribution/src/requester/mod.rs b/node/network/availability-distribution/src/requester/mod.rs index e27f40982ae8..446988f7cc0d 100644 --- a/node/network/availability-distribution/src/requester/mod.rs +++ b/node/network/availability-distribution/src/requester/mod.rs @@ -114,8 +114,8 @@ impl Requester { .with_string_tag("leaf", format!("{:?}", leaf.hash)) .with_stage(jaeger::Stage::AvailabilityDistribution); - // Order important! We need to handle activated, prior to deactivated, otherwise we might - // cancel still needed jobs. + // Order important! We need to handle activated, prior to deactivated, otherwise we + // might cancel still needed jobs. self.start_requesting_chunks(ctx, runtime, leaf, &span).await?; } @@ -168,8 +168,8 @@ impl Requester { // any tasks separately. // // The next time the subsystem receives leaf update, some of spawned task will be bumped - // to be live in fresh relay parent, while some might get dropped due to the current leaf - // being deactivated. + // to be live in fresh relay parent, while some might get dropped due to the current + // leaf being deactivated. self.add_cores(ctx, runtime, leaf, leaf_session_index, cores, span).await?; } @@ -177,7 +177,6 @@ impl Requester { } /// Stop requesting chunks for obsolete heads. - /// fn stop_requesting_chunks(&mut self, obsolete_leaves: impl Iterator) { let obsolete_leaves: HashSet<_> = obsolete_leaves.collect(); self.fetches.retain(|_, task| { @@ -226,10 +225,10 @@ impl Requester { .with_session_info( context, runtime, - // We use leaf here, the relay_parent must be in the same session as the - // leaf. This is guaranteed by runtime which ensures that cores are cleared - // at session boundaries. At the same time, only leaves are guaranteed to - // be fetchable by the state trie. + // We use leaf here, the relay_parent must be in the same session as + // the leaf. This is guaranteed by runtime which ensures that cores are + // cleared at session boundaries. At the same time, only leaves are + // guaranteed to be fetchable by the state trie. leaf, leaf_session_index, |info| FetchTaskConfig::new(leaf, &core, tx, metrics, info, span), diff --git a/node/network/availability-recovery/src/futures_undead.rs b/node/network/availability-recovery/src/futures_undead.rs index 225f6693a725..04ef3e749399 100644 --- a/node/network/availability-recovery/src/futures_undead.rs +++ b/node/network/availability-recovery/src/futures_undead.rs @@ -23,7 +23,6 @@ //! was almost done, thus we would have wasted time with our impatience. By simply making them //! not count towards length, we can make sure to have enough "live" requests ongoing, while at the //! same time taking advantage of some maybe "late" response from the undead. -//! use std::{ pin::Pin, diff --git a/node/network/availability-recovery/src/lib.rs b/node/network/availability-recovery/src/lib.rs index e8503ee454a2..fb0cdb720571 100644 --- a/node/network/availability-recovery/src/lib.rs +++ b/node/network/availability-recovery/src/lib.rs @@ -111,7 +111,8 @@ const SMALL_POV_LIMIT: usize = 128 * 1024; pub enum RecoveryStrategy { /// We always try the backing group first, then fallback to validator chunks. BackersFirstAlways, - /// We try the backing group first if PoV size is lower than specified, then fallback to validator chunks. + /// We try the backing group first if PoV size is lower than specified, then fallback to + /// validator chunks. BackersFirstIfSizeLower(usize), /// We always recover using validator chunks. ChunksAlways, @@ -132,7 +133,8 @@ impl RecoveryStrategy { } } - /// Returns the PoV size limit in bytes for `BackersFirstIfSizeLower` strategy, otherwise `None`. + /// Returns the PoV size limit in bytes for `BackersFirstIfSizeLower` strategy, otherwise + /// `None`. pub fn pov_size_limit(&self) -> Option { match *self { RecoveryStrategy::BackersFirstIfSizeLower(limit) => Some(limit), @@ -165,8 +167,8 @@ struct RequestChunksFromValidators { /// /// including failed ones. total_received_responses: usize, - /// a random shuffling of the validators which indicates the order in which we connect to the validators and - /// request the chunk from them. + /// a random shuffling of the validators which indicates the order in which we connect to the + /// validators and request the chunk from them. shuffling: VecDeque, /// Chunks received so far. received_chunks: HashMap, @@ -215,7 +217,8 @@ enum ErasureTask { HashMap, oneshot::Sender>, ), - /// Re-encode `AvailableData` into erasure chunks in order to verify the provided root hash of the Merkle tree. + /// Re-encode `AvailableData` into erasure chunks in order to verify the provided root hash of + /// the Merkle tree. Reencode(usize, Hash, AvailableData, oneshot::Sender>), } @@ -808,8 +811,8 @@ where self.params.metrics.on_recovery_started(); loop { - // These only fail if we cannot reach the underlying subsystem, which case there is nothing - // meaningful we can do. + // These only fail if we cannot reach the underlying subsystem, which case there is + // nothing meaningful we can do. match self.source { Source::RequestFromBackers(ref mut from_backers) => { match from_backers.run(&self.params, &mut self.sender).await { @@ -1008,7 +1011,8 @@ async fn launch_recovery_task( ); backing_group = backing_group.filter(|_| { - // We keep the backing group only if `1/3` of chunks sum up to less than `small_pov_limit`. + // We keep the backing group only if `1/3` of chunks sum up to less than + // `small_pov_limit`. prefer_backing_group }); } @@ -1194,18 +1198,21 @@ impl AvailabilityRecoverySubsystem { let (erasure_task_tx, erasure_task_rx) = futures::channel::mpsc::channel(16); let mut erasure_task_rx = erasure_task_rx.fuse(); - // `ThreadPoolBuilder` spawns the tasks using `spawn_blocking`. For each worker there will be a `mpsc` channel created. - // Each of these workers take the `Receiver` and poll it in an infinite loop. - // All of the sender ends of the channel are sent as a vec which we then use to create a `Cycle` iterator. - // We use this iterator to assign work in a round-robin fashion to the workers in the pool. + // `ThreadPoolBuilder` spawns the tasks using `spawn_blocking`. For each worker there will + // be a `mpsc` channel created. Each of these workers take the `Receiver` and poll it in an + // infinite loop. All of the sender ends of the channel are sent as a vec which we then use + // to create a `Cycle` iterator. We use this iterator to assign work in a round-robin + // fashion to the workers in the pool. // // How work is dispatched to the pool from the recovery tasks: - // - Once a recovery task finishes retrieving the availability data, it needs to reconstruct from chunks and/or + // - Once a recovery task finishes retrieving the availability data, it needs to reconstruct + // from chunks and/or // re-encode the data which are heavy CPU computations. - // To do so it sends an `ErasureTask` to the main loop via the `erasure_task` channel, and waits for the results - // over a `oneshot` channel. + // To do so it sends an `ErasureTask` to the main loop via the `erasure_task` channel, and + // waits for the results over a `oneshot` channel. // - In the subsystem main loop we poll the `erasure_task_rx` receiver. - // - We forward the received `ErasureTask` to the `next()` sender yielded by the `Cycle` iterator. + // - We forward the received `ErasureTask` to the `next()` sender yielded by the `Cycle` + // iterator. // - Some worker thread handles it and sends the response over the `oneshot` channel. // Create a thread pool with 2 workers. @@ -1348,11 +1355,13 @@ impl ThreadPoolBuilder { // Creates a pool of `size` workers, where 1 <= `size` <= `MAX_THREADS`. // // Each worker is created by `spawn_blocking` and takes the receiver side of a channel - // while all of the senders are returned to the caller. Each worker runs `erasure_task_thread` that - // polls the `Receiver` for an `ErasureTask` which is expected to be CPU intensive. The larger - // the input (more or larger chunks/availability data), the more CPU cycles will be spent. + // while all of the senders are returned to the caller. Each worker runs `erasure_task_thread` + // that polls the `Receiver` for an `ErasureTask` which is expected to be CPU intensive. The + // larger the input (more or larger chunks/availability data), the more CPU cycles will be + // spent. // - // For example, for 32KB PoVs, we'd expect re-encode to eat as much as 90ms and 500ms for 2.5MiB. + // For example, for 32KB PoVs, we'd expect re-encode to eat as much as 90ms and 500ms for + // 2.5MiB. // // After executing such a task, the worker sends the response via a provided `oneshot` sender. // diff --git a/node/network/availability-recovery/src/tests.rs b/node/network/availability-recovery/src/tests.rs index 26a99e91a5e2..c5647a12f589 100644 --- a/node/network/availability-recovery/src/tests.rs +++ b/node/network/availability-recovery/src/tests.rs @@ -817,7 +817,8 @@ fn wrong_chunk_index_leads_to_recovery_error() { let candidate_hash = test_state.candidate.hash(); - // These chunks should fail the index check as they don't have the correct index for validator. + // These chunks should fail the index check as they don't have the correct index for + // validator. test_state.chunks[1] = test_state.chunks[0].clone(); test_state.chunks[2] = test_state.chunks[0].clone(); test_state.chunks[3] = test_state.chunks[0].clone(); diff --git a/node/network/bridge/src/rx/mod.rs b/node/network/bridge/src/rx/mod.rs index 11a2dc6be83a..950bb3d6e6da 100644 --- a/node/network/bridge/src/rx/mod.rs +++ b/node/network/bridge/src/rx/mod.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! The Network Bridge Subsystem - handles _incoming_ messages from the network, forwarded to the relevant subsystems. +//! The Network Bridge Subsystem - handles _incoming_ messages from the network, forwarded to the +//! relevant subsystems. use super::*; use always_assert::never; @@ -86,7 +87,8 @@ pub struct NetworkBridgeRx { } impl NetworkBridgeRx { - /// Create a new network bridge subsystem with underlying network service and authority discovery service. + /// Create a new network bridge subsystem with underlying network service and authority + /// discovery service. /// /// This assumes that the network service has had the notifications protocol for the network /// bridge already registered. See [`peers_sets_info`](peers_sets_info). diff --git a/node/network/bridge/src/rx/tests.rs b/node/network/bridge/src/rx/tests.rs index 078f6591ae2a..e18a7e541832 100644 --- a/node/network/bridge/src/rx/tests.rs +++ b/node/network/bridge/src/rx/tests.rs @@ -795,8 +795,9 @@ fn peer_messages_sent_via_overseer() { network_handle.disconnect_peer(peer.clone(), PeerSet::Validation).await; - // Approval distribution message comes first, and the message is only sent to that subsystem. - // then a disconnection event arises that is sent to all validation networking subsystems. + // Approval distribution message comes first, and the message is only sent to that + // subsystem. then a disconnection event arises that is sent to all validation networking + // subsystems. assert_matches!( virtual_overseer.recv().await, diff --git a/node/network/bridge/src/tx/mod.rs b/node/network/bridge/src/tx/mod.rs index 2b54f6f0f06d..93916dd70fec 100644 --- a/node/network/bridge/src/tx/mod.rs +++ b/node/network/bridge/src/tx/mod.rs @@ -61,7 +61,8 @@ pub struct NetworkBridgeTx { } impl NetworkBridgeTx { - /// Create a new network bridge subsystem with underlying network service and authority discovery service. + /// Create a new network bridge subsystem with underlying network service and authority + /// discovery service. /// /// This assumes that the network service has had the notifications protocol for the network /// bridge already registered. See [`peers_sets_info`](peers_sets_info). diff --git a/node/network/bridge/src/validator_discovery.rs b/node/network/bridge/src/validator_discovery.rs index 098416c5b88d..d4d1df3da467 100644 --- a/node/network/bridge/src/validator_discovery.rs +++ b/node/network/bridge/src/validator_discovery.rs @@ -106,9 +106,10 @@ impl Service { /// It will ask the network to connect to the validators and not disconnect /// from them at least until the next request is issued for the same peer set. /// - /// This method will also disconnect from previously connected validators not in the `validator_ids` set. - /// it takes `network_service` and `authority_discovery_service` by value - /// and returns them as a workaround for the Future: Send requirement imposed by async function implementation. + /// This method will also disconnect from previously connected validators not in the + /// `validator_ids` set. it takes `network_service` and `authority_discovery_service` by value + /// and returns them as a workaround for the Future: Send requirement imposed by async function + /// implementation. pub async fn on_request( &mut self, validator_ids: Vec, diff --git a/node/network/collator-protocol/src/collator_side/mod.rs b/node/network/collator-protocol/src/collator_side/mod.rs index 39b23c152cbb..e4adfdc9d941 100644 --- a/node/network/collator-protocol/src/collator_side/mod.rs +++ b/node/network/collator-protocol/src/collator_side/mod.rs @@ -225,8 +225,8 @@ struct State { /// Our validator groups per active leaf. our_validators_groups: HashMap, - /// The mapping from [`PeerId`] to [`HashSet`]. This is filled over time as we learn the [`PeerId`]'s - /// by `PeerConnected` events. + /// The mapping from [`PeerId`] to [`HashSet`]. This is filled over time + /// as we learn the [`PeerId`]'s by `PeerConnected` events. peer_ids: HashMap>, /// Tracks which validators we want to stay connected to. @@ -241,8 +241,8 @@ struct State { /// All collation fetching requests that are still waiting to be answered. /// - /// They are stored per relay parent, when our view changes and the relay parent moves out, we will cancel the fetch - /// request. + /// They are stored per relay parent, when our view changes and the relay parent moves out, we + /// will cancel the fetch request. waiting_collation_fetches: HashMap, /// Active collation fetches. @@ -526,8 +526,8 @@ async fn connect_to_validators( /// Advertise collation to the given `peer`. /// -/// This will only advertise a collation if there exists one for the given `relay_parent` and the given `peer` is -/// set as validator for our para at the given `relay_parent`. +/// This will only advertise a collation if there exists one for the given `relay_parent` and the +/// given `peer` is set as validator for our para at the given `relay_parent`. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn advertise_collation( ctx: &mut Context, @@ -638,7 +638,8 @@ async fn process_msg( ); }, NetworkBridgeUpdate(event) => { - // We should count only this shoulder in the histogram, as other shoulders are just introducing noise + // We should count only this shoulder in the histogram, as other shoulders are just + // introducing noise let _ = state.metrics.time_process_msg(); if let Err(e) = handle_network_msg(ctx, runtime, state, event).await { diff --git a/node/network/collator-protocol/src/collator_side/tests.rs b/node/network/collator-protocol/src/collator_side/tests.rs index 757ef813a3d0..e406e5d869cc 100644 --- a/node/network/collator-protocol/src/collator_side/tests.rs +++ b/node/network/collator-protocol/src/collator_side/tests.rs @@ -160,8 +160,8 @@ impl TestState { /// Generate a new relay parent and inform the subsystem about the new view. /// - /// If `merge_views == true` it means the subsystem will be informed that we are working on the old `relay_parent` - /// and the new one. + /// If `merge_views == true` it means the subsystem will be informed that we are working on the + /// old `relay_parent` and the new one. async fn advance_to_new_round( &mut self, virtual_overseer: &mut VirtualOverseer, @@ -901,7 +901,8 @@ fn collate_on_two_different_relay_chain_blocks() { let old_relay_parent = test_state.relay_parent; - // Advance to a new round, while informing the subsystem that the old and the new relay parent are active. + // Advance to a new round, while informing the subsystem that the old and the new relay + // parent are active. test_state.advance_to_new_round(virtual_overseer, true).await; distribute_collation(virtual_overseer, &test_state, true).await; @@ -1085,7 +1086,8 @@ where .await .unwrap(); - // Keep the feedback channel alive because we need to use it to inform about the finished transfer. + // Keep the feedback channel alive because we need to use it to inform about the + // finished transfer. let feedback_tx = assert_matches!( rx.await, Ok(full_response) => { diff --git a/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/node/network/collator-protocol/src/collator_side/validators_buffer.rs index 851923a6d0d4..13ed3f66e0f1 100644 --- a/node/network/collator-protocol/src/collator_side/validators_buffer.rs +++ b/node/network/collator-protocol/src/collator_side/validators_buffer.rs @@ -23,9 +23,9 @@ //! We keep a simple FIFO buffer of N validator groups and a bitvec for each advertisement, //! 1 indicating we want to be connected to i-th validator in a buffer, 0 otherwise. //! -//! The bit is set to 1 for the whole **group** whenever it's inserted into the buffer. Given a relay -//! parent, one can reset a bit back to 0 for particular **validator**. For example, if a collation -//! was fetched or some timeout has been hit. +//! The bit is set to 1 for the whole **group** whenever it's inserted into the buffer. Given a +//! relay parent, one can reset a bit back to 0 for particular **validator**. For example, if a +//! collation was fetched or some timeout has been hit. //! //! The bitwise OR over known advertisements gives us validators indices for connection request. diff --git a/node/network/collator-protocol/src/validator_side/tests.rs b/node/network/collator-protocol/src/validator_side/tests.rs index a2e92e8c78d2..47409e8d10f3 100644 --- a/node/network/collator-protocol/src/validator_side/tests.rs +++ b/node/network/collator-protocol/src/validator_side/tests.rs @@ -730,7 +730,8 @@ fn reject_connection_to_next_group() { }) } -// Ensure that we fetch a second collation, after the first checked collation was found to be invalid. +// Ensure that we fetch a second collation, after the first checked collation was found to be +// invalid. #[test] fn fetch_next_collation_on_invalid_collation() { let test_state = TestState::default(); diff --git a/node/network/dispute-distribution/src/lib.rs b/node/network/dispute-distribution/src/lib.rs index a39f78358f44..ad99bc41fa64 100644 --- a/node/network/dispute-distribution/src/lib.rs +++ b/node/network/dispute-distribution/src/lib.rs @@ -60,8 +60,8 @@ use self::sender::{DisputeSender, DisputeSenderMessage}; /// ## The receiver [`DisputesReceiver`] /// -/// The receiving side is implemented as `DisputesReceiver` and is run as a separate long running task within -/// this subsystem ([`DisputesReceiver::run`]). +/// The receiving side is implemented as `DisputesReceiver` and is run as a separate long running +/// task within this subsystem ([`DisputesReceiver::run`]). /// /// Conceptually all the receiver has to do, is waiting for incoming requests which are passed in /// via a dedicated channel and forwarding them to the dispute coordinator via @@ -101,8 +101,8 @@ const LOG_TARGET: &'static str = "parachain::dispute-distribution"; /// Rate limit on the `receiver` side. /// -/// If messages from one peer come in at a higher rate than every `RECEIVE_RATE_LIMIT` on average, we -/// start dropping messages from that peer to enforce that limit. +/// If messages from one peer come in at a higher rate than every `RECEIVE_RATE_LIMIT` on average, +/// we start dropping messages from that peer to enforce that limit. pub const RECEIVE_RATE_LIMIT: Duration = Duration::from_millis(100); /// Rate limit on the `sender` side. diff --git a/node/network/dispute-distribution/src/receiver/batches/batch.rs b/node/network/dispute-distribution/src/receiver/batches/batch.rs index 75f37107dff9..11380b7c072e 100644 --- a/node/network/dispute-distribution/src/receiver/batches/batch.rs +++ b/node/network/dispute-distribution/src/receiver/batches/batch.rs @@ -192,8 +192,8 @@ impl Batch { /// Calculate when the next tick should happen. /// - /// This will usually return `now + BATCH_COLLECTING_INTERVAL`, except if the lifetime of this batch - /// would exceed `MAX_BATCH_LIFETIME`. + /// This will usually return `now + BATCH_COLLECTING_INTERVAL`, except if the lifetime of this + /// batch would exceed `MAX_BATCH_LIFETIME`. /// /// # Arguments /// diff --git a/node/network/dispute-distribution/src/receiver/batches/waiting_queue.rs b/node/network/dispute-distribution/src/receiver/batches/waiting_queue.rs index 72f6e80a26a4..9a5e665a5756 100644 --- a/node/network/dispute-distribution/src/receiver/batches/waiting_queue.rs +++ b/node/network/dispute-distribution/src/receiver/batches/waiting_queue.rs @@ -50,8 +50,8 @@ impl WaitingQueue { /// Push a `PendingWake`. /// - /// The next call to `wait_ready` will make sure to wake soon enough to process that new event in a - /// timely manner. + /// The next call to `wait_ready` will make sure to wake soon enough to process that new event + /// in a timely manner. pub fn push(&mut self, wake: PendingWake) { self.pending_wakes.push(wake); // Reset timer as it is potentially obsolete now: diff --git a/node/network/dispute-distribution/src/receiver/mod.rs b/node/network/dispute-distribution/src/receiver/mod.rs index ed108a67fac3..827a77281ccb 100644 --- a/node/network/dispute-distribution/src/receiver/mod.rs +++ b/node/network/dispute-distribution/src/receiver/mod.rs @@ -382,11 +382,11 @@ where if let Err(pending_response) = batch_result { // We don't expect honest peers to send redundant votes within a single batch, // as the timeout for retry is much higher. Still we don't want to punish the - // node as it might not be the node's fault. Some other (malicious) node could have been - // faster sending the same votes in order to harm the reputation of that honest - // node. Given that we already have a rate limit, if a validator chooses to - // waste available rate with redundant votes - so be it. The actual dispute - // resolution is unaffected. + // node as it might not be the node's fault. Some other (malicious) node could + // have been faster sending the same votes in order to harm the reputation of + // that honest node. Given that we already have a rate limit, if a validator + // chooses to waste available rate with redundant votes - so be it. The actual + // dispute resolution is unaffected. gum::debug!( target: LOG_TARGET, ?peer, diff --git a/node/network/dispute-distribution/src/sender/send_task.rs b/node/network/dispute-distribution/src/sender/send_task.rs index fcd670ff9ce9..18c66066d162 100644 --- a/node/network/dispute-distribution/src/sender/send_task.rs +++ b/node/network/dispute-distribution/src/sender/send_task.rs @@ -45,8 +45,8 @@ use crate::{ /// /// The unit of work for a `SendTask` is an authority/validator. pub struct SendTask { - /// The request we are supposed to get out to all `parachain` validators of the dispute's session - /// and to all current authorities. + /// The request we are supposed to get out to all `parachain` validators of the dispute's + /// session and to all current authorities. request: DisputeRequest, /// The set of authorities we need to send our messages to. This set will change at session @@ -185,7 +185,8 @@ impl SendTask { /// Handle a finished response waiting task. /// - /// Called by `DisputeSender` upon reception of the corresponding message from our spawned `wait_response_task`. + /// Called by `DisputeSender` upon reception of the corresponding message from our spawned + /// `wait_response_task`. pub fn on_finished_send(&mut self, authority: &AuthorityDiscoveryId, result: TaskResult) { match result { TaskResult::Failed(err) => { @@ -204,8 +205,8 @@ impl SendTask { TaskResult::Succeeded => { let status = match self.deliveries.get_mut(&authority) { None => { - // Can happen when a sending became irrelevant while the response was already - // queued. + // Can happen when a sending became irrelevant while the response was + // already queued. gum::debug!( target: LOG_TARGET, candidate = ?self.request.0.candidate_receipt.hash(), diff --git a/node/network/gossip-support/src/lib.rs b/node/network/gossip-support/src/lib.rs index 62a071aa6f4c..3c178ad9dfa5 100644 --- a/node/network/gossip-support/src/lib.rs +++ b/node/network/gossip-support/src/lib.rs @@ -246,7 +246,8 @@ where { let mut connections = authorities_past_present_future(sender, leaf).await?; - // Remove all of our locally controlled validator indices so we don't connect to ourself. + // Remove all of our locally controlled validator indices so we don't connect to + // ourself. let connections = if remove_all_controlled(&self.keystore, &mut connections) != 0 { connections diff --git a/node/network/protocol/src/grid_topology.rs b/node/network/protocol/src/grid_topology.rs index 1b356f67617b..99dd513c4d79 100644 --- a/node/network/protocol/src/grid_topology.rs +++ b/node/network/protocol/src/grid_topology.rs @@ -17,17 +17,20 @@ //! Grid topology support implementation //! The basic operation of the 2D grid topology is that: //! * A validator producing a message sends it to its row-neighbors and its column-neighbors -//! * A validator receiving a message originating from one of its row-neighbors sends it to its column-neighbors -//! * A validator receiving a message originating from one of its column-neighbors sends it to its row-neighbors +//! * A validator receiving a message originating from one of its row-neighbors sends it to its +//! column-neighbors +//! * A validator receiving a message originating from one of its column-neighbors sends it to its +//! row-neighbors //! -//! This grid approach defines 2 unique paths for every validator to reach every other validator in at most 2 hops. +//! This grid approach defines 2 unique paths for every validator to reach every other validator in +//! at most 2 hops. //! //! However, we also supplement this with some degree of random propagation: //! every validator, upon seeing a message for the first time, propagates it to 8 random peers. //! This inserts some redundancy in case the grid topology isn't working or is being attacked - //! an adversary doesn't know which peers a validator will send to. -//! This is combined with the property that the adversary doesn't know which validators will elect to check a block. -//! +//! This is combined with the property that the adversary doesn't know which validators will elect +//! to check a block. use crate::PeerId; use polkadot_primitives::{AuthorityDiscoveryId, SessionIndex, ValidatorIndex}; @@ -188,7 +191,8 @@ impl GridNeighbors { (false, false) => RequiredRouting::None, (true, false) => RequiredRouting::GridY, // messages from X go to Y (false, true) => RequiredRouting::GridX, // messages from Y go to X - (true, true) => RequiredRouting::GridXY, // if the grid works as expected, this shouldn't happen. + (true, true) => RequiredRouting::GridXY, /* if the grid works as expected, this + * shouldn't happen. */ } } @@ -213,7 +217,8 @@ impl GridNeighbors { "Grid topology is unexpected, play it safe and send to X AND Y" ); RequiredRouting::GridXY - }, // if the grid works as expected, this shouldn't happen. + }, /* if the grid works as expected, this + * shouldn't happen. */ } } diff --git a/node/network/protocol/src/lib.rs b/node/network/protocol/src/lib.rs index 948c422a82f8..2df926ac55d8 100644 --- a/node/network/protocol/src/lib.rs +++ b/node/network/protocol/src/lib.rs @@ -91,7 +91,8 @@ impl Into for ObservedRole { /// Specialized wrapper around [`View`]. /// -/// Besides the access to the view itself, it also gives access to the [`jaeger::Span`] per leave/head. +/// Besides the access to the view itself, it also gives access to the [`jaeger::Span`] per +/// leave/head. #[derive(Debug, Clone, Default)] pub struct OurView { view: View, @@ -131,7 +132,8 @@ impl std::ops::Deref for OurView { } } -/// Construct a new [`OurView`] with the given chain heads, finalized number 0 and disabled [`jaeger::Span`]'s. +/// Construct a new [`OurView`] with the given chain heads, finalized number 0 and disabled +/// [`jaeger::Span`]'s. /// /// NOTE: Use for tests only. /// diff --git a/node/network/protocol/src/peer_set.rs b/node/network/protocol/src/peer_set.rs index ce47ac30811a..b9fa80d5c4a2 100644 --- a/node/network/protocol/src/peer_set.rs +++ b/node/network/protocol/src/peer_set.rs @@ -98,7 +98,8 @@ impl PeerSet { max_notification_size, handshake: None, set_config: SetConfig { - // Non-authority nodes don't need to accept incoming connections on this peer set: + // Non-authority nodes don't need to accept incoming connections on this peer + // set: in_peers: if is_authority == IsAuthority::Yes { 100 } else { 0 }, out_peers: 0, reserved_nodes: Vec::new(), diff --git a/node/network/protocol/src/request_response/incoming/mod.rs b/node/network/protocol/src/request_response/incoming/mod.rs index e2b8ad526488..445544838672 100644 --- a/node/network/protocol/src/request_response/incoming/mod.rs +++ b/node/network/protocol/src/request_response/incoming/mod.rs @@ -78,8 +78,8 @@ where /// reputation changes in that case. /// /// Params: - /// - The raw request to decode - /// - Reputation changes to apply for the peer in case decoding fails. + /// - The raw request to decode + /// - Reputation changes to apply for the peer in case decoding fails. fn try_from_raw( raw: sc_network::config::IncomingRequest, reputation_changes: Vec, diff --git a/node/network/protocol/src/request_response/mod.rs b/node/network/protocol/src/request_response/mod.rs index d895a90079cc..912447c0c626 100644 --- a/node/network/protocol/src/request_response/mod.rs +++ b/node/network/protocol/src/request_response/mod.rs @@ -110,9 +110,9 @@ pub const MAX_PARALLEL_STATEMENT_REQUESTS: u32 = 3; /// Response size limit for responses of POV like data. /// /// This is larger than `MAX_POV_SIZE` to account for protocol overhead and for additional data in -/// `CollationFetchingV1` or `AvailableDataFetchingV1` for example. We try to err on larger limits here -/// as a too large limit only allows an attacker to waste our bandwidth some more, a too low limit -/// might have more severe effects. +/// `CollationFetchingV1` or `AvailableDataFetchingV1` for example. We try to err on larger limits +/// here as a too large limit only allows an attacker to waste our bandwidth some more, a too low +/// limit might have more severe effects. const POV_RESPONSE_SIZE: u64 = MAX_POV_SIZE as u64 + 10_000; /// Maximum response sizes for `StatementFetchingV1`. diff --git a/node/network/statement-distribution/src/lib.rs b/node/network/statement-distribution/src/lib.rs index 160132011589..4cdf0d8af467 100644 --- a/node/network/statement-distribution/src/lib.rs +++ b/node/network/statement-distribution/src/lib.rs @@ -185,8 +185,8 @@ struct VcPerPeerTracker { } impl VcPerPeerTracker { - /// Note that the remote should now be aware that a validator has seconded a given candidate (by hash) - /// based on a message that we have sent it from our local pool. + /// Note that the remote should now be aware that a validator has seconded a given candidate (by + /// hash) based on a message that we have sent it from our local pool. fn note_local(&mut self, h: CandidateHash) { if !note_hash(&mut self.local_observed, h) { gum::warn!( @@ -198,8 +198,8 @@ impl VcPerPeerTracker { } } - /// Note that the remote should now be aware that a validator has seconded a given candidate (by hash) - /// based on a message that it has sent us. + /// Note that the remote should now be aware that a validator has seconded a given candidate (by + /// hash) based on a message that it has sent us. /// /// Returns `true` if the peer was allowed to send us such a message, `false` otherwise. fn note_remote(&mut self, h: CandidateHash) -> bool { @@ -226,8 +226,8 @@ fn note_hash( /// knowledge that a peer has about goings-on in a relay parent. #[derive(Default)] struct PeerRelayParentKnowledge { - /// candidates that the peer is aware of because we sent statements to it. This indicates that we can - /// send other statements pertaining to that candidate. + /// candidates that the peer is aware of because we sent statements to it. This indicates that + /// we can send other statements pertaining to that candidate. sent_candidates: HashSet, /// candidates that peer is aware of, because we received statements from it. received_candidates: HashSet, @@ -321,13 +321,13 @@ impl PeerRelayParentKnowledge { } } - /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based on - /// a message we are receiving from the peer. + /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based + /// on a message we are receiving from the peer. /// /// Provide the maximum message count that we can receive per candidate. In practice we should - /// not receive more statements for any one candidate than there are members in the group assigned - /// to that para, but this maximum needs to be lenient to account for equivocations that may be - /// cross-group. As such, a maximum of 2 * `n_validators` is recommended. + /// not receive more statements for any one candidate than there are members in the group + /// assigned to that para, but this maximum needs to be lenient to account for equivocations + /// that may be cross-group. As such, a maximum of 2 * `n_validators` is recommended. /// /// This returns an error if the peer should not have sent us this message according to protocol /// rules for flood protection. @@ -490,13 +490,13 @@ impl PeerData { self.view_knowledge.get(relay_parent).map_or(false, |k| k.can_send(fingerprint)) } - /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based on - /// a message we are receiving from the peer. + /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based + /// on a message we are receiving from the peer. /// /// Provide the maximum message count that we can receive per candidate. In practice we should - /// not receive more statements for any one candidate than there are members in the group assigned - /// to that para, but this maximum needs to be lenient to account for equivocations that may be - /// cross-group. As such, a maximum of 2 * `n_validators` is recommended. + /// not receive more statements for any one candidate than there are members in the group + /// assigned to that para, but this maximum needs to be lenient to account for equivocations + /// that may be cross-group. As such, a maximum of 2 * `n_validators` is recommended. /// /// This returns an error if the peer should not have sent us this message according to protocol /// rules for flood protection. @@ -600,8 +600,8 @@ enum NotedStatement<'a> { /// Large statement fetching status. enum LargeStatementStatus { - /// We are currently fetching the statement data from a remote peer. We keep a list of other nodes - /// claiming to have that data and will fallback on them. + /// We are currently fetching the statement data from a remote peer. We keep a list of other + /// nodes claiming to have that data and will fallback on them. Fetching(FetchingInfo), /// Statement data is fetched or we got it locally via `StatementDistributionMessage::Share`. FetchedOrShared(CommittedCandidateReceipt), @@ -712,8 +712,8 @@ impl ActiveHeadData { /// to have been checked, including that the validator index is not out-of-bounds and /// the signature is valid. /// - /// Any other statements or those that reference a candidate we are not aware of cannot be accepted - /// and will return `NotedStatement::NotUseful`. + /// Any other statements or those that reference a candidate we are not aware of cannot be + /// accepted and will return `NotedStatement::NotUseful`. fn note_statement(&mut self, statement: SignedFullStatement) -> NotedStatement { let validator_index = statement.validator_index(); let comparator = StoredStatementComparator { @@ -1272,9 +1272,9 @@ async fn retrieve_statement_from_message<'a, Context>( } }, protocol_v1::StatementDistributionMessage::Statement(_, s) => { - // No fetch in progress, safe to return any statement immediately (we don't bother - // about normal network jitter which might cause `Valid` statements to arrive early - // for now.). + // No fetch in progress, safe to return any statement immediately (we don't + // bother about normal network jitter which might cause `Valid` statements to + // arrive early for now.). return Some(s) }, } @@ -1470,7 +1470,8 @@ async fn handle_incoming_message<'a, Context>( ); match rep { - // This happens when a Valid statement has been received but there is no corresponding Seconded + // This happens when a Valid statement has been received but there is no corresponding + // Seconded COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE => { metrics.on_unexpected_statement_valid(); // Report peer merely if this is not a duplicate out-of-view statement that diff --git a/node/network/statement-distribution/src/tests.rs b/node/network/statement-distribution/src/tests.rs index 3f3e6e589616..62167f77a1e0 100644 --- a/node/network/statement-distribution/src/tests.rs +++ b/node/network/statement-distribution/src/tests.rs @@ -824,8 +824,8 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { }) .await; - // receive a seconded statement from peer A. it should be propagated onwards to peer B and to - // candidate backing. + // receive a seconded statement from peer A. it should be propagated onwards to peer B and + // to candidate backing. let statement = { let signing_context = SigningContext { parent_hash: hash_a, session_index }; @@ -2536,8 +2536,8 @@ fn handle_multiple_seconded_statements() { }) .await; - // receive a seconded statement from peer A. it should be propagated onwards to peer B and to - // candidate backing. + // receive a seconded statement from peer A. it should be propagated onwards to peer B and + // to candidate backing. let statement = { let signing_context = SigningContext { parent_hash: relay_parent_hash, session_index }; diff --git a/node/overseer/src/lib.rs b/node/overseer/src/lib.rs index a2d553779fdc..ebf33d5247b1 100644 --- a/node/overseer/src/lib.rs +++ b/node/overseer/src/lib.rs @@ -211,10 +211,10 @@ impl Handle { /// Wait for a block with the given hash to be in the active-leaves set. /// - /// The response channel responds if the hash was activated and is closed if the hash was deactivated. - /// Note that due the fact the overseer doesn't store the whole active-leaves set, only deltas, - /// the response channel may never return if the hash was deactivated before this call. - /// In this case, it's the caller's responsibility to ensure a timeout is set. + /// The response channel responds if the hash was activated and is closed if the hash was + /// deactivated. Note that due the fact the overseer doesn't store the whole active-leaves set, + /// only deltas, the response channel may never return if the hash was deactivated before this + /// call. In this case, it's the caller's responsibility to ensure a timeout is set. pub async fn wait_for_activation( &mut self, hash: Hash, @@ -355,7 +355,6 @@ pub async fn forward_events>(client: Arc

, mut hand /// +-----------+ /// | | /// +-----------+ -/// /// ``` /// /// [`Subsystem`]: trait.Subsystem.html @@ -363,8 +362,8 @@ pub async fn forward_events>(client: Arc

, mut hand /// # Example /// /// The [`Subsystems`] may be any type as long as they implement an expected interface. -/// Here, we create a mock validation subsystem and a few dummy ones and start the `Overseer` with them. -/// For the sake of simplicity the termination of the example is done with a timeout. +/// Here, we create a mock validation subsystem and a few dummy ones and start the `Overseer` with +/// them. For the sake of simplicity the termination of the example is done with a timeout. /// ``` /// # use std::time::Duration; /// # use futures::{executor, pin_mut, select, FutureExt}; @@ -394,11 +393,11 @@ pub async fn forward_events>(client: Arc

, mut hand /// impl overseer::Subsystem for ValidationSubsystem /// where /// Ctx: overseer::SubsystemContext< -/// Message=CandidateValidationMessage, -/// AllMessages=AllMessages, -/// Signal=OverseerSignal, -/// Error=SubsystemError, -/// >, +/// Message=CandidateValidationMessage, +/// AllMessages=AllMessages, +/// Signal=OverseerSignal, +/// Error=SubsystemError, +/// >, /// { /// fn start( /// self, @@ -426,10 +425,10 @@ pub async fn forward_events>(client: Arc

, mut hand /// /// let spawner = sp_core::testing::TaskExecutor::new(); /// let (overseer, _handle) = dummy_overseer_builder(spawner, AlwaysSupportsParachains, None) -/// .unwrap() -/// .replace_candidate_validation(|_| ValidationSubsystem) -/// .build() -/// .unwrap(); +/// .unwrap() +/// .replace_candidate_validation(|_| ValidationSubsystem) +/// .build() +/// .unwrap(); /// /// let timer = Delay::new(Duration::from_millis(50)).fuse(); /// @@ -825,7 +824,8 @@ where // If there are no leaves being deactivated, we don't need to send an update. // - // Our peers will be informed about our finalized block the next time we activating/deactivating some leaf. + // Our peers will be informed about our finalized block the next time we + // activating/deactivating some leaf. if !update.is_empty() { self.broadcast_signal(OverseerSignal::ActiveLeaves(update)).await?; } diff --git a/node/primitives/src/disputes/message.rs b/node/primitives/src/disputes/message.rs index 992d70ba1324..89d3ea6c0af9 100644 --- a/node/primitives/src/disputes/message.rs +++ b/node/primitives/src/disputes/message.rs @@ -105,8 +105,8 @@ impl DisputeMessage { /// - the invalid statement is indeed an invalid one /// - the valid statement is indeed a valid one /// - The passed `CandidateReceipt` has the correct hash (as signed in the statements). - /// - the given validator indices match with the given `ValidatorId`s in the statements, - /// given a `SessionInfo`. + /// - the given validator indices match with the given `ValidatorId`s in the statements, given a + /// `SessionInfo`. /// /// We don't check whether the given `SessionInfo` matches the `SessionIndex` in the /// statements, because we can't without doing a runtime query. Nevertheless this smart diff --git a/node/primitives/src/disputes/status.rs b/node/primitives/src/disputes/status.rs index 309225edc94b..d93c3ec846ce 100644 --- a/node/primitives/src/disputes/status.rs +++ b/node/primitives/src/disputes/status.rs @@ -16,7 +16,8 @@ use parity_scale_codec::{Decode, Encode}; -/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS reboots. +/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS +/// reboots. pub type Timestamp = u64; /// The status of dispute. @@ -88,8 +89,8 @@ impl DisputeStatus { } } - /// Transition the status to a new status after observing the dispute has concluded for the candidate. - /// This may be a no-op if the status was already concluded. + /// Transition the status to a new status after observing the dispute has concluded for the + /// candidate. This may be a no-op if the status was already concluded. pub fn conclude_for(self, now: Timestamp) -> DisputeStatus { match self { DisputeStatus::Active | DisputeStatus::Confirmed => DisputeStatus::ConcludedFor(now), @@ -98,8 +99,8 @@ impl DisputeStatus { } } - /// Transition the status to a new status after observing the dispute has concluded against the candidate. - /// This may be a no-op if the status was already concluded. + /// Transition the status to a new status after observing the dispute has concluded against the + /// candidate. This may be a no-op if the status was already concluded. pub fn conclude_against(self, now: Timestamp) -> DisputeStatus { match self { DisputeStatus::Active | DisputeStatus::Confirmed => diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 1177dbc17caa..d49cd806d54e 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -180,8 +180,8 @@ impl std::fmt::Debug for Statement { impl Statement { /// Get the candidate hash referenced by this statement. /// - /// If this is a `Statement::Seconded`, this does hash the candidate receipt, which may be expensive - /// for large candidates. + /// If this is a `Statement::Seconded`, this does hash the candidate receipt, which may be + /// expensive for large candidates. pub fn candidate_hash(&self) -> CandidateHash { match *self { Statement::Valid(ref h) => *h, @@ -215,8 +215,8 @@ impl EncodeAs for Statement { /// /// Signing context and validator set should be apparent from context. /// -/// This statement is "full" in the sense that the `Seconded` variant includes the candidate receipt. -/// Only the compact `SignedStatement` is suitable for submission to the chain. +/// This statement is "full" in the sense that the `Seconded` variant includes the candidate +/// receipt. Only the compact `SignedStatement` is suitable for submission to the chain. pub type SignedFullStatement = Signed; /// Variant of `SignedFullStatement` where the signature has not yet been verified. @@ -256,8 +256,8 @@ pub enum InvalidCandidate { /// Result of the validation of the candidate. #[derive(Debug)] pub enum ValidationResult { - /// Candidate is valid. The validation process yields these outputs and the persisted validation - /// data used to form inputs. + /// Candidate is valid. The validation process yields these outputs and the persisted + /// validation data used to form inputs. Valid(CandidateCommitments, PersistedValidationData), /// Candidate is invalid. Invalid(InvalidCandidate), @@ -321,7 +321,8 @@ pub struct Collation { pub proof_of_validity: MaybeCompressedPoV, /// The number of messages processed from the DMQ. pub processed_downward_messages: u32, - /// The mark which specifies the block number up to which all inbound HRMP messages are processed. + /// The mark which specifies the block number up to which all inbound HRMP messages are + /// processed. pub hrmp_watermark: BlockNumber, } @@ -344,9 +345,9 @@ pub struct CollationResult { pub collation: Collation, /// An optional result sender that should be informed about a successfully seconded collation. /// - /// There is no guarantee that this sender is informed ever about any result, it is completely okay to just drop it. - /// However, if it is called, it should be called with the signed statement of a parachain validator seconding the - /// collation. + /// There is no guarantee that this sender is informed ever about any result, it is completely + /// okay to just drop it. However, if it is called, it should be called with the signed + /// statement of a parachain validator seconding the collation. pub result_sender: Option>, } @@ -362,8 +363,9 @@ impl CollationResult { /// Collation function. /// -/// Will be called with the hash of the relay chain block the parachain block should be build on and the -/// [`ValidationData`] that provides information about the state of the parachain on the relay chain. +/// Will be called with the hash of the relay chain block the parachain block should be build on and +/// the [`ValidationData`] that provides information about the state of the parachain on the relay +/// chain. /// /// Returns an optional [`CollationResult`]. #[cfg(not(target_os = "unknown"))] diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index a9e6b45f3b2d..7aabfa6e9185 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -529,11 +529,12 @@ fn kusama_staging_testnet_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeG hex!["12b782529c22032ed4694e0f6e7d486be7daa6d12088f6bc74d593b3900b8438"].into(), ]; - // for i in 1 2 3 4; do for j in stash controller; do subkey inspect "$SECRET//$i//$j"; done; done - // for i in 1 2 3 4; do for j in babe; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done - // for i in 1 2 3 4; do for j in grandpa; do subkey --ed25519 inspect "$SECRET//$i//$j"; done; done - // for i in 1 2 3 4; do for j in im_online; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done - // for i in 1 2 3 4; do for j in para_validator para_assignment; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done + // for i in 1 2 3 4; do for j in stash controller; do subkey inspect "$SECRET//$i//$j"; done; + // done for i in 1 2 3 4; do for j in babe; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; + // done for i in 1 2 3 4; do for j in grandpa; do subkey --ed25519 inspect "$SECRET//$i//$j"; + // done; done for i in 1 2 3 4; do for j in im_online; do subkey --sr25519 inspect + // "$SECRET//$i//$j"; done; done for i in 1 2 3 4; do for j in para_validator para_assignment; + // do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done let initial_authorities: Vec<( AccountId, AccountId, diff --git a/node/service/src/fake_runtime_api.rs b/node/service/src/fake_runtime_api.rs index b322114cbb75..d9553afa024b 100644 --- a/node/service/src/fake_runtime_api.rs +++ b/node/service/src/fake_runtime_api.rs @@ -16,7 +16,8 @@ //! Provides "fake" runtime API implementations //! -//! These are used to provide a type that implements these runtime APIs without requiring to import the native runtimes. +//! These are used to provide a type that implements these runtime APIs without requiring to import +//! the native runtimes. use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; use grandpa_primitives::AuthorityId as GrandpaId; diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index fa8cb8ec77f7..4dda57110825 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -696,9 +696,10 @@ pub const AVAILABILITY_CONFIG: AvailabilityConfig = AvailabilityConfig { /// 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. +/// `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. /// /// `workers_path` is used to get the path to the directory where auxiliary worker binaries reside. /// If not specified, the main binary's directory is searched first, then `/usr/lib/polkadot` is @@ -1331,9 +1332,10 @@ pub fn new_chain_ops( /// 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. +/// `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, diff --git a/node/service/src/relay_chain_selection.rs b/node/service/src/relay_chain_selection.rs index afc0ce320610..189073783f0d 100644 --- a/node/service/src/relay_chain_selection.rs +++ b/node/service/src/relay_chain_selection.rs @@ -472,8 +472,8 @@ where let lag = initial_leaf_number.saturating_sub(subchain_number); self.metrics.note_approval_checking_finality_lag(lag); - // Messages sent to `approval-distrbution` are known to have high `ToF`, we need to spawn a task for sending - // the message to not block here and delay finality. + // Messages sent to `approval-distrbution` are known to have high `ToF`, we need to spawn a + // task for sending the message to not block here and delay finality. if let Some(spawn_handle) = &self.spawn_handle { let mut overseer_handle = self.overseer.clone(); let lag_update_task = async move { @@ -537,9 +537,10 @@ where error = ?e, "Call to `DetermineUndisputedChain` failed", ); - // We need to return a sane finality target. But, we are unable to ensure we are not - // finalizing something that is being disputed or has been concluded as invalid. We will be - // conservative here and not vote for finality above the ancestor passed in. + // We need to return a sane finality target. But, we are unable to ensure we + // are not finalizing something that is being disputed or has been concluded + // as invalid. We will be conservative here and not vote for finality above + // the ancestor passed in. return Ok(target_hash) }, }; diff --git a/node/service/src/tests.rs b/node/service/src/tests.rs index 424af4d22a26..95d5765bad45 100644 --- a/node/service/src/tests.rs +++ b/node/service/src/tests.rs @@ -498,8 +498,8 @@ struct CaseVars { /// ```raw /// genesis -- 0xA1 --- 0xA2 --- 0xA3 --- 0xA4(!avail) --- 0xA5(!avail) -/// \ -/// `- 0xB2 +/// \ +/// `- 0xB2 /// ``` fn chain_undisputed() -> CaseVars { let head: Hash = ChainBuilder::GENESIS_HASH; @@ -529,8 +529,8 @@ fn chain_undisputed() -> CaseVars { /// ```raw /// genesis -- 0xA1 --- 0xA2 --- 0xA3(disputed) --- 0xA4(!avail) --- 0xA5(!avail) -/// \ -/// `- 0xB2 +/// \ +/// `- 0xB2 /// ``` fn chain_0() -> CaseVars { let head: Hash = ChainBuilder::GENESIS_HASH; @@ -560,8 +560,8 @@ fn chain_0() -> CaseVars { /// ```raw /// genesis -- 0xA1 --- 0xA2(disputed) --- 0xA3 -/// \ -/// `- 0xB2 --- 0xB3(!available) +/// \ +/// `- 0xB2 --- 0xB3(!available) /// ``` fn chain_1() -> CaseVars { let head: Hash = ChainBuilder::GENESIS_HASH; @@ -588,8 +588,8 @@ fn chain_1() -> CaseVars { /// ```raw /// genesis -- 0xA1 --- 0xA2(disputed) --- 0xA3 -/// \ -/// `- 0xB2 --- 0xB3 +/// \ +/// `- 0xB2 --- 0xB3 /// ``` fn chain_2() -> CaseVars { let head: Hash = ChainBuilder::GENESIS_HASH; @@ -616,8 +616,8 @@ fn chain_2() -> CaseVars { /// ```raw /// genesis -- 0xA1 --- 0xA2 --- 0xA3(disputed) -/// \ -/// `- 0xB2 --- 0xB3 +/// \ +/// `- 0xB2 --- 0xB3 /// ``` fn chain_3() -> CaseVars { let head: Hash = ChainBuilder::GENESIS_HASH; @@ -644,10 +644,10 @@ fn chain_3() -> CaseVars { /// ```raw /// genesis -- 0xA1 --- 0xA2 --- 0xA3(disputed) -/// \ -/// `- 0xB2 --- 0xB3 +/// \ +/// `- 0xB2 --- 0xB3 /// -/// ? --- NEX(does_not_exist) +/// ? --- NEX(does_not_exist) /// ``` fn chain_4() -> CaseVars { let head: Hash = ChainBuilder::GENESIS_HASH; diff --git a/node/subsystem-test-helpers/src/lib.rs b/node/subsystem-test-helpers/src/lib.rs index 4170f22c5b86..fb908278aa7d 100644 --- a/node/subsystem-test-helpers/src/lib.rs +++ b/node/subsystem-test-helpers/src/lib.rs @@ -310,7 +310,8 @@ pub fn make_buffered_subsystem_context( /// Test a subsystem, mocking the overseer /// -/// Pass in two async closures: one mocks the overseer, the other runs the test from the perspective of a subsystem. +/// Pass in two async closures: one mocks the overseer, the other runs the test from the perspective +/// of a subsystem. /// /// Times out in 5 seconds. pub fn subsystem_test_harness( diff --git a/node/subsystem-types/src/lib.rs b/node/subsystem-types/src/lib.rs index 88c7165bcd80..f438a09592c1 100644 --- a/node/subsystem-types/src/lib.rs +++ b/node/subsystem-types/src/lib.rs @@ -82,8 +82,8 @@ pub struct ActivatedLeaf { pub status: LeafStatus, /// An associated [`jaeger::Span`]. /// - /// NOTE: Each span should only be kept active as long as the leaf is considered active and should be dropped - /// when the leaf is deactivated. + /// NOTE: Each span should only be kept active as long as the leaf is considered active and + /// should be dropped when the leaf is deactivated. pub span: Arc, } diff --git a/node/subsystem-types/src/messages.rs b/node/subsystem-types/src/messages.rs index 8f2e3375b6f1..d5dcea7a2565 100644 --- a/node/subsystem-types/src/messages.rs +++ b/node/subsystem-types/src/messages.rs @@ -16,8 +16,8 @@ //! Message types for the overseer and subsystems. //! -//! These messages are intended to define the protocol by which different subsystems communicate with each -//! other and signals that they receive from an overseer to coordinate their work. +//! These messages are intended to define the protocol by which different subsystems communicate +//! with each other and signals that they receive from an overseer to coordinate their work. //! This is intended for use with the `polkadot-overseer` crate. //! //! Subsystems' APIs are defined separately from their implementation, leading to easier mocking. @@ -62,12 +62,13 @@ pub enum CandidateBackingMessage { /// Requests a set of backable candidates that could be backed in a child of the given /// relay-parent, referenced by its hash. GetBackedCandidates(Hash, Vec, oneshot::Sender>), - /// Note that the Candidate Backing subsystem should second the given candidate in the context of the - /// given relay-parent (ref. by hash). This candidate must be validated. + /// Note that the Candidate Backing subsystem should second the given candidate in the context + /// of the given relay-parent (ref. by hash). This candidate must be validated. Second(Hash, CandidateReceipt, PoV), - /// Note a validator's statement about a particular candidate. Disagreements about validity must be escalated - /// to a broader check by the Disputes Subsystem, though that escalation is deferred until the approval voting - /// stage to guarantee availability. Agreements are simply tallied until a quorum is reached. + /// Note a validator's statement about a particular candidate. Disagreements about validity + /// must be escalated to a broader check by the Disputes Subsystem, though that escalation is + /// deferred until the approval voting stage to guarantee availability. Agreements are simply + /// tallied until a quorum is reached. Statement(Hash, SignedFullStatement), } @@ -143,8 +144,8 @@ pub enum CandidateValidationMessage { /// Try to compile the given validation code and send back /// the outcome. /// - /// The validation code is specified by the hash and will be queried from the runtime API at the - /// given relay-parent. + /// The validation code is specified by the hash and will be queried from the runtime API at + /// the given relay-parent. PreCheck( // Relay-parent Hash, @@ -157,16 +158,16 @@ pub enum CandidateValidationMessage { #[derive(Debug, derive_more::From)] pub enum CollatorProtocolMessage { /// Signal to the collator protocol that it should connect to validators with the expectation - /// of collating on the given para. This is only expected to be called once, early on, if at all, - /// and only by the Collation Generation subsystem. As such, it will overwrite the value of - /// the previous signal. + /// of collating on the given para. This is only expected to be called once, early on, if at + /// all, and only by the Collation Generation subsystem. As such, it will overwrite the value + /// of the previous signal. /// /// This should be sent before any `DistributeCollation` message. CollateOn(ParaId), /// Provide a collation to distribute to validators with an optional result sender. /// - /// The result sender should be informed when at least one parachain validator seconded the collation. It is also - /// completely okay to just drop the sender. + /// The result sender should be informed when at least one parachain validator seconded the + /// collation. It is also completely okay to just drop the sender. DistributeCollation(CandidateReceipt, PoV, Option>), /// Report a collator as having provided an invalid collation. This should lead to disconnect /// and blacklist of the collator. @@ -174,7 +175,8 @@ pub enum CollatorProtocolMessage { /// Get a network bridge update. #[from] NetworkBridgeUpdate(NetworkBridgeEvent), - /// We recommended a particular candidate to be seconded, but it was invalid; penalize the collator. + /// We recommended a particular candidate to be seconded, but it was invalid; penalize the + /// collator. /// /// The hash is the relay parent. Invalid(Hash, CandidateReceipt), @@ -198,14 +200,15 @@ impl Default for CollatorProtocolMessage { pub enum DisputeCoordinatorMessage { /// Import statements by validators about a candidate. /// - /// The subsystem will silently discard ancient statements or sets of only dispute-specific statements for - /// candidates that are previously unknown to the subsystem. The former is simply because ancient - /// data is not relevant and the latter is as a DoS prevention mechanism. Both backing and approval - /// statements already undergo anti-DoS procedures in their respective subsystems, but statements - /// cast specifically for disputes are not necessarily relevant to any candidate the system is - /// already aware of and thus present a DoS vector. Our expectation is that nodes will notify each - /// other of disputes over the network by providing (at least) 2 conflicting statements, of which one is either - /// a backing or validation statement. + /// The subsystem will silently discard ancient statements or sets of only dispute-specific + /// statements for candidates that are previously unknown to the subsystem. The former is + /// simply because ancient data is not relevant and the latter is as a DoS prevention + /// mechanism. Both backing and approval statements already undergo anti-DoS procedures in + /// their respective subsystems, but statements cast specifically for disputes are not + /// necessarily relevant to any candidate the system is already aware of and thus present a DoS + /// vector. Our expectation is that nodes will notify each other of disputes over the network + /// by providing (at least) 2 conflicting statements, of which one is either a backing or + /// validation statement. /// /// This does not do any checking of the message signature. ImportStatements { @@ -222,16 +225,16 @@ pub enum DisputeCoordinatorMessage { /// /// This is: /// - we discarded the votes because - /// - they were ancient or otherwise invalid (result: `InvalidImport`) - /// - or we were not able to recover availability for an unknown candidate (result: + /// - they were ancient or otherwise invalid (result: `InvalidImport`) + /// - or we were not able to recover availability for an unknown candidate (result: /// `InvalidImport`) - /// - or were known already (in that case the result will still be `ValidImport`) + /// - or were known already (in that case the result will still be `ValidImport`) /// - or we recorded them because (`ValidImport`) - /// - we cast our own vote already on that dispute - /// - or we have approval votes on that candidate - /// - or other explicit votes on that candidate already recorded - /// - or recovered availability for the candidate - /// - or the imported statements are backing/approval votes, which are always accepted. + /// - we cast our own vote already on that dispute + /// - or we have approval votes on that candidate + /// - or other explicit votes on that candidate already recorded + /// - or recovered availability for the candidate + /// - or the imported statements are backing/approval votes, which are always accepted. pending_confirmation: Option>, }, /// Fetch a list of all recent disputes the coordinator is aware of. @@ -246,15 +249,17 @@ pub enum DisputeCoordinatorMessage { Vec<(SessionIndex, CandidateHash)>, oneshot::Sender>, ), - /// Sign and issue local dispute votes. A value of `true` indicates validity, and `false` invalidity. + /// Sign and issue local dispute votes. A value of `true` indicates validity, and `false` + /// invalidity. IssueLocalStatement(SessionIndex, CandidateHash, CandidateReceipt, bool), /// Determine the highest undisputed block within the given chain, based on where candidates /// were included. If even the base block should not be finalized due to a dispute, /// then `None` should be returned on the channel. /// - /// The block descriptions begin counting upwards from the block after the given `base_number`. The `base_number` - /// is typically the number of the last finalized block but may be slightly higher. This block - /// is inevitably going to be finalized so it is not accounted for by this function. + /// The block descriptions begin counting upwards from the block after the given `base_number`. + /// The `base_number` is typically the number of the last finalized block but may be slightly + /// higher. This block is inevitably going to be finalized so it is not accounted for by this + /// function. DetermineUndisputedChain { /// The lowest possible block to vote on. base: (BlockNumber, Hash), @@ -369,8 +374,8 @@ pub enum NetworkBridgeTxMessage { /// authority discovery has failed to resolve. failed: oneshot::Sender, }, - /// Alternative to `ConnectToValidators` in case you already know the `Multiaddrs` you want to be - /// connected to. + /// Alternative to `ConnectToValidators` in case you already know the `Multiaddrs` you want to + /// be connected to. ConnectToResolvedValidators { /// Each entry corresponds to the addresses of an already resolved validator. validator_addrs: Vec>, @@ -576,8 +581,8 @@ pub enum RuntimeApiRequest { OccupiedCoreAssumption, RuntimeApiSender>, ), - /// Get the persisted validation data for a particular para along with the current validation code - /// hash, matching the data hash against an expected one. + /// Get the persisted validation data for a particular para along with the current validation + /// code hash, matching the data hash against an expected one. AssumedValidationData( ParaId, Hash, @@ -595,10 +600,11 @@ pub enum RuntimeApiRequest { /// will inform on how the validation data should be computed if the para currently /// occupies a core. ValidationCode(ParaId, OccupiedCoreAssumption, RuntimeApiSender>), - /// Get validation code by its hash, either past, current or future code can be returned, as long as state is still - /// available. + /// Get validation code by its hash, either past, current or future code can be returned, as + /// long as state is still available. ValidationCodeByHash(ValidationCodeHash, RuntimeApiSender>), - /// Get a the candidate pending availability for a particular parachain by parachain / core index + /// Get a the candidate pending availability for a particular parachain by parachain / core + /// index CandidatePendingAvailability(ParaId, RuntimeApiSender>), /// Get all events concerning candidates (backing, inclusion, time-out) in the parent of /// the block in whose state this request is executed. @@ -623,8 +629,9 @@ pub enum RuntimeApiRequest { SubmitPvfCheckStatement(PvfCheckStatement, ValidatorSignature, RuntimeApiSender<()>), /// Returns code hashes of PVFs that require pre-checking by validators in the active set. PvfsRequirePrecheck(RuntimeApiSender>), - /// Get the validation code used by the specified para, taking the given `OccupiedCoreAssumption`, which - /// will inform on how the validation data should be computed if the para currently occupies a core. + /// Get the validation code used by the specified para, taking the given + /// `OccupiedCoreAssumption`, which will inform on how the validation data should be computed + /// if the para currently occupies a core. ValidationCodeHash( ParaId, OccupiedCoreAssumption, @@ -686,13 +693,15 @@ pub enum StatementDistributionMessage { NetworkBridgeUpdate(NetworkBridgeEvent), } -/// This data becomes intrinsics or extrinsics which should be included in a future relay chain block. +/// This data becomes intrinsics or extrinsics which should be included in a future relay chain +/// block. // It needs to be cloneable because multiple potential block authors can request copies. #[derive(Debug, Clone)] pub enum ProvisionableData { /// This bitfield indicates the availability of various candidate blocks. Bitfield(Hash, SignedAvailabilityBitfield), - /// The Candidate Backing subsystem believes that this candidate is valid, pending availability. + /// The Candidate Backing subsystem believes that this candidate is valid, pending + /// availability. BackedCandidate(CandidateReceipt), /// Misbehavior reports are self-contained proofs of validator misbehavior. MisbehaviorReport(Hash, ValidatorIndex, Misbehavior), @@ -716,11 +725,11 @@ pub struct ProvisionerInherentData { /// In all cases, the Hash is that of the relay parent. #[derive(Debug)] pub enum ProvisionerMessage { - /// This message allows external subsystems to request the set of bitfields and backed candidates - /// associated with a particular potential block hash. + /// This message allows external subsystems to request the set of bitfields and backed + /// candidates associated with a particular potential block hash. /// - /// This is expected to be used by a proposer, to inject that information into the `InherentData` - /// where it can be assembled into the `ParaInherent`. + /// This is expected to be used by a proposer, to inject that information into the + /// `InherentData` where it can be assembled into the `ParaInherent`. RequestInherentData(Hash, oneshot::Sender), /// This data should become part of a relay chain block ProvisionableData(Hash, ProvisionableData), diff --git a/node/subsystem-types/src/runtime_client.rs b/node/subsystem-types/src/runtime_client.rs index 196b928ad62b..4d8eddde73e9 100644 --- a/node/subsystem-types/src/runtime_client.rs +++ b/node/subsystem-types/src/runtime_client.rs @@ -138,7 +138,7 @@ pub trait RuntimeApiSubsystemClient { async fn on_chain_votes(&self, at: Hash) -> Result>, ApiError>; - /***** Added in v2 *****/ + /***** Added in v2 **** */ /// Get the session info for the given session, if stored. /// @@ -164,7 +164,8 @@ pub trait RuntimeApiSubsystemClient { /// NOTE: This function is only available since parachain host version 2. async fn pvfs_require_precheck(&self, at: Hash) -> Result, ApiError>; - /// Fetch the hash of the validation code used by a para, making the given `OccupiedCoreAssumption`. + /// Fetch the hash of the validation code used by a para, making the given + /// `OccupiedCoreAssumption`. /// /// NOTE: This function is only available since parachain host version 2. async fn validation_code_hash( @@ -174,7 +175,7 @@ pub trait RuntimeApiSubsystemClient { assumption: OccupiedCoreAssumption, ) -> Result, ApiError>; - /***** Added in v3 *****/ + /***** Added in v3 **** */ /// Returns all onchain disputes. /// This is a staging method! Do not use on production runtimes! diff --git a/node/subsystem-util/src/lib.rs b/node/subsystem-util/src/lib.rs index de869bd91f12..e0b81608ff2f 100644 --- a/node/subsystem-util/src/lib.rs +++ b/node/subsystem-util/src/lib.rs @@ -20,7 +20,8 @@ //! or determining what their validator ID is. These common interests are factored into //! this module. //! -//! This crate also reexports Prometheus metric types which are expected to be implemented by subsystems. +//! This crate also reexports Prometheus metric types which are expected to be implemented by +//! subsystems. #![warn(missing_docs)] @@ -60,7 +61,8 @@ pub use polkadot_node_network_protocol::MIN_GOSSIP_PEERS; pub use determine_new_blocks::determine_new_blocks; -/// These reexports are required so that external crates can use the `delegated_subsystem` macro properly. +/// These reexports are required so that external crates can use the `delegated_subsystem` macro +/// properly. pub mod reexports { pub use polkadot_overseer::gen::{SpawnedSubsystem, Spawner, Subsystem, SubsystemContext}; } @@ -367,7 +369,8 @@ pub struct Validator { } impl Validator { - /// Get a struct representing this node's validator if this node is in fact a validator in the context of the given block. + /// Get a struct representing this node's validator if this node is in fact a validator in the + /// context of the given block. pub async fn new(parent: Hash, keystore: KeystorePtr, sender: &mut S) -> Result where S: SubsystemSender, diff --git a/node/subsystem-util/src/nesting_sender.rs b/node/subsystem-util/src/nesting_sender.rs index 4417efbefb04..5d80dbf78101 100644 --- a/node/subsystem-util/src/nesting_sender.rs +++ b/node/subsystem-util/src/nesting_sender.rs @@ -33,14 +33,14 @@ //! //! This module helps with this in part. It does not break the multithreaded by default approach, //! but it breaks the `spawn everything` approach. So once you `spawn` you will still be -//! multithreaded by default, despite that for most tasks we spawn (which just wait for network or some -//! message to arrive), that is very much pointless and needless overhead. You will just spawn less in -//! the first place. +//! multithreaded by default, despite that for most tasks we spawn (which just wait for network or +//! some message to arrive), that is very much pointless and needless overhead. You will just spawn +//! less in the first place. //! //! By default your code is single threaded, except when actually needed: -//! - need to wait for long running synchronous IO (a threaded runtime is actually useful here) -//! - need to wait for some async event (message to arrive) -//! - need to do some hefty CPU bound processing (a thread is required here as well) +//! - need to wait for long running synchronous IO (a threaded runtime is actually useful here) +//! - need to wait for some async event (message to arrive) +//! - need to do some hefty CPU bound processing (a thread is required here as well) //! //! and it is not acceptable to block the main task for waiting for the result, because we actually //! really have other things to do or at least need to stay responsive just in case. @@ -48,7 +48,8 @@ //! With the types and traits in this module you can achieve exactly that: You write modules which //! just execute logic and can call into the functions of other modules - yes we are calling normal //! functions. For the case a module you are calling into requires an occasional background task, -//! you provide it with a `NestingSender` that it can pass to any spawned tasks. +//! you provide it with a `NestingSender` that it can pass to any spawned +//! tasks. //! //! This way you don't have to spawn a task for each module just for it to be able to handle //! asynchronous events. The module relies on the using/enclosing code/module to forward it any @@ -65,9 +66,9 @@ //! Because the wrapping is optional and transparent to the lower modules, each module can also be //! used at the top directly without any wrapping, e.g. for standalone use or for testing purposes. //! -//! Checkout the documentation of [`NestingSender`][nesting_sender::NestingSender] below for a basic usage example. For a real -//! world usage I would like to point you to the dispute-distribution subsystem which makes use of -//! this architecture. +//! Checkout the documentation of [`NestingSender`][nesting_sender::NestingSender] below for a basic +//! usage example. For a real world usage I would like to point you to the dispute-distribution +//! subsystem which makes use of this architecture. //! //! ## Limitations //! diff --git a/node/subsystem-util/src/reputation.rs b/node/subsystem-util/src/reputation.rs index 09c00bb4688a..89e3eb64df9b 100644 --- a/node/subsystem-util/src/reputation.rs +++ b/node/subsystem-util/src/reputation.rs @@ -48,7 +48,8 @@ impl ReputationAggregator { /// /// * `send_immediately_if` - A function, takes `UnifiedReputationChange`, /// results shows if we need to send the changes right away. - /// By default, it is used for sending `UnifiedReputationChange::Malicious` changes immediately and for testing. + /// By default, it is used for sending `UnifiedReputationChange::Malicious` changes immediately + /// and for testing. pub fn new(send_immediately_if: fn(UnifiedReputationChange) -> bool) -> Self { Self { by_peer: Default::default(), send_immediately_if } } diff --git a/node/test/client/src/block_builder.rs b/node/test/client/src/block_builder.rs index 88160e782a70..0987cef55c1f 100644 --- a/node/test/client/src/block_builder.rs +++ b/node/test/client/src/block_builder.rs @@ -32,15 +32,16 @@ use sp_state_machine::BasicExternalities; pub trait InitPolkadotBlockBuilder { /// Init a Polkadot specific block builder that works for the test runtime. /// - /// This will automatically create and push the inherents for you to make the block valid for the test runtime. + /// This will automatically create and push the inherents for you to make the block valid for + /// the test runtime. fn init_polkadot_block_builder( &self, ) -> sc_block_builder::BlockBuilder; /// Init a Polkadot specific block builder at a specific block that works for the test runtime. /// - /// Same as [`InitPolkadotBlockBuilder::init_polkadot_block_builder`] besides that it takes a [`BlockId`] to say - /// which should be the parent block of the block that is being build. + /// Same as [`InitPolkadotBlockBuilder::init_polkadot_block_builder`] besides that it takes a + /// [`BlockId`] to say which should be the parent block of the block that is being build. fn init_polkadot_block_builder_at( &self, hash: ::Hash, @@ -60,7 +61,8 @@ impl InitPolkadotBlockBuilder for Client { let last_timestamp = self.runtime_api().get_last_timestamp(hash).expect("Get last timestamp"); - // `MinimumPeriod` is a storage parameter type that requires externalities to access the value. + // `MinimumPeriod` is a storage parameter type that requires externalities to access the + // value. let minimum_period = BasicExternalities::new_empty() .execute_with(|| polkadot_test_runtime::MinimumPeriod::get()); @@ -73,7 +75,8 @@ impl InitPolkadotBlockBuilder for Client { last_timestamp + minimum_period }; - // `SlotDuration` is a storage parameter type that requires externalities to access the value. + // `SlotDuration` is a storage parameter type that requires externalities to access the + // value. let slot_duration = BasicExternalities::new_empty() .execute_with(|| polkadot_test_runtime::SlotDuration::get()); @@ -130,9 +133,9 @@ impl InitPolkadotBlockBuilder for Client { pub trait BlockBuilderExt { /// Push a Polkadot test runtime specific extrinsic to the block. /// - /// This will internally use the [`BlockBuilder::push`] method, but this method expects a opaque extrinsic. So, - /// we provide this wrapper which converts a test runtime specific extrinsic to a opaque extrinsic and pushes it to - /// the block. + /// This will internally use the [`BlockBuilder::push`] method, but this method expects a opaque + /// extrinsic. So, we provide this wrapper which converts a test runtime specific extrinsic to a + /// opaque extrinsic and pushes it to the block. /// /// Returns the result of the application of the extrinsic. fn push_polkadot_extrinsic( diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index a2c1b1941003..ed25d28d2925 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -257,7 +257,8 @@ pub struct PolkadotTestNode { pub client: Arc, /// A handle to Overseer. pub overseer_handle: Handle, - /// The `MultiaddrWithPeerId` to this node. This is useful if you want to pass it as "boot node" to other nodes. + /// The `MultiaddrWithPeerId` to this node. This is useful if you want to pass it as "boot + /// node" to other nodes. pub addr: MultiaddrWithPeerId, /// `RPCHandlers` to make RPC queries. pub rpc_handlers: RpcHandlers, @@ -312,14 +313,15 @@ impl PolkadotTestNode { self.send_sudo(call, Sr25519Keyring::Alice, 1).await } - /// Wait for `count` blocks to be imported in the node and then exit. This function will not return if no blocks - /// are ever created, thus you should restrict the maximum amount of time of the test execution. + /// Wait for `count` blocks to be imported in the node and then exit. This function will not + /// return if no blocks are ever created, thus you should restrict the maximum amount of time of + /// the test execution. pub fn wait_for_blocks(&self, count: usize) -> impl Future { self.client.wait_for_blocks(count) } - /// Wait for `count` blocks to be finalized and then exit. Similarly with `wait_for_blocks` this function will - /// not return if no block are ever finalized. + /// Wait for `count` blocks to be finalized and then exit. Similarly with `wait_for_blocks` this + /// function will not return if no block are ever finalized. pub async fn wait_for_finalized_blocks(&self, count: usize) { let mut import_notification_stream = self.client.finality_notification_stream(); let mut blocks = HashSet::new(); diff --git a/parachain/src/primitives.rs b/parachain/src/primitives.rs index 18da89aa97a1..55577618c469 100644 --- a/parachain/src/primitives.rs +++ b/parachain/src/primitives.rs @@ -287,13 +287,13 @@ impl IsSystem for Sibling { } } -/// A type that uniquely identifies an HRMP channel. An HRMP channel is established between two paras. -/// In text, we use the notation `(A, B)` to specify a channel between A and B. The channels are -/// unidirectional, meaning that `(A, B)` and `(B, A)` refer to different channels. The convention is -/// that we use the first item tuple for the sender and the second for the recipient. Only one channel -/// is allowed between two participants in one direction, i.e. there cannot be 2 different channels -/// identified by `(A, B)`. A channel with the same para id in sender and recipient is invalid. That -/// is, however, not enforced. +/// A type that uniquely identifies an HRMP channel. An HRMP channel is established between two +/// paras. In text, we use the notation `(A, B)` to specify a channel between A and B. The channels +/// are unidirectional, meaning that `(A, B)` and `(B, A)` refer to different channels. The +/// convention is that we use the first item tuple for the sender and the second for the recipient. +/// Only one channel is allowed between two participants in one direction, i.e. there cannot be 2 +/// different channels identified by `(A, B)`. A channel with the same para id in sender and +/// recipient is invalid. That is, however, not enforced. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(Hash))] pub struct HrmpChannelId { @@ -414,6 +414,7 @@ pub struct ValidationResult { /// /// It is expected that the Parachain processes them from first to last. pub processed_downward_messages: u32, - /// The mark which specifies the block number up to which all inbound HRMP messages are processed. + /// The mark which specifies the block number up to which all inbound HRMP messages are + /// processed. pub hrmp_watermark: RelayChainBlockNumber, } diff --git a/parachain/test-parachains/adder/collator/src/lib.rs b/parachain/test-parachains/adder/collator/src/lib.rs index 02a4598f9e47..1ac561dda2ba 100644 --- a/parachain/test-parachains/adder/collator/src/lib.rs +++ b/parachain/test-parachains/adder/collator/src/lib.rs @@ -147,7 +147,8 @@ impl Collator { /// Create the collation function. /// - /// This collation function can be plugged into the overseer to generate collations for the adder parachain. + /// This collation function can be plugged into the overseer to generate collations for the + /// adder parachain. pub fn create_collation_function( &self, spawner: impl SpawnNamed + Clone + 'static, @@ -228,8 +229,9 @@ impl Collator { /// Wait until `seconded` collations of this collator are seconded by a parachain validator. /// - /// The internal counter isn't de-duplicating the collations when counting the number of seconded collations. This - /// means when one collation is seconded by X validators, we record X seconded messages. + /// The internal counter isn't de-duplicating the collations when counting the number of + /// seconded collations. This means when one collation is seconded by X validators, we record X + /// seconded messages. pub async fn wait_for_seconded_collations(&self, seconded: u32) { let seconded_collations = self.seconded_collations.clone(); loop { diff --git a/parachain/test-parachains/adder/collator/tests/integration.rs b/parachain/test-parachains/adder/collator/tests/integration.rs index 9ab1c0c337a6..b891b29db59c 100644 --- a/parachain/test-parachains/adder/collator/tests/integration.rs +++ b/parachain/test-parachains/adder/collator/tests/integration.rs @@ -19,7 +19,8 @@ const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_adder_collator_puppet_worker"); -// If this test is failing, make sure to run all tests with the `real-overseer` feature being enabled. +// If this test is failing, make sure to run all tests with the `real-overseer` feature being +// enabled. #[substrate_test_utils::test(flavor = "multi_thread")] async fn collating_using_adder_collator() { diff --git a/parachain/test-parachains/undying/collator/src/lib.rs b/parachain/test-parachains/undying/collator/src/lib.rs index 838590fa16f5..cc0f592dc253 100644 --- a/parachain/test-parachains/undying/collator/src/lib.rs +++ b/parachain/test-parachains/undying/collator/src/lib.rs @@ -221,7 +221,8 @@ impl Collator { /// Create the collation function. /// - /// This collation function can be plugged into the overseer to generate collations for the undying parachain. + /// This collation function can be plugged into the overseer to generate collations for the + /// undying parachain. pub fn create_collation_function( &self, spawner: impl SpawnNamed + Clone + 'static, @@ -309,8 +310,9 @@ impl Collator { /// Wait until `seconded` collations of this collator are seconded by a parachain validator. /// - /// The internal counter isn't de-duplicating the collations when counting the number of seconded collations. This - /// means when one collation is seconded by X validators, we record X seconded messages. + /// The internal counter isn't de-duplicating the collations when counting the number of + /// seconded collations. This means when one collation is seconded by X validators, we record X + /// seconded messages. pub async fn wait_for_seconded_collations(&self, seconded: u32) { let seconded_collations = self.seconded_collations.clone(); loop { diff --git a/parachain/test-parachains/undying/collator/tests/integration.rs b/parachain/test-parachains/undying/collator/tests/integration.rs index 8ca6eec9aa62..21d174fb06c7 100644 --- a/parachain/test-parachains/undying/collator/tests/integration.rs +++ b/parachain/test-parachains/undying/collator/tests/integration.rs @@ -19,7 +19,8 @@ const PUPPET_EXE: &str = env!("CARGO_BIN_EXE_undying_collator_puppet_worker"); -// If this test is failing, make sure to run all tests with the `real-overseer` feature being enabled. +// If this test is failing, make sure to run all tests with the `real-overseer` feature being +// enabled. #[substrate_test_utils::test(flavor = "multi_thread")] async fn collating_using_undying_collator() { use polkadot_primitives::Id as ParaId; diff --git a/primitives/src/runtime_api.rs b/primitives/src/runtime_api.rs index ec05beea9d5f..c3a150a642e0 100644 --- a/primitives/src/runtime_api.rs +++ b/primitives/src/runtime_api.rs @@ -30,10 +30,9 @@ //! The versioning is achieved with the `api_version` attribute. It can be //! placed on: //! * trait declaration - represents the base version of the API. -//! * method declaration (inside a trait declaration) - represents a versioned -//! method, which is not available in the base version. -//! * trait implementation - represents which version of the API is being -//! implemented. +//! * method declaration (inside a trait declaration) - represents a versioned method, which is not +//! available in the base version. +//! * trait implementation - represents which version of the API is being implemented. //! //! Let's see a quick example: //! @@ -90,14 +89,14 @@ //! # How versioned methods are used for `ParachainHost` //! //! Let's introduce two types of `ParachainHost` API implementation: -//! * stable - used on stable production networks like Polkadot and Kusama. There is only one -//! stable API at a single point in time. +//! * stable - used on stable production networks like Polkadot and Kusama. There is only one stable +//! API at a single point in time. //! * staging - methods that are ready for production, but will be released on Rococo first. We can //! batch together multiple changes and then release all of them to production, by making staging //! production (bump base version). We can not change or remove any method in staging after a -//! release, as this would break Rococo. It should be ok to keep adding methods to staging -//! across several releases. For experimental methods, you have to keep them on a separate branch -//! until ready. +//! release, as this would break Rococo. It should be ok to keep adding methods to staging across +//! several releases. For experimental methods, you have to keep them on a separate branch until +//! ready. //! //! The stable version of `ParachainHost` is indicated by the base version of the API. Any staging //! method must use `api_version` attribute so that it is assigned to a specific version of a @@ -111,8 +110,8 @@ //! ``` //! indicates a function from the stable `v2` API. //! -//! All staging API functions should use primitives from `vstaging`. They should be clearly separated -//! from the stable primitives. +//! All staging API functions should use primitives from `vstaging`. They should be clearly +//! separated from the stable primitives. use crate::{ vstaging, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, diff --git a/primitives/src/v5/metrics.rs b/primitives/src/v5/metrics.rs index f947c7392dcb..97f7678e4373 100644 --- a/primitives/src/v5/metrics.rs +++ b/primitives/src/v5/metrics.rs @@ -164,8 +164,8 @@ pub mod metric_definitions { }; /// Counts the number of `imported`, `current` and `concluded_invalid` dispute statements sets - /// processed in `process_inherent_data`. The `current` label refers to the disputes statement sets of - /// the current session. + /// processed in `process_inherent_data`. The `current` label refers to the disputes statement + /// sets of the current session. pub const PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED: CounterVecDefinition = CounterVecDefinition { name: "polkadot_parachain_inherent_data_dispute_sets_processed", @@ -174,7 +174,8 @@ pub mod metric_definitions { labels: &["category"], }; - /// Counts the number of `valid` and `invalid` bitfields signature checked in `process_inherent_data`. + /// Counts the number of `valid` and `invalid` bitfields signature checked in + /// `process_inherent_data`. pub const PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS: CounterVecDefinition = CounterVecDefinition { name: "polkadot_parachain_create_inherent_bitfields_signature_checks", @@ -183,7 +184,8 @@ pub mod metric_definitions { labels: &["validity"], }; - /// Measures how much time does it take to verify a single validator signature of a dispute statement + /// Measures how much time does it take to verify a single validator signature of a dispute + /// statement pub const PARACHAIN_VERIFY_DISPUTE_SIGNATURE: HistogramDefinition = HistogramDefinition { name: "polkadot_parachain_verify_dispute_signature", diff --git a/primitives/src/v5/mod.rs b/primitives/src/v5/mod.rs index 3498c0762d4c..bdd10e623190 100644 --- a/primitives/src/v5/mod.rs +++ b/primitives/src/v5/mod.rs @@ -103,7 +103,8 @@ pub trait TypeIndex { fn type_index(&self) -> usize; } -/// Index of the validator is used as a lightweight replacement of the `ValidatorId` when appropriate. +/// Index of the validator is used as a lightweight replacement of the `ValidatorId` when +/// appropriate. #[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))] pub struct ValidatorIndex(pub u32); @@ -589,25 +590,27 @@ impl Ord for CommittedCandidateReceipt { } } -/// The validation data provides information about how to create the inputs for validation of a candidate. -/// This information is derived from the chain state and will vary from para to para, although some -/// fields may be the same for every para. +/// The validation data provides information about how to create the inputs for validation of a +/// candidate. This information is derived from the chain state and will vary from para to para, +/// although some fields may be the same for every para. /// -/// Since this data is used to form inputs to the validation function, it needs to be persisted by the -/// availability system to avoid dependence on availability of the relay-chain state. +/// Since this data is used to form inputs to the validation function, it needs to be persisted by +/// the availability system to avoid dependence on availability of the relay-chain state. /// -/// Furthermore, the validation data acts as a way to authorize the additional data the collator needs -/// to pass to the validation function. For example, the validation function can check whether the incoming -/// messages (e.g. downward messages) were actually sent by using the data provided in the validation data -/// using so called MQC heads. +/// Furthermore, the validation data acts as a way to authorize the additional data the collator +/// needs to pass to the validation function. For example, the validation function can check whether +/// the incoming messages (e.g. downward messages) were actually sent by using the data provided in +/// the validation data using so called MQC heads. /// -/// Since the commitments of the validation function are checked by the relay-chain, secondary checkers -/// can rely on the invariant that the relay-chain only includes para-blocks for which these checks have -/// already been done. As such, there is no need for the validation data used to inform validators and -/// collators about the checks the relay-chain will perform to be persisted by the availability system. +/// Since the commitments of the validation function are checked by the relay-chain, secondary +/// checkers can rely on the invariant that the relay-chain only includes para-blocks for which +/// these checks have already been done. As such, there is no need for the validation data used to +/// inform validators and collators about the checks the relay-chain will perform to be persisted by +/// the availability system. /// -/// The `PersistedValidationData` should be relatively lightweight primarily because it is constructed -/// during inclusion for each candidate and therefore lies on the critical path of inclusion. +/// The `PersistedValidationData` should be relatively lightweight primarily because it is +/// constructed during inclusion for each candidate and therefore lies on the critical path of +/// inclusion. #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Default))] pub struct PersistedValidationData { @@ -642,7 +645,8 @@ pub struct CandidateCommitments { pub head_data: HeadData, /// The number of messages processed from the DMQ. pub processed_downward_messages: u32, - /// The mark which specifies the block number up to which all inbound HRMP messages are processed. + /// The mark which specifies the block number up to which all inbound HRMP messages are + /// processed. pub hrmp_watermark: N, } @@ -677,7 +681,8 @@ pub type UncheckedSignedAvailabilityBitfield = UncheckedSigned; -/// A set of unchecked signed availability bitfields. Should be sorted by validator index, ascending. +/// A set of unchecked signed availability bitfields. Should be sorted by validator index, +/// ascending. pub type UncheckedSignedAvailabilityBitfields = Vec; /// A backed (or backable, depending on context) candidate. @@ -975,8 +980,9 @@ pub enum CoreState { /// variant. #[codec(index = 1)] Scheduled(ScheduledCore), - /// The core is currently free and there is nothing scheduled. This can be the case for parathread - /// cores when there are no parathread blocks queued. Parachain cores will never be left idle. + /// The core is currently free and there is nothing scheduled. This can be the case for + /// parathread cores when there are no parathread blocks queued. Parachain cores will never be + /// left idle. #[codec(index = 2)] Free, } @@ -1079,8 +1085,8 @@ impl From for u8 { } } -/// Abridged version of `HostConfiguration` (from the `Configuration` parachains host runtime module) -/// meant to be used by a parachain or PDK such as cumulus. +/// Abridged version of `HostConfiguration` (from the `Configuration` parachains host runtime +/// module) meant to be used by a parachain or PDK such as cumulus. #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct AbridgedHostConfiguration { @@ -1156,17 +1162,18 @@ pub enum UpgradeRestriction { #[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub enum UpgradeGoAhead { /// Abort the upgrade process. There is something wrong with the validation code previously - /// submitted by the parachain. This variant can also be used to prevent upgrades by the governance - /// should an emergency emerge. + /// submitted by the parachain. This variant can also be used to prevent upgrades by the + /// governance should an emergency emerge. /// /// The expected reaction on this variant is that the parachain will admit this message and /// remove all the data about the pending upgrade. Depending on the nature of the problem (to - /// be examined offchain for now), it can try to send another validation code or just retry later. + /// be examined offchain for now), it can try to send another validation code or just retry + /// later. #[codec(index = 0)] Abort, - /// Apply the pending code change. The parablock that is built on a relay-parent that is descendant - /// of the relay-parent where the parachain observed this signal must use the upgraded validation - /// code. + /// Apply the pending code change. The parablock that is built on a relay-parent that is + /// descendant of the relay-parent where the parachain observed this signal must use the + /// upgraded validation code. #[codec(index = 1)] GoAhead, } @@ -1646,7 +1653,7 @@ pub const fn supermajority_threshold(n: usize) -> usize { #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct SessionInfo { - /****** New in v2 *******/ + /****** New in v2 ****** */ /// All the validators actively participating in parachain consensus. /// Indices are into the broader validator set. pub active_validator_indices: Vec, @@ -1655,11 +1662,11 @@ pub struct SessionInfo { /// The amount of sessions to keep for disputes. pub dispute_period: SessionIndex, - /****** Old fields ******/ + /****** Old fields ***** */ /// Validators in canonical ordering. /// - /// NOTE: There might be more authorities in the current session, than `validators` participating - /// in parachain consensus. See + /// NOTE: There might be more authorities in the current session, than `validators` + /// participating in parachain consensus. See /// [`max_validators`](https://github.com/paritytech/polkadot/blob/a52dca2be7840b23c19c153cf7e110b1e3e475f8/runtime/parachains/src/configuration.rs#L148). /// /// `SessionInfo::validators` will be limited to to `max_validators` when set. @@ -1667,8 +1674,8 @@ pub struct SessionInfo { /// Validators' authority discovery keys for the session in canonical ordering. /// /// NOTE: The first `validators.len()` entries will match the corresponding validators in - /// `validators`, afterwards any remaining authorities can be found. This is any authorities not - /// participating in parachain consensus - see + /// `validators`, afterwards any remaining authorities can be found. This is any authorities + /// not participating in parachain consensus - see /// [`max_validators`](https://github.com/paritytech/polkadot/blob/a52dca2be7840b23c19c153cf7e110b1e3e475f8/runtime/parachains/src/configuration.rs#L148) pub discovery_keys: Vec, /// The assignment keys for validators. @@ -1679,8 +1686,8 @@ pub struct SessionInfo { /// /// Therefore: /// ```ignore - /// assignment_keys.len() == validators.len() && validators.len() <= discovery_keys.len() - /// ``` + /// assignment_keys.len() == validators.len() && validators.len() <= discovery_keys.len() + /// ``` pub assignment_keys: Vec, /// Validators in shuffled ordering - these are the validator groups as produced /// by the `Scheduler` module for the session and are typically referred to by diff --git a/primitives/test-helpers/src/lib.rs b/primitives/test-helpers/src/lib.rs index ac7af5b5fa7d..a8fc0f7ccc26 100644 --- a/primitives/test-helpers/src/lib.rs +++ b/primitives/test-helpers/src/lib.rs @@ -17,7 +17,8 @@ #![forbid(unused_crate_dependencies)] #![forbid(unused_extern_crates)] -//! A set of primitive constructors, to aid in crafting meaningful testcase while reducing repetition. +//! A set of primitive constructors, to aid in crafting meaningful testcase while reducing +//! repetition. //! //! Note that `dummy_` prefixed values are meant to be fillers, that should not matter, and will //! contain randomness based data. diff --git a/runtime/common/slot_range_helper/src/lib.rs b/runtime/common/slot_range_helper/src/lib.rs index 626232032fbd..bbe5b61ae1f3 100644 --- a/runtime/common/slot_range_helper/src/lib.rs +++ b/runtime/common/slot_range_helper/src/lib.rs @@ -36,15 +36,15 @@ pub use sp_std::{ops::Add, result}; /// /// This will generate an enum `SlotRange` with the following properties: /// -/// * Enum variants will range from all consecutive combinations of inputs, i.e. -/// `ZeroZero`, `ZeroOne`, `ZeroTwo`, `ZeroThree`, `OneOne`, `OneTwo`, `OneThree`... +/// * Enum variants will range from all consecutive combinations of inputs, i.e. `ZeroZero`, +/// `ZeroOne`, `ZeroTwo`, `ZeroThree`, `OneOne`, `OneTwo`, `OneThree`... /// * A constant `LEASE_PERIODS_PER_SLOT` will count the number of lease periods. /// * A constant `SLOT_RANGE_COUNT` will count the total number of enum variants. /// * A function `as_pair` will return a tuple representation of the `SlotRange`. /// * A function `intersects` will tell you if two slot ranges intersect with one another. /// * A function `len` will tell you the length of occupying a `SlotRange`. -/// * A function `new_bounded` will generate a `SlotRange` from an input of the current -/// lease period, the starting lease period, and the final lease period. +/// * A function `new_bounded` will generate a `SlotRange` from an input of the current lease +/// period, the starting lease period, and the final lease period. #[macro_export] macro_rules! generate_slot_range{ // Entry point diff --git a/runtime/common/src/assigned_slots.rs b/runtime/common/src/assigned_slots.rs index 4424738c9835..b3c1381c9ec9 100644 --- a/runtime/common/src/assigned_slots.rs +++ b/runtime/common/src/assigned_slots.rs @@ -322,7 +322,8 @@ pub mod pallet { }, Err(err) => { // Treat failed lease creation as warning .. slot will be allocated a lease - // in a subsequent lease period by the `allocate_temporary_slot_leases` function. + // in a subsequent lease period by the `allocate_temporary_slot_leases` + // function. log::warn!(target: "assigned_slots", "Failed to allocate a temp slot for para {:?} at period {:?}: {:?}", id, current_lease_period, err @@ -398,7 +399,8 @@ impl Pallet { /// total number of lease (lower first), and then when they last a turn (older ones first). /// If any remaining ex-aequo, we just take the para ID in ascending order as discriminator. /// - /// Assigned slots with a `period_begin` bigger than current lease period are not considered (yet). + /// Assigned slots with a `period_begin` bigger than current lease period are not considered + /// (yet). /// /// The function will call out to `Leaser::lease_out` to create the appropriate slot leases. fn allocate_temporary_slot_leases(lease_period_index: LeasePeriodOf) -> DispatchResult { @@ -525,7 +527,8 @@ impl Pallet { /// Handles start of a lease period. fn manage_lease_period_start(lease_period_index: LeasePeriodOf) -> Weight { - // Note: leases that have ended in previous lease period, should have been cleaned in slots pallet. + // Note: leases that have ended in previous lease period, should have been cleaned in slots + // pallet. if let Err(err) = Self::allocate_temporary_slot_leases(lease_period_index) { log::error!(target: "assigned_slots", "Allocating slots failed for lease period {:?}, with: {:?}", diff --git a/runtime/common/src/auctions.rs b/runtime/common/src/auctions.rs index 7ab12eec7998..901c9c27da28 100644 --- a/runtime/common/src/auctions.rs +++ b/runtime/common/src/auctions.rs @@ -138,8 +138,8 @@ pub mod pallet { Reserved { bidder: T::AccountId, extra_reserved: BalanceOf, total_amount: BalanceOf }, /// Funds were unreserved since bidder is no longer active. `[bidder, amount]` Unreserved { bidder: T::AccountId, amount: BalanceOf }, - /// Someone attempted to lease the same slot twice for a parachain. The amount is held in reserve - /// but no parachain slot has been leased. + /// Someone attempted to lease the same slot twice for a parachain. The amount is held in + /// reserve but no parachain slot has been leased. ReserveConfiscated { para_id: ParaId, leaser: T::AccountId, amount: BalanceOf }, /// A new bid has been accepted as the current winner. BidAccepted { @@ -149,7 +149,8 @@ pub mod pallet { first_slot: LeasePeriodOf, last_slot: LeasePeriodOf, }, - /// The winning offset was chosen for an auction. This will map into the `Winning` storage map. + /// The winning offset was chosen for an auction. This will map into the `Winning` storage + /// map. WinningOffset { auction_index: AuctionIndex, block_number: BlockNumberFor }, } @@ -217,9 +218,9 @@ pub mod pallet { fn on_initialize(n: BlockNumberFor) -> Weight { let mut weight = T::DbWeight::get().reads(1); - // If the current auction was in its ending period last block, then ensure that the (sub-)range - // winner information is duplicated from the previous block in case no bids happened in the - // last block. + // If the current auction was in its ending period last block, then ensure that the + // (sub-)range winner information is duplicated from the previous block in case no bids + // happened in the last block. if let AuctionStatus::EndingPeriod(offset, _sub_sample) = Self::auction_status(n) { weight = weight.saturating_add(T::DbWeight::get().reads(1)); if !Winning::::contains_key(&offset) { @@ -555,8 +556,9 @@ impl Pallet { }); let res = Winning::::get(offset) .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); - // This `remove_all` statement should remove at most `EndingPeriod` / `SampleLength` items, - // which should be bounded and sensibly configured in the runtime. + // This `remove_all` statement should remove at most `EndingPeriod` / + // `SampleLength` items, which should be bounded and sensibly configured in the + // runtime. #[allow(deprecated)] Winning::::remove_all(None); AuctionInfo::::kill(); @@ -574,8 +576,8 @@ impl Pallet { auction_lease_period_index: LeasePeriodOf, winning_ranges: WinningData, ) { - // First, unreserve all amounts that were reserved for the bids. We will later re-reserve the - // amounts from the bidders that ended up being assigned the slot so there's no need to + // First, unreserve all amounts that were reserved for the bids. We will later re-reserve + // the amounts from the bidders that ended up being assigned the slot so there's no need to // special-case them here. for ((bidder, _), amount) in ReservedAmounts::::drain() { CurrencyOf::::unreserve(&bidder, amount); @@ -596,12 +598,12 @@ impl Pallet { Err(LeaseError::ReserveFailed) | Err(LeaseError::AlreadyEnded) | Err(LeaseError::NoLeasePeriod) => { - // Should never happen since we just unreserved this amount (and our offset is from the - // present period). But if it does, there's not much we can do. + // Should never happen since we just unreserved this amount (and our offset is + // from the present period). But if it does, there's not much we can do. }, Err(LeaseError::AlreadyLeased) => { - // The leaser attempted to get a second lease on the same para ID, possibly griefing us. Let's - // keep the amount reserved and let governance sort it out. + // The leaser attempted to get a second lease on the same para ID, possibly + // griefing us. Let's keep the amount reserved and let governance sort it out. if CurrencyOf::::reserve(&leaser, amount).is_ok() { Self::deposit_event(Event::::ReserveConfiscated { para_id: para, @@ -1123,11 +1125,11 @@ mod tests { Auctions::auction_status(System::block_number()), AuctionStatus::::EndingPeriod(2, 0) ); - // This will prevent the auction's winner from being decided in the next block, since the random - // seed was known before the final bids were made. + // This will prevent the auction's winner from being decided in the next block, since + // the random seed was known before the final bids were made. set_last_random(H256::zero(), 8); - // Auction definitely ended now, but we don't know exactly when in the last 3 blocks yet since - // no randomness available yet. + // Auction definitely ended now, but we don't know exactly when in the last 3 blocks yet + // since no randomness available yet. run_to_block(9); // Auction has now ended... But auction winner still not yet decided, so no leases yet. assert_eq!( @@ -1136,8 +1138,8 @@ mod tests { ); assert_eq!(leases(), vec![]); - // Random seed now updated to a value known at block 9, when the auction ended. This means - // that the winner can now be chosen. + // Random seed now updated to a value known at block 9, when the auction ended. This + // means that the winner can now be chosen. set_last_random(H256::zero(), 9); run_to_block(10); // Auction ended and winner selected diff --git a/runtime/common/src/claims.rs b/runtime/common/src/claims.rs index 6a41a8f3f472..9cc06b2bede2 100644 --- a/runtime/common/src/claims.rs +++ b/runtime/common/src/claims.rs @@ -193,8 +193,8 @@ pub mod pallet { SignerHasNoClaim, /// Account ID sending transaction has no claim. SenderHasNoClaim, - /// There's not enough in the pot to pay out some unvested amount. Generally implies a logic - /// error. + /// There's not enough in the pot to pay out some unvested amount. Generally implies a + /// logic error. PotUnderflow, /// A needed statement was not included. InvalidStatement, @@ -288,8 +288,8 @@ pub mod pallet { /// /// Parameters: /// - `dest`: The destination account to payout the claim. - /// - `ethereum_signature`: The signature of an ethereum signed message - /// matching the format described above. + /// - `ethereum_signature`: The signature of an ethereum signed message matching the format + /// described above. /// /// /// The weight of this call is invariant over the input parameters. @@ -368,9 +368,10 @@ pub mod pallet { /// /// Parameters: /// - `dest`: The destination account to payout the claim. - /// - `ethereum_signature`: The signature of an ethereum signed message - /// matching the format described above. - /// - `statement`: The identity of the statement which is being attested to in the signature. + /// - `ethereum_signature`: The signature of an ethereum signed message matching the format + /// described above. + /// - `statement`: The identity of the statement which is being attested to in the + /// signature. /// /// /// The weight of this call is invariant over the input parameters. @@ -400,14 +401,16 @@ pub mod pallet { /// Attest to a statement, needed to finalize the claims process. /// - /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a `SignedExtension`. + /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a + /// `SignedExtension`. /// /// Unsigned Validation: /// A call to attest is deemed valid if the sender has a `Preclaim` registered /// and provides a `statement` which is expected for the account. /// /// Parameters: - /// - `statement`: The identity of the statement which is being attested to in the signature. + /// - `statement`: The identity of the statement which is being attested to in the + /// signature. /// /// /// The weight of this call is invariant over the input parameters. diff --git a/runtime/common/src/crowdloan/migration.rs b/runtime/common/src/crowdloan/migration.rs index 4a47f3283de3..03c4ab6c3119 100644 --- a/runtime/common/src/crowdloan/migration.rs +++ b/runtime/common/src/crowdloan/migration.rs @@ -134,8 +134,8 @@ pub mod crowdloan_index_migration { Ok(()) } - /// This migration converts crowdloans to use a crowdloan index rather than the parachain id as a - /// unique identifier. This makes it easier to swap two crowdloans between parachains. + /// This migration converts crowdloans to use a crowdloan index rather than the parachain id as + /// a unique identifier. This makes it easier to swap two crowdloans between parachains. pub fn migrate() -> frame_support::weights::Weight { let mut weight = Weight::zero(); diff --git a/runtime/common/src/crowdloan/mod.rs b/runtime/common/src/crowdloan/mod.rs index 18c86e68e5df..1db046c52701 100644 --- a/runtime/common/src/crowdloan/mod.rs +++ b/runtime/common/src/crowdloan/mod.rs @@ -45,9 +45,9 @@ //! slot auction enters its ending period, then parachains will each place a bid; the bid will be //! raised once per block if the parachain had additional funds contributed since the last bid. //! -//! Successful funds remain tracked (in the `Funds` storage item and the associated child trie) as long as -//! the parachain remains active. Users can withdraw their funds once the slot is completed and funds are -//! returned to the crowdloan account. +//! Successful funds remain tracked (in the `Funds` storage item and the associated child trie) as +//! long as the parachain remains active. Users can withdraw their funds once the slot is completed +//! and funds are returned to the crowdloan account. pub mod migration; @@ -164,11 +164,11 @@ pub struct FundInfo { /// If this is `Ending(n)`, this fund received a contribution during the current ending period, /// where `n` is how far into the ending period the contribution was made. pub last_contribution: LastContribution, - /// First lease period in range to bid on; it's actually a `LeasePeriod`, but that's the same type - /// as `BlockNumber`. + /// First lease period in range to bid on; it's actually a `LeasePeriod`, but that's the same + /// type as `BlockNumber`. pub first_period: LeasePeriod, - /// Last lease period in range to bid on; it's actually a `LeasePeriod`, but that's the same type - /// as `BlockNumber`. + /// Last lease period in range to bid on; it's actually a `LeasePeriod`, but that's the same + /// type as `BlockNumber`. pub last_period: LeasePeriod, /// Unique index used to represent this fund. pub fund_index: FundIndex, @@ -192,15 +192,16 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// `PalletId` for the crowdloan pallet. An appropriate value could be `PalletId(*b"py/cfund")` + /// `PalletId` for the crowdloan pallet. An appropriate value could be + /// `PalletId(*b"py/cfund")` #[pallet::constant] type PalletId: Get; /// The amount to be held on deposit by the depositor of a crowdloan. type SubmissionDeposit: Get>; - /// The minimum amount that may be contributed into a crowdloan. Should almost certainly be at - /// least `ExistentialDeposit`. + /// The minimum amount that may be contributed into a crowdloan. Should almost certainly be + /// at least `ExistentialDeposit`. #[pallet::constant] type MinContribution: Get>; @@ -208,8 +209,8 @@ pub mod pallet { #[pallet::constant] type RemoveKeysLimit: Get; - /// The parachain registrar type. We just use this to ensure that only the manager of a para is able to - /// start a crowdloan for its slot. + /// The parachain registrar type. We just use this to ensure that only the manager of a para + /// is able to start a crowdloan for its slot. type Registrar: Registrar; /// The type representing the auctioning system. @@ -314,7 +315,8 @@ pub mod pallet { FundNotEnded, /// There are no contributions stored in this crowdloan. NoContributions, - /// The crowdloan is not ready to dissolve. Potentially still has a slot or in retirement period. + /// The crowdloan is not ready to dissolve. Potentially still has a slot or in retirement + /// period. NotReadyToDissolve, /// Invalid signature. InvalidSignature, @@ -342,8 +344,9 @@ pub mod pallet { for (fund, para_id) in new_raise.into_iter().filter_map(|i| Self::funds(i).map(|f| (f, i))) { - // Care needs to be taken by the crowdloan creator that this function will succeed given - // the crowdloaning configuration. We do some checks ahead of time in crowdloan `create`. + // Care needs to be taken by the crowdloan creator that this function will + // succeed given the crowdloaning configuration. We do some checks ahead of time + // in crowdloan `create`. let result = T::Auctioneer::place_bid( Self::fund_account_id(fund.fund_index), para_id, @@ -363,7 +366,8 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Create a new crowdloaning campaign for a parachain slot with the given lease period range. + /// Create a new crowdloaning campaign for a parachain slot with the given lease period + /// range. /// /// This applies a lock to your parachain configuration, ensuring that it cannot be changed /// by the parachain manager. @@ -462,16 +466,16 @@ pub mod pallet { /// /// Origin must be signed, but can come from anyone. /// - /// The fund must be either in, or ready for, retirement. For a fund to be *in* retirement, then the retirement - /// flag must be set. For a fund to be ready for retirement, then: + /// The fund must be either in, or ready for, retirement. For a fund to be *in* retirement, + /// then the retirement flag must be set. For a fund to be ready for retirement, then: /// - it must not already be in retirement; /// - the amount of raised funds must be bigger than the _free_ balance of the account; /// - and either: /// - the block number must be at least `end`; or /// - the current lease period must be greater than the fund's `last_period`. /// - /// In this case, the fund's retirement flag is set and its `end` is reset to the current block - /// number. + /// In this case, the fund's retirement flag is set and its `end` is reset to the current + /// block number. /// /// - `who`: The account whose contribution should be withdrawn. /// - `index`: The parachain to whose crowdloan the contribution was made. @@ -653,8 +657,9 @@ pub mod pallet { Ok(()) } - /// Contribute your entire balance to a crowd sale. This will transfer the entire balance of a user over to fund a parachain - /// slot. It will be withdrawable when the crowdloan has ended and the funds are unused. + /// Contribute your entire balance to a crowd sale. This will transfer the entire balance of + /// a user over to fund a parachain slot. It will be withdrawable when the crowdloan has + /// ended and the funds are unused. #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::contribute())] pub fn contribute_all( @@ -719,8 +724,8 @@ impl Pallet { } /// This function checks all conditions which would qualify a crowdloan has ended. - /// * If we have reached the `fund.end` block OR the first lease period the fund is - /// trying to bid for has started already. + /// * If we have reached the `fund.end` block OR the first lease period the fund is trying to + /// bid for has started already. /// * And, if the fund has enough free funds to refund full raised amount. fn ensure_crowdloan_ended( now: BlockNumberFor, @@ -775,8 +780,8 @@ impl Pallet { Error::::BidOrLeaseActive ); - // We disallow any crowdloan contributions during the VRF Period, so that people do not sneak their - // contributions into the auction when it would not impact the outcome. + // We disallow any crowdloan contributions during the VRF Period, so that people do not + // sneak their contributions into the auction when it would not impact the outcome. ensure!(!T::Auctioneer::auction_status(now).is_vrf(), Error::::VrfDelayInProgress); let (old_balance, memo) = Self::contribution_get(fund.fund_index, &who); @@ -1287,7 +1292,8 @@ mod tests { ); // Cannot create a crowdloan with nonsense end date - // This crowdloan would end in lease period 2, but is bidding for some slot that starts in lease period 1. + // This crowdloan would end in lease period 2, but is bidding for some slot that starts + // in lease period 1. assert_noop!( Crowdloan::create(RuntimeOrigin::signed(1), para, 1000, 1, 4, 41, None), Error::::EndTooFarInFuture @@ -1457,7 +1463,8 @@ mod tests { let para_2 = new_para(); let index = NextFundIndex::::get(); assert_ok!(Crowdloan::create(RuntimeOrigin::signed(1), para_2, 1000, 1, 4, 40, None)); - // Emulate a win by leasing out and putting a deposit. Slots pallet would normally do this. + // Emulate a win by leasing out and putting a deposit. Slots pallet would normally do + // this. let crowdloan_account = Crowdloan::fund_account_id(index); set_winner(para_2, crowdloan_account, true); assert_noop!( @@ -1465,8 +1472,8 @@ mod tests { Error::::BidOrLeaseActive ); - // Move past lease period 1, should not be allowed to have further contributions with a crowdloan - // that has starting period 1. + // Move past lease period 1, should not be allowed to have further contributions with a + // crowdloan that has starting period 1. let para_3 = new_para(); assert_ok!(Crowdloan::create(RuntimeOrigin::signed(1), para_3, 1000, 1, 4, 40, None)); run_to_block(40); diff --git a/runtime/common/src/integration_tests.rs b/runtime/common/src/integration_tests.rs index fa21fbf9ef69..34a49bc230b6 100644 --- a/runtime/common/src/integration_tests.rs +++ b/runtime/common/src/integration_tests.rs @@ -471,7 +471,8 @@ fn basic_end_to_end_works() { ); assert_eq!( slots::Leases::::get(ParaId::from(para_2)), - // -- 1 --- 2 --- 3 --- 4 --- 5 ---------------- 6 --------------------------- 7 ---------------- + // -- 1 --- 2 --- 3 --- 4 --- 5 ---------------- 6 --------------------------- 7 + // ---------------- vec![ None, None, @@ -599,7 +600,8 @@ fn basic_errors_fail() { #[test] fn competing_slots() { - // This test will verify that competing slots, from different sources will resolve appropriately. + // This test will verify that competing slots, from different sources will resolve + // appropriately. new_test_ext().execute_with(|| { assert!(System::block_number().is_one()); let max_bids = 10u32; @@ -789,7 +791,8 @@ fn competing_bids() { let crowdloan_1 = Crowdloan::fund_account_id(fund_1.fund_index); assert_eq!( slots::Leases::::get(ParaId::from(2000)), - // -- 1 --- 2 --- 3 --- 4 --- 5 ------------- 6 ------------------------ 7 ------------- + // -- 1 --- 2 --- 3 --- 4 --- 5 ------------- 6 ------------------------ 7 + // ------------- vec![ None, None, diff --git a/runtime/common/src/paras_registrar.rs b/runtime/common/src/paras_registrar.rs index 550f443a5a78..57d9e21bcf53 100644 --- a/runtime/common/src/paras_registrar.rs +++ b/runtime/common/src/paras_registrar.rs @@ -107,9 +107,9 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The aggregated origin type must support the `parachains` origin. We require that we can - /// infallibly convert between this origin and the system origin, but in reality, they're the - /// same type, we just can't express that to the Rust type system without writing a `where` - /// clause everywhere. + /// infallibly convert between this origin and the system origin, but in reality, they're + /// the same type, we just can't express that to the Rust type system without writing a + /// `where` clause everywhere. type RuntimeOrigin: From<::RuntimeOrigin> + Into::RuntimeOrigin>>; @@ -163,14 +163,15 @@ pub mod pallet { CannotDowngrade, /// Cannot schedule upgrade of parathread to parachain CannotUpgrade, - /// Para is locked from manipulation by the manager. Must use parachain or relay chain governance. + /// Para is locked from manipulation by the manager. Must use parachain or relay chain + /// governance. ParaLocked, /// The ID given for registration has not been reserved. NotReserved, /// Registering parachain with empty code is not allowed. EmptyCode, - /// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras are - /// correct for the swap to work. + /// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras + /// are correct for the swap to work. CannotSwap, } @@ -180,8 +181,8 @@ pub mod pallet { /// Amount held on deposit for each para and the original depositor. /// - /// The given account ID is responsible for registering the code and initial head data, but may only do - /// so if it isn't yet registered. (After that, it's up to governance to do so.) + /// The given account ID is responsible for registering the code and initial head data, but may + /// only do so if it isn't yet registered. (After that, it's up to governance to do so.) #[pallet::storage] pub type Paras = StorageMap<_, Twox64Concat, ParaId, ParaInfo>>; @@ -224,8 +225,8 @@ pub mod pallet { /// - `validation_code`: The initial validation code of the parachain/thread. /// /// ## Deposits/Fees - /// The origin signed account must reserve a corresponding deposit for the registration. Anything already - /// reserved previously for this para ID is accounted for. + /// The origin signed account must reserve a corresponding deposit for the registration. + /// Anything already reserved previously for this para ID is accounted for. /// /// ## Events /// The `Registered` event is emitted in case of success. @@ -264,7 +265,8 @@ pub mod pallet { /// Deregister a Para Id, freeing all data and returning any deposit. /// - /// The caller must be Root, the `para` owner, or the `para` itself. The para must be a parathread. + /// The caller must be Root, the `para` owner, or the `para` itself. The para must be a + /// parathread. #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::deregister())] pub fn deregister(origin: OriginFor, id: ParaId) -> DispatchResult { @@ -345,17 +347,20 @@ pub mod pallet { /// Reserve a Para Id on the relay chain. /// /// This function will reserve a new Para Id to be owned/managed by the origin account. - /// The origin account is able to register head data and validation code using `register` to create - /// a parathread. Using the Slots pallet, a parathread can then be upgraded to get a parachain slot. + /// The origin account is able to register head data and validation code using `register` to + /// create a parathread. Using the Slots pallet, a parathread can then be upgraded to get a + /// parachain slot. /// /// ## Arguments - /// - `origin`: Must be called by a `Signed` origin. Becomes the manager/owner of the new para ID. + /// - `origin`: Must be called by a `Signed` origin. Becomes the manager/owner of the new + /// para ID. /// /// ## Deposits/Fees /// The origin must reserve a deposit of `ParaDeposit` for the registration. /// /// ## Events - /// The `Reserved` event is emitted in case of success, which provides the ID reserved for use. + /// The `Reserved` event is emitted in case of success, which provides the ID reserved for + /// use. #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::reserve())] pub fn reserve(origin: OriginFor) -> DispatchResult { @@ -369,7 +374,8 @@ pub mod pallet { /// Add a manager lock from a para. This will prevent the manager of a /// para to deregister or swap a para. /// - /// Can be called by Root, the parachain, or the parachain manager if the parachain is unlocked. + /// Can be called by Root, the parachain, or the parachain manager if the parachain is + /// unlocked. #[pallet::call_index(6)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn add_lock(origin: OriginFor, para: ParaId) -> DispatchResult { @@ -380,7 +386,8 @@ pub mod pallet { /// Schedule a parachain upgrade. /// - /// Can be called by Root, the parachain, or the parachain manager if the parachain is unlocked. + /// Can be called by Root, the parachain, or the parachain manager if the parachain is + /// unlocked. #[pallet::call_index(7)] #[pallet::weight(::WeightInfo::schedule_code_upgrade(new_code.0.len() as u32))] pub fn schedule_code_upgrade( @@ -395,7 +402,8 @@ pub mod pallet { /// Set the parachain's current head. /// - /// Can be called by Root, the parachain, or the parachain manager if the parachain is unlocked. + /// Can be called by Root, the parachain, or the parachain manager if the parachain is + /// unlocked. #[pallet::call_index(8)] #[pallet::weight(::WeightInfo::set_current_head(new_head.0.len() as u32))] pub fn set_current_head( diff --git a/runtime/common/src/paras_sudo_wrapper.rs b/runtime/common/src/paras_sudo_wrapper.rs index 8944e932e9ef..d18eb8650aaf 100644 --- a/runtime/common/src/paras_sudo_wrapper.rs +++ b/runtime/common/src/paras_sudo_wrapper.rs @@ -45,8 +45,8 @@ pub mod pallet { ParaDoesntExist, /// The specified parachain or parathread is already registered. ParaAlreadyExists, - /// A DMP message couldn't be sent because it exceeds the maximum size allowed for a downward - /// message. + /// A DMP message couldn't be sent because it exceeds the maximum size allowed for a + /// downward message. ExceedsMaxMessageSize, /// Could not schedule para cleanup. CouldntCleanup, @@ -127,8 +127,8 @@ pub mod pallet { /// Send a downward XCM to the given para. /// - /// The given parachain should exist and the payload should not exceed the preconfigured size - /// `config.max_downward_message_size`. + /// The given parachain should exist and the payload should not exceed the preconfigured + /// size `config.max_downward_message_size`. #[pallet::call_index(4)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_queue_downward_xcm( diff --git a/runtime/common/src/purchase.rs b/runtime/common/src/purchase.rs index 246511a5d3d8..72795a733ea9 100644 --- a/runtime/common/src/purchase.rs +++ b/runtime/common/src/purchase.rs @@ -82,7 +82,8 @@ pub struct AccountStatus { locked_balance: Balance, /// Their sr25519/ed25519 signature verifying they have signed our required statement. signature: Vec, - /// The percentage of VAT the purchaser is responsible for. This is already factored into account balance. + /// The percentage of VAT the purchaser is responsible for. This is already factored into + /// account balance. vat: Permill, } @@ -333,12 +334,14 @@ pub mod pallet { if !status.locked_balance.is_zero() { let unlock_block = UnlockBlock::::get(); - // We allow some configurable portion of the purchased locked DOTs to be unlocked for basic usage. + // We allow some configurable portion of the purchased locked DOTs to be + // unlocked for basic usage. let unlocked = (T::UnlockedProportion::get() * status.locked_balance) .min(T::MaxUnlocked::get()); let locked = status.locked_balance.saturating_sub(unlocked); - // We checked that this account has no existing vesting schedule. So this function should - // never fail, however if it does, not much we can do about it at this point. + // We checked that this account has no existing vesting schedule. So this + // function should never fail, however if it does, not much we can do about + // it at this point. let _ = T::VestingSchedule::add_vesting_schedule( // Apply vesting schedule to this user &who, @@ -351,7 +354,8 @@ pub mod pallet { ); } - // Setting the user account to `Completed` ends the purchase process for this user. + // Setting the user account to `Completed` ends the purchase process for this + // user. status.validity = AccountValidity::Completed; Self::deposit_event(Event::::PaymentComplete { who: who.clone(), @@ -645,17 +649,20 @@ mod tests { } fn alice_signature() -> [u8; 64] { - // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold race lonely fit walk//Alice" + // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold + // race lonely fit walk//Alice" hex_literal::hex!("20e0faffdf4dfe939f2faa560f73b1d01cde8472e2b690b7b40606a374244c3a2e9eb9c8107c10b605138374003af8819bd4387d7c24a66ee9253c2e688ab881") } fn bob_signature() -> [u8; 64] { - // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold race lonely fit walk//Bob" + // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold + // race lonely fit walk//Bob" hex_literal::hex!("d6d460187ecf530f3ec2d6e3ac91b9d083c8fbd8f1112d92a82e4d84df552d18d338e6da8944eba6e84afaacf8a9850f54e7b53a84530d649be2e0119c7ce889") } fn alice_signature_ed25519() -> [u8; 64] { - // echo -n "Hello, World" | subkey -e sign "bottom drive obey lake curtain smoke basket hold race lonely fit walk//Alice" + // echo -n "Hello, World" | subkey -e sign "bottom drive obey lake curtain smoke basket hold + // race lonely fit walk//Alice" hex_literal::hex!("ee3f5a6cbfc12a8f00c18b811dc921b550ddf272354cda4b9a57b1d06213fcd8509f5af18425d39a279d13622f14806c3e978e2163981f2ec1c06e9628460b0e") } diff --git a/runtime/common/src/slots/mod.rs b/runtime/common/src/slots/mod.rs index 0be75fcba2b1..b4e136b1211c 100644 --- a/runtime/common/src/slots/mod.rs +++ b/runtime/common/src/slots/mod.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Parathread and parachains leasing system. Allows para IDs to be claimed, the code and data to be initialized and -//! parachain slots (i.e. continuous scheduling) to be leased. Also allows for parachains and parathreads to be -//! swapped. +//! Parathread and parachains leasing system. Allows para IDs to be claimed, the code and data to be +//! initialized and parachain slots (i.e. continuous scheduling) to be leased. Also allows for +//! parachains and parathreads to be swapped. //! -//! This doesn't handle the mechanics of determining which para ID actually ends up with a parachain lease. This -//! must handled by a separately, through the trait interface that this pallet provides or the root dispatchables. +//! This doesn't handle the mechanics of determining which para ID actually ends up with a parachain +//! lease. This must handled by a separately, through the trait interface that this pallet provides +//! or the root dispatchables. pub mod migration; @@ -98,8 +99,8 @@ pub mod pallet { /// Amounts held on deposit for each (possibly future) leased parachain. /// - /// The actual amount locked on its behalf by any account at any time is the maximum of the second values - /// of the items in this list whose first value is the account. + /// The actual amount locked on its behalf by any account at any time is the maximum of the + /// second values of the items in this list whose first value is the account. /// /// The first item in the list is the amount locked for the current Lease Period. Following /// items are for the subsequent lease periods. @@ -160,8 +161,8 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Just a connect into the `lease_out` call, in case Root wants to force some lease to happen - /// independently of any other on-chain mechanism to use it. + /// Just a connect into the `lease_out` call, in case Root wants to force some lease to + /// happen independently of any other on-chain mechanism to use it. /// /// The dispatch origin for this call must match `T::ForceOrigin`. #[pallet::call_index(0)] @@ -268,8 +269,8 @@ impl Pallet { // deposit for the parachain. let now_held = Self::deposit_held(para, &ended_lease.0); - // If this is less than what we were holding for this leaser's now-ended lease, then - // unreserve it. + // If this is less than what we were holding for this leaser's now-ended lease, + // then unreserve it. if let Some(rebate) = ended_lease.1.checked_sub(&now_held) { T::Currency::unreserve(&ended_lease.0, rebate); } @@ -392,8 +393,8 @@ impl Leaser> for Pallet { } } - // Figure out whether we already have some funds of `leaser` held in reserve for `para_id`. - // If so, then we can deduct those from the amount that we need to reserve. + // Figure out whether we already have some funds of `leaser` held in reserve for + // `para_id`. If so, then we can deduct those from the amount that we need to reserve. let maybe_additional = amount.checked_sub(&Self::deposit_held(para, &leaser)); if let Some(ref additional) = maybe_additional { T::Currency::reserve(&leaser, *additional) @@ -403,7 +404,8 @@ impl Leaser> for Pallet { let reserved = maybe_additional.unwrap_or_default(); // Check if current lease period is same as period begin, and onboard them directly. - // This will allow us to support onboarding new parachains in the middle of a lease period. + // This will allow us to support onboarding new parachains in the middle of a lease + // period. if current_lease_period == period_begin { // Best effort. Not much we can do if this fails. let _ = T::Registrar::make_parachain(para); @@ -481,7 +483,8 @@ impl Leaser> for Pallet { None => return true, }; - // Get the leases, and check each item in the vec which is part of the range we are checking. + // Get the leases, and check each item in the vec which is part of the range we are + // checking. let leases = Leases::::get(para_id); for slot in offset..=offset + period_count { if let Some(Some(_)) = leases.get(slot) { diff --git a/runtime/common/src/traits.rs b/runtime/common/src/traits.rs index f24a5b977968..940c3dfa2fb3 100644 --- a/runtime/common/src/traits.rs +++ b/runtime/common/src/traits.rs @@ -113,11 +113,12 @@ pub trait Leaser { /// /// `leaser` shall have a total of `amount` balance reserved by the implementer of this trait. /// - /// Note: The implementer of the trait (the leasing system) is expected to do all reserve/unreserve calls. The - /// caller of this trait *SHOULD NOT* pre-reserve the deposit (though should ensure that it is reservable). + /// Note: The implementer of the trait (the leasing system) is expected to do all + /// reserve/unreserve calls. The caller of this trait *SHOULD NOT* pre-reserve the deposit + /// (though should ensure that it is reservable). /// - /// The lease will last from `period_begin` for `period_count` lease periods. It is undefined if the `para` - /// already has a slot leased during those periods. + /// The lease will last from `period_begin` for `period_count` lease periods. It is undefined if + /// the `para` already has a slot leased during those periods. /// /// Returns `Err` in the case of an error, and in which case nothing is changed. fn lease_out( @@ -128,8 +129,8 @@ pub trait Leaser { period_count: Self::LeasePeriod, ) -> Result<(), LeaseError>; - /// Return the amount of balance currently held in reserve on `leaser`'s account for leasing `para`. This won't - /// go down outside a lease period. + /// Return the amount of balance currently held in reserve on `leaser`'s account for leasing + /// `para`. This won't go down outside a lease period. fn deposit_held( para: ParaId, leaser: &Self::AccountId, @@ -147,7 +148,8 @@ pub trait Leaser { fn lease_period_index(block: BlockNumber) -> Option<(Self::LeasePeriod, bool)>; /// Returns true if the parachain already has a lease in any of lease periods in the inclusive - /// range `[first_period, last_period]`, intersected with the unbounded range [`current_lease_period`..] . + /// range `[first_period, last_period]`, intersected with the unbounded range + /// [`current_lease_period`..] . fn already_leased( para_id: ParaId, first_period: Self::LeasePeriod, @@ -169,7 +171,8 @@ pub enum AuctionStatus { /// will be `EndingPeriod(1, 5)`. EndingPeriod(BlockNumber, BlockNumber), /// We have completed the bidding process and are waiting for the VRF to return some acceptable - /// randomness to select the winner. The number represents how many blocks we have been waiting. + /// randomness to select the winner. The number represents how many blocks we have been + /// waiting. VrfDelay(BlockNumber), } @@ -224,9 +227,9 @@ pub trait Auctioneer { /// - `last_slot`: The last lease period index of the range to be bid on (inclusive). /// - `amount`: The total amount to be the bid for deposit over the range. /// - /// The account `Bidder` must have at least `amount` available as a free balance in `Currency`. The - /// implementation *MUST* remove or reserve `amount` funds from `bidder` and those funds should be returned - /// or freed once the bid is rejected or lease has ended. + /// The account `Bidder` must have at least `amount` available as a free balance in `Currency`. + /// The implementation *MUST* remove or reserve `amount` funds from `bidder` and those funds + /// should be returned or freed once the bid is rejected or lease has ended. fn place_bid( bidder: Self::AccountId, para: ParaId, diff --git a/runtime/kusama/src/xcm_config.rs b/runtime/kusama/src/xcm_config.rs index 59e32f2ca544..5725f54eddd5 100644 --- a/runtime/kusama/src/xcm_config.rs +++ b/runtime/kusama/src/xcm_config.rs @@ -63,8 +63,8 @@ parameter_types! { pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); } -/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to determine -/// the sovereign account controlled by a location. +/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to +/// determine the sovereign account controlled by a location. pub type SovereignAccountOf = ( // We can convert a child parachain using the standard `AccountId` conversion. ChildParachainConvertsVia, @@ -72,8 +72,8 @@ pub type SovereignAccountOf = ( AccountId32Aliases, ); -/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of -/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the +/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. /// /// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. pub type LocalAssetTransactor = XcmCurrencyAdapter< @@ -360,8 +360,8 @@ parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); } -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain. +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. pub type LocalOriginToLocation = ( // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, @@ -374,8 +374,8 @@ pub type StakingAdminToPlurality = /// Type to convert the Fellows origin to a Plurality `MultiLocation` value. pub type FellowsToPlurality = OriginToPluralityVoice; -/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain for a destination chain. +/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an +/// interior location of this chain for a destination chain. pub type LocalPalletOriginToLocation = ( // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. StakingAdminToPlurality, @@ -386,16 +386,17 @@ pub type LocalPalletOriginToLocation = ( impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We only allow the root, the council, fellows and the staking admin to send messages. - // This is basically safe to enable for everyone (safe the possibility of someone spamming the parachain - // if they're willing to pay the KSM to send from the Relay-chain), but it's useless until we bring in XCM v3 - // which will make `DescendOrigin` a bit more useful. + // This is basically safe to enable for everyone (safe the possibility of someone spamming the + // parachain if they're willing to pay the KSM to send from the Relay-chain), but it's useless + // until we bring in XCM v3 which will make `DescendOrigin` a bit more useful. type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally. type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Everything; type XcmExecutor = xcm_executor::XcmExecutor; - // Anyone is able to use teleportation regardless of who they are and what they want to teleport. + // Anyone is able to use teleportation regardless of who they are and what they want to + // teleport. type XcmTeleportFilter = Everything; // Anyone is able to use reserve transfers regardless of who they are and what they want to // transfer. @@ -450,7 +451,8 @@ fn karura_liquid_staking_xcm_has_sane_weight_upper_limt() { else { panic!("no Transact instruction found") }; - // should be pallet_utility.as_derivative { index: 0, call: pallet_staking::bond_extra { max_additional: 2490000000000 } } + // should be pallet_utility.as_derivative { index: 0, call: pallet_staking::bond_extra { + // max_additional: 2490000000000 } } let message_call = call.take_decoded().expect("can't decode Transact call"); let call_weight = message_call.get_dispatch_info().weight; // Ensure that the Transact instruction is giving a sensible `require_weight_at_most` value diff --git a/runtime/parachains/src/builder.rs b/runtime/parachains/src/builder.rs index e46c9f59b957..892e934e6dfc 100644 --- a/runtime/parachains/src/builder.rs +++ b/runtime/parachains/src/builder.rs @@ -174,7 +174,8 @@ impl BenchBuilder { configuration::Pallet::::config().max_validators.unwrap_or(200) } - /// Maximum number of validators participating in parachains consensus (a.k.a. active validators). + /// Maximum number of validators participating in parachains consensus (a.k.a. active + /// validators). fn max_validators(&self) -> u32 { self.max_validators.unwrap_or(Self::fallback_max_validators()) } @@ -186,8 +187,8 @@ impl BenchBuilder { self } - /// Maximum number of validators per core (a.k.a. max validators per group). This value is used if none is - /// explicitly set on the builder. + /// Maximum number of validators per core (a.k.a. max validators per group). This value is used + /// if none is explicitly set on the builder. pub(crate) fn fallback_max_validators_per_core() -> u32 { configuration::Pallet::::config().max_validators_per_core.unwrap_or(5) } @@ -479,7 +480,8 @@ impl BenchBuilder { /// Create backed candidates for `cores_with_backed_candidates`. You need these cores to be /// scheduled _within_ paras inherent, which requires marking the available bitfields as fully /// available. - /// - `cores_with_backed_candidates` Mapping of `para_id`/`core_idx`/`group_idx` seed to number of + /// - `cores_with_backed_candidates` Mapping of `para_id`/`core_idx`/`group_idx` seed to number + /// of /// validity votes. fn create_backed_candidates( &self, @@ -687,9 +689,9 @@ impl BenchBuilder { ); assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores as usize,); - // Mark all the used cores as occupied. We expect that their are `backed_and_concluding_cores` - // that are pending availability and that there are `used_cores - backed_and_concluding_cores ` - // which are about to be disputed. + // Mark all the used cores as occupied. We expect that their are + // `backed_and_concluding_cores` that are pending availability and that there are + // `used_cores - backed_and_concluding_cores ` which are about to be disputed. scheduler::AvailabilityCores::::set(vec![ Some(CoreOccupied::Parachain); used_cores as usize diff --git a/runtime/parachains/src/configuration.rs b/runtime/parachains/src/configuration.rs index 38a24211fb67..d4ad8619f16e 100644 --- a/runtime/parachains/src/configuration.rs +++ b/runtime/parachains/src/configuration.rs @@ -54,12 +54,12 @@ const LOG_TARGET: &str = "runtime::configuration"; serde::Deserialize, )] pub struct HostConfiguration { - // NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct requires - // special treatment. + // NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct + // requires special treatment. // - // A parachain requested this struct can only depend on the subset of this struct. Specifically, - // only a first few fields can be depended upon. These fields cannot be changed without - // corresponding migration of the parachains. + // A parachain requested this struct can only depend on the subset of this struct. + // Specifically, only a first few fields can be depended upon. These fields cannot be changed + // without corresponding migration of the parachains. /** * The parameters that are required for the parachains. */ @@ -88,9 +88,9 @@ pub struct HostConfiguration { pub hrmp_max_message_num_per_candidate: u32, /// The minimum period, in blocks, between which parachains can update their validation code. /// - /// This number is used to prevent parachains from spamming the relay chain with validation code - /// upgrades. The only thing it controls is the number of blocks the `UpgradeRestrictionSignal` - /// is set for the parachain in question. + /// This number is used to prevent parachains from spamming the relay chain with validation + /// code upgrades. The only thing it controls is the number of blocks the + /// `UpgradeRestrictionSignal` is set for the parachain in question. /// /// If PVF pre-checking is enabled this should be greater than the maximum number of blocks /// PVF pre-checking can take. Intuitively, this number should be greater than the duration @@ -113,14 +113,15 @@ pub struct HostConfiguration { /// been completed. /// /// Note, there are situations in which `expected_at` in the past. For example, if - /// [`chain_availability_period`] or [`thread_availability_period`] is less than the delay set by - /// this field or if PVF pre-check took more time than the delay. In such cases, the upgrade is - /// further at the earliest possible time determined by [`minimum_validation_upgrade_delay`]. + /// [`chain_availability_period`] or [`thread_availability_period`] is less than the delay set + /// by this field or if PVF pre-check took more time than the delay. In such cases, the upgrade + /// is further at the earliest possible time determined by + /// [`minimum_validation_upgrade_delay`]. /// /// The rationale for this delay has to do with relay-chain reversions. In case there is an - /// invalid candidate produced with the new version of the code, then the relay-chain can revert - /// [`validation_upgrade_delay`] many blocks back and still find the new code in the storage by - /// hash. + /// invalid candidate produced with the new version of the code, then the relay-chain can + /// revert [`validation_upgrade_delay`] many blocks back and still find the new code in the + /// storage by hash. /// /// [#4601]: https://github.com/paritytech/polkadot/issues/4601 pub validation_upgrade_delay: BlockNumber, @@ -179,13 +180,13 @@ pub struct HostConfiguration { /// Must be non-zero. pub group_rotation_frequency: BlockNumber, /// The availability period, in blocks, for parachains. This is the amount of blocks - /// after inclusion that validators have to make the block available and signal its availability to - /// the chain. + /// after inclusion that validators have to make the block available and signal its + /// availability to the chain. /// /// Must be at least 1. pub chain_availability_period: BlockNumber, - /// The availability period, in blocks, for parathreads. Same as the `chain_availability_period`, - /// but a differing timeout due to differing requirements. + /// The availability period, in blocks, for parathreads. Same as the + /// `chain_availability_period`, but a differing timeout due to differing requirements. /// /// Must be at least 1. pub thread_availability_period: BlockNumber, @@ -217,8 +218,8 @@ pub struct HostConfiguration { pub needed_approvals: u32, /// The number of samples to do of the `RelayVRFModulo` approval assignment criterion. pub relay_vrf_modulo_samples: u32, - /// If an active PVF pre-checking vote observes this many number of sessions it gets automatically - /// rejected. + /// If an active PVF pre-checking vote observes this many number of sessions it gets + /// automatically rejected. /// /// 0 means PVF pre-checking will be rejected on the first observed session unless the voting /// gained supermajority before that the session change. @@ -849,7 +850,8 @@ pub mod pallet { }) } - /// Sets the maximum total size of items that can present in a upward dispatch queue at once. + /// Sets the maximum total size of items that can present in a upward dispatch queue at + /// once. #[pallet::call_index(24)] #[pallet::weight(( T::WeightInfo::set_config_with_u32(), @@ -1257,8 +1259,8 @@ impl Pallet { // 3. pending_configs = [(cur+1, X)] // There is a pending configuration scheduled and it will be applied in the next session. // - // We will use X as the base configuration. We need to schedule a new configuration change - // for the `scheduled_session` and use X as the base for the new configuration. + // We will use X as the base configuration. We need to schedule a new configuration + // change for the `scheduled_session` and use X as the base for the new configuration. // // 4. pending_configs = [(cur+1, X), (cur+2, Y)] // There is a pending configuration change in the next session and for the scheduled diff --git a/runtime/parachains/src/configuration/migration/v7.rs b/runtime/parachains/src/configuration/migration/v7.rs index cdff80a31a3a..78a7cf9e4dc0 100644 --- a/runtime/parachains/src/configuration/migration/v7.rs +++ b/runtime/parachains/src/configuration/migration/v7.rs @@ -182,10 +182,12 @@ mod tests { // Steps: // 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate // 2. Set these parameters: - // 2.1. selected state query: configuration; activeConfig(): PolkadotRuntimeParachainsConfigurationHostConfiguration - // 2.2. blockhash to query at: 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of the block) - // 2.3. Note the value of encoded storage key -> 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the referenced block. - // 2.4. You'll also need the decoded values to update the test. + // 2.1. selected state query: configuration; activeConfig(): + // PolkadotRuntimeParachainsConfigurationHostConfiguration 2.2. blockhash to query at: + // 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of the + // block) 2.3. Note the value of encoded storage key -> + // 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the referenced + // block. 2.4. You'll also need the decoded values to update the test. // 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage // 3.1 Enter the encoded storage key and you get the raw config. @@ -196,8 +198,8 @@ mod tests { let v6 = V6HostConfiguration::::decode(&mut &raw_config[..]).unwrap(); - // We check only a sample of the values here. If we missed any fields or messed up data types - // that would skew all the fields coming after. + // We check only a sample of the values here. If we missed any fields or messed up data + // types that would skew all the fields coming after. assert_eq!(v6.max_code_size, 3_145_728); assert_eq!(v6.validation_upgrade_cooldown, 200); assert_eq!(v6.max_pov_size, 5_242_880); @@ -209,8 +211,8 @@ mod tests { #[test] fn test_migrate_to_v7() { - // Host configuration has lots of fields. However, in this migration we only remove one field. - // The most important part to check are a couple of the last fields. We also pick + // Host configuration has lots of fields. However, in this migration we only remove one + // field. The most important part to check are a couple of the last fields. We also pick // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and // also their type. // @@ -291,7 +293,8 @@ mod tests { }); } - // Test that migration doesn't panic in case there're no pending configurations upgrades in pallet's storage. + // Test that migration doesn't panic in case there're no pending configurations upgrades in + // pallet's storage. #[test] fn test_migrate_to_v7_no_pending() { let v6 = V6HostConfiguration::::default(); diff --git a/runtime/parachains/src/disputes.rs b/runtime/parachains/src/disputes.rs index 7b03cde8ed28..cf2e99e7359a 100644 --- a/runtime/parachains/src/disputes.rs +++ b/runtime/parachains/src/disputes.rs @@ -887,8 +887,8 @@ impl Pallet { #[allow(deprecated)] >::remove_prefix(to_prune, None); - // This is larger, and will be extracted to the `shared` pallet for more proper pruning. - // TODO: https://github.com/paritytech/polkadot/issues/3469 + // This is larger, and will be extracted to the `shared` pallet for more proper + // pruning. TODO: https://github.com/paritytech/polkadot/issues/3469 #[allow(deprecated)] >::remove_prefix(to_prune, None); } @@ -1178,7 +1178,8 @@ impl Pallet { >::insert(&session, &candidate_hash, &summary.state); - // Freeze if the INVALID votes against some local candidate are above the byzantine threshold + // Freeze if the INVALID votes against some local candidate are above the byzantine + // threshold if summary.new_flags.contains(DisputeStateFlags::AGAINST_BYZANTINE) { if let Some(revert_to) = >::get(&session, &candidate_hash) { Self::revert_and_freeze(revert_to); diff --git a/runtime/parachains/src/disputes/migration.rs b/runtime/parachains/src/disputes/migration.rs index af216fa0408e..ccd367e41b36 100644 --- a/runtime/parachains/src/disputes/migration.rs +++ b/runtime/parachains/src/disputes/migration.rs @@ -79,14 +79,16 @@ pub mod v1 { } } - /// Migrates the pallet storage to the most recent version, checking and setting the `StorageVersion`. + /// Migrates the pallet storage to the most recent version, checking and setting the + /// `StorageVersion`. pub fn migrate_to_v1() -> Weight { let mut weight: Weight = Weight::zero(); // SpamSlots should not contain too many keys so removing everything at once should be safe let res = SpamSlots::::clear(u32::MAX, None); // `loops` is the number of iterations => used to calculate read weights - // `backend` is the number of keys removed from the backend => used to calculate write weights + // `backend` is the number of keys removed from the backend => used to calculate write + // weights weight = weight .saturating_add(T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64)); diff --git a/runtime/parachains/src/disputes/tests.rs b/runtime/parachains/src/disputes/tests.rs index 93dcd58264b2..acdba343274c 100644 --- a/runtime/parachains/src/disputes/tests.rs +++ b/runtime/parachains/src/disputes/tests.rs @@ -871,7 +871,8 @@ mod unconfirmed_disputes { use assert_matches::assert_matches; use sp_runtime::ModuleError; - // Shared initialization code between `test_unconfirmed_are_ignored` and `test_unconfirmed_disputes_cause_block_import_error` + // Shared initialization code between `test_unconfirmed_are_ignored` and + // `test_unconfirmed_disputes_cause_block_import_error` fn generate_dispute_statement_set_and_run_to_block() -> DisputeStatementSet { // 7 validators needed for byzantine threshold of 2. let v0 = ::Pair::generate().0; @@ -2060,7 +2061,8 @@ fn deduplication_and_sorting_works() { ) .unwrap_err(); - // assert ordering of local only disputes, and at the same time, and being free of duplicates + // 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| { diff --git a/runtime/parachains/src/hrmp.rs b/runtime/parachains/src/hrmp.rs index c876749e853d..1be2fe57b1df 100644 --- a/runtime/parachains/src/hrmp.rs +++ b/runtime/parachains/src/hrmp.rs @@ -117,12 +117,12 @@ pub struct HrmpOpenChannelRequest { #[derive(Encode, Decode, TypeInfo)] #[cfg_attr(test, derive(Debug))] pub struct HrmpChannel { - // NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct requires - // special treatment. + // NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct + // requires special treatment. // - // A parachain requested this struct can only depend on the subset of this struct. Specifically, - // only a first few fields can be depended upon (See `AbridgedHrmpChannel`). These fields cannot - // be changed without corresponding migration of parachains. + // A parachain requested this struct can only depend on the subset of this struct. + // Specifically, only a first few fields can be depended upon (See `AbridgedHrmpChannel`). + // These fields cannot be changed without corresponding migration of parachains. /// The maximum number of messages that can be pending in the channel at once. pub max_capacity: u32, /// The maximum total size of the messages that can be pending in the channel at once. @@ -370,7 +370,8 @@ pub mod pallet { /// The HRMP watermark associated with each para. /// Invariant: - /// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a session. + /// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a + /// session. #[pallet::storage] pub type HrmpWatermarks = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor>; @@ -968,9 +969,9 @@ impl Pallet { out_hrmp_msgs.iter().enumerate().map(|(idx, out_msg)| (idx as u32, out_msg)) { match last_recipient { - // the messages must be sorted in ascending order and there must be no two messages sent - // to the same recipient. Thus we can check that every recipient is strictly greater than - // the previous one. + // the messages must be sorted in ascending order and there must be no two messages + // sent to the same recipient. Thus we can check that every recipient is strictly + // greater than the previous one. Some(last_recipient) if out_msg.recipient <= last_recipient => return Err(OutboundHrmpAcceptanceErr::NotSorted { idx }), _ => last_recipient = Some(out_msg.recipient), diff --git a/runtime/parachains/src/inclusion/mod.rs b/runtime/parachains/src/inclusion/mod.rs index c71657d1ac43..f4ef3b95065e 100644 --- a/runtime/parachains/src/inclusion/mod.rs +++ b/runtime/parachains/src/inclusion/mod.rs @@ -17,8 +17,8 @@ //! The inclusion pallet is responsible for inclusion and availability of scheduled parachains //! and parathreads. //! -//! It is responsible for carrying candidates from being backable to being backed, and then from backed -//! to included. +//! It is responsible for carrying candidates from being backable to being backed, and then from +//! backed to included. use crate::{ configuration::{self, HostConfiguration}, @@ -76,8 +76,8 @@ impl WeightInfo for () { /// Maximum value that `config.max_upward_message_size` can be set to. /// -/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the `configuration` -/// pallet to check these values before setting. +/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the +/// `configuration` pallet to check these values before setting. pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 128 * 1024; /// A bitfield signed by a validator indicating that it is keeping its piece of the erasure-coding @@ -354,8 +354,8 @@ pub mod pallet { InvalidOutboundHrmp, /// The validation code hash of the candidate is not valid. InvalidValidationCodeHash, - /// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual para head in the - /// commitments. + /// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual + /// para head in the commitments. ParaHeadMismatch, /// A bitfield that references a freed core, /// either intentionally or as part of a concluded @@ -492,8 +492,8 @@ impl Pallet { /// /// Updates storage items `PendingAvailability` and `AvailabilityBitfields`. /// - /// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became available, - /// and cores free. + /// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became + /// available, and cores free. pub(crate) fn update_pending_availability_and_get_freed_cores( expected_bits: usize, validators: &[ValidatorId], @@ -530,8 +530,8 @@ impl Pallet { continue }; - // defensive check - this is constructed by loading the availability bitfield record, - // which is always `Some` if the core is occupied - that's why we're here. + // defensive check - this is constructed by loading the availability bitfield + // record, which is always `Some` if the core is occupied - that's why we're here. let validator_index = validator_index.0 as usize; if let Some(mut bit) = pending_availability.as_mut().and_then(|candidate_pending_availability| { @@ -591,8 +591,8 @@ impl Pallet { freed_cores } - /// Process candidates that have been backed. Provide the relay storage root, a set of candidates - /// and scheduled cores. + /// Process candidates that have been backed. Provide the relay storage root, a set of + /// candidates and scheduled cores. /// /// Both should be sorted ascending by core index, and the candidates should be a subset of /// scheduled cores. If these conditions are not met, the execution of the function fails. @@ -968,7 +968,8 @@ impl Pallet { }) } // make sure that the queue is not overfilled. - // we do it here only once since returning false invalidates the whole relay-chain block. + // we do it here only once since returning false invalidates the whole relay-chain + // block. if para_queue_size.saturating_add(msg_size as u64) > config.max_upward_queue_size as u64 { return Err(UmpAcceptanceCheckErr::TotalSizeExceeded { diff --git a/runtime/parachains/src/initializer.rs b/runtime/parachains/src/initializer.rs index b9ecc3038ca2..e006c38e6dec 100644 --- a/runtime/parachains/src/initializer.rs +++ b/runtime/parachains/src/initializer.rs @@ -17,7 +17,8 @@ //! This module is responsible for maintaining a consistent initialization order for all other //! parachains modules. It's also responsible for finalization and session change notifications. //! -//! This module can throw fatal errors if session-change notifications are received after initialization. +//! This module can throw fatal errors if session-change notifications are received after +//! initialization. use crate::{ configuration::{self, HostConfiguration}, @@ -128,9 +129,9 @@ pub mod pallet { /// Semantically a `bool`, but this guarantees it should never hit the trie, /// as this is cleared in `on_finalize` and Frame optimizes `None` values to be empty values. /// - /// As a `bool`, `set(false)` and `remove()` both lead to the next `get()` being false, but one of - /// them writes to the trie and one does not. This confusion makes `Option<()>` more suitable for - /// the semantics of this variable. + /// As a `bool`, `set(false)` and `remove()` both lead to the next `get()` being false, but one + /// of them writes to the trie and one does not. This confusion makes `Option<()>` more suitable + /// for the semantics of this variable. #[pallet::storage] pub(super) type HasInitialized = StorageValue<_, ()>; @@ -190,7 +191,8 @@ pub mod pallet { // Apply buffered session changes as the last thing. This way the runtime APIs and the // next block will observe the next session. // - // Note that we only apply the last session as all others lasted less than a block (weirdly). + // Note that we only apply the last session as all others lasted less than a block + // (weirdly). if let Some(BufferedSessionChange { session_index, validators, queued }) = BufferedSessionChanges::::take().pop() { diff --git a/runtime/parachains/src/origin.rs b/runtime/parachains/src/origin.rs index 14f8c3786c96..c83fec1b8923 100644 --- a/runtime/parachains/src/origin.rs +++ b/runtime/parachains/src/origin.rs @@ -38,7 +38,6 @@ where /// belongs to. /// /// This module fulfills only the single purpose of housing the `Origin` in `construct_runtime`. -/// // ideally, though, the `construct_runtime` should support a free-standing origin. #[frame_support::pallet] pub mod pallet { diff --git a/runtime/parachains/src/paras/mod.rs b/runtime/parachains/src/paras/mod.rs index 98c5075a4c94..4570bb2b13bd 100644 --- a/runtime/parachains/src/paras/mod.rs +++ b/runtime/parachains/src/paras/mod.rs @@ -43,10 +43,10 @@ //! //! The conditions that must be met before the para can use the new validation code are: //! -//! 1. The validation code should have been "soaked" in the storage for a given number of blocks. That -//! is, the validation code should have been stored in on-chain storage for some time, so that in -//! case of a revert with a non-extreme height difference, that validation code can still be -//! found on-chain. +//! 1. The validation code should have been "soaked" in the storage for a given number of blocks. +//! That is, the validation code should have been stored in on-chain storage for some time, so +//! that in case of a revert with a non-extreme height difference, that validation code can still +//! be found on-chain. //! //! 2. The validation code was vetted by the validators and declared as non-malicious in a processes //! known as PVF pre-checking. @@ -105,7 +105,6 @@ //! start──────▶│reset│ //! └─────┘ //! ``` -//! use crate::{ configuration, @@ -152,8 +151,8 @@ pub struct ReplacementTimes { /// first parablock included with a relay-parent with number >= this value. expected_at: N, /// The relay-chain block number at which the parablock activating the code upgrade was - /// actually included. This means considered included and available, so this is the time at which - /// that parablock enters the acceptance period in this fork of the relay-chain. + /// actually included. This means considered included and available, so this is the time at + /// which that parablock enters the acceptance period in this fork of the relay-chain. activated_at: N, } @@ -332,7 +331,8 @@ impl<'de> Deserialize<'de> for ParaKind { } } -// Manual encoding, decoding, and TypeInfo as the parakind field in ParaGenesisArgs used to be a bool +// Manual encoding, decoding, and TypeInfo as the parakind field in ParaGenesisArgs used to be a +// bool impl Encode for ParaKind { fn size_hint(&self) -> usize { true.size_hint() @@ -373,12 +373,15 @@ pub(crate) enum PvfCheckCause { Onboarding(ParaId), /// PVF vote was initiated by signalling of an upgrade by the given para. Upgrade { - /// The ID of the parachain that initiated or is waiting for the conclusion of pre-checking. + /// The ID of the parachain that initiated or is waiting for the conclusion of + /// pre-checking. id: ParaId, - /// The relay-chain block number of **inclusion** of candidate that that initiated the upgrade. + /// The relay-chain block number of **inclusion** of candidate that that initiated the + /// upgrade. /// - /// It's important to count upgrade enactment delay from the inclusion of this candidate instead - /// of its relay parent -- in order to keep PVF available in case of chain reversions. + /// It's important to count upgrade enactment delay from the inclusion of this candidate + /// instead of its relay parent -- in order to keep PVF available in case of chain + /// reversions. /// /// See https://github.com/paritytech/polkadot/issues/4601 for detailed explanation. included_at: BlockNumber, @@ -681,11 +684,11 @@ pub mod pallet { pub(super) type PastCodeMeta = StorageMap<_, Twox64Concat, ParaId, ParaPastCodeMeta>, ValueQuery>; - /// Which paras have past code that needs pruning and the relay-chain block at which the code was replaced. - /// Note that this is the actual height of the included block, not the expected height at which the - /// code upgrade would be applied, although they may be equal. - /// This is to ensure the entire acceptance period is covered, not an offset acceptance period starting - /// from the time at which the parachain perceives a code upgrade as having occurred. + /// Which paras have past code that needs pruning and the relay-chain block at which the code + /// was replaced. Note that this is the actual height of the included block, not the expected + /// height at which the code upgrade would be applied, although they may be equal. + /// This is to ensure the entire acceptance period is covered, not an offset acceptance period + /// starting from the time at which the parachain perceives a code upgrade as having occurred. /// Multiple entries for a single para are permitted. Ordered ascending by block number. #[pallet::storage] pub(super) type PastCodePruning = @@ -706,12 +709,13 @@ pub mod pallet { pub(super) type FutureCodeHash = StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>; - /// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade procedure. + /// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade + /// procedure. /// /// This value is absent when there are no upgrades scheduled or during the time the relay chain - /// performs the checks. It is set at the first relay-chain block when the corresponding parachain - /// can switch its upgrade function. As soon as the parachain's block is included, the value - /// gets reset to `None`. + /// performs the checks. It is set at the first relay-chain block when the corresponding + /// parachain can switch its upgrade function. As soon as the parachain's block is included, the + /// value gets reset to `None`. /// /// NOTE that this field is used by parachains via merkle storage proofs, therefore changing /// the format will require migration of parachains. @@ -896,8 +900,9 @@ pub mod pallet { /// Otherwise, the code will be added into the storage. Note that the code will be added /// into storage with reference count 0. This is to account the fact that there are no users /// for this code yet. The caller will have to make sure that this code eventually gets - /// used by some parachain or removed from the storage to avoid storage leaks. For the latter - /// prefer to use the `poke_unused_validation_code` dispatchable to raw storage manipulation. + /// used by some parachain or removed from the storage to avoid storage leaks. For the + /// latter prefer to use the `poke_unused_validation_code` dispatchable to raw storage + /// manipulation. /// /// This function is mainly meant to be used for upgrading parachains that do not follow /// the go-ahead signal while the PVF pre-checking feature is enabled. @@ -1569,10 +1574,11 @@ impl Pallet { match cause { PvfCheckCause::Onboarding(id) => { - // Here we need to undo everything that was done during `schedule_para_initialize`. - // Essentially, the logic is similar to offboarding, with exception that before - // actual onboarding the parachain did not have a chance to reach to upgrades. - // Therefore we can skip all the upgrade related storage items here. + // Here we need to undo everything that was done during + // `schedule_para_initialize`. Essentially, the logic is similar to offboarding, + // with exception that before actual onboarding the parachain did not have a + // chance to reach to upgrades. Therefore we can skip all the upgrade related + // storage items here. weight += T::DbWeight::get().writes(3); UpcomingParasGenesis::::remove(&id); CurrentCodeHash::::remove(&id); @@ -1629,8 +1635,8 @@ impl Pallet { // // - Doing it within the context of the PR that introduces this change is undesirable, since // it is already a big change, and that change would require a migration. Moreover, if we - // run the new version of the runtime, there will be less things to worry about during - // the eventual proper migration. + // run the new version of the runtime, there will be less things to worry about during the + // eventual proper migration. // // - This data type already is used for generating genesis, and changing it will probably // introduce some unnecessary burden. @@ -1641,8 +1647,8 @@ impl Pallet { // get rid of hashing of the validation code when onboarding. // // - Replace `validation_code` with a sentinel value: an empty vector. This should be fine - // as long we do not allow registering parachains with empty code. At the moment of writing - // this should already be the case. + // as long we do not allow registering parachains with empty code. At the moment of + // writing this should already be the case. // // - Empty value is treated as the current code is already inserted during the onboarding. // @@ -1670,7 +1676,8 @@ impl Pallet { /// /// Will return error if either is true: /// - /// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is `false`) + /// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is + /// `false`) /// - para has a pending upgrade. /// - para has unprocessed messages in its UMP queue. /// @@ -1683,7 +1690,8 @@ impl Pallet { // ongoing PVF pre-checking votes. It also removes some nasty edge cases. // // However, an upcoming upgrade on its own imposes no restrictions. An upgrade is enacted - // with a new para head, so if a para never progresses we still should be able to offboard it. + // with a new para head, so if a para never progresses we still should be able to offboard + // it. // // This implicitly assumes that the given para exists, i.e. it's lifecycle != None. if let Some(future_code_hash) = FutureCodeHash::::get(&id) { @@ -1768,13 +1776,14 @@ impl Pallet { /// the relay-chain block number will be determined at which the upgrade will take place. We /// call that block `expected_at`. /// - /// Once the candidate with the relay-parent >= `expected_at` is enacted, the new validation code - /// will be applied. Therefore, the new code will be used to validate the next candidate. + /// Once the candidate with the relay-parent >= `expected_at` is enacted, the new validation + /// code will be applied. Therefore, the new code will be used to validate the next candidate. /// /// The new code should not be equal to the current one, otherwise the upgrade will be aborted. /// If there is already a scheduled code upgrade for the para, this is a no-op. /// - /// Inclusion block number specifies relay parent which enacted candidate initiating the upgrade. + /// Inclusion block number specifies relay parent which enacted candidate initiating the + /// upgrade. pub(crate) fn schedule_code_upgrade( id: ParaId, new_code: ValidationCode, @@ -1905,8 +1914,8 @@ impl Pallet { // We increase the code RC here in any case. Intuitively the parachain that requested this // action is now a user of that PVF. // - // If the result of the pre-checking is reject, then we would decrease the RC for each cause, - // including the current. + // If the result of the pre-checking is reject, then we would decrease the RC for each + // cause, including the current. // // If the result of the pre-checking is accept, then we do nothing to the RC because the PVF // will continue be used by the same users. @@ -1918,9 +1927,9 @@ impl Pallet { weight } - /// Note that a para has progressed to a new head, where the new head was executed in the context - /// of a relay-chain block with given number. This will apply pending code upgrades based - /// on the relay-parent block number provided. + /// Note that a para has progressed to a new head, where the new head was executed in the + /// context of a relay-chain block with given number. This will apply pending code upgrades + /// based on the relay-parent block number provided. pub(crate) fn note_new_head( id: ParaId, new_head: HeadData, diff --git a/runtime/parachains/src/paras/tests.rs b/runtime/parachains/src/paras/tests.rs index 2bf30bb273e5..4a3be6d7d50e 100644 --- a/runtime/parachains/src/paras/tests.rs +++ b/runtime/parachains/src/paras/tests.rs @@ -649,7 +649,8 @@ fn submit_code_change_when_not_allowed_is_err() { Paras::schedule_code_upgrade(para_id, newer_code.clone(), 2, &Configuration::config()); assert_eq!( FutureCodeUpgrades::::get(¶_id), - Some(1 + validation_upgrade_delay), // did not change since the same assertion from the last time. + Some(1 + validation_upgrade_delay), /* did not change since the same assertion from + * the last time. */ ); assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); check_code_is_not_stored(&newer_code); @@ -1554,8 +1555,9 @@ fn increase_code_ref_doesnt_have_allergy_on_add_trusted_validation_code() { #[test] fn add_trusted_validation_code_insta_approval() { - // In particular, this tests that `kick_off_pvf_check` reacts to the `add_trusted_validation_code` - // and uses the `CodeByHash::contains_key` which is what `add_trusted_validation_code` uses. + // In particular, this tests that `kick_off_pvf_check` reacts to the + // `add_trusted_validation_code` and uses the `CodeByHash::contains_key` which is what + // `add_trusted_validation_code` uses. let para_id = 100.into(); let validation_code = ValidationCode(vec![1, 2, 3]); let validation_upgrade_delay = 25; diff --git a/runtime/parachains/src/paras_inherent/mod.rs b/runtime/parachains/src/paras_inherent/mod.rs index 61be0d4adae8..a40a3422a669 100644 --- a/runtime/parachains/src/paras_inherent/mod.rs +++ b/runtime/parachains/src/paras_inherent/mod.rs @@ -285,8 +285,9 @@ pub mod pallet { } impl Pallet { - /// Create the `ParachainsInherentData` that gets passed to [`Self::enter`] in [`Self::create_inherent`]. - /// This code is pulled out of [`Self::create_inherent`] so it can be unit tested. + /// Create the `ParachainsInherentData` that gets passed to [`Self::enter`] in + /// [`Self::create_inherent`]. This code is pulled out of [`Self::create_inherent`] so it can be + /// unit tested. fn create_inherent_inner(data: &InherentData) -> Option>> { let parachains_inherent_data = match data.get_data(&Self::INHERENT_IDENTIFIER) { Ok(Some(d)) => d, @@ -313,11 +314,11 @@ impl Pallet { /// The given inherent data is processed and state is altered accordingly. If any data could /// not be applied (inconsitencies, weight limit, ...) it is removed. /// - /// When called from `create_inherent` the `context` must be set to `ProcessInherentDataContext::ProvideInherent` - /// so it guarantees the invariant that inherent is not overweight. - /// - /// It is **mandatory** that calls from `enter` set `context` to `ProcessInherentDataContext::Enter` to ensure - /// the weight invariant is checked. + /// When called from `create_inherent` the `context` must be set to + /// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent + /// is not overweight. + /// It is **mandatory** that calls from `enter` set `context` to + /// `ProcessInherentDataContext::Enter` to ensure the weight invariant is checked. /// /// Returns: Result containing processed inherent data and weight, the processed inherent would /// consume. @@ -379,8 +380,8 @@ impl Pallet { let dispatch_class = DispatchClass::Mandatory; let max_block_weight_full = ::BlockWeights::get(); log::debug!(target: LOG_TARGET, "Max block weight: {}", max_block_weight_full.max_block); - // Get max block weight for the mandatory class if defined, otherwise total max weight of - // the block. + // Get max block weight for the mandatory class if defined, otherwise total max weight + // of the block. let max_weight = max_block_weight_full .per_class .get(dispatch_class) @@ -412,7 +413,8 @@ impl Pallet { T::DisputesHandler::filter_dispute_data(set, post_conclusion_acceptance_period) }; - // Limit the disputes first, since the following statements depend on the votes include here. + // Limit the disputes first, since the following statements depend on the votes include + // here. let (checked_disputes_sets, checked_disputes_sets_consumed_weight) = limit_and_sanitize_disputes::( disputes, @@ -449,8 +451,8 @@ impl Pallet { } all_weight_after } else { - // This check is performed in the context of block execution. Ensures inherent weight invariants guaranteed - // by `create_inherent_data` for block authorship. + // This check is performed in the context of block execution. Ensures inherent weight + // invariants guaranteed by `create_inherent_data` for block authorship. if all_weight_before.any_gt(max_block_weight) { log::error!( "Overweight para inherent data reached the runtime {:?}: {} > {}", @@ -714,13 +716,14 @@ fn random_sel Weight>( /// If there is sufficient space, all bitfields and all candidates /// will be included. /// -/// Otherwise tries to include all disputes, and then tries to fill the remaining space with bitfields and then candidates. +/// Otherwise tries to include all disputes, and then tries to fill the remaining space with +/// bitfields and then candidates. /// -/// The selection process is random. For candidates, there is an exception for code upgrades as they are preferred. -/// And for disputes, local and older disputes are preferred (see `limit_and_sanitize_disputes`). -/// for backed candidates, since with a increasing number of parachains their chances of -/// inclusion become slim. All backed candidates are checked beforehands in `fn create_inherent_inner` -/// which guarantees sanity. +/// The selection process is random. For candidates, there is an exception for code upgrades as they +/// are preferred. And for disputes, local and older disputes are preferred (see +/// `limit_and_sanitize_disputes`). for backed candidates, since with a increasing number of +/// parachains their chances of inclusion become slim. All backed candidates are checked +/// beforehands in `fn create_inherent_inner` which guarantees sanity. /// /// Assumes disputes are already filtered by the time this is called. /// @@ -977,7 +980,8 @@ fn compute_entropy(parent_hash: T::Hash) -> [u8; 32] { /// 1. If weight is exceeded by locals, pick the older ones (lower indices) /// until the weight limit is reached. /// -/// Returns the consumed weight amount, that is guaranteed to be less than the provided `max_consumable_weight`. +/// Returns the consumed weight amount, that is guaranteed to be less than the provided +/// `max_consumable_weight`. fn limit_and_sanitize_disputes< T: Config, CheckValidityFn: FnMut(DisputeStatementSet) -> Option, diff --git a/runtime/parachains/src/paras_inherent/tests.rs b/runtime/parachains/src/paras_inherent/tests.rs index c2e80e7525fb..faf52b555ba3 100644 --- a/runtime/parachains/src/paras_inherent/tests.rs +++ b/runtime/parachains/src/paras_inherent/tests.rs @@ -68,9 +68,9 @@ mod enter { } #[test] - // Validate that if we create 2 backed candidates which are assigned to 2 cores that will be freed via - // becoming fully available, the backed candidates will not be filtered out in `create_inherent` and - // will not cause `enter` to early. + // Validate that if we create 2 backed candidates which are assigned to 2 cores that will be + // freed via becoming fully available, the backed candidates will not be filtered out in + // `create_inherent` and will not cause `enter` to early. fn include_backed_candidates() { new_test_ext(MockGenesisConfig::default()).execute_with(|| { let dispute_statements = BTreeMap::new(); @@ -252,7 +252,8 @@ mod enter { let expected_para_inherent_data = scenario.data.clone(); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 3 disputes => 3 cores, 15 validators) + // * 1 bitfield per validator (5 validators per core, 3 disputes => 3 cores, 15 + // validators) assert_eq!(expected_para_inherent_data.bitfields.len(), 15); // * 0 backed candidate per core assert_eq!(expected_para_inherent_data.backed_candidates.len(), 0); @@ -389,7 +390,8 @@ mod enter { let expected_para_inherent_data = scenario.data.clone(); // Check the para inherent data is as expected: - // * 1 bitfield per validator (4 validators per core, 2 backed candidates, 3 disputes => 4*5 = 20) + // * 1 bitfield per validator (4 validators per core, 2 backed candidates, 3 disputes => + // 4*5 = 20) assert_eq!(expected_para_inherent_data.bitfields.len(), 20); // * 2 backed candidates assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2); @@ -408,7 +410,8 @@ mod enter { Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); assert!(limit_inherent_data != expected_para_inherent_data); - // Three disputes is over weight (see previous test), so we expect to only see 2 disputes + // Three disputes is over weight (see previous test), so we expect to only see 2 + // disputes assert_eq!(limit_inherent_data.disputes.len(), 2); // Ensure disputes are filtered as expected assert_eq!(limit_inherent_data.disputes[0].session, 1); @@ -418,7 +421,8 @@ mod enter { limit_inherent_data.bitfields.len(), expected_para_inherent_data.bitfields.len() ); - // Ensure that all backed candidates are filtered out as either would make the block over weight + // Ensure that all backed candidates are filtered out as either would make the block + // over weight assert_eq!(limit_inherent_data.backed_candidates.len(), 0); assert_ok!(Pallet::::enter( @@ -470,7 +474,8 @@ mod enter { let expected_para_inherent_data = scenario.data.clone(); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 4*5 = 20), + // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => + // 4*5 = 20), assert_eq!(expected_para_inherent_data.bitfields.len(), 25); // * 2 backed candidates, assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2); @@ -493,14 +498,16 @@ mod enter { assert!(inherent_data_weight(&limit_inherent_data) .all_lte(max_block_weight_proof_size_adjusted())); - // Three disputes is over weight (see previous test), so we expect to only see 2 disputes + // Three disputes is over weight (see previous test), so we expect to only see 2 + // disputes assert_eq!(limit_inherent_data.disputes.len(), 2); // Ensure disputes are filtered as expected assert_eq!(limit_inherent_data.disputes[0].session, 1); assert_eq!(limit_inherent_data.disputes[1].session, 2); // Ensure all bitfields are included as these are still not over weight assert_eq!(limit_inherent_data.bitfields.len(), 20,); - // Ensure that all backed candidates are filtered out as either would make the block over weight + // Ensure that all backed candidates are filtered out as either would make the block + // over weight assert_eq!(limit_inherent_data.backed_candidates.len(), 0); assert_ok!(Pallet::::enter( @@ -551,7 +558,8 @@ mod enter { let expected_para_inherent_data = scenario.data.clone(); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 5*5 = 25) + // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => + // 5*5 = 25) assert_eq!(expected_para_inherent_data.bitfields.len(), 25); // * 2 backed candidates assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2); @@ -632,7 +640,8 @@ mod enter { .any_lt(inherent_data_weight(&expected_para_inherent_data))); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 5*5 = 25) + // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => + // 5*5 = 25) assert_eq!(expected_para_inherent_data.bitfields.len(), 25); // * 2 backed candidates assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2); @@ -645,7 +654,8 @@ mod enter { let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); - // Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes + // Expect that inherent data is filtered to include only 1 backed candidate and 2 + // disputes assert!(limit_inherent_data != expected_para_inherent_data); assert!( max_block_weight_proof_size_adjusted() @@ -727,7 +737,8 @@ mod enter { .unwrap(); let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); - // Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes + // Expect that inherent data is filtered to include only 1 backed candidate and 2 + // disputes assert!(limit_inherent_data != expected_para_inherent_data); assert!( max_block_weight_proof_size_adjusted() @@ -792,7 +803,8 @@ mod enter { let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); - // Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes + // Expect that inherent data is filtered to include only 1 backed candidate and 2 + // disputes assert!(limit_inherent_data != expected_para_inherent_data); assert!( max_block_weight_proof_size_adjusted() @@ -841,7 +853,8 @@ mod enter { .any_lt(inherent_data_weight(&expected_para_inherent_data))); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 0 disputes => 2*5 = 10) + // * 1 bitfield per validator (5 validators per core, 2 backed candidates, 0 disputes => + // 2*5 = 10) assert_eq!(expected_para_inherent_data.bitfields.len(), 10); // * 2 backed candidates assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2); @@ -854,7 +867,8 @@ mod enter { let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); - // Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes + // Expect that inherent data is filtered to include only 1 backed candidate and 2 + // disputes assert!(limit_inherent_data != expected_para_inherent_data); assert!( max_block_weight_proof_size_adjusted() @@ -903,7 +917,8 @@ mod enter { .any_lt(inherent_data_weight(&expected_para_inherent_data))); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 30 backed candidates, 3 disputes => 5*33 = 165) + // * 1 bitfield per validator (5 validators per core, 30 backed candidates, 3 disputes + // => 5*33 = 165) assert_eq!(expected_para_inherent_data.bitfields.len(), 165); // * 30 backed candidates assert_eq!(expected_para_inherent_data.backed_candidates.len(), 30); diff --git a/runtime/parachains/src/runtime_api_impl/v5.rs b/runtime/parachains/src/runtime_api_impl/v5.rs index 1257c0c91702..4c9c8c911f62 100644 --- a/runtime/parachains/src/runtime_api_impl/v5.rs +++ b/runtime/parachains/src/runtime_api_impl/v5.rs @@ -393,7 +393,8 @@ pub fn pvfs_require_precheck() -> Vec { >::pvfs_require_precheck() } -/// Returns the validation code hash for the given parachain making the given `OccupiedCoreAssumption`. +/// Returns the validation code hash for the given parachain making the given +/// `OccupiedCoreAssumption`. pub fn validation_code_hash( para_id: ParaId, assumption: OccupiedCoreAssumption, diff --git a/runtime/parachains/src/scheduler.rs b/runtime/parachains/src/scheduler.rs index b69c16ae8d01..6882834187dc 100644 --- a/runtime/parachains/src/scheduler.rs +++ b/runtime/parachains/src/scheduler.rs @@ -21,19 +21,20 @@ //! - Scheduling parachains and parathreads //! //! It aims to achieve these tasks with these goals in mind: -//! - It should be possible to know at least a block ahead-of-time, ideally more, -//! which validators are going to be assigned to which parachains. -//! - Parachains that have a candidate pending availability in this fork of the chain -//! should not be assigned. +//! - It should be possible to know at least a block ahead-of-time, ideally more, which validators +//! are going to be assigned to which parachains. +//! - Parachains that have a candidate pending availability in this fork of the chain should not be +//! assigned. //! - Validator assignments should not be gameable. Malicious cartels should not be able to //! manipulate the scheduler to assign themselves as desired. -//! - High or close to optimal throughput of parachains and parathreads. Work among validator groups should be balanced. +//! - High or close to optimal throughput of parachains and parathreads. Work among validator groups +//! should be balanced. //! //! The Scheduler manages resource allocation using the concept of "Availability Cores". //! There will be one availability core for each parachain, and a fixed number of cores //! used for multiplexing parathreads. Validators will be partitioned into groups, with the same -//! number of groups as availability cores. Validator groups will be assigned to different availability cores -//! over time. +//! number of groups as availability cores. Validator groups will be assigned to different +//! availability cores over time. use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; @@ -169,8 +170,9 @@ pub mod pallet { /// broader set of Polkadot validators, but instead just the subset used for parachains during /// this session. /// - /// Bound: The number of cores is the sum of the numbers of parachains and parathread multiplexers. - /// Reasonably, 100-1000. The dominant factor is the number of validators: safe upper bound at 10k. + /// Bound: The number of cores is the sum of the numbers of parachains and parathread + /// multiplexers. Reasonably, 100-1000. The dominant factor is the number of validators: safe + /// upper bound at 10k. #[pallet::storage] #[pallet::getter(fn validator_groups)] pub(crate) type ValidatorGroups = StorageValue<_, Vec>, ValueQuery>; @@ -182,8 +184,8 @@ pub mod pallet { #[pallet::storage] pub(crate) type ParathreadQueue = StorageValue<_, ParathreadClaimQueue, ValueQuery>; - /// One entry for each availability core. Entries are `None` if the core is not currently occupied. Can be - /// temporarily `Some` if scheduled but not occupied. + /// One entry for each availability core. Entries are `None` if the core is not currently + /// occupied. Can be temporarily `Some` if scheduled but not occupied. /// The i'th parachain belongs to the i'th core, with the remaining cores all being /// parathread-multiplexers. /// @@ -197,11 +199,13 @@ pub mod pallet { /// An index used to ensure that only one claim on a parathread exists in the queue or is /// currently being handled by an occupied core. /// - /// Bounded by the number of parathread cores and scheduling lookahead. Reasonably, 10 * 50 = 500. + /// Bounded by the number of parathread cores and scheduling lookahead. Reasonably, 10 * 50 = + /// 500. #[pallet::storage] pub(crate) type ParathreadClaimIndex = StorageValue<_, Vec, ValueQuery>; - /// The block number where the session start occurred. Used to track how many group rotations have occurred. + /// The block number where the session start occurred. Used to track how many group rotations + /// have occurred. /// /// Note that in the context of parachains modules the session change is signaled during /// the block and enacted at the end of the block (at the finalization stage, to be exact). @@ -215,8 +219,8 @@ pub mod pallet { /// /// Bounded by the number of cores: one for each parachain and parathread multiplexer. /// - /// The value contained here will not be valid after the end of a block. Runtime APIs should be used to determine scheduled cores/ - /// for the upcoming block. + /// The value contained here will not be valid after the end of a block. Runtime APIs should be + /// used to determine scheduled cores/ for the upcoming block. #[pallet::storage] #[pallet::getter(fn scheduled)] pub(crate) type Scheduled = StorageValue<_, Vec, ValueQuery>; @@ -380,8 +384,9 @@ impl Pallet { }) } - /// Free unassigned cores. Provide a list of cores that should be considered newly-freed along with the reason - /// for them being freed. The list is assumed to be sorted in ascending order by core index. + /// Free unassigned cores. Provide a list of cores that should be considered newly-freed along + /// with the reason for them being freed. The list is assumed to be sorted in ascending order by + /// core index. pub(crate) fn free_cores(just_freed_cores: impl IntoIterator) { let config = >::config(); @@ -403,8 +408,8 @@ impl Pallet { }) }, FreedReason::TimedOut => { - // If a parathread candidate times out, it's not the collator's fault, - // so we don't increment retries. + // If a parathread candidate times out, it's not the collator's + // fault, so we don't increment retries. ParathreadQueue::::mutate(|queue| { queue.enqueue_entry(entry, config.parathread_cores); }) @@ -417,9 +422,9 @@ impl Pallet { }) } - /// Schedule all unassigned cores, where possible. Provide a list of cores that should be considered - /// newly-freed along with the reason for them being freed. The list is assumed to be sorted in - /// ascending order by core index. + /// Schedule all unassigned cores, where possible. Provide a list of cores that should be + /// considered newly-freed along with the reason for them being freed. The list is assumed to be + /// sorted in ascending order by core index. pub(crate) fn schedule( just_freed_cores: impl IntoIterator, now: BlockNumberFor, @@ -455,10 +460,10 @@ impl Pallet { // check the first entry already scheduled with core index >= than the one we // are looking at. 3 cases: - // 1. No such entry, clearly this core is not scheduled, so we need to schedule and put at the end. - // 2. Entry exists and has same index as the core we are inspecting. do not schedule again. - // 3. Entry exists and has higher index than the core we are inspecting. schedule and note - // insertion position. + // 1. No such entry, clearly this core is not scheduled, so we need to schedule + // and put at the end. 2. Entry exists and has same index as the core we are + // inspecting. do not schedule again. 3. Entry exists and has higher index than + // the core we are inspecting. schedule and note insertion position. prev_scheduled_in_order.peek().map_or( Some(scheduled.len()), |(idx_in_scheduled, assign)| { @@ -509,8 +514,9 @@ impl Pallet { } } - // at this point, because `Scheduled` is guaranteed to be sorted and we navigated unassigned - // core indices in ascending order, we can enact the updates prepared by the previous actions. + // at this point, because `Scheduled` is guaranteed to be sorted and we navigated + // unassigned core indices in ascending order, we can enact the updates prepared by the + // previous actions. // // while inserting, we have to account for the amount of insertions already done. // @@ -522,20 +528,20 @@ impl Pallet { scheduled.insert(insert_at, to_insert); } - // scheduled is guaranteed to be sorted after this point because it was sorted before, and we - // applied sorted updates at their correct positions, accounting for the offsets of previous - // insertions. + // scheduled is guaranteed to be sorted after this point because it was sorted before, + // and we applied sorted updates at their correct positions, accounting for the offsets + // of previous insertions. } Scheduled::::set(scheduled); ParathreadQueue::::set(parathread_queue); } - /// Note that the given cores have become occupied. Behavior undefined if any of the given cores were not scheduled - /// or the slice is not sorted ascending by core index. + /// Note that the given cores have become occupied. Behavior undefined if any of the given cores + /// were not scheduled or the slice is not sorted ascending by core index. /// - /// Complexity: O(n) in the number of scheduled cores, which is capped at the number of total cores. - /// This is efficient in the case that most scheduled cores are occupied. + /// Complexity: O(n) in the number of scheduled cores, which is capped at the number of total + /// cores. This is efficient in the case that most scheduled cores are occupied. pub(crate) fn occupied(now_occupied: &[CoreIndex]) { if now_occupied.is_empty() { return @@ -568,8 +574,8 @@ impl Pallet { AvailabilityCores::::set(availability_cores); } - /// Get the para (chain or thread) ID assigned to a particular core or index, if any. Core indices - /// out of bounds will return `None`, as will indices of unassigned cores. + /// Get the para (chain or thread) ID assigned to a particular core or index, if any. Core + /// indices out of bounds will return `None`, as will indices of unassigned cores. pub(crate) fn core_para(core_index: CoreIndex) -> Option { let cores = AvailabilityCores::::get(); match cores.get(core_index.0 as usize).and_then(|c| c.as_ref()) { @@ -587,8 +593,9 @@ impl Pallet { ValidatorGroups::::get().get(group_index.0 as usize).map(|g| g.clone()) } - /// Get the group assigned to a specific core by index at the current block number. Result undefined if the core index is unknown - /// or the block number is less than the session start index. + /// Get the group assigned to a specific core by index at the current block number. Result + /// undefined if the core index is unknown or the block number is less than the session start + /// index. pub(crate) fn group_assigned_to_core( core: CoreIndex, at: BlockNumberFor, @@ -622,10 +629,11 @@ impl Pallet { /// Returns an optional predicate that should be used for timing out occupied cores. /// - /// If `None`, no timing-out should be done. The predicate accepts the index of the core, and the - /// block number since which it has been occupied, and the respective parachain and parathread - /// timeouts, i.e. only within `max(config.chain_availability_period, config.thread_availability_period)` - /// of the last rotation would this return `Some`, unless there are no rotations. + /// If `None`, no timing-out should be done. The predicate accepts the index of the core, and + /// the block number since which it has been occupied, and the respective parachain and + /// parathread timeouts, i.e. only within `max(config.chain_availability_period, + /// config.thread_availability_period)` of the last rotation would this return `Some`, unless + /// there are no rotations. /// /// This really should not be a box, but is working around a compiler limitation filed here: /// https://github.com/rust-lang/rust/issues/73226 diff --git a/runtime/parachains/src/scheduler/tests.rs b/runtime/parachains/src/scheduler/tests.rs index 2188bb15b2e5..c4830f4bf253 100644 --- a/runtime/parachains/src/scheduler/tests.rs +++ b/runtime/parachains/src/scheduler/tests.rs @@ -56,7 +56,8 @@ fn run_to_block( 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. + // 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(); } @@ -104,8 +105,9 @@ fn default_config() -> HostConfiguration { scheduling_lookahead: 2, parathread_retries: 1, // 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`. + // 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() } @@ -626,9 +628,9 @@ fn schedule_schedules_including_just_freed() { 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`. + // 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())); diff --git a/runtime/parachains/src/shared.rs b/runtime/parachains/src/shared.rs index 857e671f0ee4..6b50bcce4054 100644 --- a/runtime/parachains/src/shared.rs +++ b/runtime/parachains/src/shared.rs @@ -62,8 +62,8 @@ pub mod pallet { pub(super) type ActiveValidatorIndices = StorageValue<_, Vec, ValueQuery>; - /// The parachain attestation keys of the validators actively participating in parachain consensus. - /// This should be the same length as `ActiveValidatorIndices`. + /// The parachain attestation keys of the validators actively participating in parachain + /// consensus. This should be the same length as `ActiveValidatorIndices`. #[pallet::storage] #[pallet::getter(fn active_validator_keys)] pub(super) type ActiveValidatorKeys = StorageValue<_, Vec, ValueQuery>; diff --git a/runtime/parachains/src/util.rs b/runtime/parachains/src/util.rs index d5b339b679e3..aa07ef080055 100644 --- a/runtime/parachains/src/util.rs +++ b/runtime/parachains/src/util.rs @@ -48,7 +48,7 @@ pub fn make_persisted_validation_data( /// the order of the `active` vec, the second item will contain the rest, in the original order. /// /// ```ignore -/// split_active_subset(active, all).0 == take_active_subset(active, all) +/// split_active_subset(active, all).0 == take_active_subset(active, all) /// ``` pub fn split_active_subset(active: &[ValidatorIndex], all: &[T]) -> (Vec, Vec) { let active_set: BTreeSet<_> = active.iter().cloned().collect(); @@ -76,7 +76,7 @@ pub fn split_active_subset(active: &[ValidatorIndex], all: &[T]) -> (V /// Uses `split_active_subset` and concatenates the inactive to the active vec. /// /// ```ignore -/// split_active_subset(active, all)[0..active.len()]) == take_active_subset(active, all) +/// split_active_subset(active, all)[0..active.len()]) == take_active_subset(active, all) /// ``` pub fn take_active_subset_and_inactive(active: &[ValidatorIndex], all: &[T]) -> Vec { let (mut a, mut i) = split_active_subset(active, all); diff --git a/runtime/polkadot/src/governance/old.rs b/runtime/polkadot/src/governance/old.rs index f4c2655a784a..4c7b503472f2 100644 --- a/runtime/polkadot/src/governance/old.rs +++ b/runtime/polkadot/src/governance/old.rs @@ -45,7 +45,8 @@ impl pallet_democracy::Config for Runtime { pallet_collective::EnsureProportionAtLeast, frame_system::EnsureRoot, >; - /// A 60% super-majority can have the next scheduled referendum be a straight majority-carries vote. + /// A 60% super-majority can have the next scheduled referendum be a straight majority-carries + /// vote. type ExternalMajorityOrigin = EitherOfDiverse< pallet_collective::EnsureProportionAtLeast, frame_system::EnsureRoot, diff --git a/runtime/polkadot/src/xcm_config.rs b/runtime/polkadot/src/xcm_config.rs index 867253ea0346..faae2e1d2619 100644 --- a/runtime/polkadot/src/xcm_config.rs +++ b/runtime/polkadot/src/xcm_config.rs @@ -63,8 +63,8 @@ parameter_types! { pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); } -/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to determine -/// the sovereign account controlled by a location. +/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to +/// determine the sovereign account controlled by a location. pub type SovereignAccountOf = ( // We can convert a child parachain using the standard `AccountId` conversion. ChildParachainConvertsVia, @@ -72,8 +72,8 @@ pub type SovereignAccountOf = ( AccountId32Aliases, ); -/// Our asset transactor. This is what allows us to interact with the runtime assets from the point of -/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// Our asset transactor. This is what allows us to interact with the runtime assets from the point +/// of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. /// /// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. pub type LocalAssetTransactor = XcmCurrencyAdapter< @@ -369,8 +369,8 @@ pub type CouncilToPlurality = BackingToPlurality< CouncilBodyId, >; -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain. +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. pub type LocalOriginToLocation = ( CouncilToPlurality, // And a usual Signed origin to be used in XCM as a corresponding AccountId32 @@ -385,11 +385,11 @@ pub type StakingAdminToPlurality = pub type FellowshipAdminToPlurality = OriginToPluralityVoice; -/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain for a destination chain. +/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an +/// interior location of this chain for a destination chain. pub type LocalPalletOriginToLocation = ( - // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality of the - // `Unit` body. + // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality + // of the `Unit` body. CouncilToPlurality, // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. StakingAdminToPlurality, @@ -399,7 +399,8 @@ pub type LocalPalletOriginToLocation = ( impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // We only allow the root, the council, the fellowship admin and the staking admin to send messages. + // We only allow the root, the council, the fellowship admin and the staking admin to send + // messages. type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally... diff --git a/runtime/rococo/src/xcm_config.rs b/runtime/rococo/src/xcm_config.rs index 714a4f69e759..75e06391c56b 100644 --- a/runtime/rococo/src/xcm_config.rs +++ b/runtime/rococo/src/xcm_config.rs @@ -56,8 +56,8 @@ parameter_types! { pub type LocationConverter = (ChildParachainConvertsVia, AccountId32Aliases); -/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of -/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the +/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. /// /// Ours is only aware of the Balances pallet, which is mapped to `RocLocation`. pub type LocalAssetTransactor = XcmCurrencyAdapter< @@ -342,11 +342,11 @@ pub type CouncilToPlurality = BackingToPlurality< CouncilBodyId, >; -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain. +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. pub type LocalOriginToLocation = ( - // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality of the - // `Unit` body. + // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality + // of the `Unit` body. CouncilToPlurality, // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, diff --git a/runtime/test-runtime/src/lib.rs b/runtime/test-runtime/src/lib.rs index c9f3aa6cb203..d7594e67c12a 100644 --- a/runtime/test-runtime/src/lib.rs +++ b/runtime/test-runtime/src/lib.rs @@ -355,8 +355,8 @@ impl pallet_staking::Config for Runtime { type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = onchain::OnChainExecution; - // Use the nominator map to iter voter AND no-ops for all SortedListProvider hooks. The migration - // to bags-list is a no-op, but the storage version will be updated. + // Use the nominator map to iter voter AND no-ops for all SortedListProvider hooks. The + // migration to bags-list is a no-op, but the storage version will be updated. type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota; diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index 21ce8c877dc3..2113bbae66ad 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -38,8 +38,8 @@ parameter_types! { pub const UniversalLocation: xcm::latest::InteriorMultiLocation = xcm::latest::Junctions::Here; } -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain. +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. pub type LocalOriginToLocation = ( // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 4b4659442cff..9bb5a6db613d 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -338,8 +338,8 @@ pub struct MaybeSignedPhase; impl Get for MaybeSignedPhase { fn get() -> u32 { - // 1 day = 4 eras -> 1 week = 28 eras. We want to disable signed phase once a week to test the fallback unsigned - // phase is able to compute elections on Westend. + // 1 day = 4 eras -> 1 week = 28 eras. We want to disable signed phase once a week to test + // the fallback unsigned phase is able to compute elections on Westend. if Staking::current_era().unwrap_or(1) % 28 == 0 { 0 } else { diff --git a/runtime/westend/src/xcm_config.rs b/runtime/westend/src/xcm_config.rs index d6a3feb3bc0f..a83c38c9f66f 100644 --- a/runtime/westend/src/xcm_config.rs +++ b/runtime/westend/src/xcm_config.rs @@ -271,8 +271,8 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } -/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location -/// of this chain. +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. pub type LocalOriginToLocation = ( // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, diff --git a/rustfmt.toml b/rustfmt.toml index 542c561edd42..e2c4a037f37f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,12 +1,20 @@ # Basic +edition = "2021" hard_tabs = true max_width = 100 use_small_heuristics = "Max" + # Imports imports_granularity = "Crate" reorder_imports = true + # Consistency newline_style = "Unix" + +# Format comments +comment_width = 100 +wrap_comments = true + # Misc chain_width = 80 spaces_around_ranges = false @@ -18,7 +26,3 @@ match_block_trailing_comma = true trailing_comma = "Vertical" trailing_semicolon = false use_field_init_shorthand = true -ignore = [ - "bridges", -] -edition = "2021" diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index b45c4c1be890..ea629f189dc8 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -114,4 +114,5 @@ cargo-clippy: - .docker-env - .test-refs script: + - cargo version && cargo clippy --version - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --locked --all-targets diff --git a/statement-table/src/generic.rs b/statement-table/src/generic.rs index fcd261b438b3..9aa445becce0 100644 --- a/statement-table/src/generic.rs +++ b/statement-table/src/generic.rs @@ -96,8 +96,8 @@ pub enum ValidityDoubleVote { } impl ValidityDoubleVote { - /// Deconstruct this misbehavior into two `(Statement, Signature)` pairs, erasing the information - /// about precisely what the problem was. + /// Deconstruct this misbehavior into two `(Statement, Signature)` pairs, erasing the + /// information about precisely what the problem was. pub fn deconstruct( self, ) -> ((Statement, Signature), (Statement, Signature)) @@ -124,8 +124,8 @@ pub enum DoubleSign { } impl DoubleSign { - /// Deconstruct this misbehavior into a statement with two signatures, erasing the information about - /// precisely where in the process the issue was detected. + /// Deconstruct this misbehavior into a statement with two signatures, erasing the information + /// about precisely where in the process the issue was detected. pub fn deconstruct(self) -> (Statement, Signature, Signature) { match self { Self::Seconded(candidate, a, b) => (Statement::Seconded(candidate), a, b), @@ -555,10 +555,11 @@ impl<'a, Ctx: Context> Iterator for DrainMisbehaviors<'a, Ctx> { type Item = (Ctx::AuthorityId, MisbehaviorFor); fn next(&mut self) -> Option { - // Note: this implementation will prematurely return `None` if `self.drain.next()` ever returns a - // tuple whose vector is empty. That will never currently happen, as the only modification - // to the backing map is currently via `drain` and `entry(...).or_default().push(...)`. - // However, future code changes might change that property. + // Note: this implementation will prematurely return `None` if `self.drain.next()` ever + // returns a tuple whose vector is empty. That will never currently happen, as the only + // modification to the backing map is currently via `drain` and + // `entry(...).or_default().push(...)`. However, future code changes might change that + // property. self.maybe_item().or_else(|| { self.in_progress = self.drain.next().map(Into::into); self.maybe_item() diff --git a/tests/common.rs b/tests/common.rs index 39b92732498f..940a0c6f18d0 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -76,7 +76,8 @@ async fn wait_n_finalized_blocks_from(n: usize, url: &str) { /// This is hack to get the actual binded sockaddr because /// polkadot assigns a random port if the specified port was already binded. /// -/// You must call `Command::new("cmd").stdout(process::Stdio::piped()).stderr(process::Stdio::piped())` +/// You must call +/// `Command::new("cmd").stdout(process::Stdio::piped()).stderr(process::Stdio::piped())` /// for this to work. pub fn find_ws_url_from_output(read: impl Read + Send) -> (String, String) { let mut data = String::new(); diff --git a/utils/staking-miner/src/opts.rs b/utils/staking-miner/src/opts.rs index 819511b55b18..ecffe4531014 100644 --- a/utils/staking-miner/src/opts.rs +++ b/utils/staking-miner/src/opts.rs @@ -58,8 +58,8 @@ pub(crate) enum Command { #[derive(Debug, Clone, Parser)] #[cfg_attr(test, derive(PartialEq))] pub(crate) struct MonitorConfig { - /// The path to a file containing the seed of the account. If the file is not found, the seed is - /// used as-is. + /// The path to a file containing the seed of the account. If the file is not found, the seed + /// is used as-is. /// /// Can also be provided via the `SEED` environment variable. /// @@ -88,9 +88,11 @@ pub(crate) struct MonitorConfig { /// /// `--submission-strategy always`: always submit. /// - /// `--submission-strategy "percent-better "`: submit if the submission is `n` percent better. + /// `--submission-strategy "percent-better "`: submit if the submission is `n` percent + /// better. /// - /// `--submission-strategy "no-worse-than "`: submit if submission is no more than `n` percent worse. + /// `--submission-strategy "no-worse-than "`: submit if submission is no more than + /// `n` percent worse. #[clap(long, default_value = "if-leading")] pub submission_strategy: SubmissionStrategy, @@ -100,8 +102,8 @@ pub(crate) struct MonitorConfig { /// a delay can be enforced to avoid submitting at /// "same time" and risk potential races with other miners. /// - /// When this is enabled and there are competing solutions, your solution might not be submitted - /// if the scores are equal. + /// When this is enabled and there are competing solutions, your solution might not be + /// submitted if the scores are equal. #[arg(long, default_value_t = 0)] pub delay: usize, } @@ -109,8 +111,8 @@ pub(crate) struct MonitorConfig { #[derive(Debug, Clone, Parser)] #[cfg_attr(test, derive(PartialEq))] pub(crate) struct DryRunConfig { - /// The path to a file containing the seed of the account. If the file is not found, the seed is - /// used as-is. + /// The path to a file containing the seed of the account. If the file is not found, the seed + /// is used as-is. /// /// Can also be provided via the `SEED` environment variable. /// @@ -165,8 +167,8 @@ pub enum SubmissionStrategy { IfLeading, /// Submit if we are no worse than `Perbill` worse than the best. ClaimNoWorseThan(Perbill), - /// Submit if we are leading, or if the solution that's leading is more that the given `Perbill` - /// better than us. This helps detect obviously fake solutions and still combat them. + /// Submit if we are leading, or if the solution that's leading is more that the given + /// `Perbill` better than us. This helps detect obviously fake solutions and still combat them. ClaimBetterThan(Perbill), } @@ -189,8 +191,8 @@ pub(crate) enum Solver { /// * --submission-strategy if-leading: only submit if leading /// * --submission-strategy always: always submit /// * --submission-strategy "percent-better ": submit if submission is `n` percent better. -/// * --submission-strategy "no-worse-than": submit if submission is no more than `n` percent worse. -/// +/// * --submission-strategy "no-worse-than": submit if submission is no more than `n` +/// percent worse. impl FromStr for SubmissionStrategy { type Err = String; diff --git a/utils/staking-miner/src/rpc.rs b/utils/staking-miner/src/rpc.rs index a95e89191a49..2d25616e2a17 100644 --- a/utils/staking-miner/src/rpc.rs +++ b/utils/staking-miner/src/rpc.rs @@ -61,7 +61,8 @@ pub trait RpcApi { at: Option<&Hash>, ) -> RpcResult>; - /// Dry run an extrinsic at a given block. Return SCALE encoded [`sp_runtime::ApplyExtrinsicResult`]. + /// Dry run an extrinsic at a given block. Return SCALE encoded + /// [`sp_runtime::ApplyExtrinsicResult`]. #[method(name = "system_dryRun")] async fn dry_run(&self, extrinsic: &Bytes, at: Option) -> RpcResult; diff --git a/xcm/pallet-xcm-benchmarks/src/generic/mod.rs b/xcm/pallet-xcm-benchmarks/src/generic/mod.rs index e5fce008a0f2..195066ee5b48 100644 --- a/xcm/pallet-xcm-benchmarks/src/generic/mod.rs +++ b/xcm/pallet-xcm-benchmarks/src/generic/mod.rs @@ -52,7 +52,8 @@ pub mod pallet { /// If set to `Err`, benchmarks which rely on an `exchange_asset` will be skipped. fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError>; - /// A `(MultiLocation, Junction)` that is one of the `UniversalAliases` configured by the XCM executor. + /// A `(MultiLocation, Junction)` that is one of the `UniversalAliases` configured by the + /// XCM executor. /// /// If set to `Err`, benchmarks which rely on a universal alias will be skipped. fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError>; @@ -75,13 +76,15 @@ pub mod pallet { /// Return an unlocker, owner and assets that can be locked and unlocked. fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError>; - /// A `(MultiLocation, NetworkId, InteriorMultiLocation)` we can successfully export message to. + /// A `(MultiLocation, NetworkId, InteriorMultiLocation)` we can successfully export message + /// to. /// /// If set to `Err`, benchmarks which rely on `export_message` will be skipped. fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError>; - /// A `(MultiLocation, MultiLocation)` that is one of the `Aliasers` configured by the XCM executor. + /// A `(MultiLocation, MultiLocation)` that is one of the `Aliasers` configured by the XCM + /// executor. /// /// If set to `Err`, benchmarks which rely on a universal alias will be skipped. fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError>; diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index d52d5ba24271..aefcf30910ed 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -195,9 +195,9 @@ pub mod pallet { /// The type used to actually dispatch an XCM to its destination. type XcmRouter: SendXcm; - /// Required origin for executing XCM messages, including the teleport functionality. If successful, - /// then it resolves to `MultiLocation` which exists as an interior location within this chain's XCM - /// context. + /// Required origin for executing XCM messages, including the teleport functionality. If + /// successful, then it resolves to `MultiLocation` which exists as an interior location + /// within this chain's XCM context. type ExecuteXcmOrigin: EnsureOrigin< ::RuntimeOrigin, Success = MultiLocation, @@ -212,7 +212,8 @@ pub mod pallet { /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(MultiLocation, Vec)>; - /// Our XCM filter which messages to be reserve-transferred using the dedicated extrinsic must pass. + /// Our XCM filter which messages to be reserve-transferred using the dedicated extrinsic + /// must pass. type XcmReserveTransferFilter: Contains<(MultiLocation, Vec)>; /// Means of measuring the weight consumed by an XCM message locally. @@ -290,8 +291,8 @@ pub mod pallet { /// Query response has been received and query is removed. The registered notification has /// been dispatched and executed successfully. Notified { query_id: QueryId, pallet_index: u8, call_index: u8 }, - /// Query response has been received and query is removed. The registered notification could - /// not be dispatched because the dispatch weight is greater than the maximum weight + /// Query response has been received and query is removed. The registered notification + /// could not be dispatched because the dispatch weight is greater than the maximum weight /// originally budgeted by this runtime for the query result. NotifyOverweight { query_id: QueryId, @@ -371,7 +372,8 @@ pub mod pallet { cost: MultiAssets, message_id: XcmHash, }, - /// We have requested that a remote chain stops sending us XCM version change notifications. + /// We have requested that a remote chain stops sending us XCM version change + /// notifications. VersionNotifyUnrequested { destination: MultiLocation, cost: MultiAssets, @@ -402,8 +404,8 @@ pub mod pallet { /// The desired destination was unreachable, generally because there is a no way of routing /// to it. Unreachable, - /// There was some other issue (i.e. not to do with routing) in sending the message. Perhaps - /// a lack of space for buffering the message. + /// There was some other issue (i.e. not to do with routing) in sending the message. + /// Perhaps a lack of space for buffering the message. SendFailure, /// The message execution fails the filter. Filtered, @@ -791,12 +793,13 @@ pub mod pallet { /// with all fees taken as needed from the asset. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. - /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send - /// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain. - /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be - /// an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the - /// `dest` side. May not be empty. + /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, + /// Parachain(..))` to send from parachain to parachain, or `X1(Parachain(..))` to send + /// from relay to parachain. + /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will + /// generally be an `AccountId32` value. + /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to + /// pay the fee on the `dest` side. May not be empty. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(1)] @@ -839,12 +842,13 @@ pub mod pallet { /// with all fees taken as needed from the asset. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. - /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send - /// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain. - /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be - /// an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the - /// `dest` side. + /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, + /// Parachain(..))` to send from parachain to parachain, or `X1(Parachain(..))` to send + /// from relay to parachain. + /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will + /// generally be an `AccountId32` value. + /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the + /// fee on the `dest` side. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(2)] @@ -885,12 +889,12 @@ pub mod pallet { /// An event is deposited indicating whether `msg` could be executed completely or only /// partially. /// - /// No more than `max_weight` will be used in its attempted execution. If this is less than the - /// maximum amount of weight that the message could take to be executed, then no execution - /// attempt will be made. + /// No more than `max_weight` will be used in its attempted execution. If this is less than + /// the maximum amount of weight that the message could take to be executed, then no + /// execution attempt will be made. /// - /// NOTE: A successful return to this does *not* imply that the `msg` was executed successfully - /// to completion; only that *some* of it was executed. + /// NOTE: A successful return to this does *not* imply that the `msg` was executed + /// successfully to completion; only that *some* of it was executed. #[pallet::call_index(3)] #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( @@ -1012,12 +1016,13 @@ pub mod pallet { /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. - /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send - /// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain. - /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be - /// an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the - /// `dest` side. + /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, + /// Parachain(..))` to send from parachain to parachain, or `X1(Parachain(..))` to send + /// from relay to parachain. + /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will + /// generally be an `AccountId32` value. + /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the + /// fee on the `dest` side. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. @@ -1063,12 +1068,13 @@ pub mod pallet { /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. - /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send - /// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain. - /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be - /// an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the - /// `dest` side. May not be empty. + /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, + /// Parachain(..))` to send from parachain to parachain, or `X1(Parachain(..))` to send + /// from relay to parachain. + /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will + /// generally be an `AccountId32` value. + /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to + /// pay the fee on the `dest` side. May not be empty. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. @@ -1561,13 +1567,13 @@ impl Pallet { /// /// - `message`: The message whose outcome should be reported. /// - `responder`: The origin from which a response should be expected. - /// - `notify`: A dispatchable function which will be called once the outcome of `message` - /// is known. It may be a dispatchable in any pallet of the local chain, but other than - /// the usual origin, it must accept exactly two arguments: `query_id: QueryId` and - /// `outcome: Response`, and in that order. It should expect that the origin is - /// `Origin::Response` and will contain the responder's location. - /// - `timeout`: The block number after which it is permissible for `notify` not to be - /// called even if a response is received. + /// - `notify`: A dispatchable function which will be called once the outcome of `message` is + /// known. It may be a dispatchable in any pallet of the local chain, but other than the usual + /// origin, it must accept exactly two arguments: `query_id: QueryId` and `outcome: Response`, + /// and in that order. It should expect that the origin is `Origin::Response` and will contain + /// the responder's location. + /// - `timeout`: The block number after which it is permissible for `notify` not to be called + /// even if a response is received. /// /// `report_outcome_notify` may return an error if the `responder` is not invertible. /// @@ -2090,8 +2096,8 @@ impl OnResponse for Pallet { call_index, }; Self::deposit_event(e); - // Not much to do with the result as it is. It's up to the parachain to ensure that the - // message makes sense. + // Not much to do with the result as it is. It's up to the + // parachain to ensure that the message makes sense. error_and_info.post_info.actual_weight }, } @@ -2159,8 +2165,8 @@ where } } -/// Filter for `MultiLocation` to find those which represent a strict majority approval of an identified -/// plurality. +/// Filter for `MultiLocation` to find those which represent a strict majority approval of an +/// identified plurality. /// /// May reasonably be used with `EnsureXcm`. pub struct IsMajorityOfBody(PhantomData<(Prefix, Body)>); @@ -2186,8 +2192,8 @@ impl, Body: Get> Contains } } -/// `EnsureOrigin` implementation succeeding with a `MultiLocation` value to recognize and filter the -/// `Origin::Xcm` item. +/// `EnsureOrigin` implementation succeeding with a `MultiLocation` value to recognize and filter +/// the `Origin::Xcm` item. pub struct EnsureXcm(PhantomData); impl, F: Contains> EnsureOrigin for EnsureXcm where diff --git a/xcm/src/double_encoded.rs b/xcm/src/double_encoded.rs index 2c8957d9ed76..c4c1276fad8d 100644 --- a/xcm/src/double_encoded.rs +++ b/xcm/src/double_encoded.rs @@ -73,7 +73,8 @@ impl DoubleEncoded { impl DoubleEncoded { /// Decode the inner encoded value and store it. - /// Returns a reference to the value in case of success and `Err(())` in case the decoding fails. + /// Returns a reference to the value in case of success and `Err(())` in case the decoding + /// fails. pub fn ensure_decoded(&mut self) -> Result<&T, ()> { if self.decoded.is_none() { self.decoded = @@ -92,8 +93,9 @@ impl DoubleEncoded { .ok_or(()) } - /// Provides an API similar to `TryInto` that allows fallible conversion to the inner value type. - /// `TryInto` implementation would collide with std blanket implementation based on `TryFrom`. + /// Provides an API similar to `TryInto` that allows fallible conversion to the inner value + /// type. `TryInto` implementation would collide with std blanket implementation based on + /// `TryFrom`. pub fn try_into(mut self) -> Result { self.ensure_decoded()?; self.decoded.ok_or(()) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 2e8ea78b5c15..a012c5f53fbf 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -360,7 +360,8 @@ impl TryFrom> for v3::Xcm { } } -/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will interpret it. +/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will +/// interpret it. pub trait WrapVersion { fn wrap_version( dest: &latest::MultiLocation, @@ -368,7 +369,8 @@ pub trait WrapVersion { ) -> Result, ()>; } -/// `()` implementation does nothing with the XCM, just sending with whatever version it was authored as. +/// `()` implementation does nothing with the XCM, just sending with whatever version it was +/// authored as. impl WrapVersion for () { fn wrap_version( _: &latest::MultiLocation, @@ -378,7 +380,8 @@ impl WrapVersion for () { } } -/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before wrapping it. +/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before +/// wrapping it. pub struct AlwaysV2; impl WrapVersion for AlwaysV2 { fn wrap_version( @@ -389,7 +392,8 @@ impl WrapVersion for AlwaysV2 { } } -/// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before wrapping it. +/// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before +/// wrapping it. pub struct AlwaysV3; impl WrapVersion for AlwaysV3 { fn wrap_version( diff --git a/xcm/src/v2/junction.rs b/xcm/src/v2/junction.rs index be075a31fe32..73a502999462 100644 --- a/xcm/src/v2/junction.rs +++ b/xcm/src/v2/junction.rs @@ -32,13 +32,13 @@ pub enum Junction { /// /// Generally used when the context is a Polkadot Relay-chain. Parachain(#[codec(compact)] u32), - /// A 32-byte identifier for an account of a specific network that is respected as a sovereign endpoint within - /// the context. + /// A 32-byte identifier for an account of a specific network that is respected as a sovereign + /// endpoint within the context. /// /// Generally used when the context is a Substrate-based chain. AccountId32 { network: NetworkId, id: [u8; 32] }, - /// An 8-byte index for an account of a specific network that is respected as a sovereign endpoint within - /// the context. + /// An 8-byte index for an account of a specific network that is respected as a sovereign + /// endpoint within the context. /// /// May be used when the context is a Frame-based chain and includes e.g. an indices pallet. AccountIndex64 { @@ -46,8 +46,8 @@ pub enum Junction { #[codec(compact)] index: u64, }, - /// A 20-byte identifier for an account of a specific network that is respected as a sovereign endpoint within - /// the context. + /// A 20-byte identifier for an account of a specific network that is respected as a sovereign + /// endpoint within the context. /// /// May be used when the context is an Ethereum or Bitcoin chain or smart-contract. AccountKey20 { network: NetworkId, key: [u8; 20] }, @@ -73,8 +73,8 @@ pub enum Junction { OnlyChild, /// A pluralistic body existing within consensus. /// - /// Typical to be used to represent a governance origin of a chain, but could in principle be used to represent - /// things such as multisigs also. + /// Typical to be used to represent a governance origin of a chain, but could in principle be + /// used to represent things such as multisigs also. Plurality { id: BodyId, part: BodyPart }, } diff --git a/xcm/src/v2/mod.rs b/xcm/src/v2/mod.rs index 014942d6b679..79cc8ead89a1 100644 --- a/xcm/src/v2/mod.rs +++ b/xcm/src/v2/mod.rs @@ -39,11 +39,10 @@ //! - `Order` is now obsolete and replaced entirely by `Instruction`. //! - `Xcm` is now a simple wrapper around a `Vec`. //! - During conversion from `Order` to `Instruction`, we do not handle `BuyExecution`s that have -//! nested XCMs, i.e. if the `instructions` field in the `BuyExecution` enum struct variant is -//! not empty, then the conversion will fail. To address this, rewrite the XCM using -//! `Instruction`s in chronological order. -//! - During conversion from `Xcm` to `Instruction`, we do not handle `RelayedFrom` messages at -//! all. +//! nested XCMs, i.e. if the `instructions` field in the `BuyExecution` enum struct variant is not +//! empty, then the conversion will fail. To address this, rewrite the XCM using `Instruction`s in +//! chronological order. +//! - During conversion from `Xcm` to `Instruction`, we do not handle `RelayedFrom` messages at all. //! //! ### XCM Pallet //! - The `Weigher` configuration item must have sensible weights defined for `BuyExecution` and @@ -153,20 +152,20 @@ pub enum BodyId { Executive, /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). Technical, - /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of - /// lock-voters). + /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a + /// majority of lock-voters). Legislative, - /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it - /// may be considered as that). + /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a + /// "grand oracle", it may be considered as that). Judicial, - /// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public referendum - /// on the `staking_admin` track). + /// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public + /// referendum on the `staking_admin` track). Defense, - /// The unambiguous administration body (for Polkadot, an opinion on the topic given via a public referendum - /// on the `general_admin` track). + /// The unambiguous administration body (for Polkadot, an opinion on the topic given via a + /// public referendum on the `general_admin` track). Administration, - /// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public referendum - /// on the `treasurer` track). + /// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public + /// referendum on the `treasurer` track). Treasury, } @@ -422,8 +421,8 @@ pub type Weight = u64; /// /// All messages are delivered from a known *origin*, expressed as a `MultiLocation`. /// -/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer -/// XCM format, known as `VersionedXcm`. +/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the +/// outer XCM format, known as `VersionedXcm`. #[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] @@ -508,8 +507,8 @@ pub enum Instruction { /// - `dest`: The location whose sovereign account will own the assets and thus the effective /// beneficiary for the assets and the notification target for the reserve asset deposit /// message. - /// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` - /// instruction, which is sent onwards to `dest`. + /// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which + /// is sent onwards to `dest`. /// /// Safety: No concerns. /// @@ -538,10 +537,11 @@ pub enum Instruction { call: DoubleEncoded, }, - /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the - /// relay-chain to a para. + /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by + /// the relay-chain to a para. /// - /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening. + /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel + /// opening. /// - `max_message_size`: The maximum size of a message proposed by the sender. /// - `max_capacity`: The maximum number of messages that can be queued in the channel. /// @@ -558,8 +558,8 @@ pub enum Instruction { }, /// A message to notify about that a previously sent open channel request has been accepted by - /// the recipient. That means that the channel will be opened during the next relay-chain session - /// change. This message is meant to be sent by the relay-chain to a para. + /// the recipient. That means that the channel will be opened during the next relay-chain + /// session change. This message is meant to be sent by the relay-chain to a para. /// /// Safety: The message should originate directly from the relay-chain. /// @@ -573,10 +573,10 @@ pub enum Instruction { recipient: u32, }, - /// A message to notify that the other party in an open channel decided to close it. In particular, - /// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close - /// will be enacted at the next relay-chain session change. This message is meant to be sent by - /// the relay-chain to a para. + /// A message to notify that the other party in an open channel decided to close it. In + /// particular, `initiator` is going to close the channel opened from `sender` to the + /// `recipient`. The close will be enacted at the next relay-chain session change. This message + /// is meant to be sent by the relay-chain to a para. /// /// Safety: The message should originate directly from the relay-chain. /// @@ -639,8 +639,8 @@ pub enum Instruction { /// /// - `assets`: The asset(s) to remove from holding. /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. - /// Only the first `max_assets` assets/instances of those matched by `assets` will be removed, - /// prioritized under standard asset ordering. Any others will remain in holding. + /// Only the first `max_assets` assets/instances of those matched by `assets` will be + /// removed, prioritized under standard asset ordering. Any others will remain in holding. /// - `beneficiary`: The new owner for the assets. /// /// Kind: *Instruction* @@ -661,13 +661,13 @@ pub enum Instruction { /// /// - `assets`: The asset(s) to remove from holding. /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. - /// Only the first `max_assets` assets/instances of those matched by `assets` will be removed, - /// prioritized under standard asset ordering. Any others will remain in holding. + /// Only the first `max_assets` assets/instances of those matched by `assets` will be + /// removed, prioritized under standard asset ordering. Any others will remain in holding. /// - `dest`: The location whose sovereign account will own the assets and thus the effective /// beneficiary for the assets and the notification target for the reserve asset deposit /// message. - /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction - /// which is sent onwards to `dest`. + /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is + /// sent onwards to `dest`. /// /// Kind: *Instruction* /// @@ -699,9 +699,9 @@ pub enum Instruction { /// /// - `assets`: The asset(s) to remove from holding. /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The - /// sovereign account of this consensus system *on the reserve location* will have appropriate - /// assets withdrawn and `effects` will be executed on them. There will typically be only one - /// valid location on any given asset/chain combination. + /// sovereign account of this consensus system *on the reserve location* will have + /// appropriate assets withdrawn and `effects` will be executed on them. There will typically + /// be only one valid location on any given asset/chain combination. /// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve /// location*. /// @@ -718,8 +718,8 @@ pub enum Instruction { /// - `xcm`: The instructions to execute on the assets once arrived *on the destination /// location*. /// - /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for all - /// `assets`. If it does not, then the assets may be lost. + /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for + /// all `assets`. If it does not, then the assets may be lost. /// /// Kind: *Instruction* /// diff --git a/xcm/src/v2/multiasset.rs b/xcm/src/v2/multiasset.rs index aae65dcbb54a..fdd7797a1230 100644 --- a/xcm/src/v2/multiasset.rs +++ b/xcm/src/v2/multiasset.rs @@ -17,11 +17,14 @@ //! Cross-Consensus Message format asset data structures. //! //! This encompasses four types for representing assets: -//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some amount of a fungible. -//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with fungibles first. -//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific kind. -//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding -//! account. +//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some +//! amount of a fungible. +//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with +//! fungibles first. +//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific +//! kind. +//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently +//! filtering an XCM holding account. use super::MultiLocation; use crate::v3::{ @@ -42,8 +45,8 @@ pub enum AssetInstance { /// Undefined - used if the non-fungible asset class has only one instance. Undefined, - /// A compact index. Technically this could be greater than `u128`, but this implementation supports only - /// values up to `2**128 - 1`. + /// A compact index. Technically this could be greater than `u128`, but this implementation + /// supports only values up to `2**128 - 1`. Index(#[codec(compact)] u128), /// A 4-byte fixed-length datum. @@ -165,19 +168,21 @@ impl AssetId { Ok(()) } - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `MultiAsset` value. + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding + /// `MultiAsset` value. pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset { MultiAsset { fun, id: self } } - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` - /// wildcard (`AllOf`) value. + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding + /// `WildMultiAsset` wildcard (`AllOf`) value. pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset { WildMultiAsset::AllOf { fun, id: self } } } -/// Classification of whether an asset is fungible or not, along with a mandatory amount or instance. +/// Classification of whether an asset is fungible or not, along with a mandatory amount or +/// instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum Fungibility { @@ -300,7 +305,8 @@ impl TryFrom for MultiAsset { } } -/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, they must be sorted. +/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, +/// they must be sorted. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct MultiAssets(Vec); @@ -370,11 +376,12 @@ impl MultiAssets { Self(Vec::new()) } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted and - /// which contain no duplicates. + /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. /// - /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. If you can't - /// guarantee that `r` is sorted and deduplicated, then use `From::>::from` which is infallible. + /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. + /// If you can't guarantee that `r` is sorted and deduplicated, then use + /// `From::>::from` which is infallible. pub fn from_sorted_and_deduplicated(r: Vec) -> Result { if r.is_empty() { return Ok(Self(Vec::new())) @@ -389,20 +396,22 @@ impl MultiAssets { Ok(Self(r)) } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted and - /// which contain no duplicates. + /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. /// - /// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation. - /// Generally though you should avoid using it unless you have a strict proof that `r` is valid. + /// In release mode, this skips any checks to ensure that `r` is correct, making it a + /// negligible-cost operation. Generally though you should avoid using it unless you have a + /// strict proof that `r` is valid. #[cfg(test)] pub fn from_sorted_and_deduplicated_skip_checks(r: Vec) -> Self { Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped") } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted and - /// which contain no duplicates. + /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. /// - /// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation. - /// Generally though you should avoid using it unless you have a strict proof that `r` is valid. + /// In release mode, this skips any checks to ensure that `r` is correct, making it a + /// negligible-cost operation. Generally though you should avoid using it unless you have a + /// strict proof that `r` is valid. /// /// In test mode, this checks anyway and panics on fail. #[cfg(not(test))] @@ -410,7 +419,8 @@ impl MultiAssets { Self(r) } - /// Add some asset onto the list, saturating. This is quite a laborious operation since it maintains the ordering. + /// Add some asset onto the list, saturating. This is quite a laborious operation since it + /// maintains the ordering. pub fn push(&mut self, a: MultiAsset) { if let Fungibility::Fungible(ref amount) = a.fun { for asset in self.0.iter_mut().filter(|x| x.id == a.id) { @@ -489,19 +499,19 @@ impl TryFrom for WildFungibility { #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum WildMultiAsset { - /// All assets in the holding register, up to `usize` individual assets (different instances of non-fungibles could - /// be separate assets). + /// All assets in the holding register, up to `usize` individual assets (different instances of + /// non-fungibles could be separate assets). All, - /// All assets in the holding register of a given fungibility and ID. If operating on non-fungibles, then a limit - /// is provided for the maximum amount of matching instances. + /// All assets in the holding register of a given fungibility and ID. If operating on + /// non-fungibles, then a limit is provided for the maximum amount of matching instances. AllOf { id: AssetId, fun: WildFungibility }, } impl WildMultiAsset { /// Returns true if `self` is a super-set of the given `inner`. /// - /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. - /// For more details, see the implementation and tests. + /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any + /// other non-wildcard. For more details, see the implementation and tests. pub fn contains(&self, inner: &MultiAsset) -> bool { use WildMultiAsset::*; match self { @@ -565,8 +575,8 @@ impl From for MultiAssetFilter { impl MultiAssetFilter { /// Returns true if `self` is a super-set of the given `inner`. /// - /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. - /// For more details, see the implementation and tests. + /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any + /// other non-wildcard. For more details, see the implementation and tests. pub fn contains(&self, inner: &MultiAsset) -> bool { match self { MultiAssetFilter::Definite(ref assets) => assets.contains(inner), diff --git a/xcm/src/v2/multilocation.rs b/xcm/src/v2/multilocation.rs index 086a83277322..9fb74e8afb35 100644 --- a/xcm/src/v2/multilocation.rs +++ b/xcm/src/v2/multilocation.rs @@ -174,8 +174,8 @@ impl MultiLocation { self.interior.push_front(new) } - /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with theoriginal value of - /// `self` in case of overflow. + /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with + /// theoriginal value of `self` in case of overflow. pub fn pushed_with_interior(self, new: Junction) -> result::Result { match self.interior.pushed_with(new) { Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), @@ -183,8 +183,8 @@ impl MultiLocation { } } - /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the original value of - /// `self` in case of overflow. + /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the + /// original value of `self` in case of overflow. pub fn pushed_front_with_interior( self, new: Junction, @@ -430,7 +430,8 @@ impl From for MultiLocation { } } -/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior. +/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner +/// interior. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct ParentThen(pub Junctions); impl From for MultiLocation { @@ -448,7 +449,8 @@ impl From for MultiLocation { } } -/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior. +/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the +/// inner interior. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct AncestorThen(pub u8, pub Interior); impl> From> for MultiLocation { @@ -598,8 +600,8 @@ impl Junctions { } } - /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the first element - /// (second item in tuple) or `None` if it was empty. + /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the + /// first element (second item in tuple) or `None` if it was empty. pub fn split_first(self) -> (Junctions, Option) { match self { Junctions::Here => (Junctions::Here, None), @@ -614,8 +616,8 @@ impl Junctions { } } - /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the last element - /// (second item in tuple) or `None` if it was empty. + /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the + /// last element (second item in tuple) or `None` if it was empty. pub fn split_last(self) -> (Junctions, Option) { match self { Junctions::Here => (Junctions::Here, None), @@ -727,7 +729,8 @@ impl Junctions { } } - /// Returns the junction at index `i`, or `None` if the location doesn't contain that many elements. + /// Returns the junction at index `i`, or `None` if the location doesn't contain that many + /// elements. pub fn at(&self, i: usize) -> Option<&Junction> { Some(match (i, self) { (0, Junctions::X1(ref a)) => a, @@ -770,8 +773,8 @@ impl Junctions { }) } - /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many - /// elements. + /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't + /// contain that many elements. pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { Some(match (i, self) { (0, Junctions::X1(ref mut a)) => a, diff --git a/xcm/src/v2/traits.rs b/xcm/src/v2/traits.rs index 524b659d57e1..ae03cf5547ba 100644 --- a/xcm/src/v2/traits.rs +++ b/xcm/src/v2/traits.rs @@ -81,7 +81,8 @@ pub enum Error { /// Used by `Transact` when the functor cannot be decoded. #[codec(index = 17)] FailedToDecode, - /// Used by `Transact` to indicate that the given weight limit could be breached by the functor. + /// Used by `Transact` to indicate that the given weight limit could be breached by the + /// functor. #[codec(index = 18)] MaxWeightInvalid, /// Used by `BuyExecution` when the Holding Register does not contain payable fees. @@ -94,7 +95,8 @@ pub enum Error { #[codec(index = 21)] Trap(u64), - // Errors that happen prior to instructions being executed. These fall outside of the XCM spec. + // Errors that happen prior to instructions being executed. These fall outside of the XCM + // spec. /// XCM version not able to be handled. UnhandledXcmVersion, /// Execution of the XCM would potentially result in a greater weight used than weight limit. @@ -161,7 +163,8 @@ pub type Result = result::Result<(), Error>; pub enum Outcome { /// Execution completed successfully; given weight was used. Complete(Weight), - /// Execution started, but did not complete successfully due to the given error; given weight was used. + /// Execution started, but did not complete successfully due to the given error; given weight + /// was used. Incomplete(Weight, Error), /// Execution did not start due to the given error. Error(Error), @@ -194,9 +197,9 @@ impl Outcome { /// Type of XCM message executor. pub trait ExecuteXcm { - /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is - /// a basic hard-limit and the implementation may place further restrictions or requirements on weight and - /// other aspects. + /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The + /// weight limit is a basic hard-limit and the implementation may place further restrictions or + /// requirements on weight and other aspects. fn execute_xcm( origin: impl Into, message: Xcm, @@ -215,8 +218,8 @@ pub trait ExecuteXcm { /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. /// - /// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow - /// execution without associated payment. + /// Some amount of `weight_credit` may be provided which, depending on the implementation, may + /// allow execution without associated payment. fn execute_xcm_in_credit( origin: impl Into, message: Xcm, @@ -263,9 +266,9 @@ pub type SendResult = result::Result<(), SendError>; /// Utility for sending an XCM message. /// -/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each router might return -/// `NotApplicable` to pass the execution to the next sender item. Note that each `NotApplicable` -/// might alter the destination and the XCM message for to the next router. +/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each +/// router might return `NotApplicable` to pass the execution to the next sender item. Note that +/// each `NotApplicable` might alter the destination and the XCM message for to the next router. /// /// /// # Example @@ -330,9 +333,9 @@ pub type SendResult = result::Result<(), SendError>; pub trait SendXcm { /// Send an XCM `message` to a given `destination`. /// - /// If it is not a destination which can be reached with this type but possibly could by others, then it *MUST* - /// return `NotApplicable`. Any other error will cause the tuple implementation to exit early without - /// trying other type fields. + /// If it is not a destination which can be reached with this type but possibly could by others, + /// then it *MUST* return `NotApplicable`. Any other error will cause the tuple implementation + /// to exit early without trying other type fields. fn send_xcm(destination: impl Into, message: Xcm<()>) -> SendResult; } diff --git a/xcm/src/v3/junction.rs b/xcm/src/v3/junction.rs index 5fee8d1f83bd..ae66e2b33364 100644 --- a/xcm/src/v3/junction.rs +++ b/xcm/src/v3/junction.rs @@ -127,20 +127,20 @@ pub enum BodyId { Executive, /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). Technical, - /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of - /// lock-voters). + /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a + /// majority of lock-voters). Legislative, - /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it - /// may be considered as that). + /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a + /// "grand oracle", it may be considered as that). Judicial, - /// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public referendum - /// on the `staking_admin` track). + /// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public + /// referendum on the `staking_admin` track). Defense, - /// The unambiguous administration body (for Polkadot, an opinion on the topic given via a public referendum - /// on the `general_admin` track). + /// The unambiguous administration body (for Polkadot, an opinion on the topic given via a + /// public referendum on the `general_admin` track). Administration, - /// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public referendum - /// on the `treasurer` track). + /// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public + /// referendum on the `treasurer` track). Treasury, } @@ -266,13 +266,13 @@ pub enum Junction { /// /// Generally used when the context is a Polkadot Relay-chain. Parachain(#[codec(compact)] u32), - /// A 32-byte identifier for an account of a specific network that is respected as a sovereign endpoint within - /// the context. + /// A 32-byte identifier for an account of a specific network that is respected as a sovereign + /// endpoint within the context. /// /// Generally used when the context is a Substrate-based chain. AccountId32 { network: Option, id: [u8; 32] }, - /// An 8-byte index for an account of a specific network that is respected as a sovereign endpoint within - /// the context. + /// An 8-byte index for an account of a specific network that is respected as a sovereign + /// endpoint within the context. /// /// May be used when the context is a Frame-based chain and includes e.g. an indices pallet. AccountIndex64 { @@ -280,8 +280,8 @@ pub enum Junction { #[codec(compact)] index: u64, }, - /// A 20-byte identifier for an account of a specific network that is respected as a sovereign endpoint within - /// the context. + /// A 20-byte identifier for an account of a specific network that is respected as a sovereign + /// endpoint within the context. /// /// May be used when the context is an Ethereum or Bitcoin chain or smart-contract. AccountKey20 { network: Option, key: [u8; 20] }, @@ -310,8 +310,8 @@ pub enum Junction { OnlyChild, /// A pluralistic body existing within consensus. /// - /// Typical to be used to represent a governance origin of a chain, but could in principle be used to represent - /// things such as multisigs also. + /// Typical to be used to represent a governance origin of a chain, but could in principle be + /// used to represent things such as multisigs also. Plurality { id: BodyId, part: BodyPart }, /// A global network capable of externalizing its own consensus. This is not generally /// meaningful outside of the universal level. @@ -413,7 +413,8 @@ impl Junction { /// Convert `self` into a `MultiLocation` containing `n` parents. /// - /// Similar to `Self::into_location`, with the added ability to specify the number of parent junctions. + /// Similar to `Self::into_location`, with the added ability to specify the number of parent + /// junctions. pub const fn into_exterior(self, n: u8) -> MultiLocation { MultiLocation { parents: n, interior: Junctions::X1(self) } } diff --git a/xcm/src/v3/junctions.rs b/xcm/src/v3/junctions.rs index da06cdbdad67..201a80fb7658 100644 --- a/xcm/src/v3/junctions.rs +++ b/xcm/src/v3/junctions.rs @@ -137,7 +137,8 @@ impl Junctions { /// Convert `self` into a `MultiLocation` containing `n` parents. /// - /// Similar to `Self::into_location`, with the added ability to specify the number of parent junctions. + /// Similar to `Self::into_location`, with the added ability to specify the number of parent + /// junctions. pub const fn into_exterior(self, n: u8) -> MultiLocation { MultiLocation { parents: n, interior: self } } @@ -309,8 +310,8 @@ impl Junctions { } } - /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the first element - /// (second item in tuple) or `None` if it was empty. + /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the + /// first element (second item in tuple) or `None` if it was empty. pub fn split_first(self) -> (Junctions, Option) { match self { Junctions::Here => (Junctions::Here, None), @@ -325,8 +326,8 @@ impl Junctions { } } - /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the last element - /// (second item in tuple) or `None` if it was empty. + /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the + /// last element (second item in tuple) or `None` if it was empty. pub fn split_last(self) -> (Junctions, Option) { match self { Junctions::Here => (Junctions::Here, None), @@ -469,7 +470,8 @@ impl Junctions { } } - /// Returns the junction at index `i`, or `None` if the location doesn't contain that many elements. + /// Returns the junction at index `i`, or `None` if the location doesn't contain that many + /// elements. pub fn at(&self, i: usize) -> Option<&Junction> { Some(match (i, self) { (0, Junctions::X1(ref a)) => a, @@ -512,8 +514,8 @@ impl Junctions { }) } - /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many - /// elements. + /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't + /// contain that many elements. pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { Some(match (i, self) { (0, Junctions::X1(ref mut a)) => a, diff --git a/xcm/src/v3/mod.rs b/xcm/src/v3/mod.rs index 772ad48ac4b2..3614dc22550d 100644 --- a/xcm/src/v3/mod.rs +++ b/xcm/src/v3/mod.rs @@ -367,8 +367,8 @@ impl XcmContext { /// /// All messages are delivered from a known *origin*, expressed as a `MultiLocation`. /// -/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer -/// XCM format, known as `VersionedXcm`. +/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the +/// outer XCM format, known as `VersionedXcm`. #[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] @@ -417,9 +417,8 @@ pub enum Instruction { /// - `response`: The message content. /// - `max_weight`: The maximum weight that handling this response should take. /// - `querier`: The location responsible for the initiation of the response, if there is one. - /// In general this will tend to be the same location as the receiver of this message. - /// NOTE: As usual, this is interpreted from the perspective of the receiving consensus - /// system. + /// In general this will tend to be the same location as the receiver of this message. NOTE: + /// As usual, this is interpreted from the perspective of the receiving consensus system. /// /// Safety: Since this is information only, there are no immediate concerns. However, it should /// be remembered that even if the Origin behaves reasonably, it can always be asked to make @@ -460,8 +459,8 @@ pub enum Instruction { /// - `dest`: The location whose sovereign account will own the assets and thus the effective /// beneficiary for the assets and the notification target for the reserve asset deposit /// message. - /// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` - /// instruction, which is sent onwards to `dest`. + /// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which + /// is sent onwards to `dest`. /// /// Safety: No concerns. /// @@ -487,10 +486,11 @@ pub enum Instruction { /// Errors: Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded }, - /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the - /// relay-chain to a para. + /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by + /// the relay-chain to a para. /// - /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening. + /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel + /// opening. /// - `max_message_size`: The maximum size of a message proposed by the sender. /// - `max_capacity`: The maximum number of messages that can be queued in the channel. /// @@ -507,8 +507,8 @@ pub enum Instruction { }, /// A message to notify about that a previously sent open channel request has been accepted by - /// the recipient. That means that the channel will be opened during the next relay-chain session - /// change. This message is meant to be sent by the relay-chain to a para. + /// the recipient. That means that the channel will be opened during the next relay-chain + /// session change. This message is meant to be sent by the relay-chain to a para. /// /// Safety: The message should originate directly from the relay-chain. /// @@ -522,10 +522,10 @@ pub enum Instruction { recipient: u32, }, - /// A message to notify that the other party in an open channel decided to close it. In particular, - /// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close - /// will be enacted at the next relay-chain session change. This message is meant to be sent by - /// the relay-chain to a para. + /// A message to notify that the other party in an open channel decided to close it. In + /// particular, `initiator` is going to close the channel opened from `sender` to the + /// `recipient`. The close will be enacted at the next relay-chain session change. This message + /// is meant to be sent by the relay-chain to a para. /// /// Safety: The message should originate directly from the relay-chain. /// @@ -593,8 +593,8 @@ pub enum Instruction { /// - `dest`: The location whose sovereign account will own the assets and thus the effective /// beneficiary for the assets and the notification target for the reserve asset deposit /// message. - /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction - /// which is sent onwards to `dest`. + /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is + /// sent onwards to `dest`. /// /// Kind: *Instruction* /// @@ -623,9 +623,9 @@ pub enum Instruction { /// /// - `assets`: The asset(s) to remove from holding. /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The - /// sovereign account of this consensus system *on the reserve location* will have appropriate - /// assets withdrawn and `effects` will be executed on them. There will typically be only one - /// valid location on any given asset/chain combination. + /// sovereign account of this consensus system *on the reserve location* will have + /// appropriate assets withdrawn and `effects` will be executed on them. There will typically + /// be only one valid location on any given asset/chain combination. /// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve /// location*. /// @@ -642,8 +642,8 @@ pub enum Instruction { /// - `xcm`: The instructions to execute on the assets once arrived *on the destination /// location*. /// - /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for all - /// `assets`. If it does not, then the assets may be lost. + /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for + /// all `assets`. If it does not, then the assets may be lost. /// /// Kind: *Instruction* /// @@ -809,7 +809,8 @@ pub enum Instruction { /// Kind: *Instruction* /// /// Errors: - /// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the parameter. + /// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the + /// parameter. ExpectTransactStatus(MaybeErrorCode), /// Query the existence of a particular pallet type. @@ -830,11 +831,15 @@ pub enum Instruction { /// Ensure that a particular pallet with a particular version exists. /// - /// - `index: Compact`: The index which identifies the pallet. An error if no pallet exists at this index. + /// - `index: Compact`: The index which identifies the pallet. An error if no pallet exists at + /// this index. /// - `name: Vec`: Name which must be equal to the name of the pallet. - /// - `module_name: Vec`: Module name which must be equal to the name of the module in which the pallet exists. - /// - `crate_major: Compact`: Version number which must be equal to the major version of the crate which implements the pallet. - /// - `min_crate_minor: Compact`: Version number which must be at most the minor version of the crate which implements the pallet. + /// - `module_name: Vec`: Module name which must be equal to the name of the module in + /// which the pallet exists. + /// - `crate_major: Compact`: Version number which must be equal to the major version of the + /// crate which implements the pallet. + /// - `min_crate_minor: Compact`: Version number which must be at most the minor version of the + /// crate which implements the pallet. /// /// Safety: No concerns. /// @@ -961,8 +966,8 @@ pub enum Instruction { /// of course, if there is no record that the asset actually is locked. /// /// - `asset`: The asset(s) to be unlocked. - /// - `locker`: The location from which a previous `NoteUnlockable` was sent and to which - /// an `UnlockAsset` should be sent. + /// - `locker`: The location from which a previous `NoteUnlockable` was sent and to which an + /// `UnlockAsset` should be sent. /// /// Kind: *Instruction*. /// @@ -971,8 +976,8 @@ pub enum Instruction { /// Sets the Fees Mode Register. /// - /// - `jit_withdraw`: The fees mode item; if set to `true` then fees for any instructions - /// are withdrawn as needed using the same mechanism as `WithdrawAssets`. + /// - `jit_withdraw`: The fees mode item; if set to `true` then fees for any instructions are + /// withdrawn as needed using the same mechanism as `WithdrawAssets`. /// /// Kind: *Instruction*. /// diff --git a/xcm/src/v3/multiasset.rs b/xcm/src/v3/multiasset.rs index a4900a71539a..1668d1b870dc 100644 --- a/xcm/src/v3/multiasset.rs +++ b/xcm/src/v3/multiasset.rs @@ -17,11 +17,14 @@ //! Cross-Consensus Message format asset data structures. //! //! This encompasses four types for representing assets: -//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some amount of a fungible. -//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with fungibles first. -//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific kind. -//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding -//! account. +//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some +//! amount of a fungible. +//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with +//! fungibles first. +//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific +//! kind. +//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently +//! filtering an XCM holding account. use super::{InteriorMultiLocation, MultiLocation}; use crate::v2::{ @@ -47,8 +50,8 @@ pub enum AssetInstance { /// Undefined - used if the non-fungible asset class has only one instance. Undefined, - /// A compact index. Technically this could be greater than `u128`, but this implementation supports only - /// values up to `2**128 - 1`. + /// A compact index. Technically this could be greater than `u128`, but this implementation + /// supports only values up to `2**128 - 1`. Index(#[codec(compact)] u128), /// A 4-byte fixed-length datum. @@ -234,7 +237,8 @@ impl TryFrom for u128 { } } -/// Classification of whether an asset is fungible or not, along with a mandatory amount or instance. +/// Classification of whether an asset is fungible or not, along with a mandatory amount or +/// instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum Fungibility { @@ -387,13 +391,14 @@ impl AssetId { Ok(()) } - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `MultiAsset` value. + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding + /// `MultiAsset` value. pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset { MultiAsset { fun, id: self } } - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` - /// wildcard (`AllOf`) value. + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding + /// `WildMultiAsset` wildcard (`AllOf`) value. pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset { WildMultiAsset::AllOf { fun, id: self } } @@ -576,11 +581,12 @@ impl MultiAssets { Self(Vec::new()) } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted and - /// which contain no duplicates. + /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. /// - /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. If you can't - /// guarantee that `r` is sorted and deduplicated, then use `From::>::from` which is infallible. + /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. + /// If you can't guarantee that `r` is sorted and deduplicated, then use + /// `From::>::from` which is infallible. pub fn from_sorted_and_deduplicated(r: Vec) -> Result { if r.is_empty() { return Ok(Self(Vec::new())) @@ -595,20 +601,22 @@ impl MultiAssets { Ok(Self(r)) } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted and - /// which contain no duplicates. + /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. /// - /// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation. - /// Generally though you should avoid using it unless you have a strict proof that `r` is valid. + /// In release mode, this skips any checks to ensure that `r` is correct, making it a + /// negligible-cost operation. Generally though you should avoid using it unless you have a + /// strict proof that `r` is valid. #[cfg(test)] pub fn from_sorted_and_deduplicated_skip_checks(r: Vec) -> Self { Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped") } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted and - /// which contain no duplicates. + /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. /// - /// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation. - /// Generally though you should avoid using it unless you have a strict proof that `r` is valid. + /// In release mode, this skips any checks to ensure that `r` is correct, making it a + /// negligible-cost operation. Generally though you should avoid using it unless you have a + /// strict proof that `r` is valid. /// /// In test mode, this checks anyway and panics on fail. #[cfg(not(test))] @@ -616,7 +624,8 @@ impl MultiAssets { Self(r) } - /// Add some asset onto the list, saturating. This is quite a laborious operation since it maintains the ordering. + /// Add some asset onto the list, saturating. This is quite a laborious operation since it + /// maintains the ordering. pub fn push(&mut self, a: MultiAsset) { for asset in self.0.iter_mut().filter(|x| x.id == a.id) { match (&a.fun, &mut asset.fun) { diff --git a/xcm/src/v3/multilocation.rs b/xcm/src/v3/multilocation.rs index 09d547503f1c..07f829d014c0 100644 --- a/xcm/src/v3/multilocation.rs +++ b/xcm/src/v3/multilocation.rs @@ -198,8 +198,8 @@ impl MultiLocation { self.interior.push_front(new) } - /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with theoriginal value of - /// `self` in case of overflow. + /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with + /// theoriginal value of `self` in case of overflow. pub fn pushed_with_interior( self, new: impl Into, @@ -210,8 +210,8 @@ impl MultiLocation { } } - /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the original value of - /// `self` in case of overflow. + /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the + /// original value of `self` in case of overflow. pub fn pushed_front_with_interior( self, new: impl Into, @@ -472,7 +472,8 @@ impl From for MultiLocation { } } -/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior. +/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner +/// interior. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct ParentThen(pub Junctions); impl From for MultiLocation { @@ -490,7 +491,8 @@ impl From for MultiLocation { } } -/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior. +/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the +/// inner interior. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct AncestorThen(pub u8, pub Interior); impl> From> for MultiLocation { diff --git a/xcm/src/v3/traits.rs b/xcm/src/v3/traits.rs index 966fb724ed11..128be42c2a2b 100644 --- a/xcm/src/v3/traits.rs +++ b/xcm/src/v3/traits.rs @@ -86,7 +86,8 @@ pub enum Error { /// Used by `Transact` when the functor cannot be decoded. #[codec(index = 17)] FailedToDecode, - /// Used by `Transact` to indicate that the given weight limit could be breached by the functor. + /// Used by `Transact` to indicate that the given weight limit could be breached by the + /// functor. #[codec(index = 18)] MaxWeightInvalid, /// Used by `BuyExecution` when the Holding Register does not contain payable fees. @@ -138,7 +139,8 @@ pub enum Error { #[codec(index = 34)] NotDepositable, - // Errors that happen prior to instructions being executed. These fall outside of the XCM spec. + // Errors that happen prior to instructions being executed. These fall outside of the XCM + // spec. /// XCM version not able to be handled. UnhandledXcmVersion, /// Execution of the XCM would potentially result in a greater weight used than weight limit. @@ -263,7 +265,8 @@ impl From for Outcome { pub enum Outcome { /// Execution completed successfully; given weight was used. Complete(Weight), - /// Execution started, but did not complete successfully due to the given error; given weight was used. + /// Execution started, but did not complete successfully due to the given error; given weight + /// was used. Incomplete(Weight, Error), /// Execution did not start due to the given error. Error(Error), diff --git a/xcm/xcm-builder/src/asset_conversion.rs b/xcm/xcm-builder/src/asset_conversion.rs index 583231d792dd..2fe26e8cd1e3 100644 --- a/xcm/xcm-builder/src/asset_conversion.rs +++ b/xcm/xcm-builder/src/asset_conversion.rs @@ -22,9 +22,9 @@ use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; use xcm_executor::traits::{Error as MatchError, MatchesFungibles, MatchesNonFungibles}; -/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be `TryFrom/TryInto`) into -/// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a -/// `PalletInstance` junction. +/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be +/// `TryFrom/TryInto`) into a `GeneralIndex` junction, prefixed by some `MultiLocation` value. +/// The `MultiLocation` value will typically be a `PalletInstance` junction. pub struct AsPrefixedGeneralIndex( PhantomData<(Prefix, AssetId, ConvertAssetId)>, ); diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index 32db840858a9..4dbd4fe8bcd0 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -44,8 +44,8 @@ impl From for XcmError { } } -/// Simple adapter to use a currency as asset transactor. This type can be used as `type AssetTransactor` in -/// `xcm::Config`. +/// Simple adapter to use a currency as asset transactor. This type can be used as `type +/// AssetTransactor` in `xcm::Config`. /// /// # Example /// ``` diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index bcb0e9c870b3..d7fded01e2db 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -63,8 +63,8 @@ impl< /// The location which is allowed to mint a particular asset. #[derive(Copy, Clone, Eq, PartialEq)] pub enum MintLocation { - /// This chain is allowed to mint the asset. When we track teleports of the asset we ensure that - /// no more of the asset returns back to the chain than has been sent out. + /// This chain is allowed to mint the asset. When we track teleports of the asset we ensure + /// that no more of the asset returns back to the chain than has been sent out. Local, /// This chain is not allowed to mint the asset. When we track teleports of the asset we ensure /// that no more of the asset is sent out from the chain than has been previously received. diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index ccc3cc040e61..26b48fc88adc 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -345,10 +345,11 @@ impl>, AccountId: From<[u8; 20]> + Into<[u8; 20]> } } -/// Converts a location which is a top-level relay chain (which provides its own consensus) into a 32-byte `AccountId`. +/// Converts a location which is a top-level relay chain (which provides its own consensus) into a +/// 32-byte `AccountId`. /// -/// This will always result in the *same account ID* being returned for the same Relay-chain, regardless of the relative security of -/// this Relay-chain compared to the local chain. +/// This will always result in the *same account ID* being returned for the same Relay-chain, +/// regardless of the relative security of this Relay-chain compared to the local chain. /// /// Note: No distinction is made between the cases when the given `UniversalLocation` lies within /// the same consensus system (i.e. is itself or a parent) and when it is a foreign consensus diff --git a/xcm/xcm-builder/src/origin_aliases.rs b/xcm/xcm-builder/src/origin_aliases.rs index 12bcdad3dfea..82c5f71b7a12 100644 --- a/xcm/xcm-builder/src/origin_aliases.rs +++ b/xcm/xcm-builder/src/origin_aliases.rs @@ -20,7 +20,8 @@ use frame_support::traits::{Contains, ContainsPair}; use sp_std::marker::PhantomData; use xcm::latest::prelude::*; -/// Alias a Foreign `AccountId32` with a local `AccountId32` if the foreign `AccountId32` matches the `Prefix` pattern. +/// Alias a Foreign `AccountId32` with a local `AccountId32` if the foreign `AccountId32` matches +/// the `Prefix` pattern. /// /// Requires that the prefixed origin `AccountId32` matches the target `AccountId32`. pub struct AliasForeignAccountId32(PhantomData); diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 0810b1ce2f8b..112b26869a99 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -24,7 +24,8 @@ use sp_std::marker::PhantomData; use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, MultiLocation, NetworkId, OriginKind}; use xcm_executor::traits::{ConvertLocation, ConvertOrigin}; -/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the `LocationConverter`. +/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the +/// `LocationConverter`. pub struct SovereignSignedViaLocation( PhantomData<(LocationConverter, RuntimeOrigin)>, ); @@ -269,10 +270,11 @@ where } } -/// `Convert` implementation to convert from some a `Signed` (system) `Origin` into an `AccountId32`. +/// `Convert` implementation to convert from some a `Signed` (system) `Origin` into an +/// `AccountId32`. /// -/// Typically used when configuring `pallet-xcm` for allowing normal accounts to dispatch an XCM from an `AccountId32` -/// origin. +/// Typically used when configuring `pallet-xcm` for allowing normal accounts to dispatch an XCM +/// from an `AccountId32` origin. pub struct SignedToAccountId32( PhantomData<(RuntimeOrigin, AccountId, Network)>, ); @@ -296,11 +298,11 @@ where } } -/// `Convert` implementation to convert from some an origin which implements `Backing` into a corresponding `Plurality` -/// `MultiLocation`. +/// `Convert` implementation to convert from some an origin which implements `Backing` into a +/// corresponding `Plurality` `MultiLocation`. /// -/// Typically used when configuring `pallet-xcm` for allowing a collective's Origin to dispatch an XCM from a -/// `Plurality` origin. +/// Typically used when configuring `pallet-xcm` for allowing a collective's Origin to dispatch an +/// XCM from a `Plurality` origin. pub struct BackingToPlurality( PhantomData<(RuntimeOrigin, COrigin, Body)>, ); diff --git a/xcm/xcm-builder/src/tests/assets.rs b/xcm/xcm-builder/src/tests/assets.rs index 9b8ba0e459de..dbcb731a1bda 100644 --- a/xcm/xcm-builder/src/tests/assets.rs +++ b/xcm/xcm-builder/src/tests/assets.rs @@ -396,7 +396,8 @@ fn max_assets_limit_should_work() { ); assert_eq!(r, Outcome::Incomplete(Weight::from_parts(95, 95), XcmError::HoldingWouldOverflow)); - // Attempt to withdraw 4 different assets and then the same 4 and then a different 4 will succeed. + // Attempt to withdraw 4 different assets and then the same 4 and then a different 4 will + // succeed. let message = Xcm(vec![ WithdrawAsset(([1u8; 32], 100u128).into()), WithdrawAsset(([2u8; 32], 100u128).into()), diff --git a/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs b/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 2f9bfcc2d80a..6870413c38d5 100644 --- a/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs +++ b/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs @@ -80,7 +80,8 @@ fn sending_to_bridged_chain_works() { )]; assert_eq!(take_received_remote_messages(), expected); - // The export cost 50 ref time and 50 proof size weight units (and thus 100 units of balance). + // The export cost 50 ref time and 50 proof size weight units (and thus 100 units of + // balance). assert_eq!(asset_list(Parachain(100)), vec![(Here, 1000u128 - price).into()]); let entry = LogEntry { @@ -154,7 +155,8 @@ fn sending_to_parachain_of_bridged_chain_works() { )]; assert_eq!(take_received_remote_messages(), expected); - // The export cost 50 ref time and 50 proof size weight units (and thus 100 units of balance). + // The export cost 50 ref time and 50 proof size weight units (and thus 100 units of + // balance). assert_eq!(asset_list(Parachain(100)), vec![(Here, 1000u128 - price).into()]); let entry = LogEntry { diff --git a/xcm/xcm-builder/src/tests/mock.rs b/xcm/xcm-builder/src/tests/mock.rs index 66a676369a67..aea780b84367 100644 --- a/xcm/xcm-builder/src/tests/mock.rs +++ b/xcm/xcm-builder/src/tests/mock.rs @@ -60,8 +60,8 @@ pub enum TestOrigin { /// A dummy call. /// -/// Each item contains the amount of weight that it *wants* to consume as the first item, and the actual amount (if -/// different from the former) in the second option. +/// Each item contains the amount of weight that it *wants* to consume as the first item, and the +/// actual amount (if different from the former) in the second option. #[derive(Debug, Encode, Decode, Eq, PartialEq, Clone, Copy, scale_info::TypeInfo)] pub enum TestCall { OnlyRoot(Weight, Option), diff --git a/xcm/xcm-builder/src/tests/querying.rs b/xcm/xcm-builder/src/tests/querying.rs index be8edfe87b8d..8fbb55eb2542 100644 --- a/xcm/xcm-builder/src/tests/querying.rs +++ b/xcm/xcm-builder/src/tests/querying.rs @@ -95,7 +95,8 @@ fn pallet_query_with_results_should_work() { #[test] fn prepaid_result_of_query_should_get_free_execution() { let query_id = 33; - // We put this in manually here, but normally this would be done at the point of crafting the message. + // We put this in manually here, but normally this would be done at the point of crafting the + // message. expect_response(query_id, Parent.into()); let the_response = Response::Assets((Parent, 100u128).into()); diff --git a/xcm/xcm-builder/src/universal_exports.rs b/xcm/xcm-builder/src/universal_exports.rs index 9a65ec7dfe40..0ee627e0ee90 100644 --- a/xcm/xcm-builder/src/universal_exports.rs +++ b/xcm/xcm-builder/src/universal_exports.rs @@ -300,7 +300,8 @@ pub trait HaulBlob { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum HaulBlobError { - /// Represents point-to-point link failure with a human-readable explanation of the specific issue is provided. + /// Represents point-to-point link failure with a human-readable explanation of the specific + /// issue is provided. Transport(&'static str), } @@ -361,8 +362,9 @@ impl< message.try_into().map_err(|_| DispatchBlobError::UnsupportedXcmVersion)?; // Prepend our bridge instance discriminator. - // Can be used for fine-grained control of origin on destination in case of multiple bridge instances, - // e.g. restrict `type UniversalAliases` and `UniversalOrigin` instruction to trust just particular bridge instance for `NetworkId`. + // Can be used for fine-grained control of origin on destination in case of multiple bridge + // instances, e.g. restrict `type UniversalAliases` and `UniversalOrigin` instruction to + // trust just particular bridge instance for `NetworkId`. if let Some(bridge_instance) = OurPlaceBridgeInstance::get() { message.0.insert(0, DescendOrigin(bridge_instance)); } diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 73cba6cb557b..f1c14a4c6517 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -114,8 +114,9 @@ where } } -/// Function trait for handling some revenue. Similar to a negative imbalance (credit) handler, but for a -/// `MultiAsset`. Sensible implementations will deposit the asset in some known treasury or block-author account. +/// Function trait for handling some revenue. Similar to a negative imbalance (credit) handler, but +/// for a `MultiAsset`. Sensible implementations will deposit the asset in some known treasury or +/// block-author account. pub trait TakeRevenue { /// Do something with the given `revenue`, which is a single non-wildcard `MultiAsset`. fn take_revenue(revenue: MultiAsset); diff --git a/xcm/xcm-builder/tests/scenarios.rs b/xcm/xcm-builder/tests/scenarios.rs index e587c4118e74..3e735720aa76 100644 --- a/xcm/xcm-builder/tests/scenarios.rs +++ b/xcm/xcm-builder/tests/scenarios.rs @@ -101,8 +101,8 @@ fn transfer_asset_works() { /// A parachain wants to be notified that a transfer worked correctly. /// It includes a `QueryHolding` order after the deposit to get notified on success. /// This somewhat abuses `QueryHolding` as an indication of execution success. It works because -/// order execution halts on error (so no `QueryResponse` will be sent if the previous order failed). -/// The inner response sent due to the query is not used. +/// order execution halts on error (so no `QueryResponse` will be sent if the previous order +/// failed). The inner response sent due to the query is not used. /// /// Asserts that the balances are updated correctly and the expected XCM is sent. #[test] diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index f5e0659931eb..d8d8936df331 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -132,15 +132,17 @@ impl Assets { /// Mutate `self` to contain all given `assets`, saturating if necessary. /// - /// NOTE: [`Assets`] are always sorted, allowing us to optimize this function from `O(n^2)` to `O(n)`. + /// NOTE: [`Assets`] are always sorted, allowing us to optimize this function from `O(n^2)` to + /// `O(n)`. pub fn subsume_assets(&mut self, mut assets: Assets) { let mut f_iter = assets.fungible.iter_mut(); let mut g_iter = self.fungible.iter_mut(); if let (Some(mut f), Some(mut g)) = (f_iter.next(), g_iter.next()) { loop { if f.0 == g.0 { - // keys are equal. in this case, we add `self`'s balance for the asset onto `assets`, balance, knowing - // that the `append` operation which follows will clobber `self`'s value and only use `assets`'s. + // keys are equal. in this case, we add `self`'s balance for the asset onto + // `assets`, balance, knowing that the `append` operation which follows will + // clobber `self`'s value and only use `assets`'s. (*f.1).saturating_accrue(*g.1); } if f.0 <= g.0 { @@ -186,8 +188,9 @@ impl Assets { /// Alter any concretely identified assets by prepending the given `MultiLocation`. /// - /// WARNING: For now we consider this infallible and swallow any errors. It is thus the caller's responsibility to - /// ensure that any internal asset IDs are able to be prepended without overflow. + /// WARNING: For now we consider this infallible and swallow any errors. It is thus the caller's + /// responsibility to ensure that any internal asset IDs are able to be prepended without + /// overflow. pub fn prepend_location(&mut self, prepend: &MultiLocation) { let mut fungible = Default::default(); mem::swap(&mut self.fungible, &mut fungible); @@ -269,8 +272,8 @@ impl Assets { self.non_fungible.is_superset(&assets.non_fungible) } - /// Returns an error unless all `assets` are contained in `self`. In the case of an error, the first asset in - /// `assets` which is not wholly in `self` is returned. + /// Returns an error unless all `assets` are contained in `self`. In the case of an error, the + /// first asset in `assets` which is not wholly in `self` is returned. pub fn ensure_contains(&self, assets: &MultiAssets) -> Result<(), TakeError> { for asset in assets.inner().iter() { match asset { @@ -292,16 +295,17 @@ impl Assets { /// Mutates `self` to its original value less `mask` and returns assets that were removed. /// - /// If `saturate` is `true`, then `self` is considered to be masked by `mask`, thereby avoiding any attempt at - /// reducing it by assets it does not contain. In this case, the function is infallible. If `saturate` is `false` - /// and `mask` references a definite asset which `self` does not contain then an error is returned. + /// If `saturate` is `true`, then `self` is considered to be masked by `mask`, thereby avoiding + /// any attempt at reducing it by assets it does not contain. In this case, the function is + /// infallible. If `saturate` is `false` and `mask` references a definite asset which `self` + /// does not contain then an error is returned. /// /// The number of unique assets which are removed will respect the `count` parameter in the /// counted wildcard variants. /// - /// Returns `Ok` with the definite assets token from `self` and mutates `self` to its value minus - /// `mask`. Returns `Err` in the non-saturating case where `self` did not contain (enough of) a definite asset to - /// be removed. + /// Returns `Ok` with the definite assets token from `self` and mutates `self` to its value + /// minus `mask`. Returns `Err` in the non-saturating case where `self` did not contain (enough + /// of) a definite asset to be removed. fn general_take( &mut self, mask: MultiAssetFilter, @@ -386,24 +390,27 @@ impl Assets { Ok(taken) } - /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least `mask`. + /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least + /// `mask`. /// - /// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its value minus - /// `mask` if `self` contains `asset`, and return `Err` otherwise. + /// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its + /// value minus `mask` if `self` contains `asset`, and return `Err` otherwise. pub fn saturating_take(&mut self, asset: MultiAssetFilter) -> Assets { self.general_take(asset, true) .expect("general_take never results in error when saturating") } - /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least `mask`. + /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least + /// `mask`. /// - /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus - /// `asset` if `self` contains `asset`, and return `Err` otherwise. + /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its + /// value minus `asset` if `self` contains `asset`, and return `Err` otherwise. pub fn try_take(&mut self, mask: MultiAssetFilter) -> Result { self.general_take(mask, false) } - /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`. + /// Consumes `self` and returns its original value excluding `asset` iff it contains at least + /// `asset`. pub fn checked_sub(mut self, asset: MultiAsset) -> Result { match asset.fun { Fungible(amount) => { diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 57ddc4322923..a48cd3259d67 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -356,7 +356,8 @@ impl XcmExecutor { } /// Execute any final operations after having executed the XCM message. - /// This includes refunding surplus weight, trapping extra holding funds, and returning any errors during execution. + /// This includes refunding surplus weight, trapping extra holding funds, and returning any + /// errors during execution. pub fn post_process(mut self, xcm_weight: Weight) -> Outcome { // We silently drop any error from our attempt to refund the surplus as it's a charitable // thing so best-effort is all we will do. @@ -533,9 +534,10 @@ impl XcmExecutor { Config::IsTeleporter::contains(asset, &origin), XcmError::UntrustedTeleportLocation ); - // We should check that the asset can actually be teleported in (for this to be in error, there - // would need to be an accounting violation by one of the trusted chains, so it's unlikely, but we - // don't want to punish a possibly innocent chain/user). + // We should check that the asset can actually be teleported in (for this to be + // in error, there would need to be an accounting violation by one of the + // trusted chains, so it's unlikely, but we don't want to punish a possibly + // innocent chain/user). Config::AssetTransactor::can_check_in(&origin, asset, &self.context)?; } for asset in assets.into_inner().into_iter() { @@ -603,8 +605,8 @@ impl XcmExecutor { Ok(()) }, ReportError(response_info) => { - // Report the given result by sending a QueryResponse XCM to a previously given outcome - // destination if one was registered. + // Report the given result by sending a QueryResponse XCM to a previously given + // outcome destination if one was registered. self.respond( self.cloned_origin(), Response::ExecutionResult(self.error), @@ -823,10 +825,12 @@ impl XcmExecutor { Ok(()) }, ExportMessage { network, destination, xcm } => { - // The actual message sent to the bridge for forwarding is prepended with `UniversalOrigin` - // and `DescendOrigin` in order to ensure that the message is executed with this Origin. + // The actual message sent to the bridge for forwarding is prepended with + // `UniversalOrigin` and `DescendOrigin` in order to ensure that the message is + // executed with this Origin. // - // Prepend the desired message with instructions which effectively rewrite the origin. + // Prepend the desired message with instructions which effectively rewrite the + // origin. // // This only works because the remote chain empowers the bridge // to speak for the local network. diff --git a/xcm/xcm-executor/src/traits/asset_exchange.rs b/xcm/xcm-executor/src/traits/asset_exchange.rs index 465468992ae4..0cb188d348de 100644 --- a/xcm/xcm-executor/src/traits/asset_exchange.rs +++ b/xcm/xcm-executor/src/traits/asset_exchange.rs @@ -24,8 +24,8 @@ pub trait AssetExchange { /// - `origin`: The location attempting the exchange; this should generally not matter. /// - `give`: The assets which have been removed from the caller. /// - `want`: The minimum amount of assets which should be given to the caller in case any - /// exchange happens. If more assets are provided, then they should generally be of the - /// same asset class if at all possible. + /// exchange happens. If more assets are provided, then they should generally be of the same + /// asset class if at all possible. /// - `maximal`: If `true`, then as much as possible should be exchanged. /// /// `Ok` is returned along with the new set of assets which have been exchanged for `give`. At diff --git a/xcm/xcm-executor/src/traits/asset_lock.rs b/xcm/xcm-executor/src/traits/asset_lock.rs index bb19e90b0c36..b5a2b22f5fc5 100644 --- a/xcm/xcm-executor/src/traits/asset_lock.rs +++ b/xcm/xcm-executor/src/traits/asset_lock.rs @@ -69,8 +69,8 @@ pub trait AssetLock { /// unlock. type UnlockTicket: Enact; - /// `Enact` implementer for `prepare_reduce_unlockable`. This type may be dropped safely to avoid doing the - /// unlock. + /// `Enact` implementer for `prepare_reduce_unlockable`. This type may be dropped safely to + /// avoid doing the unlock. type ReduceTicket: Enact; /// Prepare to lock an asset. On success, a `Self::LockTicket` it returned, which can be used diff --git a/xcm/xcm-executor/src/traits/conversion.rs b/xcm/xcm-executor/src/traits/conversion.rs index 2f584a900f69..dac099ffaf8e 100644 --- a/xcm/xcm-executor/src/traits/conversion.rs +++ b/xcm/xcm-executor/src/traits/conversion.rs @@ -40,9 +40,9 @@ impl ConvertLocation for Tuple { /// A converter `trait` for origin types. /// -/// Can be amalgamated into tuples. If any of the tuple elements returns `Ok(_)`, it short circuits. Else, the `Err(_)` -/// of the last tuple item is returned. Each intermediate `Err(_)` might return a different `origin` of type `Origin` -/// which is passed to the next convert item. +/// Can be amalgamated into tuples. If any of the tuple elements returns `Ok(_)`, it short circuits. +/// Else, the `Err(_)` of the last tuple item is returned. Each intermediate `Err(_)` might return a +/// different `origin` of type `Origin` which is passed to the next convert item. /// /// ```rust /// # use xcm::latest::{MultiLocation, Junctions, Junction, OriginKind}; diff --git a/xcm/xcm-executor/src/traits/filter_asset_location.rs b/xcm/xcm-executor/src/traits/filter_asset_location.rs index 7aeb26b28094..b162a8b0729d 100644 --- a/xcm/xcm-executor/src/traits/filter_asset_location.rs +++ b/xcm/xcm-executor/src/traits/filter_asset_location.rs @@ -19,7 +19,8 @@ use xcm::latest::{MultiAsset, MultiLocation}; /// Filters assets/location pairs. /// -/// Can be amalgamated into tuples. If any item returns `true`, it short-circuits, else `false` is returned. +/// Can be amalgamated into tuples. If any item returns `true`, it short-circuits, else `false` is +/// returned. #[deprecated = "Use `frame_support::traits::ContainsPair` instead"] pub trait FilterAssetLocation { /// A filter to distinguish between asset/location pairs. diff --git a/xcm/xcm-executor/src/traits/on_response.rs b/xcm/xcm-executor/src/traits/on_response.rs index 34bb7eb9597d..b0f8b35bb98f 100644 --- a/xcm/xcm-executor/src/traits/on_response.rs +++ b/xcm/xcm-executor/src/traits/on_response.rs @@ -107,11 +107,14 @@ impl VersionChangeNotifier for () { /// The possible state of an XCM query response. #[derive(Debug, PartialEq, Eq)] pub enum QueryResponseStatus { - /// The response has arrived, and includes the inner Response and the block number it arrived at. + /// The response has arrived, and includes the inner Response and the block number it arrived + /// at. Ready { response: Response, at: BlockNumber }, - /// The response has not yet arrived, the XCM might still be executing or the response might be in transit. + /// The response has not yet arrived, the XCM might still be executing or the response might be + /// in transit. Pending { timeout: BlockNumber }, - /// No response with the given `QueryId` was found, or the response was already queried and removed from local storage. + /// No response with the given `QueryId` was found, or the response was already queried and + /// removed from local storage. NotFound, /// Got an unexpected XCM version. UnexpectedVersion, @@ -144,7 +147,8 @@ pub trait QueryHandler { /// /// - `message`: The message whose outcome should be reported. /// - `responder`: The origin from which a response should be expected. - /// - `timeout`: The block number after which it is permissible to return `NotFound` from `take_response`. + /// - `timeout`: The block number after which it is permissible to return `NotFound` from + /// `take_response`. /// /// `report_outcome` may return an error if the `responder` is not invertible. /// diff --git a/xcm/xcm-executor/src/traits/should_execute.rs b/xcm/xcm-executor/src/traits/should_execute.rs index 2b634e375136..d85458b54709 100644 --- a/xcm/xcm-executor/src/traits/should_execute.rs +++ b/xcm/xcm-executor/src/traits/should_execute.rs @@ -32,8 +32,8 @@ pub struct Properties { /// Trait to determine whether the execution engine should actually execute a given XCM. /// -/// Can be amalgamated into a tuple to have multiple trials. If any of the tuple elements returns `Ok()`, the -/// execution stops. Else, `Err(_)` is returned if all elements reject the message. +/// Can be amalgamated into a tuple to have multiple trials. If any of the tuple elements returns +/// `Ok()`, the execution stops. Else, `Err(_)` is returned if all elements reject the message. pub trait ShouldExecute { /// Returns `true` if the given `message` may be executed. /// diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 832397a0fd25..34cdb0c71413 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -20,11 +20,13 @@ use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmRes /// Facility for asset transacting. /// -/// This should work with as many asset/location combinations as possible. Locations to support may include non-account -/// locations such as a `MultiLocation::X1(Junction::Parachain)`. Different chains may handle them in different ways. +/// This should work with as many asset/location combinations as possible. Locations to support may +/// include non-account locations such as a `MultiLocation::X1(Junction::Parachain)`. Different +/// chains may handle them in different ways. /// -/// Can be amalgamated as a tuple of items that implement this trait. In such executions, if any of the transactors -/// returns `Ok(())`, then it will short circuit. Else, execution is passed to the next transactor. +/// Can be amalgamated as a tuple of items that implement this trait. In such executions, if any of +/// the transactors returns `Ok(())`, then it will short circuit. Else, execution is passed to the +/// next transactor. pub trait TransactAsset { /// Ensure that `check_in` will do as expected. /// @@ -37,19 +39,23 @@ pub trait TransactAsset { Err(XcmError::Unimplemented) } - /// An asset has been teleported in from the given origin. This should do whatever housekeeping is needed. + /// An asset has been teleported in from the given origin. This should do whatever housekeeping + /// is needed. /// - /// NOTE: This will make only a best-effort at bookkeeping. The caller should ensure that `can_check_in` has - /// returned with `Ok` in order to guarantee that this operation proceeds properly. + /// NOTE: This will make only a best-effort at bookkeeping. The caller should ensure that + /// `can_check_in` has returned with `Ok` in order to guarantee that this operation proceeds + /// properly. /// - /// Implementation note: In general this will do one of two things: On chains where the asset is native, - /// it will reduce the assets from a special "teleported" account so that a) total-issuance is preserved; - /// and b) to ensure that no more assets can be teleported in than were teleported out overall (this should - /// not be needed if the teleporting chains are to be trusted, but better to be safe than sorry). On chains - /// where the asset is not native then it will generally just be a no-op. + /// Implementation note: In general this will do one of two things: On chains where the asset is + /// native, it will reduce the assets from a special "teleported" account so that a) + /// total-issuance is preserved; and b) to ensure that no more assets can be teleported in than + /// were teleported out overall (this should not be needed if the teleporting chains are to be + /// trusted, but better to be safe than sorry). On chains where the asset is not native then it + /// will generally just be a no-op. /// - /// When composed as a tuple, all type-items are called. It is up to the implementer that there exists no - /// value for `_what` which can cause side-effects for more than one of the type-items. + /// When composed as a tuple, all type-items are called. It is up to the implementer that there + /// exists no value for `_what` which can cause side-effects for more than one of the + /// type-items. fn check_in(_origin: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} /// Ensure that `check_out` will do as expected. @@ -63,16 +69,19 @@ pub trait TransactAsset { Err(XcmError::Unimplemented) } - /// An asset has been teleported out to the given destination. This should do whatever housekeeping is needed. + /// An asset has been teleported out to the given destination. This should do whatever + /// housekeeping is needed. /// - /// Implementation note: In general this will do one of two things: On chains where the asset is native, - /// it will increase the assets in a special "teleported" account so that a) total-issuance is preserved; and - /// b) to ensure that no more assets can be teleported in than were teleported out overall (this should not - /// be needed if the teleporting chains are to be trusted, but better to be safe than sorry). On chains where - /// the asset is not native then it will generally just be a no-op. + /// Implementation note: In general this will do one of two things: On chains where the asset is + /// native, it will increase the assets in a special "teleported" account so that a) + /// total-issuance is preserved; and b) to ensure that no more assets can be teleported in than + /// were teleported out overall (this should not be needed if the teleporting chains are to be + /// trusted, but better to be safe than sorry). On chains where the asset is not native then it + /// will generally just be a no-op. /// - /// When composed as a tuple, all type-items are called. It is up to the implementer that there exists no - /// value for `_what` which can cause side-effects for more than one of the type-items. + /// When composed as a tuple, all type-items are called. It is up to the implementer that there + /// exists no value for `_what` which can cause side-effects for more than one of the + /// type-items. fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} /// Deposit the `what` asset into the account of `who`. diff --git a/xcm/xcm-executor/src/traits/weight.rs b/xcm/xcm-executor/src/traits/weight.rs index 06e6b5f55bce..bc40c10074f5 100644 --- a/xcm/xcm-executor/src/traits/weight.rs +++ b/xcm/xcm-executor/src/traits/weight.rs @@ -56,8 +56,8 @@ pub trait WeightTrader: Sized { context: &XcmContext, ) -> Result; - /// Attempt a refund of `weight` into some asset. The caller does not guarantee that the weight was - /// purchased using `buy_weight`. + /// Attempt a refund of `weight` into some asset. The caller does not guarantee that the weight + /// was purchased using `buy_weight`. /// /// Default implementation refunds nothing. fn refund_weight(&mut self, _weight: Weight, _context: &XcmContext) -> Option { @@ -93,8 +93,8 @@ impl WeightTrader for Tuple { log::trace!(target: "xcm::buy_weight", "last_error: {:?}, too_expensive_error_found: {}", last_error, too_expensive_error_found); - // if we have multiple traders, and first one returns `TooExpensive` and others fail e.g. `AssetNotFound` - // then it is more accurate to return `TooExpensive` then `AssetNotFound` + // if we have multiple traders, and first one returns `TooExpensive` and others fail e.g. + // `AssetNotFound` then it is more accurate to return `TooExpensive` then `AssetNotFound` Err(if too_expensive_error_found { XcmError::TooExpensive } else { diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index f98eb6e571e6..cf56784f7d4e 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -161,12 +161,12 @@ macro_rules! decl_test_relay_chain { /// /// ```ignore /// decl_test_parachain! { -/// pub struct ParaA { -/// Runtime = parachain::Runtime, -/// XcmpMessageHandler = parachain::MsgQueue, -/// DmpMessageHandler = parachain::MsgQueue, -/// new_ext = para_ext(), -/// } +/// pub struct ParaA { +/// Runtime = parachain::Runtime, +/// XcmpMessageHandler = parachain::MsgQueue, +/// DmpMessageHandler = parachain::MsgQueue, +/// new_ext = para_ext(), +/// } /// } /// ``` #[macro_export] @@ -272,13 +272,13 @@ thread_local! { /// /// ```ignore /// decl_test_network! { -/// pub struct ExampleNet { -/// relay_chain = Relay, -/// parachains = vec![ -/// (1, ParaA), -/// (2, ParaB), -/// ], -/// } +/// pub struct ExampleNet { +/// relay_chain = Relay, +/// parachains = vec![ +/// (1, ParaA), +/// (2, ParaB), +/// ], +/// } /// } /// ``` #[macro_export] From 1a50cb1aede201e08df18d9deb501e32f833f40b Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Mon, 14 Aug 2023 17:34:38 +0300 Subject: [PATCH 16/45] Disable validation/collation protocols for normal full nodes (#7601) If authority discovery is not enabled, `Overseer` is not enabled, meaning `NetworkBridge` is not started. Validation/collation protocols are, however, enabled even if the `NetworkBridge` is not started. Currently this results in normal Polkadot full nodes advertising these protocols, accepting inbound substreams and even establishing outbound substreams for the validation protocol. Since the `NetworkBridge` is not started and no protocol in Substrate is interested in these protocol events, the events are relayed to all protocol handlers but are getting discarded because no installed protocol is interested in them. Co-authored-by: parity-processbot <> --- node/service/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 4dda57110825..d0b6db17ed0e 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -828,10 +828,11 @@ pub fn new_full( net_config.add_request_response_protocol(beefy_req_resp_cfg); } + // validation/collation protocols are enabled only if `Overseer` is enabled let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); - { + if auth_or_collator || overseer_enable_anyways { use polkadot_network_bridge::{peer_sets_info, IsAuthority}; let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; for config in peer_sets_info(is_authority, &peerset_protocol_names) { From b10c8af5db47d549fd60a349db2ce7547e7cce2d Mon Sep 17 00:00:00 2001 From: Lulu Date: Mon, 14 Aug 2023 16:31:13 +0100 Subject: [PATCH 17/45] Don't publish test crates (#7588) --- node/subsystem-test-helpers/Cargo.toml | 1 + node/test/client/Cargo.toml | 1 + node/test/performance-test/Cargo.toml | 1 + node/test/service/Cargo.toml | 1 + parachain/test-parachains/adder/Cargo.toml | 1 + parachain/test-parachains/adder/collator/Cargo.toml | 1 + parachain/test-parachains/halt/Cargo.toml | 1 + parachain/test-parachains/undying/Cargo.toml | 1 + parachain/test-parachains/undying/collator/Cargo.toml | 1 + primitives/test-helpers/Cargo.toml | 1 + runtime/test-runtime/Cargo.toml | 1 + runtime/test-runtime/constants/Cargo.toml | 1 + utils/remote-ext-tests/bags-list/Cargo.toml | 1 + xcm/xcm-executor/integration-tests/Cargo.toml | 1 + 14 files changed, 14 insertions(+) diff --git a/node/subsystem-test-helpers/Cargo.toml b/node/subsystem-test-helpers/Cargo.toml index 81bc19a13031..adb0587370ec 100644 --- a/node/subsystem-test-helpers/Cargo.toml +++ b/node/subsystem-test-helpers/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-node-subsystem-test-helpers" description = "Subsystem traits and message definitions" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/test/client/Cargo.toml b/node/test/client/Cargo.toml index 33c240443d02..aac46bd4b8fc 100644 --- a/node/test/client/Cargo.toml +++ b/node/test/client/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-test-client" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/test/performance-test/Cargo.toml b/node/test/performance-test/Cargo.toml index c6d0ce7f7ec9..1bddc6b08702 100644 --- a/node/test/performance-test/Cargo.toml +++ b/node/test/performance-test/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-performance-test" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/node/test/service/Cargo.toml b/node/test/service/Cargo.toml index 08e9e3889b06..8912e19306e0 100644 --- a/node/test/service/Cargo.toml +++ b/node/test/service/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-test-service" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/parachain/test-parachains/adder/Cargo.toml b/parachain/test-parachains/adder/Cargo.toml index 5e1b9a7d174c..d2b2224328a7 100644 --- a/parachain/test-parachains/adder/Cargo.toml +++ b/parachain/test-parachains/adder/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true version.workspace = true authors.workspace = true +publish = false [dependencies] parachain = { package = "polkadot-parachain", path = "../../", default-features = false, features = [ "wasm-api" ] } diff --git a/parachain/test-parachains/adder/collator/Cargo.toml b/parachain/test-parachains/adder/collator/Cargo.toml index 08dcbcaa644e..fad51a863a15 100644 --- a/parachain/test-parachains/adder/collator/Cargo.toml +++ b/parachain/test-parachains/adder/collator/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "test-parachain-adder-collator" description = "Collator for the adder test parachain" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/parachain/test-parachains/halt/Cargo.toml b/parachain/test-parachains/halt/Cargo.toml index 99076aae6aa3..85ee5d99d891 100644 --- a/parachain/test-parachains/halt/Cargo.toml +++ b/parachain/test-parachains/halt/Cargo.toml @@ -2,6 +2,7 @@ name = "test-parachain-halt" description = "Test parachain which executes forever" build = "build.rs" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/parachain/test-parachains/undying/Cargo.toml b/parachain/test-parachains/undying/Cargo.toml index 43cb1bc37fda..030032e7754d 100644 --- a/parachain/test-parachains/undying/Cargo.toml +++ b/parachain/test-parachains/undying/Cargo.toml @@ -2,6 +2,7 @@ name = "test-parachain-undying" description = "Test parachain for zombienet integration tests" build = "build.rs" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/parachain/test-parachains/undying/collator/Cargo.toml b/parachain/test-parachains/undying/collator/Cargo.toml index 5b5656efb4ac..b0118555506c 100644 --- a/parachain/test-parachains/undying/collator/Cargo.toml +++ b/parachain/test-parachains/undying/collator/Cargo.toml @@ -5,6 +5,7 @@ edition.workspace = true license.workspace = true version.workspace = true authors.workspace = true +publish = false [[bin]] name = "undying-collator" diff --git a/primitives/test-helpers/Cargo.toml b/primitives/test-helpers/Cargo.toml index a1f7f9268b9f..b43bac1e8550 100644 --- a/primitives/test-helpers/Cargo.toml +++ b/primitives/test-helpers/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "polkadot-primitives-test-helpers" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/runtime/test-runtime/Cargo.toml b/runtime/test-runtime/Cargo.toml index 76bd63d59462..41fbebb39f3a 100644 --- a/runtime/test-runtime/Cargo.toml +++ b/runtime/test-runtime/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "polkadot-test-runtime" build = "build.rs" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/runtime/test-runtime/constants/Cargo.toml b/runtime/test-runtime/constants/Cargo.toml index 9b435da80682..15ab1dbdd4fe 100644 --- a/runtime/test-runtime/constants/Cargo.toml +++ b/runtime/test-runtime/constants/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "test-runtime-constants" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/utils/remote-ext-tests/bags-list/Cargo.toml b/utils/remote-ext-tests/bags-list/Cargo.toml index 772efb1eddd0..c84c95ab0498 100644 --- a/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/utils/remote-ext-tests/bags-list/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "remote-ext-tests-bags-list" +publish = false version.workspace = true authors.workspace = true edition.workspace = true diff --git a/xcm/xcm-executor/integration-tests/Cargo.toml b/xcm/xcm-executor/integration-tests/Cargo.toml index d2af1304beb6..18a729e082d2 100644 --- a/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/xcm/xcm-executor/integration-tests/Cargo.toml @@ -5,6 +5,7 @@ authors.workspace = true edition.workspace = true license.workspace = true version.workspace = true +publish = false [dependencies] frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } From f2ad8c531c96c32437df041b02c757edb69d3e4c Mon Sep 17 00:00:00 2001 From: Marcin S Date: Mon, 14 Aug 2023 12:14:30 -0400 Subject: [PATCH 18/45] PVF workers: some fixes for cargo run and cargo install (#7608) - Update some places where `cargo run` was used - Add note to error messages about `cargo build` before `cargo run` - Fix call to `cargo install` in readme --- README.md | 7 ++++++- node/service/src/lib.rs | 4 ++-- parachain/test-parachains/adder/collator/README.md | 8 +++++++- utils/staking-miner/README.md | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f3d1f5e276cd..c6e969760362 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,11 @@ cargo build --release **Note:** compilation is a memory intensive process. We recommend having 4 GiB of physical RAM or swap available (keep in mind that if a build hits swap it tends to be very slow). -**Note:** if you want to move the built `polkadot` binary somewhere (e.g. into $PATH) you will also need to move `polkadot-execute-worker` and `polkadot-prepare-worker`. You can let cargo do all this for you by running `cargo install --path .`. +**Note:** if you want to move the built `polkadot` binary somewhere (e.g. into $PATH) you will also need to move `polkadot-execute-worker` and `polkadot-prepare-worker`. You can let cargo do all this for you by running: + +```sh +cargo install --path . --locked +``` #### Build from Source with Docker @@ -193,6 +197,7 @@ cargo test --workspace --release You can start a development chain with: ```bash +cargo build cargo run -- --dev ``` diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index d0b6db17ed0e..d42c737330cd 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -243,7 +243,7 @@ pub enum Error { InvalidWorkerBinaries { prep_worker_path: PathBuf, exec_worker_path: PathBuf }, #[cfg(feature = "full-node")] - #[error("Worker binaries could not be found, make sure polkadot was built/installed correctly. Searched given workers path ({given_workers_path:?}), polkadot binary path ({current_exe_path:?}), and lib path (/usr/lib/polkadot), workers names: {workers_names:?}")] + #[error("Worker binaries could not be found, make sure polkadot was built/installed correctly. If you ran with `cargo run`, please run `cargo build` first. Searched given workers path ({given_workers_path:?}), polkadot binary path ({current_exe_path:?}), and lib path (/usr/lib/polkadot), workers names: {workers_names:?}")] MissingWorkerBinaries { given_workers_path: Option, current_exe_path: PathBuf, @@ -251,7 +251,7 @@ pub enum Error { }, #[cfg(feature = "full-node")] - #[error("Version of worker binary ({worker_version}) is different from node version ({node_version}), worker_path: {worker_path}. TESTING ONLY: this check can be disabled with --disable-worker-version-check")] + #[error("Version of worker binary ({worker_version}) is different from node version ({node_version}), worker_path: {worker_path}. If you ran with `cargo run`, please run `cargo build` first, otherwise try to `cargo clean`. TESTING ONLY: this check can be disabled with --disable-worker-version-check")] WorkerBinaryVersionMismatch { worker_version: String, node_version: String, diff --git a/parachain/test-parachains/adder/collator/README.md b/parachain/test-parachains/adder/collator/README.md index 4347a9a8ced7..a1378544c386 100644 --- a/parachain/test-parachains/adder/collator/README.md +++ b/parachain/test-parachains/adder/collator/README.md @@ -1,6 +1,12 @@ # How to run this collator -First start two validators that will run for the relay chain: +First, build Polkadot: + +```sh +cargo build --release +``` + +Then start two validators that will run for the relay chain: ```sh cargo run --release -- -d alice --chain rococo-local --validator --alice --port 50551 diff --git a/utils/staking-miner/README.md b/utils/staking-miner/README.md index b7f70de573b0..7e7254dc7759 100644 --- a/utils/staking-miner/README.md +++ b/utils/staking-miner/README.md @@ -64,5 +64,7 @@ docker run --rm -i \ ### Test locally +Make sure you've built Polkadot, then: + 1. `cargo run -p polkadot --features fast-runtime -- --chain polkadot-dev --tmp --alice -lruntime=debug` 2. `cargo run -p staking-miner -- --uri ws://localhost:9944 monitor --seed-or-path //Alice phrag-mms` From 1a57e74ec72fe9d5f2731c25c2e3693e7a89d839 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 14 Aug 2023 14:30:12 -0700 Subject: [PATCH 19/45] XCM: Rename Instruction instructions to Command instructions (#7593) Co-authored-by: parity-processbot <> --- xcm/src/v2/mod.rs | 44 +++++++++++++------------- xcm/src/v3/mod.rs | 80 +++++++++++++++++++++++------------------------ 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/xcm/src/v2/mod.rs b/xcm/src/v2/mod.rs index 79cc8ead89a1..8a67b771c9e9 100644 --- a/xcm/src/v2/mod.rs +++ b/xcm/src/v2/mod.rs @@ -434,7 +434,7 @@ pub enum Instruction { /// /// - `assets`: The asset(s) to be withdrawn into holding. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: WithdrawAsset(MultiAssets), @@ -492,7 +492,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: TransferAsset { assets: MultiAssets, beneficiary: MultiLocation }, @@ -512,7 +512,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> }, @@ -527,7 +527,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: Transact { @@ -600,14 +600,14 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: ClearOrigin, /// Mutate the origin to some interior location. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: DescendOrigin(InteriorMultiLocation), @@ -623,7 +623,7 @@ pub enum Instruction { /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the /// response may not execute at all. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ReportError { @@ -643,7 +643,7 @@ pub enum Instruction { /// removed, prioritized under standard asset ordering. Any others will remain in holding. /// - `beneficiary`: The new owner for the assets. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: DepositAsset { @@ -669,7 +669,7 @@ pub enum Instruction { /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is /// sent onwards to `dest`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: DepositReserveAsset { @@ -689,7 +689,7 @@ pub enum Instruction { /// - `give`: The asset(s) to remove from holding. /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets }, @@ -705,7 +705,7 @@ pub enum Instruction { /// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve /// location*. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> }, @@ -721,7 +721,7 @@ pub enum Instruction { /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for /// all `assets`. If it does not, then the assets may be lost. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> }, @@ -739,7 +739,7 @@ pub enum Instruction { /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the /// response may not execute at all. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: QueryHolding { @@ -759,14 +759,14 @@ pub enum Instruction { /// expected maximum weight of the total XCM to be executed for the /// `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: BuyExecution { fees: MultiAsset, weight_limit: WeightLimit }, /// Refund any surplus weight previously bought with `BuyExecution`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. RefundSurplus, @@ -782,7 +782,7 @@ pub enum Instruction { /// weight however includes only the difference between the previous handler and the new /// handler, which can reasonably be negative, which would result in a surplus. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. SetErrorHandler(Xcm), @@ -798,14 +798,14 @@ pub enum Instruction { /// weight however includes only the difference between the previous appendix and the new /// appendix, which can reasonably be negative, which would result in a surplus. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. SetAppendix(Xcm), /// Clear the Error Register. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. ClearError, @@ -817,14 +817,14 @@ pub enum Instruction { /// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the /// asset. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ClaimAsset { assets: MultiAssets, ticket: MultiLocation }, /// Always throws an error of type `Trap`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `Trap`: All circumstances, whose inner value is the same as this item's inner value. @@ -839,7 +839,7 @@ pub enum Instruction { /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the /// response may not execute at all. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible* SubscribeVersion { @@ -851,7 +851,7 @@ pub enum Instruction { /// Cancel the effect of a previous `SubscribeVersion` instruction. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible* UnsubscribeVersion, diff --git a/xcm/src/v3/mod.rs b/xcm/src/v3/mod.rs index 3614dc22550d..360867957862 100644 --- a/xcm/src/v3/mod.rs +++ b/xcm/src/v3/mod.rs @@ -380,7 +380,7 @@ pub enum Instruction { /// /// - `assets`: The asset(s) to be withdrawn into holding. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: WithdrawAsset(MultiAssets), @@ -444,7 +444,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: TransferAsset { assets: MultiAssets, beneficiary: MultiLocation }, @@ -464,7 +464,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> }, @@ -481,7 +481,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded }, @@ -549,14 +549,14 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: ClearOrigin, /// Mutate the origin to some interior location. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: DescendOrigin(InteriorMultiLocation), @@ -567,7 +567,7 @@ pub enum Instruction { /// /// - `response_info`: Information for making the response. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ReportError(QueryResponseInfo), @@ -578,7 +578,7 @@ pub enum Instruction { /// - `assets`: The asset(s) to remove from holding. /// - `beneficiary`: The new owner for the assets. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: DepositAsset { assets: MultiAssetFilter, beneficiary: MultiLocation }, @@ -596,7 +596,7 @@ pub enum Instruction { /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is /// sent onwards to `dest`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> }, @@ -613,7 +613,7 @@ pub enum Instruction { /// and receive accordingly more. If `false`, then prefer to give as little as possible in /// order to receive as little as possible while receiving at least `want`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ExchangeAsset { give: MultiAssetFilter, want: MultiAssets, maximal: bool }, @@ -629,7 +629,7 @@ pub enum Instruction { /// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve /// location*. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> }, @@ -645,7 +645,7 @@ pub enum Instruction { /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for /// all `assets`. If it does not, then the assets may be lost. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> }, @@ -659,7 +659,7 @@ pub enum Instruction { /// will be, asset-wise, *the lesser of this value and the holding register*. No wildcards /// will be used when reporting assets back. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ReportHolding { response_info: QueryResponseInfo, assets: MultiAssetFilter }, @@ -672,14 +672,14 @@ pub enum Instruction { /// expected maximum weight of the total XCM to be executed for the /// `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: BuyExecution { fees: MultiAsset, weight_limit: WeightLimit }, /// Refund any surplus weight previously bought with `BuyExecution`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. RefundSurplus, @@ -695,7 +695,7 @@ pub enum Instruction { /// weight however includes only the difference between the previous handler and the new /// handler, which can reasonably be negative, which would result in a surplus. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. SetErrorHandler(Xcm), @@ -711,14 +711,14 @@ pub enum Instruction { /// weight however includes only the difference between the previous appendix and the new /// appendix, which can reasonably be negative, which would result in a surplus. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. SetAppendix(Xcm), /// Clear the Error Register. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. ClearError, @@ -730,14 +730,14 @@ pub enum Instruction { /// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the /// asset. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: ClaimAsset { assets: MultiAssets, ticket: MultiLocation }, /// Always throws an error of type `Trap`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `Trap`: All circumstances, whose inner value is the same as this item's inner value. @@ -752,7 +752,7 @@ pub enum Instruction { /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the /// response may not execute at all. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible* SubscribeVersion { @@ -763,7 +763,7 @@ pub enum Instruction { /// Cancel the effect of a previous `SubscribeVersion` instruction. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible* UnsubscribeVersion, @@ -774,14 +774,14 @@ pub enum Instruction { /// error if the Holding does not contain the assets (to make this an error, use `ExpectAsset` /// prior). /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Infallible* BurnAsset(MultiAssets), /// Throw an error if Holding does not contain at least the given assets. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `ExpectationFalse`: If Holding Register does not contain the assets in the parameter. @@ -789,7 +789,7 @@ pub enum Instruction { /// Ensure that the Origin Register equals some given value and throw an error if not. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `ExpectationFalse`: If Origin Register is not equal to the parameter. @@ -797,7 +797,7 @@ pub enum Instruction { /// Ensure that the Error Register equals some given value and throw an error if not. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `ExpectationFalse`: If the value of the Error Register is not equal to the parameter. @@ -806,7 +806,7 @@ pub enum Instruction { /// Ensure that the Transact Status Register equals some given value and throw an error if /// not. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the @@ -824,7 +824,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible*. QueryPallet { module_name: Vec, response_info: QueryResponseInfo }, @@ -843,7 +843,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: /// - `ExpectationFalse`: In case any of the expectations are broken. @@ -866,7 +866,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible*. ReportTransactStatus(QueryResponseInfo), @@ -875,7 +875,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Infallible*. ClearTransactStatus, @@ -890,7 +890,7 @@ pub enum Instruction { /// The `Junction` parameter should generally be a `GlobalConsensus` variant since it is only /// these which are children of the Universal Ancestor. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible*. UniversalOrigin(Junction), @@ -911,7 +911,7 @@ pub enum Instruction { /// `destination: X1(Parachain(1000))`. Alternatively, to export a message for execution on /// Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: *Fallible*. ExportMessage { network: NetworkId, destination: InteriorMultiLocation, xcm: Xcm<()> }, @@ -927,7 +927,7 @@ pub enum Instruction { /// - `unlocker`: The value which the Origin must be for a corresponding `UnlockAsset` /// instruction to work. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: LockAsset { asset: MultiAsset, unlocker: MultiLocation }, @@ -940,7 +940,7 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: UnlockAsset { asset: MultiAsset, target: MultiLocation }, @@ -969,7 +969,7 @@ pub enum Instruction { /// - `locker`: The location from which a previous `NoteUnlockable` was sent and to which an /// `UnlockAsset` should be sent. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: RequestUnlock { asset: MultiAsset, locker: MultiLocation }, @@ -979,7 +979,7 @@ pub enum Instruction { /// - `jit_withdraw`: The fees mode item; if set to `true` then fees for any instructions are /// withdrawn as needed using the same mechanism as `WithdrawAssets`. /// - /// Kind: *Instruction*. + /// Kind: *Command*. /// /// Errors: SetFeesMode { jit_withdraw: bool }, @@ -992,21 +992,21 @@ pub enum Instruction { /// /// Safety: No concerns. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: SetTopic([u8; 32]), /// Clear the Topic Register. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: None. ClearTopic, /// Alter the current Origin to another given origin. /// - /// Kind: *Instruction* + /// Kind: *Command* /// /// Errors: If the existing state would not allow such a change. AliasOrigin(MultiLocation), From e074364b08d07266aaba952004456d5af61dbc5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 15 Aug 2023 10:51:27 +0200 Subject: [PATCH 20/45] Remove superflous parameter `overseer_enable_anyways` and make parachain node type more explicit (#7617) * Remove superflous parameter `overseer_enable_anyways` We don't need this flag, as we don't need the overseer enabled when the node isn't a collator or validator. * Rename `IsCollator` to `IsParachainNode` `IsParachainNode` is more expressive and also encapsulates the state of the parachain node being a full node. Some functionality like the overseer needs to run always when the node runs alongside a parachain node. The parachain node needs the overseer to e.g. recover PoVs. Other things like candidate validation or pvf checking are only required for when the node is running as validator. * FMT * Fix CI --- cli/src/command.rs | 3 +- node/core/approval-voting/src/lib.rs | 2 +- node/core/pvf/execute-worker/src/lib.rs | 4 +- node/network/approval-distribution/src/lib.rs | 14 +- .../approval-distribution/src/tests.rs | 4 +- node/network/collator-protocol/src/lib.rs | 28 ++-- node/network/gossip-support/src/lib.rs | 3 +- .../statement-distribution/src/responder.rs | 4 +- node/service/src/lib.rs | 146 ++++++++++-------- node/service/src/overseer.rs | 13 +- node/test/service/src/lib.rs | 11 +- .../adder/collator/src/main.rs | 9 +- .../undying/collator/src/main.rs | 9 +- runtime/parachains/src/configuration.rs | 19 ++- runtime/parachains/src/paras_inherent/mod.rs | 4 +- .../parachains/src/runtime_api_impl/mod.rs | 5 +- 16 files changed, 148 insertions(+), 130 deletions(-) diff --git a/cli/src/command.rs b/cli/src/command.rs index c75f96ee2ebf..dcffa09aaf91 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -287,14 +287,13 @@ where let task_manager = service::build_full( config, service::NewFullParams { - is_collator: service::IsCollator::No, + is_parachain_node: service::IsParachainNode::No, grandpa_pause, jaeger_agent, telemetry_worker_handle: None, node_version, workers_path: cli.run.workers_path, workers_names: None, - overseer_enable_anyways: false, overseer_gen, overseer_message_channel_capacity_override: cli .run diff --git a/node/core/approval-voting/src/lib.rs b/node/core/approval-voting/src/lib.rs index 7e29e64c400a..b29e47b4c435 100644 --- a/node/core/approval-voting/src/lib.rs +++ b/node/core/approval-voting/src/lib.rs @@ -2253,7 +2253,7 @@ where // // 1. This is not a local approval, as we don't store anything new in the approval entry. // 2. The candidate is not newly approved, as we haven't altered the approval entry's - // approved flag with `mark_approved` above. + // approved flag with `mark_approved` above. // 3. The approver, if any, had already approved the candidate, as we haven't altered the // bitfield. if transition.is_local_approval() || newly_approved || !already_approved_by.unwrap_or(true) diff --git a/node/core/pvf/execute-worker/src/lib.rs b/node/core/pvf/execute-worker/src/lib.rs index 6f632a0ae95e..7a14de18a82f 100644 --- a/node/core/pvf/execute-worker/src/lib.rs +++ b/node/core/pvf/execute-worker/src/lib.rs @@ -55,8 +55,8 @@ use tokio::{io, net::UnixStream}; // // There are quirks to that configuration knob: // -// 1. It only limits the amount of stack space consumed by wasm but does not ensure nor check -// that the stack space is actually available. +// 1. It only limits the amount of stack space consumed by wasm but does not ensure nor check that +// the stack space is actually available. // // That means, if the calling thread has 1 MiB of stack space left and the wasm code consumes // more, then the wasmtime limit will **not** trigger. Instead, the wasm code will hit the diff --git a/node/network/approval-distribution/src/lib.rs b/node/network/approval-distribution/src/lib.rs index 803a56251495..b94ebb282219 100644 --- a/node/network/approval-distribution/src/lib.rs +++ b/node/network/approval-distribution/src/lib.rs @@ -1319,13 +1319,13 @@ impl State { } // Here we're leaning on a few behaviors of assignment propagation: - // 1. At this point, the only peer we're aware of which has the approval - // message is the source peer. - // 2. We have sent the assignment message to every peer in the required routing - // which is aware of this block _unless_ the peer we originally received the - // assignment from was part of the required routing. In that case, we've sent - // the assignment to all aware peers in the required routing _except_ the original - // source of the assignment. Hence the `in_topology_check`. + // 1. At this point, the only peer we're aware of which has the approval message is + // the source peer. + // 2. We have sent the assignment message to every peer in the required routing which + // is aware of this block _unless_ the peer we originally received the assignment + // from was part of the required routing. In that case, we've sent the assignment + // to all aware peers in the required routing _except_ the original source of the + // assignment. Hence the `in_topology_check`. // 3. Any randomly selected peers have been sent the assignment already. let in_topology = topology .map_or(false, |t| t.local_grid_neighbors().route_to_peer(required_routing, peer)); diff --git a/node/network/approval-distribution/src/tests.rs b/node/network/approval-distribution/src/tests.rs index 979f0ada4ee6..422157a1eda9 100644 --- a/node/network/approval-distribution/src/tests.rs +++ b/node/network/approval-distribution/src/tests.rs @@ -463,8 +463,8 @@ fn delay_reputation_change() { /// /// /// 1. Send a view update that removes block B from their view. -/// 2. Send a message from B that they incur `COST_UNEXPECTED_MESSAGE` for, -/// but then they receive `BENEFIT_VALID_MESSAGE`. +/// 2. Send a message from B that they incur `COST_UNEXPECTED_MESSAGE` for, but then they receive +/// `BENEFIT_VALID_MESSAGE`. /// 3. Send all other messages related to B. #[test] fn spam_attack_results_in_negative_reputation_change() { diff --git a/node/network/collator-protocol/src/lib.rs b/node/network/collator-protocol/src/lib.rs index 8e710a26ad71..68d882be6fa1 100644 --- a/node/network/collator-protocol/src/lib.rs +++ b/node/network/collator-protocol/src/lib.rs @@ -37,7 +37,7 @@ use polkadot_node_network_protocol::{ }; use polkadot_primitives::CollatorPair; -use polkadot_node_subsystem::{errors::SubsystemError, overseer, SpawnedSubsystem}; +use polkadot_node_subsystem::{errors::SubsystemError, overseer, DummySubsystem, SpawnedSubsystem}; mod error; @@ -82,6 +82,8 @@ pub enum ProtocolSide { IncomingRequestReceiver, collator_side::Metrics, ), + /// No protocol side, just disable it. + None, } /// The collator protocol subsystem. @@ -98,24 +100,22 @@ impl CollatorProtocolSubsystem { pub fn new(protocol_side: ProtocolSide) -> Self { Self { protocol_side } } - - async fn run(self, ctx: Context) -> std::result::Result<(), error::FatalError> { - match self.protocol_side { - ProtocolSide::Validator { keystore, eviction_policy, metrics } => - validator_side::run(ctx, keystore, eviction_policy, metrics).await, - ProtocolSide::Collator(local_peer_id, collator_pair, req_receiver, metrics) => - collator_side::run(ctx, local_peer_id, collator_pair, req_receiver, metrics).await, - } - } } #[overseer::subsystem(CollatorProtocol, error=SubsystemError, prefix=self::overseer)] impl CollatorProtocolSubsystem { fn start(self, ctx: Context) -> SpawnedSubsystem { - let future = self - .run(ctx) - .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) - .boxed(); + let future = match self.protocol_side { + ProtocolSide::Validator { keystore, eviction_policy, metrics } => + validator_side::run(ctx, keystore, eviction_policy, metrics) + .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) + .boxed(), + ProtocolSide::Collator(local_peer_id, collator_pair, req_receiver, metrics) => + collator_side::run(ctx, local_peer_id, collator_pair, req_receiver, metrics) + .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) + .boxed(), + ProtocolSide::None => return DummySubsystem.start(ctx), + }; SpawnedSubsystem { name: "collator-protocol-subsystem", future } } diff --git a/node/network/gossip-support/src/lib.rs b/node/network/gossip-support/src/lib.rs index 3c178ad9dfa5..b92aa4e9fe39 100644 --- a/node/network/gossip-support/src/lib.rs +++ b/node/network/gossip-support/src/lib.rs @@ -183,8 +183,7 @@ where } /// 1. Determine if the current session index has changed. - /// 2. If it has, determine relevant validators - /// and issue a connection request. + /// 2. If it has, determine relevant validators and issue a connection request. async fn handle_active_leaves( &mut self, sender: &mut impl overseer::GossipSupportSenderTrait, diff --git a/node/network/statement-distribution/src/responder.rs b/node/network/statement-distribution/src/responder.rs index 4dad10eb5e4f..68976436039d 100644 --- a/node/network/statement-distribution/src/responder.rs +++ b/node/network/statement-distribution/src/responder.rs @@ -62,8 +62,8 @@ pub async fn respond( // // 1. We want some requesters to have full data fast, rather then lots of them having them // late, as each requester having the data will help distributing it. - // 2. If we take too long, the requests timing out will not yet have had any data sent, - // thus we wasted no bandwidth. + // 2. If we take too long, the requests timing out will not yet have had any data sent, thus + // we wasted no bandwidth. // 3. If the queue is full, requestes will get an immediate error instead of running in a // timeout, thus requesters can immediately try another peer and be faster. // diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index d42c737330cd..dab69473c6ba 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -627,7 +627,7 @@ where #[cfg(feature = "full-node")] pub struct NewFullParams { - pub is_collator: IsCollator, + pub is_parachain_node: IsParachainNode, pub grandpa_pause: Option<(u32, u32)>, pub jaeger_agent: Option, pub telemetry_worker_handle: Option, @@ -638,7 +638,6 @@ pub struct NewFullParams { pub workers_path: Option, /// Optional custom names for the prepare and execute workers. pub workers_names: Option<(String, String)>, - pub overseer_enable_anyways: bool, pub overseer_gen: OverseerGenerator, pub overseer_message_channel_capacity_override: Option, #[allow(dead_code)] @@ -657,32 +656,46 @@ pub struct NewFull { pub backend: Arc, } -/// Is this node a collator? +/// Is this node running as in-process node for a parachain node? #[cfg(feature = "full-node")] #[derive(Clone)] -pub enum IsCollator { - /// This node is a collator. - Yes(CollatorPair), - /// This node is not a collator. +pub enum IsParachainNode { + /// This node is running as in-process node for a parachain collator. + Collator(CollatorPair), + /// This node is running as in-process node for a parachain full node. + FullNode, + /// This node is not running as in-process node for a parachain node, aka a normal relay chain + /// node. No, } #[cfg(feature = "full-node")] -impl std::fmt::Debug for IsCollator { +impl std::fmt::Debug for IsParachainNode { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { use sp_core::Pair; match self { - IsCollator::Yes(pair) => write!(fmt, "Yes({})", pair.public()), - IsCollator::No => write!(fmt, "No"), + IsParachainNode::Collator(pair) => write!(fmt, "Collator({})", pair.public()), + IsParachainNode::FullNode => write!(fmt, "FullNode"), + IsParachainNode::No => write!(fmt, "No"), } } } #[cfg(feature = "full-node")] -impl IsCollator { - /// Is this a collator? +impl IsParachainNode { + /// Is this running alongside a collator? fn is_collator(&self) -> bool { - matches!(self, Self::Yes(_)) + matches!(self, Self::Collator(_)) + } + + /// Is this running alongside a full node? + fn is_full_node(&self) -> bool { + matches!(self, Self::FullNode) + } + + /// Is this node running alongside a relay chain node? + fn is_running_alongside_parachain_node(&self) -> bool { + self.is_collator() || self.is_full_node() } } @@ -696,11 +709,6 @@ pub const AVAILABILITY_CONFIG: AvailabilityConfig = AvailabilityConfig { /// 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. -/// /// `workers_path` is used to get the path to the directory where auxiliary worker binaries reside. /// If not specified, the main binary's directory is searched first, then `/usr/lib/polkadot` is /// searched. If the path points to an executable rather then directory, that executable is used @@ -709,14 +717,13 @@ pub const AVAILABILITY_CONFIG: AvailabilityConfig = AvailabilityConfig { pub fn new_full( mut config: Configuration, NewFullParams { - is_collator, + is_parachain_node, grandpa_pause, jaeger_agent, telemetry_worker_handle, node_version, workers_path, workers_names, - overseer_enable_anyways, overseer_gen, overseer_message_channel_capacity_override, malus_finality_delay: _malus_finality_delay, @@ -768,8 +775,9 @@ pub fn new_full( let chain_spec = config.chain_spec.cloned_box(); let keystore = basics.keystore_container.local_keystore(); - let auth_or_collator = role.is_authority() || is_collator.is_collator(); - let pvf_checker_enabled = role.is_authority() && !is_collator.is_collator(); + let auth_or_collator = role.is_authority() || is_parachain_node.is_collator(); + // We only need to enable the pvf checker when this is a validator. + let pvf_checker_enabled = role.is_authority(); let select_chain = if auth_or_collator { let metrics = @@ -832,7 +840,12 @@ pub fn new_full( let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); - if auth_or_collator || overseer_enable_anyways { + // If this is a validator or running alongside a parachain node, we need to enable the + // networking protocols. + // + // Collators and parachain full nodes require the collator and validator networking to send + // collations and to be able to recover PoVs. + if role.is_authority() || is_parachain_node.is_running_alongside_parachain_node() { use polkadot_network_bridge::{peer_sets_info, IsAuthority}; let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; for config in peer_sets_info(is_authority, &peerset_protocol_names) { @@ -910,7 +923,7 @@ pub fn new_full( slot_duration_millis: slot_duration.as_millis() as u64, }; - let candidate_validation_config = if role.is_authority() && !is_collator.is_collator() { + let candidate_validation_config = if role.is_authority() { let (prep_worker_path, exec_worker_path) = workers::determine_workers_paths(workers_path, workers_names, node_version.clone())?; log::info!("🚀 Using prepare-worker binary at: {:?}", prep_worker_path); @@ -979,46 +992,50 @@ pub fn new_full( let overseer_client = client.clone(); let spawner = task_manager.spawn_handle(); - let authority_discovery_service = if auth_or_collator || overseer_enable_anyways { - use futures::StreamExt; - use sc_network::{Event, NetworkEventStream}; + let authority_discovery_service = + // We need the authority discovery if this node is either a validator or running alongside a parachain node. + // Parachains node require the authority discovery for finding relay chain validators for sending + // their PoVs or recovering PoVs. + if role.is_authority() || is_parachain_node.is_running_alongside_parachain_node() { + use futures::StreamExt; + use sc_network::{Event, NetworkEventStream}; - let authority_discovery_role = if role.is_authority() { - sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore()) + 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 not an authority (collator, cumulus, ..) + sc_authority_discovery::Role::Discover + }; + let dht_event_stream = + network.event_stream("authority-discovery").filter_map(|e| async move { + match e { + Event::Dht(e) => Some(e), + _ => None, + } + }); + let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config( + sc_authority_discovery::WorkerConfig { + publish_non_global_ips: auth_disc_publish_non_global_ips, + // Require that authority discovery records are signed. + strict_record_validation: true, + ..Default::default() + }, + client.clone(), + network.clone(), + Box::pin(dht_event_stream), + authority_discovery_role, + prometheus_registry.clone(), + ); + + task_manager.spawn_handle().spawn( + "authority-discovery-worker", + Some("authority-discovery"), + Box::pin(worker.run()), + ); + Some(service) } else { - // don't publish our addresses when we're not an authority (collator, cumulus, ..) - sc_authority_discovery::Role::Discover + None }; - let dht_event_stream = - network.event_stream("authority-discovery").filter_map(|e| async move { - match e { - Event::Dht(e) => Some(e), - _ => None, - } - }); - let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config( - sc_authority_discovery::WorkerConfig { - publish_non_global_ips: auth_disc_publish_non_global_ips, - // Require that authority discovery records are signed. - strict_record_validation: true, - ..Default::default() - }, - client.clone(), - network.clone(), - Box::pin(dht_event_stream), - authority_discovery_role, - prometheus_registry.clone(), - ); - - task_manager.spawn_handle().spawn( - "authority-discovery-worker", - Some("authority-discovery"), - Box::pin(worker.run()), - ); - Some(service) - } else { - None - }; let overseer_handle = if let Some(authority_discovery_service) = authority_discovery_service { let (overseer, overseer_handle) = overseer_gen @@ -1039,7 +1056,7 @@ pub fn new_full( dispute_req_receiver, registry: prometheus_registry.as_ref(), spawner, - is_collator, + is_parachain_node, approval_voting_config, availability_config: AVAILABILITY_CONFIG, candidate_validation_config, @@ -1332,11 +1349,6 @@ pub fn new_chain_ops( /// /// 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, diff --git a/node/service/src/overseer.rs b/node/service/src/overseer.rs index 29122ddca162..b315d2847c07 100644 --- a/node/service/src/overseer.rs +++ b/node/service/src/overseer.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use super::{AuthorityDiscoveryApi, Block, Error, Hash, IsCollator, Registry}; +use super::{AuthorityDiscoveryApi, Block, Error, Hash, IsParachainNode, Registry}; use polkadot_node_subsystem_types::DefaultSubsystemClient; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_core::traits::SpawnNamed; @@ -108,7 +108,7 @@ where /// Task spawner to be used throughout the overseer and the APIs it provides. pub spawner: Spawner, /// Determines the behavior of the collator. - pub is_collator: IsCollator, + pub is_parachain_node: IsParachainNode, /// Configuration for the approval voting subsystem. pub approval_voting_config: ApprovalVotingConfig, /// Configuration for the availability store subsystem. @@ -149,7 +149,7 @@ pub fn prepared_overseer_builder( dispute_req_receiver, registry, spawner, - is_collator, + is_parachain_node, approval_voting_config, availability_config, candidate_validation_config, @@ -266,14 +266,15 @@ where .chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?)) .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) .collator_protocol({ - let side = match is_collator { - IsCollator::Yes(collator_pair) => ProtocolSide::Collator( + let side = match is_parachain_node { + IsParachainNode::Collator(collator_pair) => ProtocolSide::Collator( network_service.local_peer_id(), collator_pair, collation_req_receiver, Metrics::register(registry)?, ), - IsCollator::No => ProtocolSide::Validator { + IsParachainNode::FullNode => ProtocolSide::None, + IsParachainNode::No => ProtocolSide::Validator { keystore: keystore.clone(), eviction_policy: Default::default(), metrics: Metrics::register(registry)?, diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index ed25d28d2925..932e95a7cab6 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -28,7 +28,7 @@ use polkadot_overseer::Handle; use polkadot_primitives::{Balance, CollatorPair, HeadData, Id as ParaId, ValidationCode}; use polkadot_runtime_common::BlockHashCount; use polkadot_runtime_parachains::paras::{ParaGenesisArgs, ParaKind}; -use polkadot_service::{Error, FullClient, IsCollator, NewFull, PrometheusConfig}; +use polkadot_service::{Error, FullClient, IsParachainNode, NewFull, PrometheusConfig}; use polkadot_test_runtime::{ ParasCall, ParasSudoWrapperCall, Runtime, SignedExtra, SignedPayload, SudoCall, UncheckedExtrinsic, VERSION, @@ -71,7 +71,7 @@ pub use polkadot_service::{FullBackend, GetLastTimestamp}; #[sc_tracing::logging::prefix_logs_with(config.network.node_name.as_str())] pub fn new_full( config: Configuration, - is_collator: IsCollator, + is_parachain_node: IsParachainNode, workers_path: Option, ) -> Result { let workers_path = Some(workers_path.unwrap_or_else(get_relative_workers_path_for_test)); @@ -79,14 +79,13 @@ pub fn new_full( polkadot_service::new_full( config, polkadot_service::NewFullParams { - is_collator, + is_parachain_node, grandpa_pause: None, jaeger_agent: None, telemetry_worker_handle: None, node_version: None, workers_path, workers_names: None, - overseer_enable_anyways: false, overseer_gen: polkadot_service::RealOverseerGen, overseer_message_channel_capacity_override: None, malus_finality_delay: None, @@ -207,7 +206,7 @@ pub fn run_validator_node( ) -> PolkadotTestNode { let multiaddr = config.network.listen_addresses[0].clone(); let NewFull { task_manager, client, network, rpc_handlers, overseer_handle, .. } = - new_full(config, IsCollator::No, worker_program_path) + new_full(config, IsParachainNode::No, worker_program_path) .expect("could not create Polkadot test service"); let overseer_handle = overseer_handle.expect("test node must have an overseer handle"); @@ -239,7 +238,7 @@ pub fn run_collator_node( let config = node_config(storage_update_func, tokio_handle, key, boot_nodes, false); let multiaddr = config.network.listen_addresses[0].clone(); let NewFull { task_manager, client, network, rpc_handlers, overseer_handle, .. } = - new_full(config, IsCollator::Yes(collator_pair), None) + new_full(config, IsParachainNode::Collator(collator_pair), None) .expect("could not create Polkadot test service"); let overseer_handle = overseer_handle.expect("test node must have an overseer handle"); diff --git a/parachain/test-parachains/adder/collator/src/main.rs b/parachain/test-parachains/adder/collator/src/main.rs index 8d8a13767178..f9efa9c68ad3 100644 --- a/parachain/test-parachains/adder/collator/src/main.rs +++ b/parachain/test-parachains/adder/collator/src/main.rs @@ -21,6 +21,7 @@ use polkadot_node_primitives::CollationGenerationConfig; use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage}; use polkadot_primitives::Id as ParaId; use sc_cli::{Error as SubstrateCliError, SubstrateCli}; +use sc_service::Role; use sp_core::hexdisplay::HexDisplay; use test_parachain_adder_collator::Collator; @@ -57,10 +58,15 @@ fn main() -> Result<()> { let collator = Collator::new(); config.disable_beefy = true; + // Zombienet is spawning all collators currently with the same CLI, this means it + // sets `--validator` and this is wrong here. + config.role = Role::Full; let full_node = polkadot_service::build_full( config, polkadot_service::NewFullParams { - is_collator: polkadot_service::IsCollator::Yes(collator.collator_key()), + is_parachain_node: polkadot_service::IsParachainNode::Collator( + collator.collator_key(), + ), grandpa_pause: None, jaeger_agent: None, telemetry_worker_handle: None, @@ -70,7 +76,6 @@ fn main() -> Result<()> { workers_path: None, workers_names: None, - overseer_enable_anyways: false, overseer_gen: polkadot_service::RealOverseerGen, overseer_message_channel_capacity_override: None, malus_finality_delay: None, diff --git a/parachain/test-parachains/undying/collator/src/main.rs b/parachain/test-parachains/undying/collator/src/main.rs index da8205ba1893..8eadc233ae78 100644 --- a/parachain/test-parachains/undying/collator/src/main.rs +++ b/parachain/test-parachains/undying/collator/src/main.rs @@ -21,6 +21,7 @@ use polkadot_node_primitives::CollationGenerationConfig; use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage}; use polkadot_primitives::Id as ParaId; use sc_cli::{Error as SubstrateCliError, SubstrateCli}; +use sc_service::Role; use sp_core::hexdisplay::HexDisplay; use test_parachain_undying_collator::Collator; @@ -57,10 +58,15 @@ fn main() -> Result<()> { let collator = Collator::new(cli.run.pov_size, cli.run.pvf_complexity); config.disable_beefy = true; + // Zombienet is spawning all collators currently with the same CLI, this means it + // sets `--validator` and this is wrong here. + config.role = Role::Full; let full_node = polkadot_service::build_full( config, polkadot_service::NewFullParams { - is_collator: polkadot_service::IsCollator::Yes(collator.collator_key()), + is_parachain_node: polkadot_service::IsParachainNode::Collator( + collator.collator_key(), + ), grandpa_pause: None, jaeger_agent: None, telemetry_worker_handle: None, @@ -70,7 +76,6 @@ fn main() -> Result<()> { workers_path: None, workers_names: None, - overseer_enable_anyways: false, overseer_gen: polkadot_service::RealOverseerGen, overseer_message_channel_capacity_override: None, malus_finality_delay: None, diff --git a/runtime/parachains/src/configuration.rs b/runtime/parachains/src/configuration.rs index d4ad8619f16e..0631b280aadd 100644 --- a/runtime/parachains/src/configuration.rs +++ b/runtime/parachains/src/configuration.rs @@ -1244,28 +1244,27 @@ impl Pallet { ) -> DispatchResult { let mut pending_configs = >::get(); - // 1. pending_configs = [] - // No pending configuration changes. + // 1. pending_configs = [] No pending configuration changes. // // That means we should use the active config as the base configuration. We will insert // the new pending configuration as (cur+2, new_config) into the list. // - // 2. pending_configs = [(cur+2, X)] - // There is a configuration that is pending for the scheduled session. + // 2. pending_configs = [(cur+2, X)] There is a configuration that is pending for the + // scheduled session. // // We will use X as the base configuration. We can update the pending configuration X // directly. // - // 3. pending_configs = [(cur+1, X)] - // There is a pending configuration scheduled and it will be applied in the next session. + // 3. pending_configs = [(cur+1, X)] There is a pending configuration scheduled and it will + // be applied in the next session. // // We will use X as the base configuration. We need to schedule a new configuration // change for the `scheduled_session` and use X as the base for the new configuration. // - // 4. pending_configs = [(cur+1, X), (cur+2, Y)] - // There is a pending configuration change in the next session and for the scheduled - // session. Due to case №3, we can be sure that Y is based on top of X. This means we - // can use Y as the base configuration and update Y directly. + // 4. pending_configs = [(cur+1, X), (cur+2, Y)] There is a pending configuration change in + // the next session and for the scheduled session. Due to case №3, we can be sure that Y + // is based on top of X. This means we can use Y as the base configuration and update Y + // directly. // // There cannot be (cur, X) because those are applied in the session change handler for the // current session. diff --git a/runtime/parachains/src/paras_inherent/mod.rs b/runtime/parachains/src/paras_inherent/mod.rs index a40a3422a669..da0b972bc92c 100644 --- a/runtime/parachains/src/paras_inherent/mod.rs +++ b/runtime/parachains/src/paras_inherent/mod.rs @@ -977,8 +977,8 @@ fn compute_entropy(parent_hash: T::Hash) -> [u8; 32] { /// 2. If exceeded: /// 1. Check validity of all dispute statements sequentially /// 2. If not exceeded: -/// 1. If weight is exceeded by locals, pick the older ones (lower indices) -/// until the weight limit is reached. +/// 1. If weight is exceeded by locals, pick the older ones (lower indices) until the weight limit +/// is reached. /// /// Returns the consumed weight amount, that is guaranteed to be less than the provided /// `max_consumable_weight`. diff --git a/runtime/parachains/src/runtime_api_impl/mod.rs b/runtime/parachains/src/runtime_api_impl/mod.rs index e22ef825858d..e066ad825a33 100644 --- a/runtime/parachains/src/runtime_api_impl/mod.rs +++ b/runtime/parachains/src/runtime_api_impl/mod.rs @@ -23,8 +23,7 @@ //! will contain methods from `vstaging`. //! The promotion consists of the following steps: //! 1. Bump the version of the stable module (e.g. `v2` becomes `v3`) -//! 2. Move methods from `vstaging` to `v3`. The new stable version should include -//! all methods from `vstaging` tagged with the new version number (e.g. all -//! `v3` methods). +//! 2. Move methods from `vstaging` to `v3`. The new stable version should include all methods from +//! `vstaging` tagged with the new version number (e.g. all `v3` methods). pub mod v5; pub mod vstaging; From 1bddab1660310bc450af0a741e827e795ae3e320 Mon Sep 17 00:00:00 2001 From: alexd10s Date: Tue, 15 Aug 2023 15:17:15 +0200 Subject: [PATCH 21/45] Change the Config of the MaxRococoNum Slot from a Constant to a Storage function (#7217) * set MaxPermanentSlots and MaxTemporarySlots with a extrinsic instead of a constant * delete the MaxPermanentSlots and MaxTemporarySlots constants from config on Rococo and Westend * migration code for assigned slots * remove getters * little refactor * set values in the GenesisConfig * refactor in the migration, adding it in the rococo runtime * refactor: fmt * Minor fix * pre_upgrade check * add migration to mod v1 * Logs following Substrate#12873 * fix: current storage version set to 1 * use enact when try-runtime * Vec seems to be missing * feature gate import * fix as per #13993 * address comments Co-authored-by: Oliver Tale-Yazdi * address comments Co-authored-by: Oliver Tale-Yazdi * benchmarking for assign_perm_parachain_slot extrinsic * benchmark all the extrinsics of the pallet * cargo fmt for assigned slots * migration added for westend * licence in benchmarking file * BuildGenesisConfig * assigned_slots default in genesis * cargo fmt * assigned_slots fix tests config * cargo fmt * fix benchmarking compile error * fix benchmarking imports * benchmark worst case scenario for validation code and head data * add assigned_slots in frame_benchmarking on Rococo and Westend * modify values for para_id in benchmarking * delete the assigned_slots in westend frame_benchmarking * fix benchmarkings and add it to westend * cargo fmt * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=rococo --target_dir=polkadot --pallet=runtime_common::assigned_slots * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=westend --target_dir=polkadot --pallet=runtime_common::assigned_slots * use generated weights in assigned_slots pallet * small changes in set_max_permanent_slots and set_max_temporary_slots * revert last commit * address some comments * wrap migration with VersionCheckedMigrateToV1 * add experimental feature in pallet, and assers in post_upgrade migration * clean warnings * clean unnecesary experimental flag * small typo in comments * cargo fmt * small comments fixes --------- Co-authored-by: al3mart <11448715+al3mart@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- node/service/src/chain_spec.rs | 4 + runtime/common/Cargo.toml | 3 + .../common/src/assigned_slots/benchmarking.rs | 160 ++++++++++++++ .../common/src/assigned_slots/migration.rs | 77 +++++++ .../mod.rs} | 202 +++++++++++++++--- runtime/rococo/Cargo.toml | 2 +- runtime/rococo/src/lib.rs | 9 +- runtime/rococo/src/weights/mod.rs | 1 + .../weights/runtime_common_assigned_slots.rs | 151 +++++++++++++ runtime/westend/Cargo.toml | 2 +- runtime/westend/src/lib.rs | 9 +- runtime/westend/src/weights/mod.rs | 1 + .../weights/runtime_common_assigned_slots.rs | 151 +++++++++++++ 13 files changed, 727 insertions(+), 45 deletions(-) create mode 100644 runtime/common/src/assigned_slots/benchmarking.rs create mode 100644 runtime/common/src/assigned_slots/migration.rs rename runtime/common/src/{assigned_slots.rs => assigned_slots/mod.rs} (88%) create mode 100644 runtime/rococo/src/weights/runtime_common_assigned_slots.rs create mode 100644 runtime/westend/src/weights/runtime_common_assigned_slots.rs diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index 7aabfa6e9185..87a8650c2ed6 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -515,6 +515,7 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim }, xcm_pallet: Default::default(), nomination_pools: Default::default(), + assigned_slots: Default::default(), } } @@ -1023,6 +1024,7 @@ fn rococo_staging_testnet_config_genesis( }, xcm_pallet: Default::default(), nis_counterpart_balances: Default::default(), + assigned_slots: Default::default(), } } @@ -1484,6 +1486,7 @@ pub fn westend_testnet_genesis( }, xcm_pallet: Default::default(), nomination_pools: Default::default(), + assigned_slots: Default::default(), } } @@ -1573,6 +1576,7 @@ pub fn rococo_testnet_genesis( }, xcm_pallet: Default::default(), nis_counterpart_balances: Default::default(), + assigned_slots: Default::default(), } } diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index c9812d806733..dda7c2e92368 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -64,6 +64,9 @@ test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../pri [features] default = ["std"] +experimental = [ + "frame-support/experimental" +] no_std = [] std = [ "bitvec/std", diff --git a/runtime/common/src/assigned_slots/benchmarking.rs b/runtime/common/src/assigned_slots/benchmarking.rs new file mode 100644 index 000000000000..61638fe6cabf --- /dev/null +++ b/runtime/common/src/assigned_slots/benchmarking.rs @@ -0,0 +1,160 @@ +// Copyright (C) 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 . + +//! Benchmarking for assigned_slots pallet + +#![cfg(feature = "runtime-benchmarks")] +use super::*; + +use frame_benchmarking::v2::*; +use frame_support::assert_ok; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use primitives::Id as ParaId; +use sp_runtime::traits::Bounded; + +type CurrencyOf = <::Leaser as Leaser>>::Currency; +type BalanceOf = <<::Leaser as Leaser>>::Currency as Currency< + ::AccountId, +>>::Balance; +#[benchmarks(where T: Config)] +mod benchmarks { + use super::*; + + use crate::assigned_slots::Pallet as AssignedSlots; + + fn register_parachain(para_id: ParaId) { + let who: T::AccountId = whitelisted_caller(); + let worst_validation_code = T::Registrar::worst_validation_code(); + let worst_head_data = T::Registrar::worst_head_data(); + + CurrencyOf::::make_free_balance_be(&who, BalanceOf::::max_value()); + + assert_ok!(T::Registrar::register( + who, + para_id, + worst_head_data, + worst_validation_code.clone() + )); + assert_ok!(paras::Pallet::::add_trusted_validation_code( + frame_system::Origin::::Root.into(), + worst_validation_code, + )); + T::Registrar::execute_pending_transitions(); + } + + #[benchmark] + fn assign_perm_parachain_slot() { + let para_id = ParaId::from(1_u32); + let caller = RawOrigin::Root; + + let _ = + AssignedSlots::::set_max_permanent_slots(frame_system::Origin::::Root.into(), 10); + register_parachain::(para_id); + + let counter = PermanentSlotCount::::get(); + let current_lease_period: BlockNumberFor = + T::Leaser::lease_period_index(frame_system::Pallet::::block_number()) + .and_then(|x| Some(x.0)) + .unwrap(); + #[extrinsic_call] + assign_perm_parachain_slot(caller, para_id); + + assert_eq!( + PermanentSlots::::get(para_id), + Some(( + current_lease_period, + LeasePeriodOf::::from(T::PermanentSlotLeasePeriodLength::get()), + )) + ); + assert_eq!(PermanentSlotCount::::get(), counter + 1); + } + + #[benchmark] + fn assign_temp_parachain_slot() { + let para_id = ParaId::from(2_u32); + let caller = RawOrigin::Root; + + let _ = + AssignedSlots::::set_max_temporary_slots(frame_system::Origin::::Root.into(), 10); + register_parachain::(para_id); + + let current_lease_period: BlockNumberFor = + T::Leaser::lease_period_index(frame_system::Pallet::::block_number()) + .and_then(|x| Some(x.0)) + .unwrap(); + + let counter = TemporarySlotCount::::get(); + #[extrinsic_call] + assign_temp_parachain_slot(caller, para_id, SlotLeasePeriodStart::Current); + + let tmp = ParachainTemporarySlot { + manager: whitelisted_caller(), + period_begin: current_lease_period, + period_count: LeasePeriodOf::::from(T::TemporarySlotLeasePeriodLength::get()), + last_lease: Some(BlockNumberFor::::zero()), + lease_count: 1, + }; + assert_eq!(TemporarySlots::::get(para_id), Some(tmp)); + assert_eq!(TemporarySlotCount::::get(), counter + 1); + } + + #[benchmark] + fn unassign_parachain_slot() { + let para_id = ParaId::from(3_u32); + let caller = RawOrigin::Root; + + let _ = + AssignedSlots::::set_max_temporary_slots(frame_system::Origin::::Root.into(), 10); + register_parachain::(para_id); + + let _ = AssignedSlots::::assign_temp_parachain_slot( + caller.clone().into(), + para_id, + SlotLeasePeriodStart::Current, + ); + + let counter = TemporarySlotCount::::get(); + #[extrinsic_call] + unassign_parachain_slot(caller, para_id); + + assert_eq!(TemporarySlots::::get(para_id), None); + assert_eq!(TemporarySlotCount::::get(), counter - 1); + } + + #[benchmark] + fn set_max_permanent_slots() { + let caller = RawOrigin::Root; + #[extrinsic_call] + set_max_permanent_slots(caller, u32::MAX); + + assert_eq!(MaxPermanentSlots::::get(), u32::MAX); + } + + #[benchmark] + fn set_max_temporary_slots() { + let caller = RawOrigin::Root; + #[extrinsic_call] + set_max_temporary_slots(caller, u32::MAX); + + assert_eq!(MaxTemporarySlots::::get(), u32::MAX); + } + + impl_benchmark_test_suite!( + AssignedSlots, + crate::assigned_slots::tests::new_test_ext(), + crate::assigned_slots::tests::Test, + ); +} diff --git a/runtime/common/src/assigned_slots/migration.rs b/runtime/common/src/assigned_slots/migration.rs new file mode 100644 index 000000000000..884d67222d28 --- /dev/null +++ b/runtime/common/src/assigned_slots/migration.rs @@ -0,0 +1,77 @@ +// Copyright (C) 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::{Config, MaxPermanentSlots, MaxTemporarySlots, Pallet, LOG_TARGET}; +use frame_support::{ + dispatch::GetStorageVersion, + traits::{Get, OnRuntimeUpgrade}, +}; + +#[cfg(feature = "try-runtime")] +use frame_support::ensure; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; + +pub mod v1 { + + use super::*; + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let onchain_version = Pallet::::on_chain_storage_version(); + ensure!(onchain_version < 1, "assigned_slots::MigrateToV1 migration can be deleted"); + Ok(Default::default()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let onchain_version = Pallet::::on_chain_storage_version(); + if onchain_version < 1 { + const MAX_PERMANENT_SLOTS: u32 = 100; + const MAX_TEMPORARY_SLOTS: u32 = 100; + + >::put(MAX_PERMANENT_SLOTS); + >::put(MAX_TEMPORARY_SLOTS); + // Return the weight consumed by the migration. + T::DbWeight::get().reads_writes(1, 3) + } else { + log::info!(target: LOG_TARGET, "MigrateToV1 should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let onchain_version = Pallet::::on_chain_storage_version(); + ensure!(onchain_version == 1, "assigned_slots::MigrateToV1 needs to be run"); + assert_eq!(>::get(), 100); + assert_eq!(>::get(), 100); + Ok(()) + } + } + + /// [`VersionUncheckedMigrateToV1`] wrapped in a + /// [`frame_support::migrations::VersionedRuntimeUpgrade`], ensuring the migration is only + /// performed when on-chain version is 0. + #[cfg(feature = "experimental")] + pub type VersionCheckedMigrateToV1 = frame_support::migrations::VersionedRuntimeUpgrade< + 0, + 1, + MigrateToV1, + Pallet, + ::DbWeight, + >; +} diff --git a/runtime/common/src/assigned_slots.rs b/runtime/common/src/assigned_slots/mod.rs similarity index 88% rename from runtime/common/src/assigned_slots.rs rename to runtime/common/src/assigned_slots/mod.rs index b3c1381c9ec9..4763c3e3f0b4 100644 --- a/runtime/common/src/assigned_slots.rs +++ b/runtime/common/src/assigned_slots/mod.rs @@ -23,10 +23,12 @@ //! This pallet should not be used on a production relay chain, //! only on a test relay chain (e.g. Rococo). +pub mod benchmarking; +pub mod migration; + use crate::{ - slots::{self, Pallet as Slots, WeightInfo}, + slots::{self, Pallet as Slots, WeightInfo as SlotsWeightInfo}, traits::{LeaseError, Leaser, Registrar}, - MAXIMUM_BLOCK_WEIGHT, }; use frame_support::{pallet_prelude::*, traits::Currency}; use frame_system::pallet_prelude::*; @@ -41,6 +43,8 @@ use scale_info::TypeInfo; use sp_runtime::traits::{One, Saturating, Zero}; use sp_std::prelude::*; +const LOG_TARGET: &str = "runtime::assigned_slots"; + /// Lease period an assigned slot should start from (current, or next one). #[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub enum SlotLeasePeriodStart { @@ -67,6 +71,33 @@ pub struct ParachainTemporarySlot { pub lease_count: u32, } +pub trait WeightInfo { + fn assign_perm_parachain_slot() -> Weight; + fn assign_temp_parachain_slot() -> Weight; + fn unassign_parachain_slot() -> Weight; + fn set_max_permanent_slots() -> Weight; + fn set_max_temporary_slots() -> Weight; +} + +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn assign_perm_parachain_slot() -> Weight { + Weight::zero() + } + fn assign_temp_parachain_slot() -> Weight { + Weight::zero() + } + fn unassign_parachain_slot() -> Weight { + Weight::zero() + } + fn set_max_permanent_slots() -> Weight { + Weight::zero() + } + fn set_max_temporary_slots() -> Weight { + Weight::zero() + } +} + type BalanceOf = <<::Leaser as Leaser>>::Currency as Currency< ::AccountId, >>::Balance; @@ -76,7 +107,11 @@ type LeasePeriodOf = <::Leaser as Leaser>>::Le pub mod pallet { use super::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -103,17 +138,12 @@ pub mod pallet { #[pallet::constant] type TemporarySlotLeasePeriodLength: Get; - /// The max number of permanent slots that can be assigned. - #[pallet::constant] - type MaxPermanentSlots: Get; - - /// The max number of temporary slots that can be assigned. - #[pallet::constant] - type MaxTemporarySlots: Get; - /// The max number of temporary slots to be scheduled per lease periods. #[pallet::constant] type MaxTemporarySlotPerLeasePeriod: Get; + + /// Weight Information for the Extrinsics in the Pallet + type WeightInfo: WeightInfo; } /// Assigned permanent slots, with their start lease period, and duration. @@ -148,13 +178,41 @@ pub mod pallet { #[pallet::getter(fn active_temporary_slot_count)] pub type ActiveTemporarySlotCount = StorageValue<_, u32, ValueQuery>; + /// The max number of temporary slots that can be assigned. + #[pallet::storage] + pub type MaxTemporarySlots = StorageValue<_, u32, ValueQuery>; + + /// The max number of permanent slots that can be assigned. + #[pallet::storage] + pub type MaxPermanentSlots = StorageValue<_, u32, ValueQuery>; + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + pub max_temporary_slots: u32, + pub max_permanent_slots: u32, + pub _config: PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + >::put(&self.max_permanent_slots); + >::put(&self.max_temporary_slots); + } + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A para was assigned a permanent parachain slot + /// A parachain was assigned a permanent parachain slot PermanentSlotAssigned(ParaId), - /// A para was assigned a temporary parachain slot + /// A parachain was assigned a temporary parachain slot TemporarySlotAssigned(ParaId), + /// The maximum number of permanent slots has been changed + MaxPermanentSlotsChanged { slots: u32 }, + /// The maximum number of temporary slots has been changed + MaxTemporarySlotsChanged { slots: u32 }, } #[pallet::error] @@ -173,9 +231,9 @@ pub mod pallet { SlotNotAssigned, /// An ongoing lease already exists. OngoingLeaseExists, - // Maximum number of permanent slots exceeded + // The maximum number of permanent slots exceeded MaxPermanentSlotsExceeded, - // Maximum number of temporary slots exceeded + // The maximum number of temporary slots exceeded MaxTemporarySlotsExceeded, } @@ -196,16 +254,15 @@ pub mod pallet { #[pallet::call] impl Pallet { - // TODO: Benchmark this /// Assign a permanent parachain slot and immediately create a lease for it. #[pallet::call_index(0)] - #[pallet::weight(((MAXIMUM_BLOCK_WEIGHT / 10) as Weight, DispatchClass::Operational))] + #[pallet::weight((::WeightInfo::assign_perm_parachain_slot(), DispatchClass::Operational))] pub fn assign_perm_parachain_slot(origin: OriginFor, id: ParaId) -> DispatchResult { T::AssignSlotOrigin::ensure_origin(origin)?; let manager = T::Registrar::manager_of(id).ok_or(Error::::ParaDoesntExist)?; - ensure!(T::Registrar::is_parathread(id), Error::::NotParathread,); + ensure!(T::Registrar::is_parathread(id), Error::::NotParathread); ensure!( !Self::has_permanent_slot(id) && !Self::has_temporary_slot(id), @@ -227,7 +284,7 @@ pub mod pallet { ); ensure!( - PermanentSlotCount::::get() < T::MaxPermanentSlots::get(), + PermanentSlotCount::::get() < MaxPermanentSlots::::get(), Error::::MaxPermanentSlotsExceeded ); @@ -253,12 +310,11 @@ pub mod pallet { Ok(()) } - // TODO: Benchmark this /// Assign a temporary parachain slot. The function tries to create a lease for it /// immediately if `SlotLeasePeriodStart::Current` is specified, and if the number /// of currently active temporary slots is below `MaxTemporarySlotPerLeasePeriod`. #[pallet::call_index(1)] - #[pallet::weight(((MAXIMUM_BLOCK_WEIGHT / 10) as Weight, DispatchClass::Operational))] + #[pallet::weight((::WeightInfo::assign_temp_parachain_slot(), DispatchClass::Operational))] pub fn assign_temp_parachain_slot( origin: OriginFor, id: ParaId, @@ -290,7 +346,7 @@ pub mod pallet { ); ensure!( - TemporarySlotCount::::get() < T::MaxTemporarySlots::get(), + TemporarySlotCount::::get() < MaxTemporarySlots::::get(), Error::::MaxTemporarySlotsExceeded ); @@ -324,9 +380,12 @@ pub mod pallet { // Treat failed lease creation as warning .. slot will be allocated a lease // in a subsequent lease period by the `allocate_temporary_slot_leases` // function. - log::warn!(target: "assigned_slots", + log::warn!( + target: LOG_TARGET, "Failed to allocate a temp slot for para {:?} at period {:?}: {:?}", - id, current_lease_period, err + id, + current_lease_period, + err ); }, } @@ -340,10 +399,9 @@ pub mod pallet { Ok(()) } - // TODO: Benchmark this /// Unassign a permanent or temporary parachain slot #[pallet::call_index(2)] - #[pallet::weight(((MAXIMUM_BLOCK_WEIGHT / 10) as Weight, DispatchClass::Operational))] + #[pallet::weight((::WeightInfo::unassign_parachain_slot(), DispatchClass::Operational))] pub fn unassign_parachain_slot(origin: OriginFor, id: ParaId) -> DispatchResult { T::AssignSlotOrigin::ensure_origin(origin.clone())?; @@ -377,15 +435,42 @@ pub mod pallet { // Treat failed downgrade as warning .. slot lease has been cleared, // so the parachain will be downgraded anyway by the slots pallet // at the end of the lease period . - log::warn!(target: "assigned_slots", + log::warn!( + target: LOG_TARGET, "Failed to downgrade parachain {:?} at period {:?}: {:?}", - id, Self::current_lease_period_index(), err + id, + Self::current_lease_period_index(), + err ); } } Ok(()) } + + /// Sets the storage value [`MaxPermanentSlots`]. + #[pallet::call_index(3)] + #[pallet::weight((::WeightInfo::set_max_permanent_slots(), DispatchClass::Operational))] + pub fn set_max_permanent_slots(origin: OriginFor, slots: u32) -> DispatchResult { + ensure_root(origin)?; + + >::put(slots); + + Self::deposit_event(Event::::MaxPermanentSlotsChanged { slots }); + Ok(()) + } + + /// Sets the storage value [`MaxTemporarySlots`]. + #[pallet::call_index(4)] + #[pallet::weight((::WeightInfo::set_max_temporary_slots(), DispatchClass::Operational))] + pub fn set_max_temporary_slots(origin: OriginFor, slots: u32) -> DispatchResult { + ensure_root(origin)?; + + >::put(slots); + + Self::deposit_event(Event::::MaxTemporarySlotsChanged { slots }); + Ok(()) + } } } @@ -530,9 +615,11 @@ impl Pallet { // Note: leases that have ended in previous lease period, should have been cleaned in slots // pallet. if let Err(err) = Self::allocate_temporary_slot_leases(lease_period_index) { - log::error!(target: "assigned_slots", + log::error!( + target: LOG_TARGET, "Allocating slots failed for lease period {:?}, with: {:?}", - lease_period_index, err + lease_period_index, + err ); } ::WeightInfo::force_lease() * @@ -673,8 +760,6 @@ mod tests { parameter_types! { pub const PermanentSlotLeasePeriodLength: u32 = 3; pub const TemporarySlotLeasePeriodLength: u32 = 2; - pub const MaxPermanentSlots: u32 = 2; - pub const MaxTemporarySlots: u32 = 6; pub const MaxTemporarySlotPerLeasePeriod: u32 = 2; } @@ -684,9 +769,8 @@ mod tests { type Leaser = Slots; type PermanentSlotLeasePeriodLength = PermanentSlotLeasePeriodLength; type TemporarySlotLeasePeriodLength = TemporarySlotLeasePeriodLength; - type MaxPermanentSlots = MaxPermanentSlots; - type MaxTemporarySlots = MaxTemporarySlots; type MaxTemporarySlotPerLeasePeriod = MaxTemporarySlotPerLeasePeriod; + type WeightInfo = crate::assigned_slots::TestWeightInfo; } // This function basically just builds a genesis storage key/value store according to @@ -698,6 +782,15 @@ mod tests { } .assimilate_storage(&mut t) .unwrap(); + + crate::assigned_slots::GenesisConfig:: { + max_temporary_slots: 6, + max_permanent_slots: 2, + _config: Default::default(), + } + .assimilate_storage(&mut t) + .unwrap(); + t.into() } @@ -1324,4 +1417,47 @@ mod tests { assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 1), false); }); } + #[test] + fn set_max_permanent_slots_fails_for_no_root_origin() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_noop!( + AssignedSlots::set_max_permanent_slots(RuntimeOrigin::signed(1), 5), + BadOrigin + ); + }); + } + #[test] + fn set_max_permanent_slots_succeeds() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_eq!(MaxPermanentSlots::::get(), 2); + assert_ok!(AssignedSlots::set_max_permanent_slots(RuntimeOrigin::root(), 10),); + assert_eq!(MaxPermanentSlots::::get(), 10); + }); + } + + #[test] + fn set_max_temporary_slots_fails_for_no_root_origin() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_noop!( + AssignedSlots::set_max_temporary_slots(RuntimeOrigin::signed(1), 5), + BadOrigin + ); + }); + } + #[test] + fn set_max_temporary_slots_succeeds() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_eq!(MaxTemporarySlots::::get(), 6); + assert_ok!(AssignedSlots::set_max_temporary_slots(RuntimeOrigin::root(), 12),); + assert_eq!(MaxTemporarySlots::::get(), 12); + }); + } } diff --git a/runtime/rococo/Cargo.toml b/runtime/rococo/Cargo.toml index 41d25d3aa6f6..f1f0d1cbe729 100644 --- a/runtime/rococo/Cargo.toml +++ b/runtime/rococo/Cargo.toml @@ -83,7 +83,7 @@ frame-try-runtime = { git = "https://github.com/paritytech/substrate", branch = frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } hex-literal = { version = "0.4.1" } -runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } +runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features=["experimental"] } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } polkadot-parachain = { path = "../../parachain", default-features = false } diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 31b657c3a5fb..d923437a67e5 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -1334,8 +1334,6 @@ impl paras_sudo_wrapper::Config for Runtime {} parameter_types! { pub const PermanentSlotLeasePeriodLength: u32 = 365; pub const TemporarySlotLeasePeriodLength: u32 = 5; - pub const MaxPermanentSlots: u32 = 100; - pub const MaxTemporarySlots: u32 = 100; pub const MaxTemporarySlotPerLeasePeriod: u32 = 5; } @@ -1345,9 +1343,8 @@ impl assigned_slots::Config for Runtime { type Leaser = Slots; type PermanentSlotLeasePeriodLength = PermanentSlotLeasePeriodLength; type TemporarySlotLeasePeriodLength = TemporarySlotLeasePeriodLength; - type MaxPermanentSlots = MaxPermanentSlots; - type MaxTemporarySlots = MaxTemporarySlots; type MaxTemporarySlotPerLeasePeriod = MaxTemporarySlotPerLeasePeriod; + type WeightInfo = weights::runtime_common_assigned_slots::WeightInfo; } impl validator_manager::Config for Runtime { @@ -1471,7 +1468,7 @@ construct_runtime! { MmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 242, ParasSudoWrapper: paras_sudo_wrapper::{Pallet, Call} = 250, - AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event} = 251, + AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event, Config} = 251, // Validator Manager pallet. ValidatorManager: validator_manager::{Pallet, Call, Storage, Event} = 252, @@ -1526,6 +1523,7 @@ pub mod migrations { pallet_society::migrations::VersionCheckedMigrateToV2, pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, + assigned_slots::migration::v1::VersionCheckedMigrateToV1, ); } @@ -1572,6 +1570,7 @@ mod benches { // Polkadot // NOTE: Make sure to prefix these with `runtime_common::` so // the that path resolves correctly in the generated file. + [runtime_common::assigned_slots, AssignedSlots] [runtime_common::auctions, Auctions] [runtime_common::crowdloan, Crowdloan] [runtime_common::claims, Claims] diff --git a/runtime/rococo/src/weights/mod.rs b/runtime/rococo/src/weights/mod.rs index 5bc39330e28e..75acfe9a5d64 100644 --- a/runtime/rococo/src/weights/mod.rs +++ b/runtime/rococo/src/weights/mod.rs @@ -42,6 +42,7 @@ pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; pub mod pallet_xcm; +pub mod runtime_common_assigned_slots; pub mod runtime_common_auctions; pub mod runtime_common_claims; pub mod runtime_common_crowdloan; diff --git a/runtime/rococo/src/weights/runtime_common_assigned_slots.rs b/runtime/rococo/src/weights/runtime_common_assigned_slots.rs new file mode 100644 index 000000000000..a6beeded4286 --- /dev/null +++ b/runtime/rococo/src/weights/runtime_common_assigned_slots.rs @@ -0,0 +1,151 @@ +// Copyright (C) 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 . + +//! Autogenerated weights for `runtime_common::assigned_slots` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_common::assigned_slots +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `runtime_common::assigned_slots`. +pub struct WeightInfo(PhantomData); +impl runtime_common::assigned_slots::WeightInfo for WeightInfo { + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:1) + /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::TemporarySlots` (r:1 w:0) + /// Proof: `AssignedSlots::TemporarySlots` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::PermanentSlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::PermanentSlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::MaxPermanentSlots` (r:1 w:0) + /// Proof: `AssignedSlots::MaxPermanentSlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn assign_perm_parachain_slot() -> Weight { + // Proof Size summary in bytes: + // Measured: `673` + // Estimated: `4138` + // Minimum execution time: 84_646_000 picoseconds. + Weight::from_parts(91_791_000, 0) + .saturating_add(Weight::from_parts(0, 4138)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) + /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::TemporarySlots` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlots` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::TemporarySlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::MaxTemporarySlots` (r:1 w:0) + /// Proof: `AssignedSlots::MaxTemporarySlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::ActiveTemporarySlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::ActiveTemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn assign_temp_parachain_slot() -> Weight { + // Proof Size summary in bytes: + // Measured: `673` + // Estimated: `4138` + // Minimum execution time: 68_091_000 picoseconds. + Weight::from_parts(77_310_000, 0) + .saturating_add(Weight::from_parts(0, 4138)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) + /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::TemporarySlots` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlots` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::TemporarySlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn unassign_parachain_slot() -> Weight { + // Proof Size summary in bytes: + // Measured: `823` + // Estimated: `4288` + // Minimum execution time: 38_081_000 picoseconds. + Weight::from_parts(40_987_000, 0) + .saturating_add(Weight::from_parts(0, 4288)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AssignedSlots::MaxPermanentSlots` (r:0 w:1) + /// Proof: `AssignedSlots::MaxPermanentSlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn set_max_permanent_slots() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_182_000 picoseconds. + Weight::from_parts(7_437_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AssignedSlots::MaxTemporarySlots` (r:0 w:1) + /// Proof: `AssignedSlots::MaxTemporarySlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn set_max_temporary_slots() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_153_000 picoseconds. + Weight::from_parts(7_456_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/runtime/westend/Cargo.toml b/runtime/westend/Cargo.toml index 4773176e1762..e665a08b1ed1 100644 --- a/runtime/westend/Cargo.toml +++ b/runtime/westend/Cargo.toml @@ -89,7 +89,7 @@ pallet-offences-benchmarking = { git = "https://github.com/paritytech/substrate" pallet-session-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } hex-literal = { version = "0.4.1", optional = true } -runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } +runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false, features=["experimental"] } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } polkadot-parachain = { path = "../../parachain", default-features = false } runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 9bb5a6db613d..9c322d6b8436 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -1007,8 +1007,6 @@ impl paras_sudo_wrapper::Config for Runtime {} parameter_types! { pub const PermanentSlotLeasePeriodLength: u32 = 26; pub const TemporarySlotLeasePeriodLength: u32 = 1; - pub const MaxPermanentSlots: u32 = 5; - pub const MaxTemporarySlots: u32 = 20; pub const MaxTemporarySlotPerLeasePeriod: u32 = 5; } @@ -1018,9 +1016,8 @@ impl assigned_slots::Config for Runtime { type Leaser = Slots; type PermanentSlotLeasePeriodLength = PermanentSlotLeasePeriodLength; type TemporarySlotLeasePeriodLength = TemporarySlotLeasePeriodLength; - type MaxPermanentSlots = MaxPermanentSlots; - type MaxTemporarySlots = MaxTemporarySlots; type MaxTemporarySlotPerLeasePeriod = MaxTemporarySlotPerLeasePeriod; + type WeightInfo = weights::runtime_common_assigned_slots::WeightInfo; } impl parachains_disputes::Config for Runtime { @@ -1231,7 +1228,7 @@ construct_runtime! { ParasSudoWrapper: paras_sudo_wrapper::{Pallet, Call} = 62, Auctions: auctions::{Pallet, Call, Storage, Event} = 63, Crowdloan: crowdloan::{Pallet, Call, Storage, Event} = 64, - AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event} = 65, + AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event, Config} = 65, // Pallet for sending XCM. XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, @@ -1285,6 +1282,7 @@ pub mod migrations { pub type Unreleased = ( pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, + assigned_slots::migration::v1::VersionCheckedMigrateToV1, ); } @@ -1309,6 +1307,7 @@ mod benches { // Polkadot // NOTE: Make sure to prefix these with `runtime_common::` so // the that path resolves correctly in the generated file. + [runtime_common::assigned_slots, AssignedSlots] [runtime_common::auctions, Auctions] [runtime_common::crowdloan, Crowdloan] [runtime_common::paras_registrar, Registrar] diff --git a/runtime/westend/src/weights/mod.rs b/runtime/westend/src/weights/mod.rs index 6341b3da8b69..531de5527de5 100644 --- a/runtime/westend/src/weights/mod.rs +++ b/runtime/westend/src/weights/mod.rs @@ -37,6 +37,7 @@ pub mod pallet_timestamp; pub mod pallet_utility; pub mod pallet_vesting; pub mod pallet_xcm; +pub mod runtime_common_assigned_slots; pub mod runtime_common_auctions; pub mod runtime_common_crowdloan; pub mod runtime_common_paras_registrar; diff --git a/runtime/westend/src/weights/runtime_common_assigned_slots.rs b/runtime/westend/src/weights/runtime_common_assigned_slots.rs new file mode 100644 index 000000000000..c3f1060a9ac0 --- /dev/null +++ b/runtime/westend/src/weights/runtime_common_assigned_slots.rs @@ -0,0 +1,151 @@ +// Copyright (C) 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 . + +//! Autogenerated weights for `runtime_common::assigned_slots` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_common::assigned_slots +// --chain=westend-dev +// --header=./file_header.txt +// --output=./runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `runtime_common::assigned_slots`. +pub struct WeightInfo(PhantomData); +impl runtime_common::assigned_slots::WeightInfo for WeightInfo { + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:1) + /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::TemporarySlots` (r:1 w:0) + /// Proof: `AssignedSlots::TemporarySlots` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::PermanentSlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::PermanentSlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::MaxPermanentSlots` (r:1 w:0) + /// Proof: `AssignedSlots::MaxPermanentSlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn assign_perm_parachain_slot() -> Weight { + // Proof Size summary in bytes: + // Measured: `640` + // Estimated: `4105` + // Minimum execution time: 74_788_000 picoseconds. + Weight::from_parts(79_847_000, 0) + .saturating_add(Weight::from_parts(0, 4105)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) + /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::TemporarySlots` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlots` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::TemporarySlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::MaxTemporarySlots` (r:1 w:0) + /// Proof: `AssignedSlots::MaxTemporarySlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::ActiveTemporarySlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::ActiveTemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn assign_temp_parachain_slot() -> Weight { + // Proof Size summary in bytes: + // Measured: `640` + // Estimated: `4105` + // Minimum execution time: 73_324_000 picoseconds. + Weight::from_parts(77_993_000, 0) + .saturating_add(Weight::from_parts(0, 4105)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) + /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `AssignedSlots::TemporarySlots` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlots` (`max_values`: None, `max_size`: Some(61), added: 2536, mode: `MaxEncodedLen`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssignedSlots::TemporarySlotCount` (r:1 w:1) + /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn unassign_parachain_slot() -> Weight { + // Proof Size summary in bytes: + // Measured: `592` + // Estimated: `4057` + // Minimum execution time: 32_796_000 picoseconds. + Weight::from_parts(35_365_000, 0) + .saturating_add(Weight::from_parts(0, 4057)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `AssignedSlots::MaxPermanentSlots` (r:0 w:1) + /// Proof: `AssignedSlots::MaxPermanentSlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn set_max_permanent_slots() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_104_000 picoseconds. + Weight::from_parts(7_358_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AssignedSlots::MaxTemporarySlots` (r:0 w:1) + /// Proof: `AssignedSlots::MaxTemporarySlots` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn set_max_temporary_slots() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_097_000 picoseconds. + Weight::from_parts(7_429_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} From 964330d6b50179b77204a7810e841f0b27fc47a0 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 15 Aug 2023 19:06:07 +0300 Subject: [PATCH 22/45] Revert "companion for 14754: cli: move no-beefy flag to sc-cli (#7600)" (#7613) * Revert "companion for 14754: cli: move no-beefy flag to sc-cli (#7600)" This reverts commit 8f05479e4bd61341af69f0721e617f01cbad8bb2. * update lockfile for {"substrate"} * fix merge damage --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 372 +++++++++--------- cli/src/cli.rs | 5 + cli/src/command.rs | 11 +- node/service/src/lib.rs | 3 +- node/test/service/src/lib.rs | 2 +- .../adder/collator/src/main.rs | 2 +- .../undying/collator/src/main.rs | 2 +- 7 files changed, 204 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85b0bf1cfa57..4d37230ea10f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -617,7 +617,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "hash-db", "log", @@ -2446,7 +2446,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", ] @@ -2469,7 +2469,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-support-procedural", @@ -2494,7 +2494,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "Inflector", "array-bytes", @@ -2542,7 +2542,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2553,7 +2553,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2570,7 +2570,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -2599,7 +2599,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-recursion", "futures", @@ -2620,7 +2620,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "aquamarine", "bitflags", @@ -2657,7 +2657,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "Inflector", "cfg-expr", @@ -2675,7 +2675,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2687,7 +2687,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro2", "quote", @@ -2697,7 +2697,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-executive", @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -2737,7 +2737,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "cfg-if", "frame-support", @@ -2756,7 +2756,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -2771,7 +2771,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "sp-api", @@ -2780,7 +2780,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "parity-scale-codec", @@ -2962,7 +2962,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "chrono", "frame-election-provider-support", @@ -4829,7 +4829,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "log", @@ -4848,7 +4848,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "anyhow", "jsonrpsee", @@ -5374,7 +5374,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5389,7 +5389,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -5405,7 +5405,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -5419,7 +5419,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5443,8 +5443,10 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ + "aquamarine", + "docify", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -5463,7 +5465,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -5482,7 +5484,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5497,7 +5499,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -5516,7 +5518,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -5540,7 +5542,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5558,7 +5560,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5577,7 +5579,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5594,7 +5596,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5611,7 +5613,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5629,7 +5631,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5652,7 +5654,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5665,7 +5667,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5684,7 +5686,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "docify", "frame-benchmarking", @@ -5703,7 +5705,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5726,7 +5728,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5742,7 +5744,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5762,7 +5764,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5779,7 +5781,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5796,7 +5798,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5815,7 +5817,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5832,7 +5834,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5848,7 +5850,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5864,7 +5866,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -5883,7 +5885,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5903,7 +5905,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -5914,7 +5916,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -5931,7 +5933,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5955,7 +5957,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5972,7 +5974,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5987,7 +5989,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6005,7 +6007,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6020,7 +6022,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6039,8 +6041,9 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -6056,7 +6059,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -6077,7 +6080,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6093,7 +6096,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6111,7 +6114,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6134,7 +6137,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6145,7 +6148,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "log", "sp-arithmetic", @@ -6154,7 +6157,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "sp-api", @@ -6163,7 +6166,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6180,7 +6183,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6195,7 +6198,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6213,7 +6216,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6232,7 +6235,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-support", "frame-system", @@ -6248,7 +6251,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6264,7 +6267,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6276,7 +6279,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6293,7 +6296,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6311,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6324,7 +6327,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6339,7 +6342,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-benchmarking", "frame-support", @@ -9361,7 +9364,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "log", "sp-core", @@ -9372,7 +9375,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "futures", @@ -9400,7 +9403,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "futures-timer", @@ -9423,7 +9426,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9438,7 +9441,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -9457,7 +9460,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -9468,7 +9471,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "chrono", @@ -9507,7 +9510,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "fnv", "futures", @@ -9533,7 +9536,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "hash-db", "kvdb", @@ -9559,7 +9562,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "futures", @@ -9584,7 +9587,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "fork-tree", @@ -9620,7 +9623,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "jsonrpsee", @@ -9642,7 +9645,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "async-channel", @@ -9676,7 +9679,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "jsonrpsee", @@ -9695,7 +9698,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9708,7 +9711,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ahash 0.8.2", "array-bytes", @@ -9749,7 +9752,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "finality-grandpa", "futures", @@ -9769,7 +9772,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "futures", @@ -9792,7 +9795,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -9814,7 +9817,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -9826,7 +9829,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "anyhow", "cfg-if", @@ -9843,7 +9846,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ansi_term", "futures", @@ -9859,7 +9862,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -9873,7 +9876,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "async-channel", @@ -9916,7 +9919,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-channel", "cid", @@ -9936,7 +9939,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "bitflags", @@ -9953,7 +9956,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ahash 0.8.2", "futures", @@ -9972,7 +9975,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "async-channel", @@ -9993,7 +9996,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "async-channel", @@ -10027,7 +10030,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "futures", @@ -10045,7 +10048,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "bytes", @@ -10079,7 +10082,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10088,7 +10091,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "jsonrpsee", @@ -10119,7 +10122,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10138,7 +10141,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "http", "jsonrpsee", @@ -10153,7 +10156,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "futures", @@ -10174,13 +10177,14 @@ dependencies = [ "sp-runtime", "sp-version", "thiserror", + "tokio", "tokio-stream", ] [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "directories", @@ -10244,7 +10248,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "log", "parity-scale-codec", @@ -10255,7 +10259,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "clap 4.2.5", "fs4", @@ -10269,7 +10273,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10288,7 +10292,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "libc", @@ -10307,7 +10311,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "chrono", "futures", @@ -10326,7 +10330,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ansi_term", "atty", @@ -10355,7 +10359,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10366,7 +10370,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "futures", @@ -10392,7 +10396,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "futures", @@ -10408,7 +10412,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-channel", "futures", @@ -10956,7 +10960,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "hash-db", "log", @@ -10977,7 +10981,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "Inflector", "blake2", @@ -10991,7 +10995,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11004,7 +11008,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "integer-sqrt", "num-traits", @@ -11018,7 +11022,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11031,7 +11035,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "sp-api", "sp-inherents", @@ -11042,7 +11046,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "log", @@ -11060,7 +11064,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "futures", @@ -11075,7 +11079,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11092,7 +11096,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11111,7 +11115,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11130,7 +11134,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "finality-grandpa", "log", @@ -11148,7 +11152,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11160,7 +11164,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11207,7 +11211,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "blake2b_simd", "byteorder", @@ -11220,7 +11224,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "quote", "sp-core-hashing", @@ -11230,7 +11234,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11239,7 +11243,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro2", "quote", @@ -11249,7 +11253,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "environmental", "parity-scale-codec", @@ -11260,7 +11264,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "serde_json", "sp-api", @@ -11271,7 +11275,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11285,7 +11289,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "bytes", "ed25519", @@ -11310,7 +11314,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "lazy_static", "sp-core", @@ -11321,7 +11325,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -11333,7 +11337,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "thiserror", "zstd 0.12.3+zstd.1.5.2", @@ -11342,7 +11346,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -11353,7 +11357,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -11371,7 +11375,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11385,7 +11389,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "sp-api", "sp-core", @@ -11395,7 +11399,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "backtrace", "lazy_static", @@ -11405,7 +11409,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "rustc-hash", "serde", @@ -11415,7 +11419,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "either", "hash256-std-hasher", @@ -11437,7 +11441,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -11455,7 +11459,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "Inflector", "proc-macro-crate", @@ -11467,7 +11471,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11482,7 +11486,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -11496,7 +11500,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "hash-db", "log", @@ -11517,7 +11521,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -11541,12 +11545,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11559,7 +11563,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11572,7 +11576,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "sp-std", @@ -11584,7 +11588,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "sp-api", "sp-runtime", @@ -11593,7 +11597,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11608,7 +11612,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ahash 0.8.2", "hash-db", @@ -11631,7 +11635,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11648,7 +11652,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -11659,7 +11663,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -11672,7 +11676,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11897,12 +11901,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -11921,7 +11925,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "hyper", "log", @@ -11933,7 +11937,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "jsonrpsee", @@ -11946,7 +11950,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11963,7 +11967,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "array-bytes", "async-trait", @@ -11989,7 +11993,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "futures", "substrate-test-utils-derive", @@ -11999,7 +12003,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12010,7 +12014,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "ansi_term", "build-helper", @@ -12882,7 +12886,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#2060c366fb1402deab188911551a43c3c41b36c0" +source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" dependencies = [ "async-trait", "clap 4.2.5", diff --git a/cli/src/cli.rs b/cli/src/cli.rs index c13340d91a04..696d381962b6 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -99,6 +99,11 @@ pub struct RunCmd { #[arg(long = "grandpa-pause", num_args = 2)] pub grandpa_pause: Vec, + /// Disable the BEEFY gadget + /// (currently enabled by default on Rococo, Wococo and Versi). + #[arg(long)] + pub no_beefy: bool, + /// Add the destination address to the jaeger agent. /// /// Must be valid socket address, of format `IP:Port` diff --git a/cli/src/command.rs b/cli/src/command.rs index dcffa09aaf91..dd76ed558695 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -235,11 +235,15 @@ fn run_node_inner( where F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), { - let mut runner = cli + let runner = cli .create_runner_with_logger_hook::(&cli.run.base, logger_hook) .map_err(Error::from)?; let chain_spec = &runner.config().chain_spec; + // By default, enable BEEFY on test networks. + let enable_beefy = (chain_spec.is_rococo() || chain_spec.is_wococo() || chain_spec.is_versi()) && + !cli.run.no_beefy; + set_default_ss58_version(chain_spec); let grandpa_pause = if cli.run.grandpa_pause.is_empty() { @@ -255,10 +259,6 @@ where info!(" KUSAMA FOUNDATION "); info!("----------------------------"); } - // BEEFY allowed only on test networks. - if !(chain_spec.is_rococo() || chain_spec.is_wococo() || chain_spec.is_versi()) { - runner.config_mut().disable_beefy = true; - } let jaeger_agent = if let Some(ref jaeger_agent) = cli.run.jaeger_agent { Some( @@ -289,6 +289,7 @@ where service::NewFullParams { is_parachain_node: service::IsParachainNode::No, grandpa_pause, + enable_beefy, jaeger_agent, telemetry_worker_handle: None, node_version, diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index dab69473c6ba..3a850c46279a 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -629,6 +629,7 @@ where pub struct NewFullParams { pub is_parachain_node: IsParachainNode, pub grandpa_pause: Option<(u32, u32)>, + pub enable_beefy: bool, pub jaeger_agent: Option, pub telemetry_worker_handle: Option, /// The version of the node. TESTING ONLY: `None` can be passed to skip the node/worker version @@ -719,6 +720,7 @@ pub fn new_full( NewFullParams { is_parachain_node, grandpa_pause, + enable_beefy, jaeger_agent, telemetry_worker_handle, node_version, @@ -752,7 +754,6 @@ pub fn new_full( Some(backoff) }; - let enable_beefy = !config.disable_beefy; // If not on a known test network, warn the user that BEEFY is still experimental. if enable_beefy && !config.chain_spec.is_rococo() && diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index 932e95a7cab6..4fc3f82eb4a9 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -81,6 +81,7 @@ pub fn new_full( polkadot_service::NewFullParams { is_parachain_node, grandpa_pause: None, + enable_beefy: true, jaeger_agent: None, telemetry_worker_handle: None, node_version: None, @@ -186,7 +187,6 @@ pub fn node_config( offchain_worker: Default::default(), force_authoring: false, disable_grandpa: false, - disable_beefy: false, dev_key_seed: Some(key_seed), tracing_targets: None, tracing_receiver: Default::default(), diff --git a/parachain/test-parachains/adder/collator/src/main.rs b/parachain/test-parachains/adder/collator/src/main.rs index f9efa9c68ad3..de1b37b50dab 100644 --- a/parachain/test-parachains/adder/collator/src/main.rs +++ b/parachain/test-parachains/adder/collator/src/main.rs @@ -57,7 +57,6 @@ fn main() -> Result<()> { runner.run_node_until_exit(|mut config| async move { let collator = Collator::new(); - config.disable_beefy = true; // Zombienet is spawning all collators currently with the same CLI, this means it // sets `--validator` and this is wrong here. config.role = Role::Full; @@ -68,6 +67,7 @@ fn main() -> Result<()> { collator.collator_key(), ), grandpa_pause: None, + enable_beefy: false, jaeger_agent: None, telemetry_worker_handle: None, diff --git a/parachain/test-parachains/undying/collator/src/main.rs b/parachain/test-parachains/undying/collator/src/main.rs index 8eadc233ae78..79420dbbc9d5 100644 --- a/parachain/test-parachains/undying/collator/src/main.rs +++ b/parachain/test-parachains/undying/collator/src/main.rs @@ -57,7 +57,6 @@ fn main() -> Result<()> { runner.run_node_until_exit(|mut config| async move { let collator = Collator::new(cli.run.pov_size, cli.run.pvf_complexity); - config.disable_beefy = true; // Zombienet is spawning all collators currently with the same CLI, this means it // sets `--validator` and this is wrong here. config.role = Role::Full; @@ -68,6 +67,7 @@ fn main() -> Result<()> { collator.collator_key(), ), grandpa_pause: None, + enable_beefy: false, jaeger_agent: None, telemetry_worker_handle: None, From a9f56c0d6cefbe0b1e5d529c6436f2eace1540ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:37:41 +0000 Subject: [PATCH 23/45] Bump actions/setup-node from 3.7.0 to 3.8.0 (#7622) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3.7.0 to 3.8.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3.7.0...v3.8.0) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/check-licenses.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 522037b6827c..b61005649eec 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -9,7 +9,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v3 - - uses: actions/setup-node@v3.7.0 + - uses: actions/setup-node@v3.8.0 with: node-version: '18.x' registry-url: 'https://npm.pkg.github.com' From 39397a5a82ff6ab77ce39e7af9113c7c9cbd4c1e Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Wed, 16 Aug 2023 14:39:40 +0300 Subject: [PATCH 24/45] Revert "[Substrate companion] update libp2p to 0.52.0 (#7472)" (#7583) * Revert "[Substrate companion] update libp2p to 0.52.0 (#7472)" This reverts commit 01fd49a7fafa01f133e2dec538a2ef7c697a26aa. * Update dependencies * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 3873 +++++++++++------ node/core/approval-voting/Cargo.toml | 2 +- node/core/runtime-api/Cargo.toml | 2 +- node/gum/proc-macro/Cargo.toml | 2 +- .../network/bridge/src/validator_discovery.rs | 4 +- node/network/gossip-support/src/tests.rs | 6 +- node/overseer/Cargo.toml | 2 +- node/service/Cargo.toml | 2 +- node/subsystem-types/Cargo.toml | 2 +- runtime/kusama/Cargo.toml | 2 +- runtime/kusama/constants/Cargo.toml | 2 +- runtime/polkadot/Cargo.toml | 2 +- runtime/polkadot/constants/Cargo.toml | 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 +- xcm/procedural/Cargo.toml | 2 +- 20 files changed, 2448 insertions(+), 1469 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d37230ea10f..50e6128a7f0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,15 @@ dependencies = [ "gimli", ] +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -33,13 +42,23 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "aead" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", + "rand_core 0.6.4", ] [[package]] @@ -49,7 +68,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array 0.14.6", + "generic-array 0.14.7", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", ] [[package]] @@ -103,34 +133,54 @@ dependencies = [ "subtle", ] +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + [[package]] name = "ahash" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.10", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom 0.2.8", + "getrandom 0.2.10", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -143,9 +193,24 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "always-assert" -version = "0.1.2" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] [[package]] name = "anes" @@ -179,15 +244,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -213,15 +278,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "approx" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "072df7202e63b127ab55acfe16ce97013d5b97bf160489336d3f1840fd78e99e" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" dependencies = [ "num-traits", ] @@ -242,9 +307,15 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.2.0" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" + +[[package]] +name = "arc-swap" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "ark-bls12-381" @@ -412,9 +483,9 @@ checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -428,15 +499,83 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "asn1-rs" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ff05a702273012438132f449575dbc804e27b2f3cbe3069aa237d26c98fa33" +dependencies = [ + "asn1-rs-derive 0.1.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.25", +] + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive 0.4.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.25", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "assert_cmd" -version = "2.0.4" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e" +checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" dependencies = [ + "anstyle", "bstr", "doc-comment", - "predicates", + "predicates 3.0.3", "predicates-core", "predicates-tree", "wait-timeout", @@ -450,39 +589,40 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-channel" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ - "concurrent-queue 2.1.0", + "concurrent-queue", "event-listener", "futures-core", ] [[package]] name = "async-io" -version = "1.6.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "concurrent-queue 1.2.2", + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", "futures-lite", - "libc", "log", - "once_cell", "parking", "polling", + "rustix 0.37.23", "slab", "socket2 0.4.9", "waker-fn", - "winapi", ] [[package]] name = "async-lock" -version = "2.4.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" dependencies = [ "event-listener", ] @@ -495,33 +635,39 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "asynchronous-codec" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" +checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" dependencies = [ "bytes", "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", ] +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + [[package]] name = "atty" version = "0.2.14" @@ -541,16 +687,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ - "addr2line", + "addr2line 0.20.0", "cc", "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.31.1", "rustc-demangle", ] @@ -577,9 +723,15 @@ dependencies = [ [[package]] name = "base-x" -version = "0.2.8" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base16ct" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" [[package]] name = "base16ct" @@ -589,27 +741,36 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" -version = "1.5.2" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "basic-toml" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2b2456fd614d856680dcd9fcc660a51a820fa09daef2e49772b56a193c8474" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +dependencies = [ + "serde", +] [[package]] name = "beef" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" dependencies = [ "serde", ] @@ -617,7 +778,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "hash-db", "log", @@ -638,19 +799,19 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", "lazycell", "peeking_take_while", - "prettyplease", + "prettyplease 0.2.12", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -659,6 +820,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bitvec" version = "1.0.1" @@ -688,31 +855,31 @@ checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.2.4", + "constant_time_eq 0.2.6", ] [[package]] name = "blake2s_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.1.5", + "constant_time_eq 0.2.6", ] [[package]] name = "blake3" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" dependencies = [ "arrayref", "arrayvec 0.7.4", "cc", "cfg-if", - "constant_time_eq 0.1.5", + "constant_time_eq 0.3.0", "digest 0.10.7", ] @@ -722,7 +889,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding", + "block-padding 0.1.5", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -734,16 +901,26 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", +] + +[[package]] +name = "block-modes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" +dependencies = [ + "block-padding 0.2.1", + "cipher 0.2.5", ] [[package]] @@ -755,6 +932,12 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + [[package]] name = "bounded-collections" version = "0.1.8" @@ -782,24 +965,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -[[package]] -name = "bs58" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" -dependencies = [ - "tinyvec", -] - [[package]] name = "bstr" -version = "0.2.17" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ - "lazy_static", "memchr", - "regex-automata", + "regex-automata 0.3.4", + "serde", ] [[package]] @@ -813,9 +987,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byte-slice-cast" @@ -831,9 +1005,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -858,26 +1032,20 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cache-padded" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" - [[package]] name = "camino" -version = "1.1.2" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" dependencies = [ "serde", ] @@ -890,7 +1058,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.16", + "semver 1.0.18", "serde", "serde_json", "thiserror", @@ -904,11 +1072,23 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" dependencies = [ "jobserver", + "libc", +] + +[[package]] +name = "ccm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" +dependencies = [ + "aead 0.3.2", + "cipher 0.2.5", + "subtle", ] [[package]] @@ -922,9 +1102,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.1" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9" +checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9" dependencies = [ "smallvec", ] @@ -968,22 +1148,24 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ - "libc", - "num-integer", + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", - "time", + "time 0.1.45", + "wasm-bindgen", "winapi", ] [[package]] name = "ciborium" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" dependencies = [ "ciborium-io", "ciborium-ll", @@ -992,15 +1174,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" [[package]] name = "ciborium-ll" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" dependencies = [ "ciborium-io", "half", @@ -1014,18 +1196,27 @@ checksum = "b9b68e3193982cd54187d71afdb2a271ad4cf8af157858e9cb911b91321de143" dependencies = [ "core2", "multibase", - "multihash 0.17.0", + "multihash", "serde", "unsigned-varint", ] +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "cipher" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -1049,9 +1240,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.3.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", @@ -1060,15 +1251,15 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", - "clap_derive 3.2.18", + "bitflags 1.3.2", + "clap_derive 3.2.25", "clap_lex 0.2.4", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim", "termcolor", @@ -1077,33 +1268,32 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.5" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a1f23fa97e1d1641371b51f35535cb26959b8e27ab50d167a8b996b5bada819" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ "clap_builder", - "clap_derive 4.2.0", + "clap_derive 4.3.12", "once_cell", ] [[package]] name = "clap_builder" -version = "4.2.5" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdc5d93c358224b4d6867ef1356d740de2303e9892edc06c5340daeccd96bab" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstream", "anstyle", - "bitflags", - "clap_lex 0.4.1", + "clap_lex 0.5.0", "strsim", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", @@ -1114,14 +1304,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.2.0" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -1135,15 +1325,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "coarsetime" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454038500439e141804c655b4cd1bc6a70bcb95cd2bc9463af5661b6956f0e46" +checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" dependencies = [ "libc", "once_cell", @@ -1163,9 +1353,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" dependencies = [ "backtrace", "eyre", @@ -1182,9 +1372,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comfy-table" -version = "7.0.0" +version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e1f7e5d046697d34b593bdba8ee31f4649366e452a2ccabb3baf3511e503d1" +checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b" dependencies = [ "strum", "strum_macros", @@ -1213,40 +1403,31 @@ checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "concurrent-queue" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" dependencies = [ "crossbeam-utils", ] [[package]] name = "console" -version = "0.15.5" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "const-oid" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" [[package]] name = "const-random" @@ -1264,7 +1445,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.10", "once_cell", "proc-macro-hack", "tiny-keccak", @@ -1272,15 +1453,15 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" [[package]] name = "constant_time_eq" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "convert_case" @@ -1290,9 +1471,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -1300,9 +1481,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "core2" @@ -1315,9 +1496,18 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.3.4" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpp_demangle" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931ab2a3e6330a07900b8e7ca4e106cdcbb93f2b9a52df55e54ee53d8305b55d" +checksum = "ee34052ee3d93d6d8f3e6f81d85c47921f6653a19a7b70e939e3e602d893a674" dependencies = [ "cfg-if", ] @@ -1334,9 +1524,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -1440,7 +1630,22 @@ dependencies = [ ] [[package]] -name = "crc32fast" +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + +[[package]] +name = "crc32fast" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" @@ -1458,7 +1663,7 @@ dependencies = [ "atty", "cast", "ciborium", - "clap 3.2.23", + "clap 3.2.25", "criterion-plot", "itertools", "lazy_static", @@ -1484,9 +1689,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1494,9 +1699,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -1505,22 +1710,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", - "memoffset 0.6.4", + "memoffset 0.9.0", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1528,9 +1733,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -1541,13 +1746,25 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-bigint" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -1559,7 +1776,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "rand_core 0.6.4", "typenum", ] @@ -1570,7 +1787,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "subtle", ] @@ -1580,20 +1797,10 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "subtle", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "ctr" version = "0.8.0" @@ -1654,9 +1861,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.80" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +checksum = "f68e12e817cb19eaab81aaec582b4052d07debd3c3c6b083b9d361db47c7dc9d" dependencies = [ "cc", "cxxbridge-flags", @@ -1666,9 +1873,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.80" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +checksum = "e789217e4ab7cf8cc9ce82253180a9fe331f35f5d339f0ccfe0270b39433f397" dependencies = [ "cc", "codespan-reporting", @@ -1676,37 +1883,72 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "cxxbridge-flags" -version = "1.0.80" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" +checksum = "78a19f4c80fd9ab6c882286fa865e92e07688f4387370a209508014ead8751d0" [[package]] name = "cxxbridge-macro" -version = "1.0.80" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fcfa71f66c8563c4fa9dd2bb68368d50267856f831ac5d85367e0805f9606c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ + "fnv", + "ident_case", "proc-macro2", "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", "syn 1.0.109", ] [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.0", "lock_api", "once_cell", - "parking_lot_core 0.9.6", + "parking_lot_core 0.9.8", ] [[package]] @@ -1717,9 +1959,9 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "data-encoding-macro" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" +checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1727,9 +1969,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" +checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" dependencies = [ "data-encoding", "syn 1.0.109", @@ -1744,6 +1986,17 @@ dependencies = [ "uuid", ] +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "der" version = "0.7.7" @@ -1754,6 +2007,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe398ac75057914d7d07307bf67dc7f3f574a26783b4fc7805a20ffa9f506e82" +dependencies = [ + "asn1-rs 0.3.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs 0.5.2", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" + [[package]] name = "derivative" version = "2.2.0" @@ -1776,6 +2063,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1791,9 +2109,9 @@ dependencies = [ [[package]] name = "diff" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "difflib" @@ -1816,7 +2134,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -1825,7 +2143,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -1852,9 +2170,9 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", @@ -1872,11 +2190,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "dissimilar" -version = "1.0.3" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ad93652f40969dead8d4bf897a41e9462095152eb21c56e5830537e41179dd" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" @@ -1930,9 +2259,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.20", + "syn 2.0.28", "termcolor", - "toml 0.7.3", + "toml 0.7.6", "walkdir", ] @@ -1944,9 +2273,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dtoa" -version = "1.0.2" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5caaa75cbd2b960ff1e5392d2cfb1f44717fffe12fc1f32b7b5d1267f99732a6" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "dyn-clonable" @@ -1971,22 +2300,34 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.4" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" + +[[package]] +name = "ecdsa" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] [[package]] name = "ecdsa" -version = "0.16.7" +version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ - "der", + "der 0.7.7", "digest 0.10.7", - "elliptic-curve", - "rfc6979", + "elliptic-curve 0.13.5", + "rfc6979 0.4.0", "signature 2.1.0", - "spki", + "spki 0.7.2", ] [[package]] @@ -2008,7 +2349,7 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "zeroize", ] @@ -2022,7 +2363,7 @@ dependencies = [ "hashbrown 0.12.3", "hex", "rand_core 0.6.4", - "sha2 0.9.8", + "sha2 0.9.9", "zeroize", ] @@ -2032,21 +2373,43 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest 0.10.7", + "ff 0.12.1", + "generic-array 0.14.7", + "group 0.12.1", + "hkdf", + "pem-rfc7468", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + [[package]] name = "elliptic-curve" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ - "base16ct", - "crypto-bigint", + "base16ct 0.2.0", + "crypto-bigint 0.5.2", "digest 0.10.7", - "ff", - "generic-array 0.14.6", - "group", - "pkcs8", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sec1", + "sec1 0.7.3", "subtle", "zeroize", ] @@ -2059,9 +2422,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -2095,28 +2458,28 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "enumn" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76" +checksum = "b893c4eb2dc092c811165f84dc7447fae16fb66521717968c34c509b39b1a5c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "env_logger" -version = "0.7.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", - "humantime 1.3.0", + "humantime", "log", "regex", "termcolor", @@ -2124,12 +2487,12 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "atty", - "humantime 2.1.0", + "humantime", + "is-terminal", "log", "regex", "termcolor", @@ -2141,11 +2504,17 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "erased-serde" -version = "0.3.20" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad132dd8d0d0b546348d7d86cb3191aad14b34e5f979781fc005c80d4ac67ffd" +checksum = "da96524cc884f6558f1769b6c46686af2fe8e8b4cd253bd5a3cdba8181b8e070" dependencies = [ "serde", ] @@ -2162,20 +2531,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -2194,9 +2552,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.1" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "exit-future" @@ -2247,14 +2605,14 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "eyre" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" dependencies = [ "indenter", "once_cell", @@ -2274,13 +2632,19 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "fatality" version = "0.0.6" @@ -2298,7 +2662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" dependencies = [ "expander 0.0.4", - "indexmap", + "indexmap 1.9.3", "proc-macro-crate", "proc-macro2", "quote", @@ -2331,6 +2695,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff" version = "0.13.0" @@ -2362,24 +2736,24 @@ checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" [[package]] name = "file-per-thread-logger" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdbe0d94371f9ce939b555dd342d0686cc4c0cadbcd4b61d70af5ff97eb4126" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.7.1", + "env_logger 0.10.0", "log", ] [[package]] name = "filetime" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys 0.36.1", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", ] [[package]] @@ -2424,9 +2798,20 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.4.0" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] [[package]] name = "float-cmp" @@ -2446,16 +2831,16 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", ] [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -2469,7 +2854,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-support-procedural", @@ -2494,12 +2879,12 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.2.5", + "clap 4.3.19", "comfy-table", "frame-benchmarking", "frame-support", @@ -2542,18 +2927,18 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2570,7 +2955,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -2599,7 +2984,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-recursion", "futures", @@ -2620,10 +3005,11 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "aquamarine", - "bitflags", + "bitflags 1.3.2", + "docify", "environmental", "frame-metadata", "frame-support-procedural", @@ -2657,7 +3043,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "Inflector", "cfg-expr", @@ -2669,35 +3055,35 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-executive", @@ -2724,7 +3110,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -2737,7 +3123,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "cfg-if", "frame-support", @@ -2756,7 +3142,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -2771,7 +3157,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "sp-api", @@ -2780,7 +3166,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "parity-scale-codec", @@ -2791,9 +3177,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ebd3504ad6116843b8375ad70df74e7bfe83cac77a1f3fe73200c844d43bfe0" +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" [[package]] name = "fs2" @@ -2807,21 +3193,14 @@ dependencies = [ [[package]] name = "fs4" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea55201cc351fdb478217c0fb641b59813da9b4efe4c414a9d8f989a657d149" +checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" dependencies = [ - "libc", - "rustix 0.35.13", - "winapi", + "rustix 0.38.6", + "windows-sys 0.48.0", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "funty" version = "2.0.0" @@ -2879,16 +3258,16 @@ checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", "parking", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "waker-fn", ] @@ -2900,7 +3279,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -2910,8 +3289,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.7", - "webpki", + "rustls 0.20.8", + "webpki 0.22.0", ] [[package]] @@ -2945,7 +3324,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "pin-utils", "slab", ] @@ -2962,7 +3341,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "chrono", "frame-election-provider-support", @@ -2984,9 +3363,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -3016,9 +3395,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -3047,26 +3426,26 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 1.9.3", "stable_deref_trait", ] [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.8" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" +checksum = "aca8bbd8e0707c1887a8bbb7e6b40e228f251ff5d62c8220a4a7a53c73aff006" dependencies = [ "aho-corasick", "bstr", @@ -3075,22 +3454,33 @@ dependencies = [ "regex", ] +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "group" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -3098,7 +3488,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -3113,16 +3503,16 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.2.2" +version = "4.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" +checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" dependencies = [ "log", "pest", "pest_derive", - "quick-error 2.0.1", "serde", "serde_json", + "thiserror", ] [[package]] @@ -3155,7 +3545,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", ] [[package]] @@ -3164,15 +3554,15 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "allocator-api2", ] [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -3185,9 +3575,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -3252,7 +3642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.6", + "generic-array 0.14.7", "hmac 0.8.1", ] @@ -3281,9 +3671,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -3298,20 +3688,20 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", ] [[package]] name = "http-range-header" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -3319,15 +3709,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error 1.2.3", -] - [[package]] name = "humantime" version = "2.1.0" @@ -3336,9 +3717,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.20" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -3350,7 +3731,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "socket2 0.4.9", "tokio", "tower-service", @@ -3360,51 +3741,81 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", "log", - "rustls 0.20.7", + "rustls 0.20.8", "rustls-native-certs", "tokio", - "tokio-rustls 0.23.2", - "webpki-roots 0.22.2", + "tokio-rustls 0.23.4", + "webpki-roots", ] [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", "log", - "rustls 0.21.2", + "rustls 0.21.6", "rustls-native-certs", "tokio", "tokio-rustls 0.24.1", ] [[package]] -name = "idna" -version = "0.2.3" +name = "iana-time-zone" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows 0.48.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -3436,7 +3847,7 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows", + "windows 0.34.0", ] [[package]] @@ -3495,22 +3906,33 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "indicatif" -version = "0.17.3" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" dependencies = [ "console", + "instant", "number_prefix", "portable-atomic", "unicode-width", @@ -3522,7 +3944,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -3536,9 +3958,9 @@ dependencies = [ [[package]] name = "integer-encoding" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c11140ffea82edce8dcd74137ce9324ec24b3cf0175fc9d7e29164da9915b8" +checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" [[package]] name = "integer-sqrt" @@ -3550,18 +3972,31 @@ dependencies = [ ] [[package]] -name = "io-lifetimes" -version = "0.7.5" +name = "interceptor" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" +checksum = "1e8a11ae2da61704edada656798b61c94b35ecac2c58eb955156987d5e6be90b" +dependencies = [ + "async-trait", + "bytes", + "log", + "rand 0.8.5", + "rtcp", + "rtp", + "thiserror", + "tokio", + "waitgroup", + "webrtc-srtp", + "webrtc-util", +] [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", "windows-sys 0.48.0", ] @@ -3574,31 +4009,30 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.4.9", + "socket2 0.5.3", "widestring", - "winapi", - "winreg 0.7.0", + "windows-sys 0.48.0", + "winreg 0.50.0", ] [[package]] name = "ipnet" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes 1.0.10", - "rustix 0.37.18", + "hermit-abi 0.3.2", + "rustix 0.38.6", "windows-sys 0.48.0", ] @@ -3613,18 +4047,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -3680,10 +4114,10 @@ dependencies = [ "soketto", "thiserror", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.23.4", "tokio-util", "tracing", - "webpki-roots 0.22.2", + "webpki-roots", ] [[package]] @@ -3722,7 +4156,7 @@ checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" dependencies = [ "async-trait", "hyper", - "hyper-rustls 0.23.0", + "hyper-rustls 0.23.2", "jsonrpsee-core", "jsonrpsee-types", "rustc-hash", @@ -3801,17 +4235,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.8", + "elliptic-curve 0.13.5", "once_cell", "sha2 0.10.7", ] [[package]] name = "keccak" -version = "0.1.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] [[package]] name = "kusama-runtime" @@ -4006,9 +4443,9 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libflate" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97822bf791bd4d5b403713886a5fbe8bf49520fe78e323b0dc480ca1a03e50b0" +checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" dependencies = [ "adler32", "crc32fast", @@ -4026,9 +4463,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", "winapi", @@ -4042,14 +4479,14 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "libp2p" -version = "0.52.1" +version = "0.51.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38039ba2df4f3255842050845daef4a004cc1f26da03dbc645535088b51910ef" +checksum = "f210d259724eae82005b5c48078619b7745edb7b76de370b03f8ba59ea103097" dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.8", + "getrandom 0.2.10", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -4062,10 +4499,12 @@ dependencies = [ "libp2p-metrics", "libp2p-noise", "libp2p-ping", + "libp2p-quic", "libp2p-request-response", "libp2p-swarm", "libp2p-tcp", "libp2p-wasm-ext", + "libp2p-webrtc", "libp2p-websocket", "libp2p-yamux", "multiaddr", @@ -4074,9 +4513,9 @@ dependencies = [ [[package]] name = "libp2p-allow-block-list" -version = "0.2.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55b46558c5c0bf99d3e2a1a38fd54ff5476ca66dd1737b12466a1824dd219311" +checksum = "510daa05efbc25184458db837f6f9a5143888f1caa742426d92e1833ddd38a50" dependencies = [ "libp2p-core", "libp2p-identity", @@ -4086,9 +4525,9 @@ dependencies = [ [[package]] name = "libp2p-connection-limits" -version = "0.2.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45dd90e8f0e1fa59e85ff5316dd4d1ac41a9a507e79cda1b0e9b7be43ad1a56" +checksum = "4caa33f1d26ed664c4fe2cca81a08c8e07d4c1c04f2f4ac7655c2dd85467fda0" dependencies = [ "libp2p-core", "libp2p-identity", @@ -4098,9 +4537,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.40.0" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef7dd7b09e71aac9271c60031d0e558966cdb3253ba0308ab369bb2de80630d0" +checksum = "3c1df63c0b582aa434fb09b2d86897fa2b419ffeccf934b36f87fcedc8e835c2" dependencies = [ "either", "fnv", @@ -4110,7 +4549,7 @@ dependencies = [ "libp2p-identity", "log", "multiaddr", - "multihash 0.19.0", + "multihash", "multistream-select", "once_cell", "parking_lot 0.12.1", @@ -4126,13 +4565,12 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.40.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4394c81c0c06d7b4a60f3face7e8e8a9b246840f98d2c80508d0721b032147" +checksum = "146ff7034daae62077c415c2376b8057368042df6ab95f5432ad5e88568b1554" dependencies = [ "futures", "libp2p-core", - "libp2p-identity", "log", "parking_lot 0.12.1", "smallvec", @@ -4141,9 +4579,9 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.43.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a29675a32dbcc87790db6cf599709e64308f1ae9d5ecea2d259155889982db8" +checksum = "5455f472243e63b9c497ff320ded0314254a9eb751799a39c283c6f20b793f3c" dependencies = [ "asynchronous-codec", "either", @@ -4153,7 +4591,7 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "log", - "lru 0.10.0", + "lru 0.10.1", "quick-protobuf", "quick-protobuf-codec", "smallvec", @@ -4163,14 +4601,15 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2874d9c6575f1d7a151022af5c42bb0ffdcdfbafe0a6fd039de870b384835a2" +checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1" dependencies = [ - "bs58 0.5.0", + "bs58", "ed25519-dalek", "log", - "multihash 0.19.0", + "multiaddr", + "multihash", "quick-protobuf", "rand 0.8.5", "sha2 0.10.7", @@ -4180,9 +4619,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.44.3" +version = "0.43.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2584b0c27f879a1cca4b753fd96874109e5a2f46bd6e30924096456c2ba9b2" +checksum = "39d5ef876a2b2323d63c258e63c2f8e36f205fe5a11f0b3095d59635650790ff" dependencies = [ "arrayvec 0.7.4", "asynchronous-codec", @@ -4208,9 +4647,9 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.44.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a2567c305232f5ef54185e9604579a894fd0674819402bb0ac0246da82f52a" +checksum = "19983e1f949f979a928f2c603de1cf180cc0dc23e4ac93a62651ccb18341460b" dependencies = [ "data-encoding", "futures", @@ -4221,7 +4660,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.5.3", + "socket2 0.4.9", "tokio", "trust-dns-proto", "void", @@ -4229,26 +4668,23 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.13.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3787ea81798dcc5bf1d8b40a8e8245cf894b168d04dd70aa48cb3ff2fff141d2" +checksum = "a42ec91e227d7d0dafa4ce88b333cdf5f277253873ab087555c92798db2ddd46" dependencies = [ - "instant", "libp2p-core", "libp2p-identify", - "libp2p-identity", "libp2p-kad", "libp2p-ping", "libp2p-swarm", - "once_cell", "prometheus-client", ] [[package]] name = "libp2p-noise" -version = "0.43.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87945db2b3f977af09b62b9aa0a5f3e4870995a577ecd845cdeba94cdf6bbca7" +checksum = "9c3673da89d29936bc6435bafc638e2f184180d554ce844db65915113f86ec5e" dependencies = [ "bytes", "curve25519-dalek 3.2.0", @@ -4256,8 +4692,6 @@ dependencies = [ "libp2p-core", "libp2p-identity", "log", - "multiaddr", - "multihash 0.19.0", "once_cell", "quick-protobuf", "rand 0.8.5", @@ -4271,27 +4705,48 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.43.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd5ee3270229443a2b34b27ed0cb7470ef6b4a6e45e54e89a8771fa683bab48" +checksum = "3e57759c19c28a73ef1eb3585ca410cefb72c1a709fcf6de1612a378e4219202" dependencies = [ "either", "futures", "futures-timer", "instant", "libp2p-core", - "libp2p-identity", "libp2p-swarm", "log", "rand 0.8.5", "void", ] +[[package]] +name = "libp2p-quic" +version = "0.7.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6b26abd81cd2398382a1edfe739b539775be8a90fa6914f39b2ab49571ec735" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "log", + "parking_lot 0.12.1", + "quinn-proto", + "rand 0.8.5", + "rustls 0.20.8", + "thiserror", + "tokio", +] + [[package]] name = "libp2p-request-response" -version = "0.25.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20bd837798cdcce4283d2675f08bcd3756a650d56eab4d4367e1b3f27eed6887" +checksum = "7ffdb374267d42dc5ed5bc53f6e601d4a64ac5964779c6e40bb9e4f14c1e30d5" dependencies = [ "async-trait", "futures", @@ -4299,17 +4754,15 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "log", "rand 0.8.5", "smallvec", - "void", ] [[package]] name = "libp2p-swarm" -version = "0.43.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de15b2097fc3bde063df8c202803538ff467fedb18f01c13bc5da55913d246c" +checksum = "903b3d592d7694e56204d211f29d31bc004be99386644ba8731fc3e3ef27b296" dependencies = [ "either", "fnv", @@ -4320,8 +4773,6 @@ dependencies = [ "libp2p-identity", "libp2p-swarm-derive", "log", - "multistream-select", - "once_cell", "rand 0.8.5", "smallvec", "tokio", @@ -4330,73 +4781,119 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.33.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d5ec2a3df00c7836d7696c136274c9c59705bac69133253696a6c932cd1d74" +checksum = "0fba456131824ab6acd4c7bf61e9c0f0a3014b5fc9868ccb8e10d344594cdc4f" dependencies = [ "heck", - "proc-macro-warning", - "proc-macro2", "quote", - "syn 2.0.20", + "syn 1.0.109", ] [[package]] name = "libp2p-tcp" -version = "0.40.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09bfdfb6f945c5c014b87872a0bdb6e0aef90e92f380ef57cd9013f118f9289d" +checksum = "33d33698596d7722d85d3ab0c86c2c322254fce1241e91208e3679b4eb3026cf" dependencies = [ "futures", "futures-timer", "if-watch", "libc", "libp2p-core", - "libp2p-identity", "log", - "socket2 0.5.3", + "socket2 0.4.9", "tokio", ] +[[package]] +name = "libp2p-tls" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08d13d0dc66e5e9ba6279c1de417b84fa0d0adc3b03e5732928c180ec02781" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core", + "libp2p-identity", + "rcgen 0.10.0", + "ring 0.16.20", + "rustls 0.20.8", + "thiserror", + "webpki 0.22.0", + "x509-parser 0.14.0", + "yasna", +] + [[package]] name = "libp2p-wasm-ext" -version = "0.40.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e5d8e3a9e07da0ef5b55a9f26c009c8fb3c725d492d8bb4b431715786eea79c" +checksum = "77dff9d32353a5887adb86c8afc1de1a94d9e8c3bc6df8b2201d7cdf5c848f43" dependencies = [ "futures", "js-sys", "libp2p-core", - "send_wrapper", + "parity-send-wrapper", "wasm-bindgen", "wasm-bindgen-futures", ] +[[package]] +name = "libp2p-webrtc" +version = "0.4.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba48592edbc2f60b4bc7c10d65445b0c3964c07df26fdf493b6880d33be36f8" +dependencies = [ + "async-trait", + "asynchronous-codec", + "bytes", + "futures", + "futures-timer", + "hex", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-noise", + "log", + "multihash", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.5", + "rcgen 0.9.3", + "serde", + "stun", + "thiserror", + "tinytemplate", + "tokio", + "tokio-util", + "webrtc", +] + [[package]] name = "libp2p-websocket" -version = "0.42.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956d981ebc84abc3377e5875483c06d94ff57bc6b25f725047f9fd52592f72d4" +checksum = "111273f7b3d3510524c752e8b7a5314b7f7a1fee7e68161c01a7d72cbb06db9f" dependencies = [ "either", "futures", "futures-rustls", "libp2p-core", - "libp2p-identity", "log", "parking_lot 0.12.1", "quicksink", "rw-stream-sink", "soketto", "url", - "webpki-roots 0.23.1", + "webpki-roots", ] [[package]] name = "libp2p-yamux" -version = "0.44.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a9b42ab6de15c6f076d8fb11dc5f48d899a10b55a2e16b12be9012a05287b0" +checksum = "4dcd21d950662700a385d4c6d68e2f5f54d778e97068cdd718522222ef513bda" dependencies = [ "futures", "libp2p-core", @@ -4422,12 +4919,12 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64 0.13.0", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -4435,7 +4932,7 @@ dependencies = [ "libsecp256k1-gen-genmult", "rand 0.8.5", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "typenum", ] @@ -4470,9 +4967,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.3" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", "pkg-config", @@ -4481,18 +4978,18 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linked_hash_set" @@ -4505,36 +5002,36 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" +checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" dependencies = [ "nalgebra", ] [[package]] name = "linux-raw-sys" -version = "0.0.46" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.3.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -4552,9 +5049,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" +checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" dependencies = [ "hashbrown 0.13.2", ] @@ -4615,7 +5112,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -4629,7 +5126,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -4640,7 +5137,7 @@ checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -4651,7 +5148,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -4672,7 +5169,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -4681,37 +5178,47 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" -version = "0.3.2" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" dependencies = [ + "autocfg", "rawpointer", ] +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memfd" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" +checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.36.7", + "rustix 0.37.23", ] [[package]] @@ -4725,9 +5232,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] @@ -4750,6 +5257,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "memory-db" version = "0.32.0" @@ -4796,9 +5312,9 @@ dependencies = [ [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" @@ -4808,9 +5324,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -4829,7 +5345,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "log", @@ -4848,7 +5364,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "anyhow", "jsonrpsee", @@ -4863,24 +5379,24 @@ dependencies = [ [[package]] name = "mockall" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" dependencies = [ "cfg-if", "downcast", "fragile", "lazy_static", "mockall_derive", - "predicates", + "predicates 2.1.5", "predicates-tree", ] [[package]] name = "mockall_derive" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", "proc-macro2", @@ -4890,16 +5406,16 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.18.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a651988b3ed3ad1bc8c87d016bb92f6f395b84ed1db9b926b32b1fc5a2c8b5" +checksum = "2b36f567c7099511fa8612bbbb52dda2419ce0bdbacf31714e3a5ffdb766d3bd" dependencies = [ "arrayref", "byteorder", "data-encoding", - "libp2p-identity", + "log", "multibase", - "multihash 0.19.0", + "multihash", "percent-encoding", "serde", "static_assertions", @@ -4929,41 +5445,12 @@ dependencies = [ "blake3", "core2", "digest 0.10.7", - "multihash-derive 0.8.0", + "multihash-derive", "sha2 0.10.7", "sha3", "unsigned-varint", ] -[[package]] -name = "multihash" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd59dcc2bbe70baabeac52cd22ae52c55eefe6c38ff11a9439f16a350a939f2" -dependencies = [ - "core2", - "unsigned-varint", -] - -[[package]] -name = "multihash-codetable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46d7ff0b9b8d818e709e12135bfb6582fcde982ba2be48ea52e6e1df098c7a4" -dependencies = [ - "blake2b_simd", - "blake2s_simd", - "blake3", - "core2", - "digest 0.10.7", - "multihash-derive 0.9.0", - "ripemd", - "sha-1 0.10.0", - "sha2 0.10.7", - "sha3", - "strobe-rs", -] - [[package]] name = "multihash-derive" version = "0.8.0" @@ -4978,31 +5465,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "multihash-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890e72cb7396cb99ed98c1246a97b243cc16394470d94e0bc8b0c2c11d84290e" -dependencies = [ - "core2", - "multihash 0.19.0", - "multihash-derive-impl", -] - -[[package]] -name = "multihash-derive-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38685e08adb338659871ecfc6ee47ba9b22dcc8abcf6975d379cc49145c3040" -dependencies = [ - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure", -] - [[package]] name = "multimap" version = "0.8.3" @@ -5011,9 +5473,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.13.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a" dependencies = [ "bytes", "futures", @@ -5025,9 +5487,9 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6515c882ebfddccaa73ead7320ca28036c4bc84c9bcca3cc0cbba8efe89223a" +checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" dependencies = [ "approx", "matrixmultiply", @@ -5041,9 +5503,9 @@ dependencies = [ [[package]] name = "nalgebra-macros" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ "proc-macro2", "quote", @@ -5056,13 +5518,22 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d66043b25d4a6cccb23619d10c19c25304b355a7dccd4a8e11423dd2382146" dependencies = [ - "clap 3.2.23", "rand 0.8.5", ] [[package]] -name = "nanorand" -version = "0.7.0" +name = "names" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" +dependencies = [ + "clap 3.2.25", + "rand 0.8.5", +] + +[[package]] +name = "nanorand" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" @@ -5085,7 +5556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", "netlink-packet-core", @@ -5094,9 +5565,9 @@ dependencies = [ [[package]] name = "netlink-packet-utils" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", @@ -5121,9 +5592,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" dependencies = [ "bytes", "futures", @@ -5134,13 +5605,14 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.1" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", + "memoffset 0.6.5", ] [[package]] @@ -5149,7 +5621,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", @@ -5165,13 +5637,12 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.0" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", - "version_check", ] [[package]] @@ -5180,6 +5651,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -5193,18 +5674,18 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] [[package]] name = "num-format" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b862ff8df690cf089058c98b183676a7ed0f974cc08b426800093227cbff3b" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec 0.7.4", "itoa", @@ -5212,9 +5693,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -5234,20 +5715,20 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi 0.3.2", "libc", ] @@ -5259,16 +5740,43 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ "crc32fast", "hashbrown 0.13.2", - "indexmap", + "indexmap 1.9.3", + "memchr", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e20717fa0541f39bd146692035c37bedfa532b3e5071b35761082407546b2a" +dependencies = [ + "asn1-rs 0.3.1", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs 0.5.2", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -5295,9 +5803,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl-probe" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "orchestra" @@ -5342,24 +5850,43 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" [[package]] -name = "output_vt100" -version = "0.1.2" +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "p256" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ - "winapi", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.7", ] [[package]] -name = "owo-colors" -version = "3.2.0" +name = "p384" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20448fd678ec04e6ea15bbe0476874af65e98a01515d667aa49f1434dc44ebf4" +checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" +dependencies = [ + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.7", +] [[package]] name = "packed_simd_2" @@ -5374,7 +5901,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5389,7 +5916,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -5405,7 +5932,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -5419,7 +5946,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5443,7 +5970,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "aquamarine", "docify", @@ -5465,7 +5992,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -5484,7 +6011,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5499,7 +6026,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -5518,7 +6045,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -5542,7 +6069,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5560,7 +6087,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5579,7 +6106,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5596,7 +6123,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5613,7 +6140,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5631,7 +6158,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5654,7 +6181,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5667,7 +6194,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5686,7 +6213,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "docify", "frame-benchmarking", @@ -5705,7 +6232,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5728,7 +6255,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5744,7 +6271,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5764,7 +6291,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5781,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5798,7 +6325,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5817,7 +6344,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5834,7 +6361,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5850,7 +6377,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5866,7 +6393,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -5885,7 +6412,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5905,7 +6432,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -5916,7 +6443,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -5933,7 +6460,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5957,7 +6484,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5974,7 +6501,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5989,7 +6516,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6007,7 +6534,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6022,7 +6549,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6041,7 +6568,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "docify", "frame-benchmarking", @@ -6059,7 +6586,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -6080,7 +6607,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6096,7 +6623,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6114,7 +6641,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6137,18 +6664,18 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "log", "sp-arithmetic", @@ -6157,7 +6684,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "sp-api", @@ -6166,7 +6693,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6183,7 +6710,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6198,7 +6725,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6216,7 +6743,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6235,7 +6762,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-support", "frame-system", @@ -6251,7 +6778,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6267,7 +6794,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6279,7 +6806,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6296,7 +6823,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6311,7 +6838,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6327,7 +6854,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6342,7 +6869,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6405,9 +6932,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4890dcb9556136a4ec2b0c51fa4a08c8b733b829506af8fff2e853f3a065985b" +checksum = "78f19d20a0d2cc52327a88d131fa1c4ea81ea4a04714aedcfeca2dd410049cf8" dependencies = [ "blake2", "crc32fast", @@ -6425,9 +6952,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.1" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2287753623c76f953acd29d15d8100bcab84d29db78fb6f352adb3c53e83b967" +checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -6440,9 +6967,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.1" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b6937b5e67bfba3351b87b040d48352a2fcb6ad72f81855412ce97b45c8f110" +checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6450,6 +6977,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parity-send-wrapper" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" + [[package]] name = "parity-wasm" version = "0.45.0" @@ -6458,9 +6991,9 @@ checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" [[package]] name = "parking_lot" @@ -6470,7 +7003,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -6480,34 +7013,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.6", + "parking_lot_core 0.9.8", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.6" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.42.0", + "windows-targets 0.48.1", ] [[package]] @@ -6518,9 +7051,9 @@ checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" [[package]] name = "paste" -version = "1.0.7" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" @@ -6546,26 +7079,45 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.1.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -6573,36 +7125,36 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1 0.8.2", + "sha2 0.10.7", ] [[package]] name = "petgraph" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -6622,7 +7174,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -6633,9 +7185,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -6643,21 +7195,31 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + [[package]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.7", + "spki 0.7.2", ] [[package]] name = "pkg-config" -version = "0.3.22" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" @@ -6691,7 +7253,7 @@ name = "polkadot-approval-distribution" version = "0.9.43" dependencies = [ "assert_matches", - "env_logger 0.9.0", + "env_logger 0.9.3", "futures", "futures-timer", "log", @@ -6719,7 +7281,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.0", + "env_logger 0.9.3", "futures", "futures-timer", "log", @@ -6773,7 +7335,7 @@ name = "polkadot-availability-recovery" version = "0.9.43" dependencies = [ "assert_matches", - "env_logger 0.9.0", + "env_logger 0.9.3", "fatality", "futures", "futures-timer", @@ -6801,7 +7363,7 @@ dependencies = [ name = "polkadot-cli" version = "0.9.43" dependencies = [ - "clap 4.2.5", + "clap 4.3.19", "frame-benchmarking-cli", "futures", "log", @@ -6832,7 +7394,7 @@ dependencies = [ "always-assert", "assert_matches", "bitvec", - "env_logger 0.9.0", + "env_logger 0.9.3", "fatality", "futures", "futures-timer", @@ -6876,7 +7438,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "indexmap", + "indexmap 1.9.3", "lazy_static", "lru 0.11.0", "parity-scale-codec", @@ -7033,7 +7595,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.0", + "env_logger 0.9.3", "futures", "futures-timer", "kvdb", @@ -7394,7 +7956,7 @@ name = "polkadot-node-metrics" version = "0.9.43" dependencies = [ "assert_cmd", - "bs58 0.4.0", + "bs58", "futures", "futures-timer", "hyper", @@ -7517,7 +8079,7 @@ dependencies = [ "assert_matches", "async-trait", "derive_more", - "env_logger 0.9.0", + "env_logger 0.9.3", "fatality", "futures", "futures-channel", @@ -7597,7 +8159,7 @@ dependencies = [ name = "polkadot-performance-test" version = "0.9.43" dependencies = [ - "env_logger 0.9.0", + "env_logger 0.9.3", "kusama-runtime", "log", "polkadot-erasure-coding", @@ -7849,7 +8411,7 @@ dependencies = [ name = "polkadot-runtime-metrics" version = "0.9.43" dependencies = [ - "bs58 0.4.0", + "bs58", "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", @@ -7862,7 +8424,7 @@ name = "polkadot-runtime-parachains" version = "0.9.43" dependencies = [ "assert_matches", - "bitflags", + "bitflags 1.3.2", "bitvec", "derive_more", "frame-benchmarking", @@ -7917,7 +8479,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "async-trait", - "env_logger 0.9.0", + "env_logger 0.9.3", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -8048,7 +8610,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "indexmap", + "indexmap 1.9.3", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -8114,7 +8676,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "async-trait", - "clap 4.2.5", + "clap 4.3.19", "color-eyre", "futures", "futures-timer", @@ -8260,7 +8822,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "0.9.43" dependencies = [ - "clap 4.2.5", + "clap 4.3.19", "generate-bags", "kusama-runtime", "polkadot-runtime", @@ -8270,15 +8832,18 @@ dependencies = [ [[package]] name = "polling" -version = "2.2.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ + "autocfg", + "bitflags 1.3.2", "cfg-if", + "concurrent-queue", "libc", "log", - "wepoll-ffi", - "winapi", + "pin-project-lite 0.2.10", + "windows-sys 0.48.0", ] [[package]] @@ -8318,22 +8883,22 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "0.3.19" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" [[package]] name = "pprof" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6472bfed9475542ac46c518734a8d06d71b0f6cb2c17f904aa301711a57786f" +checksum = "196ded5d4be535690899a4631cc9f18cdc41b7ebf24a79400f46f48e49a11059" dependencies = [ "backtrace", "cfg-if", "findshlibs", "libc", "log", - "nix 0.24.1", + "nix 0.26.2", "once_cell", "parking_lot 0.12.1", "smallvec", @@ -8350,9 +8915,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "predicates" -version = "2.1.0" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e5a7689e456ab905c22c2b48225bb921aba7c8dfa58440d68ba13f6222a715" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", "float-cmp", @@ -8362,17 +8927,29 @@ dependencies = [ "regex", ] +[[package]] +name = "predicates" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +dependencies = [ + "anstyle", + "difflib", + "itertools", + "predicates-core", +] + [[package]] name = "predicates-core" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ "predicates-core", "termtree", @@ -8380,24 +8957,32 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ - "ctor", "diff", - "output_vt100", "yansi", ] [[package]] name = "prettyplease" -version = "0.2.4" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -8477,37 +9062,37 @@ checksum = "70550716265d1ec349c41f70dd4f964b4fd88394efe4405f0c1da679c4799a07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.0" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ "cfg-if", "fnv", "lazy_static", "memchr", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "thiserror", ] [[package]] name = "prometheus-client" -version = "0.21.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" +checksum = "5d6fa99d535dd930d1249e6c79cb3c2915f9172a540fe2b02a4c8f9ca954721e" dependencies = [ "dtoa", "itoa", @@ -8528,40 +9113,31 @@ dependencies = [ [[package]] name = "prometheus-parse" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c996f3caea1c51aa034c0d2dfd8447a12c555f4567b02677ef8a865ac4cce712" +checksum = "0c2aa5feb83bf4b2c8919eaf563f51dbab41183de73ba2353c0e03cd7b6bd892" dependencies = [ "chrono", - "lazy_static", + "itertools", + "once_cell", "regex", ] [[package]] name = "prost" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" -dependencies = [ - "bytes", - "prost-derive 0.10.1", -] - -[[package]] -name = "prost" -version = "0.11.0" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive 0.11.0", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.11.1" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", "heck", @@ -8570,31 +9146,20 @@ dependencies = [ "log", "multimap", "petgraph", - "prost 0.11.0", + "prettyplease 0.1.25", + "prost", "prost-types", "regex", + "syn 1.0.109", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.11.0" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools", @@ -8605,35 +9170,34 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.1" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "bytes", - "prost 0.11.0", + "prost", ] [[package]] name = "psm" -version = "0.1.16" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd136ff4382c4753fc061cb9e4712ab2af263376b95bbd5bd8cd50c020b78e69" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" dependencies = [ "cc", ] [[package]] name = "pyroscope" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6636d352280fb587c8716f10e1d61fe88cb002660e0a8b0d3e47de17f3b5aaed" +checksum = "91ce54d81c50f7fd6442ee671597f661a068ccebd82ed1557775b6791b14aba7" dependencies = [ "json", "libc", "libflate", "log", - "names", - "prost 0.10.4", + "names 0.14.0", + "prost", "reqwest", "thiserror", "url", @@ -8642,9 +9206,9 @@ dependencies = [ [[package]] name = "pyroscope_pprofrs" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e699bf3e7da41b3a7573d5944d77b1bd96a187aa72f5fa96afb4ed5609cc45" +checksum = "57add45daa57783490913a5d3d88e3249126971b61ac97ee0c7bac293ef0114a" dependencies = [ "log", "pprof", @@ -8658,12 +9222,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - [[package]] name = "quick-protobuf" version = "0.8.1" @@ -8675,9 +9233,9 @@ dependencies = [ [[package]] name = "quick-protobuf-codec" -version = "0.2.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" +checksum = "1693116345026436eb2f10b677806169c1a1260c1c60eaaffe3fb5a29ae23d8b" dependencies = [ "asynchronous-codec", "bytes", @@ -8697,11 +9255,29 @@ dependencies = [ "pin-project-lite 0.1.12", ] +[[package]] +name = "quinn-proto" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring 0.16.20", + "rustc-hash", + "rustls 0.20.8", + "slab", + "thiserror", + "tinyvec", + "tracing", + "webpki 0.22.0", +] + [[package]] name = "quote" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -8771,7 +9347,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.10", ] [[package]] @@ -8800,46 +9376,78 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.5.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] +[[package]] +name = "rcgen" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +dependencies = [ + "pem", + "ring 0.16.20", + "time 0.3.25", + "x509-parser 0.13.2", + "yasna", +] + +[[package]] +name = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring 0.16.20", + "time 0.3.25", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.8", - "redox_syscall", + "getrandom 0.2.10", + "redox_syscall 0.2.16", + "thiserror", ] [[package]] @@ -8857,22 +9465,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.6" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +checksum = "61ef7e18e8841942ddb1cf845054f8008410030a3997875d9e49b7a363063df1" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.6" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +checksum = "2dfaf0c85b766276c797f3791f5bc6d5bd116b41d53049af2789666b0c0bc9fa" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -8889,13 +9497,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.3.4", + "regex-syntax 0.7.4", ] [[package]] @@ -8904,20 +9513,37 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "remote-ext-tests-bags-list" version = "0.9.43" dependencies = [ - "clap 4.2.5", + "clap 4.3.19", "frame-system", "kusama-runtime", "kusama-runtime-constants", @@ -8933,21 +9559,12 @@ dependencies = [ ] [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "reqwest" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "winapi", -] - -[[package]] -name = "reqwest" -version = "0.11.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" -dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "bytes", "encoding_rs", "futures-core", @@ -8956,27 +9573,27 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-rustls 0.23.0", + "hyper-rustls 0.24.1", "ipnet", "js-sys", "log", "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.9", - "rustls 0.20.7", - "rustls-pemfile 1.0.2", + "pin-project-lite 0.2.10", + "rustls 0.21.6", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.22.2", + "webpki-roots", "winreg 0.10.1", ] @@ -8987,7 +9604,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ "hostname", - "quick-error 1.2.3", + "quick-error", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac 0.12.1", + "zeroize", ] [[package]] @@ -9030,15 +9658,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -9164,14 +9783,26 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.0.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", + "rtoolbox", "winapi", ] +[[package]] +name = "rtcp" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1919efd6d4a6a85d13388f9487549bb8e359f17198cc03ffd72f79b553873691" +dependencies = [ + "bytes", + "thiserror", + "webrtc-util", +] + [[package]] name = "rtnetlink" version = "0.10.1" @@ -9182,16 +9813,40 @@ dependencies = [ "log", "netlink-packet-route", "netlink-proto", - "nix 0.24.1", + "nix 0.24.3", "thiserror", "tokio", ] +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rtp" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a095411ff00eed7b12e4c6a118ba984d113e1079582570d56a5ee723f11f80" +dependencies = [ + "async-trait", + "bytes", + "rand 0.8.5", + "serde", + "thiserror", + "webrtc-util", +] + [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" @@ -9211,110 +9866,122 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.16", + "semver 1.0.18", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", ] [[package]] name = "rustix" -version = "0.35.13" +version = "0.36.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" dependencies = [ - "bitflags", - "errno 0.2.8", - "io-lifetimes 0.7.5", + "bitflags 1.3.2", + "errno", + "io-lifetimes", "libc", - "linux-raw-sys 0.0.46", - "windows-sys 0.42.0", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", ] [[package]] name = "rustix" -version = "0.36.7" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "bitflags", - "errno 0.2.8", - "io-lifetimes 1.0.10", + "bitflags 1.3.2", + "errno", + "io-lifetimes", "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.42.0", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", ] [[package]] name = "rustix" -version = "0.37.18" +version = "0.38.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfc1d1c7c40c01715f47d71444744a81669ca84e8b63e25a55e169b1f86433" +checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f" dependencies = [ - "bitflags", - "errno 0.3.1", - "io-lifetimes 1.0.10", + "bitflags 2.3.3", + "errno", "libc", - "linux-raw-sys 0.3.6", + "linux-raw-sys 0.4.5", "windows-sys 0.48.0", ] [[package]] name = "rustls" -version = "0.20.7" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ + "base64 0.13.1", "log", "ring 0.16.20", - "sct", - "webpki", + "sct 0.6.1", + "webpki 0.21.4", ] [[package]] name = "rustls" -version = "0.21.2" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring 0.16.20", - "rustls-webpki", - "sct", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] -name = "rustls-native-certs" -version = "0.6.1" +name = "rustls" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ - "openssl-probe", - "rustls-pemfile 0.2.1", - "schannel", - "security-framework", + "log", + "ring 0.16.20", + "rustls-webpki", + "sct 0.7.0", ] [[package]] -name = "rustls-pemfile" -version = "0.2.1" +name = "rustls-native-certs" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ - "base64 0.13.0", + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", ] [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", ] [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.101.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" dependencies = [ "ring 0.16.20", "untrusted", @@ -9322,15 +9989,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "rw-stream-sink" -version = "0.4.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" dependencies = [ "futures", "pin-project", @@ -9339,15 +10006,15 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.6" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "safe_arch" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" dependencies = [ "bytemuck", ] @@ -9364,7 +10031,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "log", "sp-core", @@ -9375,7 +10042,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "futures", @@ -9383,9 +10050,9 @@ dependencies = [ "ip_network", "libp2p", "log", - "multihash-codetable", + "multihash", "parity-scale-codec", - "prost 0.11.0", + "prost", "prost-build", "rand 0.8.5", "sc-client-api", @@ -9403,7 +10070,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "futures-timer", @@ -9426,7 +10093,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9441,7 +10108,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -9460,27 +10127,27 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "chrono", - "clap 4.2.5", + "clap 4.3.19", "fdlimit", "futures", "libp2p-identity", "log", - "names", + "names 0.13.0", "parity-scale-codec", "rand 0.8.5", "regex", @@ -9510,7 +10177,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "fnv", "futures", @@ -9536,7 +10203,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "hash-db", "kvdb", @@ -9562,7 +10229,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "futures", @@ -9587,7 +10254,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "fork-tree", @@ -9623,7 +10290,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "jsonrpsee", @@ -9645,7 +10312,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "async-channel", @@ -9679,7 +10346,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "jsonrpsee", @@ -9698,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9711,9 +10378,9 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "async-trait", "dyn-clone", @@ -9752,7 +10419,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "finality-grandpa", "futures", @@ -9772,7 +10439,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "futures", @@ -9795,7 +10462,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -9817,7 +10484,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -9829,13 +10496,13 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "anyhow", "cfg-if", "libc", "log", - "rustix 0.36.7", + "rustix 0.36.15", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -9846,7 +10513,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "ansi_term", "futures", @@ -9862,7 +10529,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -9876,7 +10543,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "async-channel", @@ -9889,7 +10556,6 @@ dependencies = [ "futures-timer", "ip_network", "libp2p", - "libp2p-kad", "linked_hash_set", "log", "mockall", @@ -9911,7 +10577,6 @@ dependencies = [ "substrate-prometheus-endpoint", "thiserror", "unsigned-varint", - "void", "wasm-timer", "zeroize", ] @@ -9919,14 +10584,14 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-channel", "cid", "futures", "libp2p-identity", "log", - "prost 0.11.0", + "prost", "prost-build", "sc-client-api", "sc-network", @@ -9939,10 +10604,10 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", - "bitflags", + "bitflags 1.3.2", "futures", "libp2p-identity", "parity-scale-codec", @@ -9956,14 +10621,13 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "futures", "futures-timer", - "libp2p-identity", + "libp2p", "log", - "multiaddr", "sc-network", "sc-network-common", "schnellru", @@ -9975,7 +10639,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "async-channel", @@ -9983,7 +10647,7 @@ dependencies = [ "libp2p-identity", "log", "parity-scale-codec", - "prost 0.11.0", + "prost", "prost-build", "sc-client-api", "sc-network", @@ -9996,7 +10660,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "async-channel", @@ -10008,7 +10672,7 @@ dependencies = [ "log", "mockall", "parity-scale-codec", - "prost 0.11.0", + "prost", "prost-build", "sc-client-api", "sc-consensus", @@ -10030,7 +10694,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "futures", @@ -10048,7 +10712,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "bytes", @@ -10056,7 +10720,7 @@ dependencies = [ "futures", "futures-timer", "hyper", - "hyper-rustls 0.24.0", + "hyper-rustls 0.24.1", "libp2p", "log", "num_cpus", @@ -10082,7 +10746,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10091,7 +10755,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "jsonrpsee", @@ -10122,7 +10786,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10141,7 +10805,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "http", "jsonrpsee", @@ -10156,7 +10820,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "futures", @@ -10184,7 +10848,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "directories", @@ -10248,7 +10912,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "log", "parity-scale-codec", @@ -10259,9 +10923,9 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ - "clap 4.2.5", + "clap 4.3.19", "fs4", "log", "sc-client-db", @@ -10273,7 +10937,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10292,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "libc", @@ -10311,7 +10975,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "chrono", "futures", @@ -10330,7 +10994,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "ansi_term", "atty", @@ -10359,18 +11023,18 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "futures", @@ -10396,7 +11060,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "futures", @@ -10412,7 +11076,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-channel", "futures", @@ -10426,9 +11090,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.5.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ "bitvec", "cfg-if", @@ -10440,9 +11104,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.5.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10452,12 +11116,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -10466,7 +11129,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "cfg-if", "hashbrown 0.13.2", ] @@ -10491,15 +11154,25 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + +[[package]] +name = "sct" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring 0.16.20", + "untrusted", +] [[package]] name = "sct" @@ -10511,34 +11184,60 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sdp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d22a5ef407871893fd72b4562ee15e4742269b173959db4b8df6f538c414e13" +dependencies = [ + "rand 0.8.5", + "substring", + "thiserror", + "url", +] + [[package]] name = "sec1" -version = "0.7.1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array 0.14.7", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", - "generic-array 0.14.6", - "pkcs8", + "base16ct 0.2.0", + "der 0.7.7", + "generic-array 0.14.7", + "pkcs8 0.10.2", "subtle", "zeroize", ] [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7058dc8eaf3f2810d7828680320acda0b25a288f6d288e19278e249bbf74226b" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" dependencies = [ "cc", ] @@ -10554,11 +11253,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.4.2" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -10567,9 +11266,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.4.2" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -10586,9 +11285,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] @@ -10599,12 +11298,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - [[package]] name = "separator" version = "0.4.1" @@ -10613,38 +11306,38 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "serde_fmt" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2963a69a2b3918c1dc75a45a18bd3fcd1120e31d3f59deb1b2f9b5d5ffb8baa4" +checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4" dependencies = [ "serde", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -10653,9 +11346,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -10694,19 +11387,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", + "syn 2.0.28", ] [[package]] @@ -10724,9 +11405,20 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.10.0" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", @@ -10747,9 +11439,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", @@ -10796,9 +11488,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", @@ -10806,9 +11498,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -10830,6 +11522,10 @@ name = "signature" version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] [[package]] name = "signature" @@ -10843,9 +11539,9 @@ dependencies = [ [[package]] name = "simba" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" dependencies = [ "approx", "num-complex", @@ -10862,15 +11558,18 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] [[package]] name = "slice-group-by" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "slot-range-helper" @@ -10947,8 +11646,9 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "bytes", + "flate2", "futures", "http", "httparse", @@ -10960,7 +11660,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "hash-db", "log", @@ -10981,7 +11681,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "Inflector", "blake2", @@ -10989,13 +11689,13 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11008,7 +11708,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "integer-sqrt", "num-traits", @@ -11022,7 +11722,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11035,7 +11735,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "sp-api", "sp-inherents", @@ -11046,7 +11746,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "log", @@ -11064,7 +11764,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "futures", @@ -11079,7 +11779,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11096,7 +11796,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11115,7 +11815,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11134,7 +11834,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "finality-grandpa", "log", @@ -11152,7 +11852,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11164,15 +11864,15 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "arrayvec 0.7.4", "bandersnatch_vrfs", - "bitflags", + "bitflags 1.3.2", "blake2", "bounded-collections", - "bs58 0.4.0", + "bs58", "dyn-clonable", "ed25519-zebra", "futures", @@ -11211,7 +11911,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "blake2b_simd", "byteorder", @@ -11224,17 +11924,17 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11243,17 +11943,17 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "environmental", "parity-scale-codec", @@ -11264,7 +11964,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "serde_json", "sp-api", @@ -11275,7 +11975,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11289,7 +11989,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "bytes", "ed25519", @@ -11314,7 +12014,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "lazy_static", "sp-core", @@ -11325,7 +12025,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -11337,16 +12037,16 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "thiserror", - "zstd 0.12.3+zstd.1.5.2", + "zstd 0.12.4", ] [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -11357,7 +12057,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -11375,7 +12075,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11389,7 +12089,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "sp-api", "sp-core", @@ -11399,7 +12099,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "backtrace", "lazy_static", @@ -11409,7 +12109,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "rustc-hash", "serde", @@ -11419,7 +12119,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "either", "hash256-std-hasher", @@ -11441,7 +12141,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -11459,19 +12159,19 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "Inflector", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11486,7 +12186,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -11500,7 +12200,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "hash-db", "log", @@ -11521,7 +12221,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -11545,12 +12245,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11563,7 +12263,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11576,7 +12276,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "sp-std", @@ -11588,7 +12288,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "sp-api", "sp-runtime", @@ -11597,7 +12297,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11612,9 +12312,9 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "hash-db", "hashbrown 0.13.2", "lazy_static", @@ -11635,7 +12335,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11652,18 +12352,18 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -11676,7 +12376,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11705,6 +12405,16 @@ dependencies = [ "strum", ] +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + [[package]] name = "spki" version = "0.7.2" @@ -11712,14 +12422,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", - "der", + "der 0.7.7", ] [[package]] name = "ss58-registry" -version = "1.36.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +checksum = "bfc443bad666016e012538782d9e3006213a7db43e9fb1dda91657dc06a6fa08" dependencies = [ "Inflector", "num-format", @@ -11741,7 +12451,7 @@ name = "staking-miner" version = "0.9.43" dependencies = [ "assert_cmd", - "clap 4.2.5", + "clap 4.3.19", "exitcode", "frame-election-provider-support", "frame-remote-externalities", @@ -11773,7 +12483,7 @@ dependencies = [ "sub-tokens", "thiserror", "tokio", - "tracing-subscriber 0.3.11", + "tracing-subscriber 0.3.17", "westend-runtime", ] @@ -11801,11 +12511,11 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg_aliases", "libc", "parking_lot 0.11.2", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", "static_init_macro 1.0.2", "winapi", ] @@ -11836,19 +12546,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "strobe-rs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabb238a1cccccfa4c4fb703670c0d157e1256c1ba695abf1b93bd2bb14bab2d" -dependencies = [ - "bitflags", - "byteorder", - "keccak", - "subtle", - "zeroize", -] - [[package]] name = "strsim" version = "0.10.0" @@ -11866,9 +12563,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.24.0" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck", "proc-macro2", @@ -11877,6 +12574,25 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "stun" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" +dependencies = [ + "base64 0.13.1", + "crc", + "lazy_static", + "md-5", + "rand 0.8.5", + "ring 0.16.20", + "subtle", + "thiserror", + "tokio", + "url", + "webrtc-util", +] + [[package]] name = "sub-tokens" version = "0.1.0" @@ -11894,19 +12610,19 @@ dependencies = [ "hmac 0.11.0", "pbkdf2 0.8.0", "schnorrkel", - "sha2 0.9.8", + "sha2 0.9.9", "zeroize", ] [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -11925,7 +12641,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "hyper", "log", @@ -11937,7 +12653,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", "jsonrpsee", @@ -11950,7 +12666,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11967,7 +12683,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "array-bytes", "async-trait", @@ -11993,7 +12709,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12003,18 +12719,18 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "ansi_term", "build-helper", @@ -12024,11 +12740,20 @@ dependencies = [ "sp-maybe-compressed-blob", "strum", "tempfile", - "toml 0.7.3", + "toml 0.7.6", "walkdir", "wasm-opt", ] +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "subtle" version = "2.4.1" @@ -12105,9 +12830,9 @@ dependencies = [ [[package]] name = "symbolic-common" -version = "9.2.1" +version = "10.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "800963ba330b09a2ae4a4f7c6392b81fbc2784099a98c1eac68c3437aa9382b2" +checksum = "1b55cdc318ede251d0957f07afe5fed912119b8c1bc5a7804151826db999e737" dependencies = [ "debugid", "memmap2", @@ -12117,11 +12842,11 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "9.2.1" +version = "10.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b940a1fdbc72bb3369e38714efe6cd332dbbe46d093cf03d668b9ac390d1ad0" +checksum = "79be897be8a483a81fff6a3a4e195b4ac838ef73ca42d348b3f722da9902e489" dependencies = [ - "cpp_demangle", + "cpp_demangle 0.4.2", "rustc-demangle", "symbolic-common", ] @@ -12139,9 +12864,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.20" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb8d4cebc40aa517dfb69618fa647a346562e67228e2236ae0042ee6ac14775" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -12162,11 +12887,11 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] @@ -12189,38 +12914,37 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.3.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "fastrand 2.0.0", + "redox_syscall 0.3.5", + "rustix 0.38.6", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "termtree" -version = "0.2.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test-parachain-adder" @@ -12239,7 +12963,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "0.9.43" dependencies = [ - "clap 4.2.5", + "clap 4.3.19", "futures", "futures-timer", "log", @@ -12288,7 +13012,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "0.9.43" dependencies = [ - "clap 4.2.5", + "clap 4.3.19", "futures", "futures-timer", "log", @@ -12343,22 +13067,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -12369,10 +13093,11 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -12400,9 +13125,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-ctl" -version = "0.5.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1" +checksum = "619bfed27d807b54f7f776b9430d4f8060e66ee138a28632ca898584d462c31c" dependencies = [ "libc", "paste", @@ -12411,20 +13136,19 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.4+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1" dependencies = [ "cc", - "fs_extra", "libc", ] [[package]] name = "tikv-jemallocator" -version = "0.5.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979" +checksum = "965fe0c26be5c56c94e38ba547249074803efd52adfb66de62107d95aab3eaca" dependencies = [ "libc", "tikv-jemalloc-sys", @@ -12432,15 +13156,43 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] +[[package]] +name = "time" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +dependencies = [ + "deranged", + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +dependencies = [ + "time-core", +] + [[package]] name = "tiny-bip39" version = "1.0.0" @@ -12490,9 +13242,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" @@ -12507,7 +13259,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "signal-hook-registry", "socket2 0.4.9", "tokio-macros", @@ -12522,7 +13274,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -12538,13 +13290,13 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.2" +version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.7", + "rustls 0.20.8", "tokio", - "webpki", + "webpki 0.22.0", ] [[package]] @@ -12553,27 +13305,27 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.2", + "rustls 0.21.6", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tokio", "tokio-util", ] [[package]] name = "tokio-tungstenite" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" dependencies = [ "futures-util", "log", @@ -12583,15 +13335,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.1" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tokio", "tracing", ] @@ -12607,9 +13359,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -12619,20 +13371,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -12652,18 +13404,18 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82" dependencies = [ - "bitflags", + "bitflags 2.3.3", "bytes", "futures-core", "futures-util", "http", "http-body", "http-range-header", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tower-layer", "tower-service", ] @@ -12676,9 +13428,9 @@ checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" @@ -12688,27 +13440,27 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -12744,7 +13496,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -12760,9 +13512,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" dependencies = [ "serde", "tracing-core", @@ -12793,13 +13545,13 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.11" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ - "ansi_term", - "lazy_static", "matchers 0.1.0", + "nu-ansi-term", + "once_cell", "regex", "sharded-slab", "smallvec", @@ -12879,17 +13631,17 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#8a2c2658a27fcf85c91c02c4f6769ceaebc53e4d" +source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" dependencies = [ "async-trait", - "clap 4.2.5", + "clap 4.3.19", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -12916,15 +13668,16 @@ dependencies = [ "sp-version", "sp-weights", "substrate-rpc-client", - "zstd 0.12.3+zstd.1.5.2", + "zstd 0.12.4", ] [[package]] name = "trybuild" -version = "1.0.75" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1212c215a87a183687a7cc7065901b1a98da6b37277d51a1b5faedbb4efd4f3" +checksum = "a84e0202ea606ba5ebee8507ab2bfbe89b98551ed9b8f0be198109275cff284b" dependencies = [ + "basic-toml", "dissimilar", "glob", "once_cell", @@ -12932,34 +13685,52 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml 0.5.11", ] [[package]] name = "tt-call" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" +checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" [[package]] name = "tungstenite" -version = "0.17.2" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "byteorder", "bytes", "http", "httparse", "log", "rand 0.8.5", - "sha-1 0.10.0", + "sha-1 0.10.1", "thiserror", "url", "utf-8", ] +[[package]] +name = "turn" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" +dependencies = [ + "async-trait", + "base64 0.13.1", + "futures", + "log", + "md-5", + "rand 0.8.5", + "ring 0.16.20", + "stun", + "thiserror", + "tokio", + "webrtc-util", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -12980,15 +13751,15 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uint" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", @@ -12998,36 +13769,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" @@ -13035,7 +13806,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "subtle", ] @@ -13069,12 +13840,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna 0.4.0", "percent-encoding", ] @@ -13092,9 +13863,12 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.2.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom 0.2.10", +] [[package]] name = "valuable" @@ -13165,6 +13939,15 @@ dependencies = [ "libc", ] +[[package]] +name = "waitgroup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" +dependencies = [ + "atomic-waker", +] + [[package]] name = "waker-fn" version = "1.1.0" @@ -13173,22 +13956,20 @@ checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -13233,7 +14014,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -13267,7 +14048,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -13289,9 +14070,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.112.0" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fef6d0d508f08334e0ab0e6877feb4c0ecb3956bcf2cb950699b22fedf3e9c" +checksum = "4d005a95f934878a1fb446a816d51c3601a0120ff929005ba3bab3c749cfd1c7" dependencies = [ "anyhow", "libc", @@ -13305,9 +14086,9 @@ dependencies = [ [[package]] name = "wasm-opt-cxx-sys" -version = "0.112.0" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc816bbc1596c8f2e8127e137a760c798023ef3d378f2ae51f0f1840e2dfa445" +checksum = "6d04e240598162810fad3b2e96fa0dec6dba1eb65a03f3bd99a9248ab8b56caa" dependencies = [ "anyhow", "cxx", @@ -13317,9 +14098,9 @@ dependencies = [ [[package]] name = "wasm-opt-sys" -version = "0.112.0" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40199e4f68ef1071b3c6d0bd8026a12b481865d4b9e49c156932ea9a6234dd14" +checksum = "2efd2aaca519d64098c4faefc8b7433a97ed511caf4c9e516384eb6aef1ff4f9" dependencies = [ "anyhow", "cc", @@ -13348,7 +14129,7 @@ version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b" dependencies = [ - "indexmap", + "indexmap 1.9.3", "url", ] @@ -13361,10 +14142,10 @@ dependencies = [ "anyhow", "bincode", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", - "object", + "object 0.30.4", "once_cell", "paste", "psm", @@ -13396,12 +14177,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.0", + "base64 0.21.2", "bincode", "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.7", + "rustix 0.36.15", "serde", "sha2 0.10.7", "toml 0.5.11", @@ -13423,7 +14204,7 @@ dependencies = [ "cranelift-wasm", "gimli", "log", - "object", + "object 0.30.4", "target-lexicon", "thiserror", "wasmparser", @@ -13441,7 +14222,7 @@ dependencies = [ "cranelift-codegen", "cranelift-native", "gimli", - "object", + "object 0.30.4", "target-lexicon", "wasmtime-environ", ] @@ -13455,9 +14236,9 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli", - "indexmap", + "indexmap 1.9.3", "log", - "object", + "object 0.30.4", "serde", "target-lexicon", "thiserror", @@ -13471,14 +14252,14 @@ version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de48df552cfca1c9b750002d3e07b45772dd033b0b206d5c0968496abf31244" dependencies = [ - "addr2line", + "addr2line 0.19.0", "anyhow", "bincode", "cfg-if", - "cpp_demangle", + "cpp_demangle 0.3.5", "gimli", "log", - "object", + "object 0.30.4", "rustc-demangle", "serde", "target-lexicon", @@ -13495,9 +14276,9 @@ version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ - "object", + "object 0.30.4", "once_cell", - "rustix 0.36.7", + "rustix 0.36.15", ] [[package]] @@ -13520,7 +14301,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "mach", @@ -13528,7 +14309,7 @@ dependencies = [ "memoffset 0.8.0", "paste", "rand 0.8.5", - "rustix 0.36.7", + "rustix 0.36.15", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -13549,14 +14330,24 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring 0.16.20", + "untrusted", +] + [[package]] name = "webpki" version = "0.22.0" @@ -13569,29 +14360,220 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.2" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ - "webpki", + "webpki 0.22.0", ] [[package]] -name = "webpki-roots" -version = "0.23.1" +name = "webrtc" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" +checksum = "2d3bc9049bdb2cea52f5fd4f6f728184225bdb867ed0dc2410eab6df5bdd67bb" dependencies = [ - "rustls-webpki", + "arc-swap", + "async-trait", + "bytes", + "hex", + "interceptor", + "lazy_static", + "log", + "rand 0.8.5", + "rcgen 0.9.3", + "regex", + "ring 0.16.20", + "rtcp", + "rtp", + "rustls 0.19.1", + "sdp", + "serde", + "serde_json", + "sha2 0.10.7", + "stun", + "thiserror", + "time 0.3.25", + "tokio", + "turn", + "url", + "waitgroup", + "webrtc-data", + "webrtc-dtls", + "webrtc-ice", + "webrtc-mdns", + "webrtc-media", + "webrtc-sctp", + "webrtc-srtp", + "webrtc-util", ] [[package]] -name = "wepoll-ffi" -version = "0.1.2" +name = "webrtc-data" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef36a4d12baa6e842582fe9ec16a57184ba35e1a09308307b67d43ec8883100" +dependencies = [ + "bytes", + "derive_builder", + "log", + "thiserror", + "tokio", + "webrtc-sctp", + "webrtc-util", +] + +[[package]] +name = "webrtc-dtls" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +checksum = "942be5bd85f072c3128396f6e5a9bfb93ca8c1939ded735d177b7bcba9a13d05" dependencies = [ + "aes 0.6.0", + "aes-gcm 0.10.2", + "async-trait", + "bincode", + "block-modes", + "byteorder", + "ccm", + "curve25519-dalek 3.2.0", + "der-parser 8.2.0", + "elliptic-curve 0.12.3", + "hkdf", + "hmac 0.12.1", + "log", + "oid-registry 0.6.1", + "p256", + "p384", + "rand 0.8.5", + "rand_core 0.6.4", + "rcgen 0.9.3", + "ring 0.16.20", + "rustls 0.19.1", + "sec1 0.3.0", + "serde", + "sha1", + "sha2 0.10.7", + "signature 1.6.4", + "subtle", + "thiserror", + "tokio", + "webpki 0.21.4", + "webrtc-util", + "x25519-dalek 2.0.0-pre.1", + "x509-parser 0.13.2", +] + +[[package]] +name = "webrtc-ice" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" +dependencies = [ + "arc-swap", + "async-trait", + "crc", + "log", + "rand 0.8.5", + "serde", + "serde_json", + "stun", + "thiserror", + "tokio", + "turn", + "url", + "uuid", + "waitgroup", + "webrtc-mdns", + "webrtc-util", +] + +[[package]] +name = "webrtc-mdns" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" +dependencies = [ + "log", + "socket2 0.4.9", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-media" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f72e1650a8ae006017d1a5280efb49e2610c19ccc3c0905b03b648aee9554991" +dependencies = [ + "byteorder", + "bytes", + "rand 0.8.5", + "rtp", + "thiserror", +] + +[[package]] +name = "webrtc-sctp" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d47adcd9427eb3ede33d5a7f3424038f63c965491beafcc20bc650a2f6679c0" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "rand 0.8.5", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-srtp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6183edc4c1c6c0175f8812eefdce84dfa0aea9c3ece71c2bf6ddd3c964de3da5" +dependencies = [ + "aead 0.4.3", + "aes 0.7.5", + "aes-gcm 0.9.4", + "async-trait", + "byteorder", + "bytes", + "ctr 0.8.0", + "hmac 0.11.0", + "log", + "rtcp", + "rtp", + "sha-1 0.9.8", + "subtle", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" +dependencies = [ + "async-trait", + "bitflags 1.3.2", + "bytes", "cc", + "ipnet", + "lazy_static", + "libc", + "log", + "nix 0.24.3", + "rand 0.8.5", + "thiserror", + "tokio", + "winapi", ] [[package]] @@ -13707,20 +14689,20 @@ dependencies = [ [[package]] name = "which" -version = "4.2.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", - "lazy_static", "libc", + "once_cell", ] [[package]] name = "wide" -version = "0.7.6" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feff0a412894d67223777b6cc8d68c0dab06d52d95e9890d5f2d47f10dd9366c" +checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" dependencies = [ "bytemuck", "safe_arch", @@ -13728,9 +14710,9 @@ dependencies = [ [[package]] name = "widestring" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" [[package]] name = "winapi" @@ -13777,31 +14759,12 @@ dependencies = [ ] [[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.48.1", ] [[package]] @@ -13819,7 +14782,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -13839,9 +14802,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -13870,12 +14833,6 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -13894,12 +14851,6 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -13918,12 +14869,6 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -13942,12 +14887,6 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -13978,12 +14917,6 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -13998,29 +14931,30 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deac0939bd6e4f24ab5919fbf751c97a8cfc8543bb083a305ed5c0c10bb241d1" +checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -14054,6 +14988,43 @@ dependencies = [ "zeroize", ] +[[package]] +name = "x509-parser" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" +dependencies = [ + "asn1-rs 0.3.1", + "base64 0.13.1", + "data-encoding", + "der-parser 7.0.0", + "lazy_static", + "nom", + "oid-registry 0.4.0", + "ring 0.16.20", + "rusticata-macros", + "thiserror", + "time 0.3.25", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs 0.5.2", + "base64 0.13.1", + "data-encoding", + "der-parser 8.2.0", + "lazy_static", + "nom", + "oid-registry 0.6.1", + "rusticata-macros", + "thiserror", + "time 0.3.25", +] + [[package]] name = "xcm" version = "0.9.43" @@ -14145,7 +15116,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.20", + "syn 2.0.28", ] [[package]] @@ -14238,6 +15209,15 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time 0.3.25", +] + [[package]] name = "zeroize" version = "1.6.0" @@ -14249,14 +15229,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure", + "syn 2.0.28", ] [[package]] @@ -14287,11 +15266,11 @@ dependencies = [ [[package]] name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" dependencies = [ - "zstd-safe 6.0.5+zstd.1.5.4", + "zstd-safe 6.0.6", ] [[package]] @@ -14306,9 +15285,9 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" +version = "6.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" dependencies = [ "libc", "zstd-sys", diff --git a/node/core/approval-voting/Cargo.toml b/node/core/approval-voting/Cargo.toml index a42e449f09f9..f31c7d0a1694 100644 --- a/node/core/approval-voting/Cargo.toml +++ b/node/core/approval-voting/Cargo.toml @@ -11,7 +11,7 @@ futures-timer = "3.0.2" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } gum = { package = "tracing-gum", path = "../../gum" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -lru = "0.11" +lru = "0.11.0" merlin = "2.0" schnorrkel = "0.9.1" kvdb = "0.13.0" diff --git a/node/core/runtime-api/Cargo.toml b/node/core/runtime-api/Cargo.toml index 22b4a96e60e8..30ba781216d0 100644 --- a/node/core/runtime-api/Cargo.toml +++ b/node/core/runtime-api/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } -lru = "0.11" +lru = "0.11.0" sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/node/gum/proc-macro/Cargo.toml b/node/gum/proc-macro/Cargo.toml index 61f31beb61f3..e7262008499b 100644 --- a/node/gum/proc-macro/Cargo.toml +++ b/node/gum/proc-macro/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.20", features = ["full", "extra-traits"] } +syn = { version = "2.0.15", features = ["full", "extra-traits"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" diff --git a/node/network/bridge/src/validator_discovery.rs b/node/network/bridge/src/validator_discovery.rs index d4d1df3da467..e89b38544684 100644 --- a/node/network/bridge/src/validator_discovery.rs +++ b/node/network/bridge/src/validator_discovery.rs @@ -157,7 +157,7 @@ impl Service { fn extract_peer_ids(multiaddr: impl Iterator) -> HashSet { multiaddr .filter_map(|mut addr| match addr.pop() { - Some(multiaddr::Protocol::P2p(peer_id)) => Some(peer_id), + Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key).ok(), _ => None, }) .collect() @@ -208,7 +208,7 @@ mod tests { let authorities = known_authorities(); let multiaddr = known_multiaddr().into_iter().zip(peer_ids.iter().cloned()).map( |(mut addr, peer_id)| { - addr.push(multiaddr::Protocol::P2p(peer_id)); + addr.push(multiaddr::Protocol::P2p(peer_id.into())); HashSet::from([addr]) }, ); diff --git a/node/network/gossip-support/src/tests.rs b/node/network/gossip-support/src/tests.rs index 72bc7ded251a..5f91fcf52147 100644 --- a/node/network/gossip-support/src/tests.rs +++ b/node/network/gossip-support/src/tests.rs @@ -106,7 +106,7 @@ impl MockAuthorityDiscovery { .clone() .into_iter() .map(|(p, a)| { - let multiaddr = Multiaddr::empty().with(Protocol::P2p(p)); + let multiaddr = Multiaddr::empty().with(Protocol::P2p(p.into())); (a, HashSet::from([multiaddr])) }) .collect(); @@ -566,11 +566,11 @@ fn test_log_output() { let unconnected_authorities = { let mut m = HashMap::new(); let peer_id = PeerId::random(); - let addr = Multiaddr::empty().with(Protocol::P2p(peer_id)); + let addr = Multiaddr::empty().with(Protocol::P2p(peer_id.into())); let addrs = HashSet::from([addr.clone(), addr]); m.insert(alice, addrs); let peer_id = PeerId::random(); - let addr = Multiaddr::empty().with(Protocol::P2p(peer_id)); + let addr = Multiaddr::empty().with(Protocol::P2p(peer_id.into())); let addrs = HashSet::from([addr.clone(), addr]); m.insert(bob, addrs); m diff --git a/node/overseer/Cargo.toml b/node/overseer/Cargo.toml index b0576f5c61ef..2e601a46a744 100644 --- a/node/overseer/Cargo.toml +++ b/node/overseer/Cargo.toml @@ -18,7 +18,7 @@ polkadot-node-metrics = { path = "../metrics" } polkadot-primitives = { path = "../../primitives" } orchestra = "0.0.5" gum = { package = "tracing-gum", path = "../gum" } -lru = "0.11" +lru = "0.11.0" sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } async-trait = "0.1.57" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml index e373dd4f0011..48e4633aa5e3 100644 --- a/node/service/Cargo.toml +++ b/node/service/Cargo.toml @@ -87,7 +87,7 @@ parity-db = { version = "0.4.8", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } async-trait = "0.1.57" -lru = "0.11" +lru = "0.11.0" log = "0.4.17" is_executable = "1.0.1" diff --git a/node/subsystem-types/Cargo.toml b/node/subsystem-types/Cargo.toml index d994682110e5..1fb9ac83b780 100644 --- a/node/subsystem-types/Cargo.toml +++ b/node/subsystem-types/Cargo.toml @@ -20,7 +20,7 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -smallvec = "1.11.0" +smallvec = "1.8.0" substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } thiserror = "1.0.31" async-trait = "0.1.57" diff --git a/runtime/kusama/Cargo.toml b/runtime/kusama/Cargo.toml index 645215bc2c22..28598bde9443 100644 --- a/runtime/kusama/Cargo.toml +++ b/runtime/kusama/Cargo.toml @@ -15,7 +15,7 @@ rustc-hex = { version = "2.1.0", default-features = false } serde = { version = "1.0.163", default-features = false } serde_derive = { version = "1.0.117", optional = true } static_assertions = "1.1.0" -smallvec = "1.11.0" +smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/runtime/kusama/constants/Cargo.toml b/runtime/kusama/constants/Cargo.toml index 11ff70cd8c9b..293c91bbd543 100644 --- a/runtime/kusama/constants/Cargo.toml +++ b/runtime/kusama/constants/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -smallvec = "1.11.0" +smallvec = "1.8.0" frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false } diff --git a/runtime/polkadot/Cargo.toml b/runtime/polkadot/Cargo.toml index 0ab06b8bbb12..5d343811fb14 100644 --- a/runtime/polkadot/Cargo.toml +++ b/runtime/polkadot/Cargo.toml @@ -15,7 +15,7 @@ rustc-hex = { version = "2.1.0", default-features = false } serde = { version = "1.0.163", default-features = false } serde_derive = { version = "1.0.117", optional = true } static_assertions = "1.1.0" -smallvec = "1.11.0" +smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/runtime/polkadot/constants/Cargo.toml b/runtime/polkadot/constants/Cargo.toml index a10546edfa7b..42a9c685ea82 100644 --- a/runtime/polkadot/constants/Cargo.toml +++ b/runtime/polkadot/constants/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -smallvec = "1.11.0" +smallvec = "1.8.0" frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false } diff --git a/runtime/rococo/Cargo.toml b/runtime/rococo/Cargo.toml index f1f0d1cbe729..95791edda710 100644 --- a/runtime/rococo/Cargo.toml +++ b/runtime/rococo/Cargo.toml @@ -13,7 +13,7 @@ log = { version = "0.4.17", default-features = false } serde = { version = "1.0.163", default-features = false } serde_derive = { version = "1.0.117", optional = true } static_assertions = "1.1.0" -smallvec = "1.11.0" +smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/runtime/rococo/constants/Cargo.toml b/runtime/rococo/constants/Cargo.toml index f9ea1186c550..e7bc81f199a1 100644 --- a/runtime/rococo/constants/Cargo.toml +++ b/runtime/rococo/constants/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -smallvec = "1.11.0" +smallvec = "1.8.0" frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false } diff --git a/runtime/test-runtime/Cargo.toml b/runtime/test-runtime/Cargo.toml index 41fbebb39f3a..9dcd8fe83a27 100644 --- a/runtime/test-runtime/Cargo.toml +++ b/runtime/test-runtime/Cargo.toml @@ -15,7 +15,7 @@ rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.163", default-features = false } serde_derive = { version = "1.0.117", optional = true } -smallvec = "1.11.0" +smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/runtime/test-runtime/constants/Cargo.toml b/runtime/test-runtime/constants/Cargo.toml index 15ab1dbdd4fe..84d8ae8ce560 100644 --- a/runtime/test-runtime/constants/Cargo.toml +++ b/runtime/test-runtime/constants/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true license.workspace = true [dependencies] -smallvec = "1.11.0" +smallvec = "1.8.0" frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false } diff --git a/runtime/westend/Cargo.toml b/runtime/westend/Cargo.toml index e665a08b1ed1..79583fc2fb1e 100644 --- a/runtime/westend/Cargo.toml +++ b/runtime/westend/Cargo.toml @@ -14,7 +14,7 @@ log = { version = "0.4.17", default-features = false } rustc-hex = { version = "2.1.0", default-features = false } serde = { version = "1.0.163", default-features = false } serde_derive = { version = "1.0.117", optional = true } -smallvec = "1.11.0" +smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/runtime/westend/constants/Cargo.toml b/runtime/westend/constants/Cargo.toml index e5d9900e22e2..63e9ad34a7f2 100644 --- a/runtime/westend/constants/Cargo.toml +++ b/runtime/westend/constants/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -smallvec = "1.11.0" +smallvec = "1.8.0" frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false } diff --git a/xcm/procedural/Cargo.toml b/xcm/procedural/Cargo.toml index b60c8eed6151..a821a73669e0 100644 --- a/xcm/procedural/Cargo.toml +++ b/xcm/procedural/Cargo.toml @@ -11,5 +11,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = "1.0.28" -syn = "2.0.20" +syn = "2.0.15" Inflector = "0.11.4" From 2157c2f4c1bdec4f1ad88c169103b3bb21fac2f0 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 16 Aug 2023 14:20:31 +0200 Subject: [PATCH 25/45] Fix clippy warnings (#7625) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix clippy check Signed-off-by: Oliver Tale-Yazdi * Autofix clippy Signed-off-by: Oliver Tale-Yazdi * Fix trivial Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * suppress warnings Signed-off-by: Oliver Tale-Yazdi * Quiet clippy 😌 Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- node/collation-generation/src/tests.rs | 2 +- node/core/av-store/src/tests.rs | 2 +- node/core/backing/src/tests.rs | 8 - node/core/chain-selection/src/tests.rs | 52 +- .../src/participation/queues/tests.rs | 2 +- node/core/dispute-coordinator/src/tests.rs | 22 +- .../disputes/prioritized_selection/tests.rs | 66 +-- node/core/pvf-checker/src/tests.rs | 16 +- node/core/pvf/tests/it/adder.rs | 9 +- node/core/runtime-api/src/tests.rs | 8 +- .../src/variants/back_garbage_candidate.rs | 4 +- node/malus/src/variants/common.rs | 5 +- .../src/variants/dispute_valid_candidates.rs | 4 +- .../src/variants/suggest_garbage_candidate.rs | 6 +- .../approval-distribution/src/tests.rs | 42 +- .../src/tests/state.rs | 11 +- .../availability-recovery/src/tests.rs | 32 +- .../bitfield-distribution/src/tests.rs | 163 +++--- node/network/bridge/src/rx/tests.rs | 132 ++--- node/network/bridge/src/tx/tests.rs | 12 +- .../network/bridge/src/validator_discovery.rs | 4 +- .../src/collator_side/tests.rs | 81 +-- .../src/validator_side/tests.rs | 100 ++-- .../dispute-distribution/src/tests/mock.rs | 2 +- node/network/gossip-support/src/tests.rs | 8 +- .../statement-distribution/src/tests.rs | 131 +++-- node/service/src/tests.rs | 16 +- node/test/service/src/lib.rs | 8 +- runtime/common/src/auctions.rs | 8 +- runtime/common/src/crowdloan/mod.rs | 6 +- runtime/common/src/xcm_sender.rs | 14 +- runtime/parachains/src/builder.rs | 22 +- runtime/parachains/src/disputes/tests.rs | 488 ++++++------------ runtime/parachains/src/inclusion/tests.rs | 5 +- runtime/parachains/src/paras/mod.rs | 2 +- runtime/parachains/src/paras/tests.rs | 13 - .../parachains/src/paras_inherent/tests.rs | 32 +- runtime/parachains/src/scheduler/tests.rs | 82 +-- runtime/parachains/src/session_info/tests.rs | 5 +- runtime/parachains/src/ump_tests.rs | 6 +- scripts/ci/gitlab/pipeline/test.yml | 3 +- statement-table/src/generic.rs | 8 +- xcm/pallet-xcm/src/tests.rs | 111 ++-- xcm/xcm-builder/src/asset_conversion.rs | 4 +- xcm/xcm-builder/src/tests/assets.rs | 5 +- xcm/xcm-builder/src/tests/bridging/mod.rs | 6 +- .../tests/bridging/paid_remote_relay_relay.rs | 4 +- xcm/xcm-builder/src/tests/mock.rs | 16 +- xcm/xcm-builder/src/tests/transacting.rs | 6 +- .../src/tests/version_subscriptions.rs | 4 +- xcm/xcm-simulator/fuzzer/src/parachain.rs | 4 +- 51 files changed, 729 insertions(+), 1073 deletions(-) diff --git a/node/collation-generation/src/tests.rs b/node/collation-generation/src/tests.rs index 1c98e1450941..09e5e88c221c 100644 --- a/node/collation-generation/src/tests.rs +++ b/node/collation-generation/src/tests.rs @@ -353,7 +353,7 @@ mod handle_new_activations { let expect_descriptor = { let mut expect_descriptor = expect_descriptor; expect_descriptor.signature = descriptor.signature.clone(); - expect_descriptor.erasure_root = descriptor.erasure_root.clone(); + expect_descriptor.erasure_root = descriptor.erasure_root; expect_descriptor }; assert_eq!(descriptor, expect_descriptor); diff --git a/node/core/av-store/src/tests.rs b/node/core/av-store/src/tests.rs index f8e30210c7c2..dbccf1401582 100644 --- a/node/core/av-store/src/tests.rs +++ b/node/core/av-store/src/tests.rs @@ -53,7 +53,7 @@ struct TestClock { impl TestClock { fn now(&self) -> Duration { - self.inner.lock().clone() + *self.inner.lock() } fn inc(&self, by: Duration) { diff --git a/node/core/backing/src/tests.rs b/node/core/backing/src/tests.rs index 386cc9e2279e..4be7516c58b4 100644 --- a/node/core/backing/src/tests.rs +++ b/node/core/backing/src/tests.rs @@ -283,7 +283,6 @@ fn backing_second_works() { pov_hash, head_data: expected_head_data.clone(), erasure_root: make_erasure_root(&test_state, pov.clone()), - ..Default::default() } .build(); @@ -373,7 +372,6 @@ fn backing_works() { pov_hash, head_data: expected_head_data.clone(), erasure_root: make_erasure_root(&test_state, pov.clone()), - ..Default::default() } .build(); @@ -522,7 +520,6 @@ fn backing_works_while_validation_ongoing() { pov_hash, head_data: expected_head_data.clone(), erasure_root: make_erasure_root(&test_state, pov.clone()), - ..Default::default() } .build(); @@ -699,7 +696,6 @@ fn backing_misbehavior_works() { pov_hash, erasure_root: make_erasure_root(&test_state, pov.clone()), head_data: expected_head_data.clone(), - ..Default::default() } .build(); @@ -884,7 +880,6 @@ fn backing_dont_second_invalid() { pov_hash: pov_hash_b, erasure_root: make_erasure_root(&test_state, pov_block_b.clone()), head_data: expected_head_data.clone(), - ..Default::default() } .build(); @@ -1215,7 +1210,6 @@ fn backing_doesnt_second_wrong_collator() { pov_hash, head_data: expected_head_data.clone(), erasure_root: make_erasure_root(&test_state, pov.clone()), - ..Default::default() } .build(); @@ -1267,7 +1261,6 @@ fn validation_work_ignores_wrong_collator() { pov_hash, head_data: expected_head_data.clone(), erasure_root: make_erasure_root(&test_state, pov.clone()), - ..Default::default() } .build(); @@ -1541,7 +1534,6 @@ fn observes_backing_even_if_not_validator() { pov_hash, head_data: expected_head_data.clone(), erasure_root: make_erasure_root(&test_state, pov.clone()), - ..Default::default() } .build(); diff --git a/node/core/chain-selection/src/tests.rs b/node/core/chain-selection/src/tests.rs index 8b475bd2e13c..c04f9aaf6606 100644 --- a/node/core/chain-selection/src/tests.rs +++ b/node/core/chain-selection/src/tests.rs @@ -568,7 +568,7 @@ fn assert_backend_contains<'a>( fn assert_backend_contains_chains(backend: &TestBackend, chains: Vec>) { for chain in chains { - assert_backend_contains(backend, chain.iter().map(|&(ref hdr, _)| hdr)) + assert_backend_contains(backend, chain.iter().map(|(hdr, _)| hdr)) } } @@ -688,7 +688,7 @@ fn import_chain_on_finalized_incrementally() { .await; assert_eq!(backend.load_first_block_number().unwrap().unwrap(), 1); - assert_backend_contains(&backend, chain.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![head_hash]); assert_leaves_query(&mut virtual_overseer, vec![head_hash]).await; @@ -721,8 +721,8 @@ fn import_two_subtrees_on_finalized() { import_blocks_into(&mut virtual_overseer, &backend, None, chain_b.clone()).await; assert_eq!(backend.load_first_block_number().unwrap().unwrap(), 1); - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![b_hash, a_hash]); assert_leaves_query(&mut virtual_overseer, vec![b_hash, a_hash]).await; @@ -755,8 +755,8 @@ fn import_two_subtrees_on_nonzero_finalized() { import_blocks_into(&mut virtual_overseer, &backend, None, chain_b.clone()).await; assert_eq!(backend.load_first_block_number().unwrap().unwrap(), 101); - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![b_hash, a_hash]); assert_leaves_query(&mut virtual_overseer, vec![b_hash, a_hash]).await; @@ -799,9 +799,9 @@ fn leaves_ordered_by_weight_and_then_number() { .await; assert_eq!(backend.load_first_block_number().unwrap().unwrap(), 1); - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_c.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_c.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![c2_hash, a3_hash, b2_hash]); assert_leaves_query(&mut virtual_overseer, vec![c2_hash, a3_hash, b2_hash]).await; virtual_overseer @@ -844,8 +844,8 @@ fn subtrees_imported_even_with_gaps() { .await; assert_eq!(backend.load_first_block_number().unwrap().unwrap(), 1); - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![b5_hash, a3_hash]); assert_leaves_query(&mut virtual_overseer, vec![b5_hash, a3_hash]).await; @@ -878,7 +878,7 @@ fn reversion_removes_viability_of_chain() { ) .await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![]); assert_finalized_leaves_query(&mut virtual_overseer, finalized_number, finalized_hash) .await; @@ -914,7 +914,7 @@ fn reversion_removes_viability_and_finds_ancestor_as_leaf() { ) .await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![a1_hash]); assert_leaves_query(&mut virtual_overseer, vec![a1_hash]).await; @@ -954,15 +954,15 @@ fn ancestor_of_unviable_is_not_leaf_if_has_children() { import_blocks_into(&mut virtual_overseer, &backend, None, chain_b.clone()).await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![a2_hash, b2_hash]); import_blocks_into(&mut virtual_overseer, &backend, None, chain_a_ext.clone()).await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_a_ext.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_a_ext.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![b2_hash]); assert_leaves_query(&mut virtual_overseer, vec![b2_hash]).await; @@ -995,7 +995,7 @@ fn self_and_future_reversions_are_ignored() { ) .await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![a3_hash]); assert_leaves_query(&mut virtual_overseer, vec![a3_hash]).await; @@ -1028,7 +1028,7 @@ fn revert_finalized_is_ignored() { ) .await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![a3_hash]); assert_leaves_query(&mut virtual_overseer, vec![a3_hash]).await; @@ -1072,8 +1072,8 @@ fn reversion_affects_viability_of_all_subtrees() { import_blocks_into(&mut virtual_overseer, &backend, None, chain_b.clone()).await; - assert_backend_contains(&backend, chain_a.iter().map(|&(ref h, _)| h)); - assert_backend_contains(&backend, chain_b.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_backend_contains(&backend, chain_b.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![a1_hash]); assert_leaves_query(&mut virtual_overseer, vec![a1_hash]).await; @@ -2034,12 +2034,12 @@ fn revert_blocks_message_triggers_proper_reversion() { .await; // Checking mini chain - assert_backend_contains(&backend, built_chain.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, built_chain.iter().map(|(h, _)| h)); assert_leaves(&backend, vec![head_hash]); assert_leaves_query(&mut virtual_overseer, vec![head_hash]).await; - let block_1_hash = backend.load_blocks_by_number(1).unwrap().get(0).unwrap().clone(); - let block_2_hash = backend.load_blocks_by_number(2).unwrap().get(0).unwrap().clone(); + let block_1_hash = *backend.load_blocks_by_number(1).unwrap().get(0).unwrap(); + let block_2_hash = *backend.load_blocks_by_number(2).unwrap().get(0).unwrap(); // Sending revert blocks message let (_, write_rx) = backend.await_next_write(); @@ -2098,7 +2098,7 @@ fn revert_blocks_against_finalized_is_ignored() { .await; // Checking mini chain - assert_backend_contains(&backend, built_chain.iter().map(|&(ref h, _)| h)); + assert_backend_contains(&backend, built_chain.iter().map(|(h, _)| h)); // Sending dispute concluded against message virtual_overseer diff --git a/node/core/dispute-coordinator/src/participation/queues/tests.rs b/node/core/dispute-coordinator/src/participation/queues/tests.rs index 5e262d895e31..d4f43639ce87 100644 --- a/node/core/dispute-coordinator/src/participation/queues/tests.rs +++ b/node/core/dispute-coordinator/src/participation/queues/tests.rs @@ -44,7 +44,7 @@ fn make_dummy_comparator( fn clone_request(request: &ParticipationRequest) -> ParticipationRequest { ParticipationRequest { candidate_receipt: request.candidate_receipt.clone(), - candidate_hash: request.candidate_hash.clone(), + candidate_hash: request.candidate_hash, session: request.session, request_timer: None, } diff --git a/node/core/dispute-coordinator/src/tests.rs b/node/core/dispute-coordinator/src/tests.rs index d0cf494d2d4d..75eae8200dc6 100644 --- a/node/core/dispute-coordinator/src/tests.rs +++ b/node/core/dispute-coordinator/src/tests.rs @@ -399,10 +399,10 @@ impl TestState { let mut response = Vec::new(); for i in target_header.number.saturating_sub(k as u32)..target_header.number { response.push( - self.block_num_to_header + *self + .block_num_to_header .get(&i) - .expect("headers and block_num_to_header should always be in sync") - .clone(), + .expect("headers and block_num_to_header should always be in sync"), ); } let _ = response_channel.send(Ok(response)); @@ -552,7 +552,7 @@ impl TestState { let (ctx, ctx_handle) = make_buffered_subsystem_context(TaskExecutor::new(), 1); let subsystem = DisputeCoordinatorSubsystem::new( self.db.clone(), - self.config.clone(), + self.config, self.subsystem_keystore.clone(), Metrics::default(), ); @@ -574,27 +574,27 @@ where // Add two more blocks after the genesis (which is created in `default()`) let h1 = Header { - parent_hash: test_state.last_block.clone(), + parent_hash: test_state.last_block, number: 1, digest: dummy_digest(), state_root: dummy_hash(), extrinsics_root: dummy_hash(), }; let h1_hash = h1.hash(); - test_state.headers.insert(h1_hash.clone(), h1); - test_state.block_num_to_header.insert(1, h1_hash.clone()); + test_state.headers.insert(h1_hash, h1); + test_state.block_num_to_header.insert(1, h1_hash); test_state.last_block = h1_hash; let h2 = Header { - parent_hash: test_state.last_block.clone(), + parent_hash: test_state.last_block, number: 2, digest: dummy_digest(), state_root: dummy_hash(), extrinsics_root: dummy_hash(), }; let h2_hash = h2.hash(); - test_state.headers.insert(h2_hash.clone(), h2); - test_state.block_num_to_header.insert(2, h2_hash.clone()); + test_state.headers.insert(h2_hash, h2); + test_state.block_num_to_header.insert(2, h2_hash); test_state.last_block = h2_hash; test_state.resume(test) @@ -3133,7 +3133,7 @@ fn participation_requests_reprioritized_for_newly_included() { // participation. let parent_block_num: BlockNumber = repetition as BlockNumber - 1; candidate_receipt.descriptor.relay_parent = - test_state.block_num_to_header.get(&parent_block_num).unwrap().clone(); + *test_state.block_num_to_header.get(&parent_block_num).unwrap(); receipts.push(candidate_receipt.clone()); } diff --git a/node/core/provisioner/src/disputes/prioritized_selection/tests.rs b/node/core/provisioner/src/disputes/prioritized_selection/tests.rs index 7798ebe51aaf..2fdeadb2f4f0 100644 --- a/node/core/provisioner/src/disputes/prioritized_selection/tests.rs +++ b/node/core/provisioner/src/disputes/prioritized_selection/tests.rs @@ -136,16 +136,16 @@ fn partitioning_happy_case() { CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(time_now - ACTIVE_DURATION_SECS * 2), ); - input.push(inactive_unknown_onchain.clone()); + input.push(inactive_unknown_onchain); let inactive_unconcluded_onchain = ( 1, CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(time_now - ACTIVE_DURATION_SECS * 2), ); - input.push(inactive_unconcluded_onchain.clone()); + input.push(inactive_unconcluded_onchain); onchain.insert( - (inactive_unconcluded_onchain.0, inactive_unconcluded_onchain.1.clone()), + (inactive_unconcluded_onchain.0, inactive_unconcluded_onchain.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 0, 0, 0, 0, 0, 0], validators_against: bitvec![u8, Lsb0; 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -155,12 +155,12 @@ fn partitioning_happy_case() { ); let active_unknown_onchain = (2, CandidateHash(Hash::random()), DisputeStatus::Active); - input.push(active_unknown_onchain.clone()); + input.push(active_unknown_onchain); let active_unconcluded_onchain = (3, CandidateHash(Hash::random()), DisputeStatus::Active); - input.push(active_unconcluded_onchain.clone()); + input.push(active_unconcluded_onchain); onchain.insert( - (active_unconcluded_onchain.0, active_unconcluded_onchain.1.clone()), + (active_unconcluded_onchain.0, active_unconcluded_onchain.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 0, 0, 0, 0, 0, 0], validators_against: bitvec![u8, Lsb0; 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -170,9 +170,9 @@ fn partitioning_happy_case() { ); let active_concluded_onchain = (4, CandidateHash(Hash::random()), DisputeStatus::Active); - input.push(active_concluded_onchain.clone()); + input.push(active_concluded_onchain); onchain.insert( - (active_concluded_onchain.0, active_concluded_onchain.1.clone()), + (active_concluded_onchain.0, active_concluded_onchain.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 1, 1, 1, 1, 1, 0], validators_against: bitvec![u8, Lsb0; 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -186,9 +186,9 @@ fn partitioning_happy_case() { CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(time_now - ACTIVE_DURATION_SECS * 2), ); - input.push(inactive_concluded_onchain.clone()); + input.push(inactive_concluded_onchain); onchain.insert( - (inactive_concluded_onchain.0, inactive_concluded_onchain.1.clone()), + (inactive_concluded_onchain.0, inactive_concluded_onchain.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 1, 1, 1, 1, 0, 0], validators_against: bitvec![u8, Lsb0; 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -254,10 +254,10 @@ fn partitioning_doubled_onchain_vote() { // Dispute B has supermajority + 1 votes, so the doubled onchain vote doesn't affect it. It // should be considered as 'can conclude onchain'. let dispute_b = (4, CandidateHash(Hash::random()), DisputeStatus::Active); - input.push(dispute_a.clone()); - input.push(dispute_b.clone()); + input.push(dispute_a); + input.push(dispute_b); onchain.insert( - (dispute_a.0, dispute_a.1.clone()), + (dispute_a.0, dispute_a.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 1, 1, 1, 1, 0, 0], validators_against: bitvec![u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0], @@ -266,7 +266,7 @@ fn partitioning_doubled_onchain_vote() { }, ); onchain.insert( - (dispute_b.0, dispute_b.1.clone()), + (dispute_b.0, dispute_b.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 1, 1, 1, 1, 1, 0], validators_against: bitvec![u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0], @@ -287,10 +287,10 @@ fn partitioning_duplicated_dispute() { let mut onchain = HashMap::<(u32, CandidateHash), DisputeState>::new(); let some_dispute = (3, CandidateHash(Hash::random()), DisputeStatus::Active); - input.push(some_dispute.clone()); - input.push(some_dispute.clone()); + input.push(some_dispute); + input.push(some_dispute); onchain.insert( - (some_dispute.0, some_dispute.1.clone()), + (some_dispute.0, some_dispute.1), DisputeState { validators_for: bitvec![u8, Lsb0; 1, 1, 1, 0, 0, 0, 0, 0, 0], validators_against: bitvec![u8, Lsb0; 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -385,7 +385,7 @@ impl TestDisputes { local_votes_count: usize, dummy_receipt: CandidateReceipt, ) { - self.local_disputes.push(dispute.clone()); + self.local_disputes.push(dispute); self.votes_db.insert( (dispute.0, dispute.1), CandidateVotes { @@ -412,7 +412,7 @@ impl TestDisputes { DisputeStatus::ConcludedAgainst(_) | DisputeStatus::ConcludedFor(_) => Some(1), }; self.onchain_disputes.insert( - (dispute.0, dispute.1.clone()), + (dispute.0, dispute.1), DisputeState { validators_for: TestDisputes::generate_bitvec( self.validators_count, @@ -434,10 +434,10 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 80 / 100; let session_idx = 0; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); self.add_onchain_dispute(d, onchain_votes_count); } @@ -452,10 +452,10 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 40 / 100; let session_idx = 1; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); self.add_onchain_dispute(d, onchain_votes_count); } @@ -469,10 +469,10 @@ impl TestDisputes { let local_votes_count = self.validators_count * 90 / 100; let session_idx = 2; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Confirmed); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); } (session_idx, local_votes_count * dispute_count) } @@ -485,10 +485,10 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 75 / 100; let session_idx = 3; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(0)); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); self.add_onchain_dispute(d, onchain_votes_count); } (session_idx, (local_votes_count - onchain_votes_count) * dispute_count) @@ -501,10 +501,10 @@ impl TestDisputes { let local_votes_count = self.validators_count * 90 / 100; let session_idx = 4; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(0)); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); } (session_idx, local_votes_count * dispute_count) } @@ -517,10 +517,10 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 10 / 100; let session_idx = 5; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); self.add_onchain_dispute(d, onchain_votes_count); } @@ -534,10 +534,10 @@ impl TestDisputes { let local_votes_count = self.validators_count * 10 / 100; let session_idx = 6; let lf = leaf(); - let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash.clone()); + let dummy_receipt = test_helpers::dummy_candidate_receipt(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); - self.add_offchain_dispute(d.clone(), local_votes_count, dummy_receipt.clone()); + self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); } (session_idx, local_votes_count * dispute_count) diff --git a/node/core/pvf-checker/src/tests.rs b/node/core/pvf-checker/src/tests.rs index b223b1b54c0b..d1daa7a58135 100644 --- a/node/core/pvf-checker/src/tests.rs +++ b/node/core/pvf-checker/src/tests.rs @@ -188,7 +188,7 @@ impl TestState { let activated = if let Some(activated_leaf) = fake_leaf { self.leaves.insert( - activated_leaf.block_hash.clone(), + activated_leaf.block_hash, LeafState { session_index: self.last_session_index, pvfs: activated_leaf.pvfs.clone(), @@ -497,9 +497,9 @@ fn reactivating_pvf_leads_to_second_check() { test_harness(|mut test_state, mut handle| { async move { let pvf = dummy_validation_code_hash(1); - let block_1 = FakeLeaf::new(dummy_hash(), 1, vec![pvf.clone()]); + let block_1 = FakeLeaf::new(dummy_hash(), 1, vec![pvf]); let block_2 = block_1.descendant(vec![]); - let block_3 = block_2.descendant(vec![pvf.clone()]); + let block_3 = block_2.descendant(vec![pvf]); test_state .activate_leaf_with_session( @@ -552,9 +552,9 @@ fn dont_double_vote_for_pvfs_in_view() { test_harness(|mut test_state, mut handle| { async move { let pvf = dummy_validation_code_hash(1); - let block_1_1 = FakeLeaf::new([1; 32].into(), 1, vec![pvf.clone()]); - let block_2_1 = FakeLeaf::new([2; 32].into(), 1, vec![pvf.clone()]); - let block_1_2 = block_1_1.descendant(vec![pvf.clone()]); + let block_1_1 = FakeLeaf::new([1; 32].into(), 1, vec![pvf]); + let block_2_1 = FakeLeaf::new([2; 32].into(), 1, vec![pvf]); + let block_1_2 = block_1_1.descendant(vec![pvf]); test_state .activate_leaf_with_session( @@ -605,8 +605,8 @@ fn judgements_come_out_of_order() { let pvf_1 = dummy_validation_code_hash(1); let pvf_2 = dummy_validation_code_hash(2); - let block_1 = FakeLeaf::new([1; 32].into(), 1, vec![pvf_1.clone()]); - let block_2 = FakeLeaf::new([2; 32].into(), 1, vec![pvf_2.clone()]); + let block_1 = FakeLeaf::new([1; 32].into(), 1, vec![pvf_1]); + let block_2 = FakeLeaf::new([2; 32].into(), 1, vec![pvf_2]); test_state .activate_leaf_with_session( diff --git a/node/core/pvf/tests/it/adder.rs b/node/core/pvf/tests/it/adder.rs index f52827699e2d..a4c2e21bdeaa 100644 --- a/node/core/pvf/tests/it/adder.rs +++ b/node/core/pvf/tests/it/adder.rs @@ -53,14 +53,14 @@ async fn execute_good_block_on_parent() { #[tokio::test] async fn execute_good_chain_on_parent() { - let mut number = 0; let mut parent_hash = [0; 32]; let mut last_state = 0; let host = TestHost::new(); - for add in 0..10 { - let parent_head = HeadData { number, parent_hash, post_state: hash_state(last_state) }; + for (number, add) in (0..10).enumerate() { + let parent_head = + HeadData { number: number as u64, parent_hash, post_state: hash_state(last_state) }; let block_data = BlockData { state: last_state, add }; @@ -80,11 +80,10 @@ async fn execute_good_chain_on_parent() { let new_head = HeadData::decode(&mut &ret.head_data.0[..]).unwrap(); - assert_eq!(new_head.number, number + 1); + assert_eq!(new_head.number, number as u64 + 1); assert_eq!(new_head.parent_hash, parent_head.hash()); assert_eq!(new_head.post_state, hash_state(last_state + add)); - number += 1; parent_hash = new_head.hash(); last_state += add; } diff --git a/node/core/runtime-api/src/tests.rs b/node/core/runtime-api/src/tests.rs index 33f5eef3869f..53b3fd56bf3e 100644 --- a/node/core/runtime-api/src/tests.rs +++ b/node/core/runtime-api/src/tests.rs @@ -984,7 +984,7 @@ fn requests_submit_pvf_check_statement() { ), }) .await; - assert_eq!(rx.await.unwrap().unwrap(), ()); + let _ = rx.await.unwrap().unwrap(); let (tx, rx) = oneshot::channel(); ctx_handle .send(FromOrchestra::Communication { @@ -994,7 +994,7 @@ fn requests_submit_pvf_check_statement() { ), }) .await; - assert_eq!(rx.await.unwrap().unwrap(), ()); + let _ = rx.await.unwrap().unwrap(); assert_eq!( &*subsystem_client.submitted_pvf_check_statement.lock().expect("poisened mutex"), @@ -1061,9 +1061,7 @@ fn requests_validation_code_hash() { let validation_code_hash = dummy_validation_code().hash(); let mut subsystem_client = MockSubsystemClient::default(); - subsystem_client - .validation_code_hash - .insert(para_a, validation_code_hash.clone()); + subsystem_client.validation_code_hash.insert(para_a, validation_code_hash); let subsystem_client = Arc::new(subsystem_client); let subsystem = diff --git a/node/malus/src/variants/back_garbage_candidate.rs b/node/malus/src/variants/back_garbage_candidate.rs index 45f1aa2e0b7f..aa904c37b80a 100644 --- a/node/malus/src/variants/back_garbage_candidate.rs +++ b/node/malus/src/variants/back_garbage_candidate.rs @@ -59,10 +59,10 @@ pub(crate) struct BackGarbageCandidates { } impl OverseerGen for BackGarbageCandidates { - fn generate<'a, Spawner, RuntimeClient>( + fn generate( &self, connector: OverseerConnector, - args: OverseerGenArgs<'a, Spawner, RuntimeClient>, + args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ) -> Result< (Overseer, Arc>>, OverseerHandle), Error, diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index ab1dfbbb360a..6bc889595362 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -392,9 +392,8 @@ where let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); match behave_maliciously { true => { - let validation_result = ValidationResult::Invalid( - self.fake_validation_error.clone().into(), - ); + let validation_result = + ValidationResult::Invalid(self.fake_validation_error.into()); gum::info!( target: MALUS, para_id = ?candidate_receipt.descriptor.para_id, diff --git a/node/malus/src/variants/dispute_valid_candidates.rs b/node/malus/src/variants/dispute_valid_candidates.rs index 9ea8449a1d0b..fa3b0c38bc2f 100644 --- a/node/malus/src/variants/dispute_valid_candidates.rs +++ b/node/malus/src/variants/dispute_valid_candidates.rs @@ -76,10 +76,10 @@ pub(crate) struct DisputeValidCandidates { } impl OverseerGen for DisputeValidCandidates { - fn generate<'a, Spawner, RuntimeClient>( + fn generate( &self, connector: OverseerConnector, - args: OverseerGenArgs<'a, Spawner, RuntimeClient>, + args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ) -> Result< (Overseer, Arc>>, OverseerHandle), Error, diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index 7d301c194b44..b0290fff949d 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -99,7 +99,7 @@ where // equal to `p`. We use `rand::thread_rng` as the source of randomness. let generate_malicious_candidate = distribution.sample(&mut rand::thread_rng()); - if generate_malicious_candidate == true { + if generate_malicious_candidate { gum::debug!(target: MALUS, "😈 Suggesting malicious candidate.",); let pov = PoV { block_data: BlockData(MALICIOUS_POV.into()) }; @@ -253,10 +253,10 @@ pub(crate) struct SuggestGarbageCandidates { } impl OverseerGen for SuggestGarbageCandidates { - fn generate<'a, Spawner, RuntimeClient>( + fn generate( &self, connector: OverseerConnector, - args: OverseerGenArgs<'a, Spawner, RuntimeClient>, + args: OverseerGenArgs<'_, Spawner, RuntimeClient>, ) -> Result< (Overseer, Arc>>, OverseerHandle), Error, diff --git a/node/network/approval-distribution/src/tests.rs b/node/network/approval-distribution/src/tests.rs index 422157a1eda9..bfd7c945069c 100644 --- a/node/network/approval-distribution/src/tests.rs +++ b/node/network/approval-distribution/src/tests.rs @@ -148,7 +148,7 @@ fn make_gossip_topology( assert!(all_peers.len() >= grid_size); let peer_info = |i: usize| TopologyPeerInfo { - peer_ids: vec![all_peers[i].0.clone()], + peer_ids: vec![all_peers[i].0], validator_index: ValidatorIndex::from(i as u32), discovery_id: all_peers[i].1.clone(), }; @@ -224,7 +224,7 @@ async fn setup_peer_with_view( overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( - peer_id.clone(), + *peer_id, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -234,8 +234,7 @@ async fn setup_peer_with_view( overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer_id.clone(), - view, + *peer_id, view, )), ) .await; @@ -249,7 +248,7 @@ async fn send_message_from_peer( overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer_id.clone(), + *peer_id, Versioned::V1(msg), )), ) @@ -480,7 +479,7 @@ fn spam_attack_results_in_negative_reputation_change() { // new block `hash_b` with 20 candidates let candidates_count = 20; let meta = BlockApprovalMeta { - hash: hash_b.clone(), + hash: hash_b, parent_hash, number: 2, candidates: vec![Default::default(); candidates_count], @@ -527,7 +526,7 @@ fn spam_attack_results_in_negative_reputation_change() { overseer_send( overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer.clone(), + *peer, View::with_finalized(2), )), ) @@ -587,7 +586,7 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { overseer_send( overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer.clone(), + *peer, view![hash], )), ) @@ -956,7 +955,7 @@ fn update_peer_view() { overseer_send( overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer.clone(), + *peer, View::new(vec![hash_b, hash_c, hash_d], 2), )), ) @@ -1009,7 +1008,7 @@ fn update_peer_view() { overseer_send( overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer.clone(), + *peer, View::with_finalized(finalized_number), )), ) @@ -1166,7 +1165,7 @@ fn sends_assignments_even_when_state_is_approved() { protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) )) )) => { - assert_eq!(peers, vec![peer.clone()]); + assert_eq!(peers, vec![*peer]); assert_eq!(sent_assignments, assignments); } ); @@ -1179,7 +1178,7 @@ fn sends_assignments_even_when_state_is_approved() { protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) )) )) => { - assert_eq!(peers, vec![peer.clone()]); + assert_eq!(peers, vec![*peer]); assert_eq!(sent_approvals, approvals); } ); @@ -1208,7 +1207,7 @@ fn race_condition_in_local_vs_remote_view_update() { // Test a small number of candidates let candidates_count = 1; let meta = BlockApprovalMeta { - hash: hash_b.clone(), + hash: hash_b, parent_hash, number: 2, candidates: vec![Default::default(); candidates_count], @@ -1811,7 +1810,7 @@ fn originator_aggression_l1() { let mut state = State::default(); state.aggression_config.resend_unfinalized_period = None; - let aggression_l1_threshold = state.aggression_config.l1_threshold.clone().unwrap(); + let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); let _ = test_harness(state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1931,8 +1930,7 @@ fn originator_aggression_l1() { assert_eq!(sent_assignments, assignments); assert!(unsent_indices.iter() - .find(|i| &peers[**i].0 == &sent_peers[0]) - .is_some()); + .any(|i| &peers[*i].0 == &sent_peers[0])); } ); } @@ -1951,8 +1949,7 @@ fn originator_aggression_l1() { assert_eq!(sent_approvals, approvals); assert!(unsent_indices.iter() - .find(|i| &peers[**i].0 == &sent_peers[0]) - .is_some()); + .any(|i| &peers[*i].0 == &sent_peers[0])); } ); } @@ -1972,7 +1969,7 @@ fn non_originator_aggression_l1() { let mut state = state_without_reputation_delay(); state.aggression_config.resend_unfinalized_period = None; - let aggression_l1_threshold = state.aggression_config.l1_threshold.clone().unwrap(); + let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); let _ = test_harness(state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2077,8 +2074,8 @@ fn non_originator_aggression_l2() { let mut state = state_without_reputation_delay(); state.aggression_config.resend_unfinalized_period = None; - let aggression_l1_threshold = state.aggression_config.l1_threshold.clone().unwrap(); - let aggression_l2_threshold = state.aggression_config.l2_threshold.clone().unwrap(); + let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); + let aggression_l2_threshold = state.aggression_config.l2_threshold.unwrap(); let _ = test_harness(state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2222,8 +2219,7 @@ fn non_originator_aggression_l2() { assert_eq!(sent_assignments, assignments); assert!(unsent_indices.iter() - .find(|i| &peers[**i].0 == &sent_peers[0]) - .is_some()); + .any(|i| &peers[*i].0 == &sent_peers[0])); } ); } diff --git a/node/network/availability-distribution/src/tests/state.rs b/node/network/availability-distribution/src/tests/state.rs index 36fb16f7e11c..706ec13a3e9b 100644 --- a/node/network/availability-distribution/src/tests/state.rs +++ b/node/network/availability-distribution/src/tests/state.rs @@ -123,13 +123,13 @@ impl Default for TestState { let (core, chunk) = OccupiedCoreBuilder { group_responsible: GroupIndex(i as _), para_id: *para_id, - relay_parent: relay_parent.clone(), + relay_parent: *relay_parent, } .build(); (CoreState::Occupied(core), chunk) }) .unzip(); - cores.insert(relay_child.clone(), p_cores); + cores.insert(*relay_child, p_cores); // Skip chunks for our own group (won't get fetched): let mut chunks_other_groups = p_chunks.into_iter(); chunks_other_groups.next(); @@ -176,12 +176,12 @@ impl TestState { .zip(advanced) .map(|(old, new)| ActiveLeavesUpdate { activated: Some(ActivatedLeaf { - hash: new.clone(), + hash: *new, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), }), - deactivated: vec![old.clone()].into(), + deactivated: vec![*old].into(), }) .collect::>() }; @@ -239,8 +239,7 @@ impl TestState { let chunk = self .chunks .get_mut(&(candidate_hash, validator_index)) - .map(Vec::pop) - .flatten() + .and_then(Vec::pop) .flatten(); tx.send(chunk).expect("Receiver is expected to be alive"); }, diff --git a/node/network/availability-recovery/src/tests.rs b/node/network/availability-recovery/src/tests.rs index c5647a12f589..de923f5967e5 100644 --- a/node/network/availability-recovery/src/tests.rs +++ b/node/network/availability-recovery/src/tests.rs @@ -562,7 +562,7 @@ fn availability_is_recovered_from_chunks_if_no_group_provided() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -648,7 +648,7 @@ fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunk overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -734,7 +734,7 @@ fn bad_merkle_path_leads_to_recovery_error() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -792,7 +792,7 @@ fn wrong_chunk_index_leads_to_recovery_error() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -866,7 +866,7 @@ fn invalid_erasure_coding_leads_to_invalid_error() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -915,7 +915,7 @@ fn fast_path_backing_group_recovers() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -965,7 +965,7 @@ fn recovers_from_only_chunks_if_pov_large() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1069,7 +1069,7 @@ fn fast_path_backing_group_recovers_if_pov_small() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1128,7 +1128,7 @@ fn no_answers_in_fast_path_causes_chunk_requests() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1190,7 +1190,7 @@ fn task_canceled_when_receivers_dropped() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1232,7 +1232,7 @@ fn chunks_retry_until_all_nodes_respond() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1293,7 +1293,7 @@ fn not_returning_requests_wont_stall_retrieval() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1365,7 +1365,7 @@ fn all_not_returning_requests_still_recovers_on_return() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1442,7 +1442,7 @@ fn returns_early_if_we_have_the_data() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1479,7 +1479,7 @@ fn does_not_query_local_validator() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), @@ -1538,7 +1538,7 @@ fn invalid_local_chunk_is_ignored() { overseer_signal( &mut virtual_overseer, OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf { - hash: test_state.current.clone(), + hash: test_state.current, number: 1, status: LeafStatus::Fresh, span: Arc::new(jaeger::Span::Disabled), diff --git a/node/network/bitfield-distribution/src/tests.rs b/node/network/bitfield-distribution/src/tests.rs index 39816a55240b..9aea5a7178b7 100644 --- a/node/network/bitfield-distribution/src/tests.rs +++ b/node/network/bitfield-distribution/src/tests.rs @@ -65,7 +65,7 @@ fn prewarmed_state( known_message: BitfieldGossipMessage, peers: Vec, ) -> ProtocolState { - let relay_parent = known_message.relay_parent.clone(); + let relay_parent = known_message.relay_parent; let mut topologies = SessionBoundGridTopologyStorage::default(); topologies.update_topology(0_u32, SessionGridTopology::new(Vec::new(), Vec::new()), None); topologies.get_current_topology_mut().local_grid_neighbors_mut().peers_x = @@ -73,7 +73,7 @@ fn prewarmed_state( ProtocolState { per_relay_parent: hashmap! { - relay_parent.clone() => + relay_parent => PerRelayParentData { signing_context, validator_set: vec![validator.clone()], @@ -99,7 +99,7 @@ fn state_with_view( ) -> (ProtocolState, SigningContext, KeystorePtr, ValidatorId) { let mut state = ProtocolState { reputation, ..Default::default() }; - let signing_context = SigningContext { session_index: 1, parent_hash: relay_parent.clone() }; + let signing_context = SigningContext { session_index: 1, parent_hash: relay_parent }; let keystore: KeystorePtr = Arc::new(MemoryKeystore::new()); let validator = Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, None) @@ -109,10 +109,10 @@ fn state_with_view( .iter() .map(|relay_parent| { ( - relay_parent.clone(), + *relay_parent, PerRelayParentData { signing_context: signing_context.clone(), - validator_set: vec![validator.clone().into()], + validator_set: vec![validator.into()], one_per_validator: hashmap! {}, message_received_from_peer: hashmap! {}, message_sent_to_peer: hashmap! {}, @@ -140,7 +140,7 @@ fn receive_invalid_signature() { let peer_b = PeerId::random(); assert_ne!(peer_a, peer_b); - let signing_context = SigningContext { session_index: 1, parent_hash: hash_a.clone() }; + let signing_context = SigningContext { session_index: 1, parent_hash: hash_a }; // another validator not part of the validatorset let keystore: KeystorePtr = Arc::new(MemoryKeystore::new()); @@ -184,28 +184,20 @@ fn receive_invalid_signature() { .flatten() .expect("should be signed"); - let invalid_msg = BitfieldGossipMessage { - relay_parent: hash_a.clone(), - signed_availability: invalid_signed.clone(), - }; + let invalid_msg = + BitfieldGossipMessage { relay_parent: hash_a, signed_availability: invalid_signed.clone() }; let invalid_msg_2 = BitfieldGossipMessage { - relay_parent: hash_a.clone(), + relay_parent: hash_a, signed_availability: invalid_signed_2.clone(), }; - let valid_msg = BitfieldGossipMessage { - relay_parent: hash_a.clone(), - signed_availability: valid_signed.clone(), - }; + let valid_msg = + BitfieldGossipMessage { relay_parent: hash_a, signed_availability: valid_signed.clone() }; let pool = sp_core::testing::TaskExecutor::new(); let (mut ctx, mut handle) = make_subsystem_context::(pool); - let mut state = prewarmed_state( - validator_0.into(), - signing_context.clone(), - valid_msg, - vec![peer_b.clone()], - ); + let mut state = + prewarmed_state(validator_0.into(), signing_context.clone(), valid_msg, vec![peer_b]); state .per_relay_parent .get_mut(&hash_a) @@ -219,7 +211,7 @@ fn receive_invalid_signature() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), invalid_msg.into_network_message()), + NetworkBridgeEvent::PeerMessage(peer_b, invalid_msg.into_network_message()), &mut rng, )); @@ -230,7 +222,7 @@ fn receive_invalid_signature() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), invalid_msg_2.into_network_message()), + NetworkBridgeEvent::PeerMessage(peer_b, invalid_msg_2.into_network_message()), &mut rng, )); // reputation change due to invalid signature @@ -261,13 +253,10 @@ fn receive_invalid_validator_index() { assert_ne!(peer_a, peer_b); // validator 0 key pair - let (mut state, signing_context, keystore, validator) = state_with_view( - our_view![hash_a, hash_b], - hash_a.clone(), - ReputationAggregator::new(|_| true), - ); + let (mut state, signing_context, keystore, validator) = + state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true)); - state.peer_views.insert(peer_b.clone(), view![hash_a]); + state.peer_views.insert(peer_b, view![hash_a]); let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); let signed = Signed::::sign( @@ -281,8 +270,7 @@ fn receive_invalid_validator_index() { .flatten() .expect("should be signed"); - let msg = - BitfieldGossipMessage { relay_parent: hash_a.clone(), signed_availability: signed.clone() }; + let msg = BitfieldGossipMessage { relay_parent: hash_a, signed_availability: signed.clone() }; let pool = sp_core::testing::TaskExecutor::new(); let (mut ctx, mut handle) = make_subsystem_context::(pool); @@ -293,7 +281,7 @@ fn receive_invalid_validator_index() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.into_network_message()), + NetworkBridgeEvent::PeerMessage(peer_b, msg.into_network_message()), &mut rng, )); @@ -325,11 +313,8 @@ fn receive_duplicate_messages() { assert_ne!(peer_a, peer_b); // validator 0 key pair - let (mut state, signing_context, keystore, validator) = state_with_view( - our_view![hash_a, hash_b], - hash_a.clone(), - ReputationAggregator::new(|_| true), - ); + let (mut state, signing_context, keystore, validator) = + state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true)); // create a signed message by validator 0 let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); @@ -345,7 +330,7 @@ fn receive_duplicate_messages() { .expect("should be signed"); let msg = BitfieldGossipMessage { - relay_parent: hash_a.clone(), + relay_parent: hash_a, signed_availability: signed_bitfield.clone(), }; @@ -359,7 +344,7 @@ fn receive_duplicate_messages() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), &mut rng, )); @@ -392,7 +377,7 @@ fn receive_duplicate_messages() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_a.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_a, msg.clone().into_network_message(),), &mut rng, )); @@ -411,7 +396,7 @@ fn receive_duplicate_messages() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), &mut rng, )); @@ -442,11 +427,8 @@ fn delay_reputation_change() { let peer = PeerId::random(); // validator 0 key pair - let (mut state, signing_context, keystore, validator) = state_with_view( - our_view![hash_a, hash_b], - hash_a.clone(), - ReputationAggregator::new(|_| false), - ); + let (mut state, signing_context, keystore, validator) = + state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| false)); // create a signed message by validator 0 let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); @@ -462,7 +444,7 @@ fn delay_reputation_change() { .expect("should be signed"); let msg = BitfieldGossipMessage { - relay_parent: hash_a.clone(), + relay_parent: hash_a, signed_availability: signed_bitfield.clone(), }; @@ -481,10 +463,7 @@ fn delay_reputation_change() { handle .send(FromOrchestra::Communication { msg: BitfieldDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage( - peer.clone(), - msg.clone().into_network_message(), - ), + NetworkBridgeEvent::PeerMessage(peer, msg.clone().into_network_message()), ), }) .await; @@ -507,10 +486,7 @@ fn delay_reputation_change() { handle .send(FromOrchestra::Communication { msg: BitfieldDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage( - peer.clone(), - msg.clone().into_network_message(), - ), + NetworkBridgeEvent::PeerMessage(peer, msg.clone().into_network_message()), ), }) .await; @@ -555,7 +531,7 @@ fn do_not_relay_message_twice() { // validator 0 key pair let (mut state, signing_context, keystore, validator) = - state_with_view(our_view![hash], hash.clone(), ReputationAggregator::new(|_| true)); + state_with_view(our_view![hash], hash, ReputationAggregator::new(|_| true)); // create a signed message by validator 0 let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); @@ -570,13 +546,11 @@ fn do_not_relay_message_twice() { .flatten() .expect("should be signed"); - state.peer_views.insert(peer_b.clone(), view![hash]); - state.peer_views.insert(peer_a.clone(), view![hash]); + state.peer_views.insert(peer_b, view![hash]); + state.peer_views.insert(peer_a, view![hash]); - let msg = BitfieldGossipMessage { - relay_parent: hash.clone(), - signed_availability: signed_bitfield.clone(), - }; + let msg = + BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() }; let pool = sp_core::testing::TaskExecutor::new(); let (mut ctx, mut handle) = make_subsystem_context::(pool); @@ -584,7 +558,7 @@ fn do_not_relay_message_twice() { executor::block_on(async move { let mut gossip_peers = GridNeighbors::empty(); - gossip_peers.peers_x = HashSet::from_iter(vec![peer_a.clone(), peer_b.clone()].into_iter()); + gossip_peers.peers_x = HashSet::from_iter(vec![peer_a, peer_b].into_iter()); relay_message( &mut ctx, @@ -665,11 +639,8 @@ fn changing_view() { assert_ne!(peer_a, peer_b); // validator 0 key pair - let (mut state, signing_context, keystore, validator) = state_with_view( - our_view![hash_a, hash_b], - hash_a.clone(), - ReputationAggregator::new(|_| true), - ); + let (mut state, signing_context, keystore, validator) = + state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true)); // create a signed message by validator 0 let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); @@ -685,7 +656,7 @@ fn changing_view() { .expect("should be signed"); let msg = BitfieldGossipMessage { - relay_parent: hash_a.clone(), + relay_parent: hash_a, signed_availability: signed_bitfield.clone(), }; @@ -699,7 +670,7 @@ fn changing_view() { &mut state, &Default::default(), NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, ValidationVersion::V1.into(), None @@ -712,7 +683,7 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![hash_a, hash_b]), + NetworkBridgeEvent::PeerViewChange(peer_b, view![hash_a, hash_b]), &mut rng, )); @@ -723,7 +694,7 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), &mut rng, )); @@ -754,7 +725,7 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![]), + NetworkBridgeEvent::PeerViewChange(peer_b, view![]), &mut rng, )); @@ -767,7 +738,7 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), &mut rng, )); @@ -786,7 +757,7 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerDisconnected(peer_b.clone()), + NetworkBridgeEvent::PeerDisconnected(peer_b), &mut rng, )); @@ -799,7 +770,7 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_a.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_a, msg.clone().into_network_message(),), &mut rng, )); @@ -846,13 +817,11 @@ fn do_not_send_message_back_to_origin() { .flatten() .expect("should be signed"); - state.peer_views.insert(peer_b.clone(), view![hash]); - state.peer_views.insert(peer_a.clone(), view![hash]); + state.peer_views.insert(peer_b, view![hash]); + state.peer_views.insert(peer_a, view![hash]); - let msg = BitfieldGossipMessage { - relay_parent: hash.clone(), - signed_availability: signed_bitfield.clone(), - }; + let msg = + BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() }; let pool = sp_core::testing::TaskExecutor::new(); let (mut ctx, mut handle) = make_subsystem_context::(pool); @@ -864,7 +833,7 @@ fn do_not_send_message_back_to_origin() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), &mut rng, )); @@ -930,13 +899,13 @@ fn topology_test() { let peers_x: Vec<_> = [0, 2, 3, 4, 5, 6] .iter() .cloned() - .map(|i| topology_peer_info[i].peer_ids[0].clone()) + .map(|i| topology_peer_info[i].peer_ids[0]) .collect(); let peers_y: Vec<_> = [8, 15, 22, 29, 36, 43] .iter() .cloned() - .map(|i| topology_peer_info[i].peer_ids[0].clone()) + .map(|i| topology_peer_info[i].peer_ids[0]) .collect(); { @@ -963,13 +932,11 @@ fn topology_test() { .expect("should be signed"); peers_x.iter().chain(peers_y.iter()).for_each(|peer| { - state.peer_views.insert(peer.clone(), view![hash]); + state.peer_views.insert(*peer, view![hash]); }); - let msg = BitfieldGossipMessage { - relay_parent: hash.clone(), - signed_availability: signed_bitfield.clone(), - }; + let msg = + BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() }; let pool = sp_core::testing::TaskExecutor::new(); let (mut ctx, mut handle) = make_subsystem_context::(pool); @@ -981,7 +948,7 @@ fn topology_test() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peers_x[0].clone(), msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage(peers_x[0], msg.clone().into_network_message(),), &mut rng, )); @@ -1064,22 +1031,22 @@ fn need_message_works() { .insert(signed_by.clone()); }; - assert!(true == pretend_send(&mut state, peer_a, &validator_set[0])); - assert!(true == pretend_send(&mut state, peer_b, &validator_set[1])); + assert!(pretend_send(&mut state, peer_a, &validator_set[0])); + assert!(pretend_send(&mut state, peer_b, &validator_set[1])); // sending the same thing must not be allowed - assert!(false == pretend_send(&mut state, peer_a, &validator_set[0])); + assert!(!pretend_send(&mut state, peer_a, &validator_set[0])); // receive by Alice pretend_receive(&mut state, peer_a, &validator_set[0]); // must be marked as not needed by Alice, so attempt to send to Alice must be false - assert!(false == pretend_send(&mut state, peer_a, &validator_set[0])); + assert!(!pretend_send(&mut state, peer_a, &validator_set[0])); // but ok for Bob - assert!(false == pretend_send(&mut state, peer_b, &validator_set[1])); + assert!(!pretend_send(&mut state, peer_b, &validator_set[1])); // receive by Bob pretend_receive(&mut state, peer_a, &validator_set[0]); // not ok for Alice - assert!(false == pretend_send(&mut state, peer_a, &validator_set[0])); + assert!(!pretend_send(&mut state, peer_a, &validator_set[0])); // also not ok for Bob - assert!(false == pretend_send(&mut state, peer_b, &validator_set[1])); + assert!(!pretend_send(&mut state, peer_b, &validator_set[1])); } diff --git a/node/network/bridge/src/rx/tests.rs b/node/network/bridge/src/rx/tests.rs index e18a7e541832..b04884edefaa 100644 --- a/node/network/bridge/src/rx/tests.rs +++ b/node/network/bridge/src/rx/tests.rs @@ -432,12 +432,8 @@ fn send_our_view_upon_connection() { handle.await_mode_switch().await; - network_handle - .connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full) - .await; - network_handle - .connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full) - .await; + network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; + network_handle.connect_peer(peer, PeerSet::Collation, ObservedRole::Full).await; await_peer_connections(&shared, 1, 1).await; @@ -446,7 +442,7 @@ fn send_our_view_upon_connection() { assert_network_actions_contains( &actions, &NetworkAction::WriteNotification( - peer.clone(), + peer, PeerSet::Validation, WireMessage::::ViewUpdate(view.clone()).encode(), ), @@ -454,7 +450,7 @@ fn send_our_view_upon_connection() { assert_network_actions_contains( &actions, &NetworkAction::WriteNotification( - peer.clone(), + peer, PeerSet::Collation, WireMessage::::ViewUpdate(view.clone()).encode(), ), @@ -482,10 +478,10 @@ fn sends_view_updates_to_peers() { handle.await_mode_switch().await; network_handle - .connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b.clone(), PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer_b, PeerSet::Collation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 1).await; @@ -545,10 +541,10 @@ fn do_not_send_view_update_until_synced() { assert_ne!(peer_a, peer_b); network_handle - .connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b.clone(), PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer_b, PeerSet::Collation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 1).await; @@ -640,10 +636,10 @@ fn do_not_send_view_update_when_only_finalized_block_changed() { let peer_b = PeerId::random(); network_handle - .connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_b, PeerSet::Validation, ObservedRole::Full) .await; await_peer_connections(&shared, 2, 0).await; @@ -700,9 +696,7 @@ fn peer_view_updates_sent_via_overseer() { let peer = PeerId::random(); - network_handle - .connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full) - .await; + network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; await_peer_connections(&shared, 1, 0).await; @@ -712,7 +706,7 @@ fn peer_view_updates_sent_via_overseer() { { assert_sends_validation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -722,7 +716,7 @@ fn peer_view_updates_sent_via_overseer() { .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), &mut virtual_overseer, ) .await; @@ -730,14 +724,14 @@ fn peer_view_updates_sent_via_overseer() { network_handle .peer_message( - peer.clone(), + peer, PeerSet::Validation, WireMessage::::ViewUpdate(view.clone()).encode(), ) .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), view), + NetworkBridgeEvent::PeerViewChange(peer, view), &mut virtual_overseer, ) .await; @@ -752,9 +746,7 @@ fn peer_messages_sent_via_overseer() { let peer = PeerId::random(); - network_handle - .connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full) - .await; + network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; await_peer_connections(&shared, 1, 0).await; @@ -762,7 +754,7 @@ fn peer_messages_sent_via_overseer() { { assert_sends_validation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -772,7 +764,7 @@ fn peer_messages_sent_via_overseer() { .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), &mut virtual_overseer, ) .await; @@ -787,13 +779,13 @@ fn peer_messages_sent_via_overseer() { network_handle .peer_message( - peer.clone(), + peer, PeerSet::Validation, WireMessage::ProtocolMessage(message_v1.clone()).encode(), ) .await; - network_handle.disconnect_peer(peer.clone(), PeerSet::Validation).await; + network_handle.disconnect_peer(peer, PeerSet::Validation).await; // Approval distribution message comes first, and the message is only sent to that // subsystem. then a disconnection event arises that is sent to all validation networking @@ -827,12 +819,8 @@ fn peer_disconnect_from_just_one_peerset() { let peer = PeerId::random(); - network_handle - .connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full) - .await; - network_handle - .connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full) - .await; + network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; + network_handle.connect_peer(peer, PeerSet::Collation, ObservedRole::Full).await; await_peer_connections(&shared, 1, 1).await; @@ -840,7 +828,7 @@ fn peer_disconnect_from_just_one_peerset() { { assert_sends_validation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -850,7 +838,7 @@ fn peer_disconnect_from_just_one_peerset() { .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), &mut virtual_overseer, ) .await; @@ -859,7 +847,7 @@ fn peer_disconnect_from_just_one_peerset() { { assert_sends_collation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -869,16 +857,16 @@ fn peer_disconnect_from_just_one_peerset() { .await; assert_sends_collation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), &mut virtual_overseer, ) .await; } - network_handle.disconnect_peer(peer.clone(), PeerSet::Validation).await; + network_handle.disconnect_peer(peer, PeerSet::Validation).await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerDisconnected(peer.clone()), + NetworkBridgeEvent::PeerDisconnected(peer), &mut virtual_overseer, ) .await; @@ -904,11 +892,7 @@ fn peer_disconnect_from_just_one_peerset() { assert_network_actions_contains( &actions, - &NetworkAction::WriteNotification( - peer.clone(), - PeerSet::Collation, - wire_message.clone(), - ), + &NetworkAction::WriteNotification(peer, PeerSet::Collation, wire_message.clone()), ); virtual_overseer }); @@ -923,10 +907,10 @@ fn relays_collation_protocol_messages() { let peer_b = PeerId::random(); network_handle - .connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b.clone(), PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer_b, PeerSet::Collation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 1).await; @@ -935,7 +919,7 @@ fn relays_collation_protocol_messages() { { assert_sends_validation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer_a.clone(), + peer_a, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -945,7 +929,7 @@ fn relays_collation_protocol_messages() { .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer_a.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer_a, View::default()), &mut virtual_overseer, ) .await; @@ -954,7 +938,7 @@ fn relays_collation_protocol_messages() { { assert_sends_collation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -964,7 +948,7 @@ fn relays_collation_protocol_messages() { .await; assert_sends_collation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer_b, View::default()), &mut virtual_overseer, ) .await; @@ -983,7 +967,7 @@ fn relays_collation_protocol_messages() { network_handle .peer_message( - peer_a.clone(), + peer_a, PeerSet::Collation, WireMessage::ProtocolMessage(message_v1.clone()).encode(), ) @@ -992,14 +976,14 @@ fn relays_collation_protocol_messages() { let actions = network_handle.next_network_actions(3).await; assert_network_actions_contains( &actions, - &NetworkAction::ReputationChange(peer_a.clone(), UNCONNECTED_PEERSET_COST.into()), + &NetworkAction::ReputationChange(peer_a, UNCONNECTED_PEERSET_COST.into()), ); // peer B has the message relayed. network_handle .peer_message( - peer_b.clone(), + peer_b, PeerSet::Collation, WireMessage::ProtocolMessage(message_v1.clone()).encode(), ) @@ -1027,12 +1011,8 @@ fn different_views_on_different_peer_sets() { let peer = PeerId::random(); - network_handle - .connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full) - .await; - network_handle - .connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full) - .await; + network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; + network_handle.connect_peer(peer, PeerSet::Collation, ObservedRole::Full).await; await_peer_connections(&shared, 1, 1).await; @@ -1040,7 +1020,7 @@ fn different_views_on_different_peer_sets() { { assert_sends_validation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -1050,7 +1030,7 @@ fn different_views_on_different_peer_sets() { .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), &mut virtual_overseer, ) .await; @@ -1059,7 +1039,7 @@ fn different_views_on_different_peer_sets() { { assert_sends_collation_event_to_all( NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -1069,7 +1049,7 @@ fn different_views_on_different_peer_sets() { .await; assert_sends_collation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), View::default()), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), &mut virtual_overseer, ) .await; @@ -1080,7 +1060,7 @@ fn different_views_on_different_peer_sets() { network_handle .peer_message( - peer.clone(), + peer, PeerSet::Validation, WireMessage::::ViewUpdate(view_a.clone()).encode(), ) @@ -1088,20 +1068,20 @@ fn different_views_on_different_peer_sets() { network_handle .peer_message( - peer.clone(), + peer, PeerSet::Collation, WireMessage::::ViewUpdate(view_b.clone()).encode(), ) .await; assert_sends_validation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), view_a.clone()), + NetworkBridgeEvent::PeerViewChange(peer, view_a.clone()), &mut virtual_overseer, ) .await; assert_sends_collation_event_to_all( - NetworkBridgeEvent::PeerViewChange(peer.clone(), view_b.clone()), + NetworkBridgeEvent::PeerViewChange(peer, view_b.clone()), &mut virtual_overseer, ) .await; @@ -1117,7 +1097,7 @@ fn sent_views_include_finalized_number_update() { let peer_a = PeerId::random(); network_handle - .connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 0).await; @@ -1146,11 +1126,7 @@ fn sent_views_include_finalized_number_update() { assert_network_actions_contains( &actions, - &NetworkAction::WriteNotification( - peer_a.clone(), - PeerSet::Validation, - wire_message.clone(), - ), + &NetworkAction::WriteNotification(peer_a, PeerSet::Validation, wire_message.clone()), ); virtual_overseer }); @@ -1164,14 +1140,14 @@ fn view_finalized_number_can_not_go_down() { let peer_a = PeerId::random(); network_handle - .connect_peer(peer_a.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 0).await; network_handle .peer_message( - peer_a.clone(), + peer_a, PeerSet::Validation, WireMessage::::ViewUpdate(View::new( vec![Hash::repeat_byte(0x01)], @@ -1183,7 +1159,7 @@ fn view_finalized_number_can_not_go_down() { network_handle .peer_message( - peer_a.clone(), + peer_a, PeerSet::Validation, WireMessage::::ViewUpdate(View::new(vec![], 0)) .encode(), @@ -1193,7 +1169,7 @@ fn view_finalized_number_can_not_go_down() { let actions = network_handle.next_network_actions(2).await; assert_network_actions_contains( &actions, - &NetworkAction::ReputationChange(peer_a.clone(), MALFORMED_VIEW_COST.into()), + &NetworkAction::ReputationChange(peer_a, MALFORMED_VIEW_COST.into()), ); virtual_overseer }); diff --git a/node/network/bridge/src/tx/tests.rs b/node/network/bridge/src/tx/tests.rs index 520218d3c481..e851cb0dee6f 100644 --- a/node/network/bridge/src/tx/tests.rs +++ b/node/network/bridge/src/tx/tests.rs @@ -242,7 +242,7 @@ fn send_messages_to_peers() { let peer = PeerId::random(); network_handle - .connect_peer(peer.clone(), PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer, PeerSet::Validation, ObservedRole::Full) .timeout(TIMEOUT) .await .expect("Timeout does not occur"); @@ -251,7 +251,7 @@ fn send_messages_to_peers() { // so the single item sink has to be free explicitly network_handle - .connect_peer(peer.clone(), PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer, PeerSet::Collation, ObservedRole::Full) .timeout(TIMEOUT) .await .expect("Timeout does not occur"); @@ -269,7 +269,7 @@ fn send_messages_to_peers() { virtual_overseer .send(FromOrchestra::Communication { msg: NetworkBridgeTxMessage::SendValidationMessage( - vec![peer.clone()], + vec![peer], Versioned::V1(message_v1.clone()), ), }) @@ -284,7 +284,7 @@ fn send_messages_to_peers() { .await .expect("Timeout does not occur"), NetworkAction::WriteNotification( - peer.clone(), + peer, PeerSet::Validation, WireMessage::ProtocolMessage(message_v1).encode(), ) @@ -306,7 +306,7 @@ fn send_messages_to_peers() { virtual_overseer .send(FromOrchestra::Communication { msg: NetworkBridgeTxMessage::SendCollationMessage( - vec![peer.clone()], + vec![peer], Versioned::V1(message_v1.clone()), ), }) @@ -319,7 +319,7 @@ fn send_messages_to_peers() { .await .expect("Timeout does not occur"), NetworkAction::WriteNotification( - peer.clone(), + peer, PeerSet::Collation, WireMessage::ProtocolMessage(message_v1).encode(), ) diff --git a/node/network/bridge/src/validator_discovery.rs b/node/network/bridge/src/validator_discovery.rs index e89b38544684..86e861fbc5b5 100644 --- a/node/network/bridge/src/validator_discovery.rs +++ b/node/network/bridge/src/validator_discovery.rs @@ -311,7 +311,7 @@ mod tests { let (ns, ads) = new_network(); let authority_ids: Vec<_> = - ads.by_peer_id.values().map(|v| v.iter()).flatten().cloned().collect(); + ads.by_peer_id.values().flat_map(|v| v.iter()).cloned().collect(); futures::executor::block_on(async move { let (failed, _) = oneshot::channel(); @@ -344,7 +344,7 @@ mod tests { let (ns, ads) = new_network(); let authority_ids: Vec<_> = - ads.by_peer_id.values().map(|v| v.iter()).flatten().cloned().collect(); + ads.by_peer_id.values().flat_map(|v| v.iter()).cloned().collect(); futures::executor::block_on(async move { let (failed, failed_rx) = oneshot::channel(); diff --git a/node/network/collator-protocol/src/collator_side/tests.rs b/node/network/collator-protocol/src/collator_side/tests.rs index e406e5d869cc..ad1096196574 100644 --- a/node/network/collator-protocol/src/collator_side/tests.rs +++ b/node/network/collator-protocol/src/collator_side/tests.rs @@ -147,7 +147,7 @@ impl TestState { fn current_group_validator_peer_ids(&self) -> Vec { self.current_group_validator_indices() .iter() - .map(|i| self.validator_peer_id[i.0 as usize].clone()) + .map(|i| self.validator_peer_id[i.0 as usize]) .collect() } @@ -412,7 +412,7 @@ async fn connect_peer( overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, polkadot_node_network_protocol::ObservedRole::Authority, CollationVersion::V1.into(), authority_id.map(|v| HashSet::from([v])), @@ -509,7 +509,7 @@ async fn send_peer_view_change( overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer.clone(), + *peer, View::new(hashes, 0), )), ) @@ -519,7 +519,7 @@ async fn send_peer_view_change( #[test] fn advertise_and_send_collation() { let mut test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -540,7 +540,7 @@ fn advertise_and_send_collation() { .into_iter() .zip(test_state.current_group_validator_peer_ids()) { - connect_peer(&mut virtual_overseer, peer.clone(), Some(val.clone())).await; + connect_peer(&mut virtual_overseer, peer, Some(val.clone())).await; } // We declare to the connected validators that we are a collator. @@ -550,7 +550,7 @@ fn advertise_and_send_collation() { expect_declare_msg(&mut virtual_overseer, &test_state, &peer_id).await; } - let peer = test_state.current_group_validator_peer_ids()[0].clone(); + let peer = test_state.current_group_validator_peer_ids()[0]; // Send info about peer's view. send_peer_view_change(&mut virtual_overseer, &peer, vec![test_state.relay_parent]) @@ -627,7 +627,7 @@ fn advertise_and_send_collation() { let old_relay_parent = test_state.relay_parent; test_state.advance_to_new_round(&mut virtual_overseer, false).await; - let peer = test_state.validator_peer_id[2].clone(); + let peer = test_state.validator_peer_id[2]; // Re-request a collation. let (pending_response, rx) = oneshot::channel(); @@ -658,7 +658,7 @@ fn advertise_and_send_collation() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - peer.clone(), + peer, view![test_state.relay_parent], )), ) @@ -674,7 +674,7 @@ fn advertise_and_send_collation() { #[test] fn delay_reputation_change() { let test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -694,7 +694,7 @@ fn delay_reputation_change() { .into_iter() .zip(test_state.current_group_validator_peer_ids()) { - connect_peer(&mut virtual_overseer, peer.clone(), Some(val.clone())).await; + connect_peer(&mut virtual_overseer, peer, Some(val.clone())).await; } // We declare to the connected validators that we are a collator. @@ -704,7 +704,7 @@ fn delay_reputation_change() { expect_declare_msg(&mut virtual_overseer, &test_state, &peer_id).await; } - let peer = test_state.current_group_validator_peer_ids()[0].clone(); + let peer = test_state.current_group_validator_peer_ids()[0]; // Send info about peer's view. send_peer_view_change(&mut virtual_overseer, &peer, vec![test_state.relay_parent]) @@ -773,6 +773,7 @@ fn delay_reputation_change() { } #[test] +#[allow(clippy::async_yields_async)] fn send_only_one_collation_per_relay_parent_at_a_time() { test_validator_send_sequence(|mut second_response_receiver, feedback_first_tx| async move { Delay::new(Duration::from_millis(100)).await; @@ -788,6 +789,7 @@ fn send_only_one_collation_per_relay_parent_at_a_time() { } #[test] +#[allow(clippy::async_yields_async)] fn send_next_collation_after_max_unshared_upload_time() { test_validator_send_sequence(|second_response_receiver, _| async move { Delay::new(MAX_UNSHARED_UPLOAD_TIME + Duration::from_millis(50)).await; @@ -798,7 +800,7 @@ fn send_next_collation_after_max_unshared_upload_time() { #[test] fn collators_declare_to_connected_peers() { let test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -806,14 +808,13 @@ fn collators_declare_to_connected_peers() { collator_pair, ReputationAggregator::new(|_| true), |mut test_harness| async move { - let peer = test_state.validator_peer_id[0].clone(); + let peer = test_state.validator_peer_id[0]; let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); setup_system(&mut test_harness.virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(&mut test_harness.virtual_overseer, peer.clone(), Some(validator_id)) - .await; + connect_peer(&mut test_harness.virtual_overseer, peer, Some(validator_id)).await; expect_declare_msg(&mut test_harness.virtual_overseer, &test_state, &peer).await; test_harness }, @@ -823,7 +824,7 @@ fn collators_declare_to_connected_peers() { #[test] fn collations_are_only_advertised_to_validators_with_correct_view() { let test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -833,19 +834,19 @@ fn collations_are_only_advertised_to_validators_with_correct_view() { |mut test_harness| async move { let virtual_overseer = &mut test_harness.virtual_overseer; - let peer = test_state.current_group_validator_peer_ids()[0].clone(); + let peer = test_state.current_group_validator_peer_ids()[0]; let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); - let peer2 = test_state.current_group_validator_peer_ids()[1].clone(); + let peer2 = test_state.current_group_validator_peer_ids()[1]; let validator_id2 = test_state.current_group_validator_authority_ids()[1].clone(); setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer.clone(), Some(validator_id)).await; + connect_peer(virtual_overseer, peer, Some(validator_id)).await; // Connect the second validator - connect_peer(virtual_overseer, peer2.clone(), Some(validator_id2)).await; + connect_peer(virtual_overseer, peer2, Some(validator_id2)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; expect_declare_msg(virtual_overseer, &test_state, &peer2).await; @@ -870,7 +871,7 @@ fn collations_are_only_advertised_to_validators_with_correct_view() { #[test] fn collate_on_two_different_relay_chain_blocks() { let mut test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -880,19 +881,19 @@ fn collate_on_two_different_relay_chain_blocks() { |mut test_harness| async move { let virtual_overseer = &mut test_harness.virtual_overseer; - let peer = test_state.current_group_validator_peer_ids()[0].clone(); + let peer = test_state.current_group_validator_peer_ids()[0]; let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); - let peer2 = test_state.current_group_validator_peer_ids()[1].clone(); + let peer2 = test_state.current_group_validator_peer_ids()[1]; let validator_id2 = test_state.current_group_validator_authority_ids()[1].clone(); setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer.clone(), Some(validator_id)).await; + connect_peer(virtual_overseer, peer, Some(validator_id)).await; // Connect the second validator - connect_peer(virtual_overseer, peer2.clone(), Some(validator_id2)).await; + connect_peer(virtual_overseer, peer2, Some(validator_id2)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; expect_declare_msg(virtual_overseer, &test_state, &peer2).await; @@ -921,7 +922,7 @@ fn collate_on_two_different_relay_chain_blocks() { #[test] fn validator_reconnect_does_not_advertise_a_second_time() { let test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -931,13 +932,13 @@ fn validator_reconnect_does_not_advertise_a_second_time() { |mut test_harness| async move { let virtual_overseer = &mut test_harness.virtual_overseer; - let peer = test_state.current_group_validator_peer_ids()[0].clone(); + let peer = test_state.current_group_validator_peer_ids()[0]; let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer.clone(), Some(validator_id.clone())).await; + connect_peer(virtual_overseer, peer, Some(validator_id.clone())).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; distribute_collation(virtual_overseer, &test_state, true).await; @@ -946,8 +947,8 @@ fn validator_reconnect_does_not_advertise_a_second_time() { expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent).await; // Disconnect and reconnect directly - disconnect_peer(virtual_overseer, peer.clone()).await; - connect_peer(virtual_overseer, peer.clone(), Some(validator_id)).await; + disconnect_peer(virtual_overseer, peer).await; + connect_peer(virtual_overseer, peer, Some(validator_id)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; send_peer_view_change(virtual_overseer, &peer, vec![test_state.relay_parent]).await; @@ -961,7 +962,7 @@ fn validator_reconnect_does_not_advertise_a_second_time() { #[test] fn collators_reject_declare_messages() { let test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); let collator_pair2 = CollatorPair::generate().0; @@ -972,19 +973,19 @@ fn collators_reject_declare_messages() { |mut test_harness| async move { let virtual_overseer = &mut test_harness.virtual_overseer; - let peer = test_state.current_group_validator_peer_ids()[0].clone(); + let peer = test_state.current_group_validator_peer_ids()[0]; let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer.clone(), Some(validator_id)).await; + connect_peer(virtual_overseer, peer, Some(validator_id)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer.clone(), + peer, Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( collator_pair2.public(), ParaId::from(5), @@ -1021,7 +1022,7 @@ where F: Future>, { let test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -1042,7 +1043,7 @@ where .into_iter() .zip(test_state.current_group_validator_peer_ids()) { - connect_peer(virtual_overseer, peer.clone(), Some(val.clone())).await; + connect_peer(virtual_overseer, peer, Some(val.clone())).await; } // We declare to the connected validators that we are a collator. @@ -1052,8 +1053,8 @@ where expect_declare_msg(virtual_overseer, &test_state, &peer_id).await; } - let validator_0 = test_state.current_group_validator_peer_ids()[0].clone(); - let validator_1 = test_state.current_group_validator_peer_ids()[1].clone(); + let validator_0 = test_state.current_group_validator_peer_ids()[0]; + let validator_1 = test_state.current_group_validator_peer_ids()[1]; // Send info about peer's view. send_peer_view_change(virtual_overseer, &validator_0, vec![test_state.relay_parent]) @@ -1149,7 +1150,7 @@ where #[test] fn connect_to_buffered_groups() { let mut test_state = TestState::default(); - let local_peer_id = test_state.local_peer_id.clone(); + let local_peer_id = test_state.local_peer_id; let collator_pair = test_state.collator_pair.clone(); test_harness( @@ -1180,7 +1181,7 @@ fn connect_to_buffered_groups() { let head_a = test_state.relay_parent; for (val, peer) in group_a.iter().zip(&peers_a) { - connect_peer(&mut virtual_overseer, peer.clone(), Some(val.clone())).await; + connect_peer(&mut virtual_overseer, *peer, Some(val.clone())).await; } for peer_id in &peers_a { diff --git a/node/network/collator-protocol/src/validator_side/tests.rs b/node/network/collator-protocol/src/validator_side/tests.rs index 47409e8d10f3..e921e6c38c3e 100644 --- a/node/network/collator-protocol/src/validator_side/tests.rs +++ b/node/network/collator-protocol/src/validator_side/tests.rs @@ -313,7 +313,7 @@ async fn connect_and_declare_collator( overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( - peer.clone(), + peer, ObservedRole::Full, CollationVersion::V1.into(), None, @@ -324,7 +324,7 @@ async fn connect_and_declare_collator( overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer.clone(), + peer, Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( collator.public(), para_id, @@ -376,13 +376,13 @@ fn act_on_advertisement() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, pair.clone(), test_state.chain_ids[0], ) .await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; assert_fetch_collation_request( &mut virtual_overseer, @@ -418,17 +418,17 @@ fn collator_reporting_works() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, test_state.collators[0].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; connect_and_declare_collator( &mut virtual_overseer, - peer_c.clone(), + peer_c, test_state.collators[1].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; @@ -477,7 +477,7 @@ fn collator_authentication_verification_works() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer_b.clone(), + peer_b, Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( test_state.collators[0].public(), test_state.chain_ids[0], @@ -529,22 +529,22 @@ fn fetch_one_collation_at_a_time() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, test_state.collators[0].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; connect_and_declare_collator( &mut virtual_overseer, - peer_c.clone(), + peer_c, test_state.collators[1].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), test_state.relay_parent).await; - advertise_collation(&mut virtual_overseer, peer_c.clone(), test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent).await; let response_channel = assert_fetch_collation_request( &mut virtual_overseer, @@ -615,31 +615,31 @@ fn fetches_next_collation() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, test_state.collators[2].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; connect_and_declare_collator( &mut virtual_overseer, - peer_c.clone(), + peer_c, test_state.collators[3].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; connect_and_declare_collator( &mut virtual_overseer, - peer_d.clone(), + peer_d, test_state.collators[4].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), second).await; - advertise_collation(&mut virtual_overseer, peer_c.clone(), second).await; - advertise_collation(&mut virtual_overseer, peer_d.clone(), second).await; + advertise_collation(&mut virtual_overseer, peer_b, second).await; + advertise_collation(&mut virtual_overseer, peer_c, second).await; + advertise_collation(&mut virtual_overseer, peer_d, second).await; // Dropping the response channel should lead to fetching the second collation. assert_fetch_collation_request(&mut virtual_overseer, second, test_state.chain_ids[0]) @@ -708,9 +708,9 @@ fn reject_connection_to_next_group() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, test_state.collators[0].clone(), - test_state.chain_ids[1].clone(), // next, not current `para_id` + test_state.chain_ids[1], // next, not current `para_id` ) .await; @@ -757,22 +757,22 @@ fn fetch_next_collation_on_invalid_collation() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, test_state.collators[0].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; connect_and_declare_collator( &mut virtual_overseer, - peer_c.clone(), + peer_c, test_state.collators[1].clone(), - test_state.chain_ids[0].clone(), + test_state.chain_ids[0], ) .await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), test_state.relay_parent).await; - advertise_collation(&mut virtual_overseer, peer_c.clone(), test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent).await; let response_channel = assert_fetch_collation_request( &mut virtual_overseer, @@ -854,12 +854,12 @@ fn inactive_disconnected() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, pair.clone(), test_state.chain_ids[0], ) .await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; assert_fetch_collation_request( &mut virtual_overseer, @@ -870,7 +870,7 @@ fn inactive_disconnected() { Delay::new(ACTIVITY_TIMEOUT * 3).await; - assert_collator_disconnect(&mut virtual_overseer, peer_b.clone()).await; + assert_collator_disconnect(&mut virtual_overseer, peer_b).await; virtual_overseer }); } @@ -905,7 +905,7 @@ fn activity_extends_life() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, pair.clone(), test_state.chain_ids[0], ) @@ -913,28 +913,28 @@ fn activity_extends_life() { Delay::new(ACTIVITY_TIMEOUT * 2 / 3).await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), hash_a).await; + advertise_collation(&mut virtual_overseer, peer_b, hash_a).await; assert_fetch_collation_request(&mut virtual_overseer, hash_a, test_state.chain_ids[0]) .await; Delay::new(ACTIVITY_TIMEOUT * 2 / 3).await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), hash_b).await; + advertise_collation(&mut virtual_overseer, peer_b, hash_b).await; assert_fetch_collation_request(&mut virtual_overseer, hash_b, test_state.chain_ids[0]) .await; Delay::new(ACTIVITY_TIMEOUT * 2 / 3).await; - advertise_collation(&mut virtual_overseer, peer_b.clone(), hash_c).await; + advertise_collation(&mut virtual_overseer, peer_b, hash_c).await; assert_fetch_collation_request(&mut virtual_overseer, hash_c, test_state.chain_ids[0]) .await; Delay::new(ACTIVITY_TIMEOUT * 3 / 2).await; - assert_collator_disconnect(&mut virtual_overseer, peer_b.clone()).await; + assert_collator_disconnect(&mut virtual_overseer, peer_b).await; virtual_overseer }); @@ -962,7 +962,7 @@ fn disconnect_if_no_declare() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, CollationVersion::V1.into(), None, @@ -970,7 +970,7 @@ fn disconnect_if_no_declare() { ) .await; - assert_collator_disconnect(&mut virtual_overseer, peer_b.clone()).await; + assert_collator_disconnect(&mut virtual_overseer, peer_b).await; virtual_overseer }) @@ -1000,7 +1000,7 @@ fn disconnect_if_wrong_declare() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, CollationVersion::V1.into(), None, @@ -1011,7 +1011,7 @@ fn disconnect_if_wrong_declare() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer_b.clone(), + peer_b, Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( pair.public(), ParaId::from(69), @@ -1031,7 +1031,7 @@ fn disconnect_if_wrong_declare() { } ); - assert_collator_disconnect(&mut virtual_overseer, peer_b.clone()).await; + assert_collator_disconnect(&mut virtual_overseer, peer_b).await; virtual_overseer }) @@ -1061,7 +1061,7 @@ fn delay_reputation_change() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, CollationVersion::V1.into(), None, @@ -1072,7 +1072,7 @@ fn delay_reputation_change() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer_b.clone(), + peer_b, Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( pair.public(), ParaId::from(69), @@ -1085,7 +1085,7 @@ fn delay_reputation_change() { overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer_b.clone(), + peer_b, Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( pair.public(), ParaId::from(69), @@ -1145,7 +1145,7 @@ fn view_change_clears_old_collators() { connect_and_declare_collator( &mut virtual_overseer, - peer_b.clone(), + peer_b, pair.clone(), test_state.chain_ids[0], ) @@ -1164,7 +1164,7 @@ fn view_change_clears_old_collators() { test_state.group_rotation_info = test_state.group_rotation_info.bump_rotation(); respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - assert_collator_disconnect(&mut virtual_overseer, peer_b.clone()).await; + assert_collator_disconnect(&mut virtual_overseer, peer_b).await; virtual_overseer }) diff --git a/node/network/dispute-distribution/src/tests/mock.rs b/node/network/dispute-distribution/src/tests/mock.rs index d248328da0a7..e6a49f14c094 100644 --- a/node/network/dispute-distribution/src/tests/mock.rs +++ b/node/network/dispute-distribution/src/tests/mock.rs @@ -70,7 +70,7 @@ pub static ref MOCK_VALIDATORS_DISCOVERY_KEYS: HashMap = expected.into_iter().map(|(_,v)| v.into_iter()).flatten().collect(); - assert_eq!(validator_addrs.into_iter().map(|v| v.into_iter()).flatten().collect::>(), expected); + let expected: HashSet = expected.into_values().flat_map(|v| v.into_iter()).collect(); + assert_eq!(validator_addrs.into_iter().flat_map(|v| v.into_iter()).collect::>(), expected); assert_eq!(peer_set, PeerSet::Validation); } ); @@ -707,8 +707,8 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { }) => { let mut expected = get_address_map(AUTHORITIES_WITHOUT_US.clone()).await; expected.remove(&bob); - let expected: HashSet = expected.into_iter().map(|(_,v)| v.into_iter()).flatten().collect(); - assert_eq!(validator_addrs.into_iter().map(|v| v.into_iter()).flatten().collect::>(), expected); + let expected: HashSet = expected.into_values().flat_map(|v| v.into_iter()).collect(); + assert_eq!(validator_addrs.into_iter().flat_map(|v| v.into_iter()).collect::>(), expected); assert_eq!(peer_set, PeerSet::Validation); } ); diff --git a/node/network/statement-distribution/src/tests.rs b/node/network/statement-distribution/src/tests.rs index 62167f77a1e0..affed80fce30 100644 --- a/node/network/statement-distribution/src/tests.rs +++ b/node/network/statement-distribution/src/tests.rs @@ -210,8 +210,8 @@ fn note_local_works() { let hash_b = CandidateHash([2; 32].into()); let mut per_peer_tracker = VcPerPeerTracker::default(); - per_peer_tracker.note_local(hash_a.clone()); - per_peer_tracker.note_local(hash_b.clone()); + per_peer_tracker.note_local(hash_a); + per_peer_tracker.note_local(hash_b); assert!(per_peer_tracker.local_observed.contains(&hash_a)); assert!(per_peer_tracker.local_observed.contains(&hash_b)); @@ -227,9 +227,9 @@ fn note_remote_works() { let hash_c = CandidateHash([3; 32].into()); let mut per_peer_tracker = VcPerPeerTracker::default(); - assert!(per_peer_tracker.note_remote(hash_a.clone())); - assert!(per_peer_tracker.note_remote(hash_b.clone())); - assert!(!per_peer_tracker.note_remote(hash_c.clone())); + assert!(per_peer_tracker.note_remote(hash_a)); + assert!(per_peer_tracker.note_remote(hash_b)); + assert!(!per_peer_tracker.note_remote(hash_c)); assert!(per_peer_tracker.remote_observed.contains(&hash_a)); assert!(per_peer_tracker.remote_observed.contains(&hash_b)); @@ -516,9 +516,9 @@ fn peer_view_update_sends_messages() { executor::block_on(async move { let mut topology = GridNeighbors::empty(); - topology.peers_x = HashSet::from_iter(vec![peer.clone()].into_iter()); + topology.peers_x = HashSet::from_iter(vec![peer].into_iter()); update_peer_view_and_maybe_send_unlocked( - peer.clone(), + peer, &topology, &mut peer_data, &mut ctx, @@ -553,7 +553,7 @@ fn peer_view_update_sends_messages() { // it will not change between runs of the program. for statement in active_head.statements_about(candidate_hash) { let message = handle.recv().await; - let expected_to = vec![peer.clone()]; + let expected_to = vec![peer]; let expected_payload = statement_message(hash_c, statement.statement.clone(), &Metrics::default()); @@ -596,14 +596,14 @@ fn circulated_statement_goes_to_all_peers_with_view() { let peer_data_from_view = |view: View| PeerData { view: view.clone(), - view_knowledge: view.iter().map(|v| (v.clone(), Default::default())).collect(), + view_knowledge: view.iter().map(|v| (*v, Default::default())).collect(), maybe_authority: None, }; let mut peer_data: HashMap<_, _> = vec![ - (peer_a.clone(), peer_data_from_view(peer_a_view)), - (peer_b.clone(), peer_data_from_view(peer_b_view)), - (peer_c.clone(), peer_data_from_view(peer_c_view)), + (peer_a, peer_data_from_view(peer_a_view)), + (peer_b, peer_data_from_view(peer_b_view)), + (peer_c, peer_data_from_view(peer_c_view)), ] .into_iter() .collect(); @@ -644,8 +644,7 @@ fn circulated_statement_goes_to_all_peers_with_view() { let statement = StoredStatement { comparator: &comparator, statement: &statement }; let mut topology = GridNeighbors::empty(); - topology.peers_x = - HashSet::from_iter(vec![peer_a.clone(), peer_b.clone(), peer_c.clone()].into_iter()); + topology.peers_x = HashSet::from_iter(vec![peer_a, peer_b, peer_c].into_iter()); let needs_dependents = circulate_statement( RequiredRouting::GridXY, &topology, @@ -786,7 +785,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_a.clone(), + peer_a, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -799,7 +798,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -811,7 +810,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_a, view![hash_a]), ), }) .await; @@ -819,7 +818,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_b, view![hash_a]), ), }) .await; @@ -853,7 +852,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_a.clone(), + peer_a, Versioned::V1(protocol_v1::StatementDistributionMessage::Statement( hash_a, statement.clone().into(), @@ -887,7 +886,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { )), ) ) => { - assert_eq!(recipients, vec![peer_b.clone()]); + assert_eq!(recipients, vec![peer_b]); assert_eq!(r, hash_a); assert_eq!(s, statement.into()); } @@ -990,7 +989,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_a.clone(), + peer_a, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Alice.public().into()])), @@ -1003,7 +1002,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Bob.public().into()])), @@ -1015,7 +1014,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_c.clone(), + peer_c, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Charlie.public().into()])), @@ -1027,7 +1026,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_bad.clone(), + peer_bad, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -1039,7 +1038,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_a, view![hash_a]), ), }) .await; @@ -1047,21 +1046,21 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_b, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_c.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_c, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_bad.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_bad, view![hash_a]), ), }) .await; @@ -1098,7 +1097,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_a.clone(), + peer_a, Versioned::V1(protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), )), @@ -1136,7 +1135,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_c.clone(), + peer_c, Versioned::V1(protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), )), @@ -1150,7 +1149,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_bad.clone(), + peer_bad, Versioned::V1(protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), )), @@ -1486,7 +1485,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_a.clone(), + peer_a, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Alice.public().into()])), @@ -1499,7 +1498,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Bob.public().into()])), @@ -1511,7 +1510,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_c.clone(), + peer_c, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Charlie.public().into()])), @@ -1523,7 +1522,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_bad.clone(), + peer_bad, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -1535,7 +1534,7 @@ fn delay_reputation_changes() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_a, view![hash_a]), ), }) .await; @@ -1543,21 +1542,21 @@ fn delay_reputation_changes() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_b, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_c.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_c, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_bad.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_bad, view![hash_a]), ), }) .await; @@ -1594,7 +1593,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_a.clone(), + peer_a, Versioned::V1(protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), )), @@ -1632,7 +1631,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_c.clone(), + peer_c, Versioned::V1(protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), )), @@ -1646,7 +1645,7 @@ fn delay_reputation_changes() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_bad.clone(), + peer_bad, Versioned::V1(protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), )), @@ -1962,7 +1961,7 @@ fn share_prioritizes_backing_group() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_a.clone(), + peer_a, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Alice.public().into()])), @@ -1974,7 +1973,7 @@ fn share_prioritizes_backing_group() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_b.clone(), + peer_b, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Bob.public().into()])), @@ -1986,7 +1985,7 @@ fn share_prioritizes_backing_group() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_c.clone(), + peer_c, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Charlie.public().into()])), @@ -1998,7 +1997,7 @@ fn share_prioritizes_backing_group() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_bad.clone(), + peer_bad, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -2010,7 +2009,7 @@ fn share_prioritizes_backing_group() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_other_group.clone(), + peer_other_group, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Dave.public().into()])), @@ -2022,7 +2021,7 @@ fn share_prioritizes_backing_group() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_a, view![hash_a]), ), }) .await; @@ -2030,28 +2029,28 @@ fn share_prioritizes_backing_group() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_b, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_c.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_c, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_bad.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_bad, view![hash_a]), ), }) .await; handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_other_group.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_other_group, view![hash_a]), ), }) .await; @@ -2232,7 +2231,7 @@ fn peer_cant_flood_with_large_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer_a.clone(), + peer_a, ObservedRole::Full, ValidationVersion::V1.into(), Some(HashSet::from([Sr25519Keyring::Alice.public().into()])), @@ -2244,7 +2243,7 @@ fn peer_cant_flood_with_large_statements() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![hash_a]), + NetworkBridgeEvent::PeerViewChange(peer_a, view![hash_a]), ), }) .await; @@ -2280,7 +2279,7 @@ fn peer_cant_flood_with_large_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_a.clone(), + peer_a, Versioned::V1( protocol_v1::StatementDistributionMessage::LargeStatement( metadata.clone(), @@ -2355,8 +2354,8 @@ fn handle_multiple_seconded_statements() { for _ in 0..MIN_GOSSIP_PEERS + 2 { all_peers.push(PeerId::random()); } - all_peers.push(peer_a.clone()); - all_peers.push(peer_b.clone()); + all_peers.push(peer_a); + all_peers.push(peer_b); let mut lucky_peers = all_peers.clone(); util::choose_random_subset_with_rng( @@ -2438,7 +2437,7 @@ fn handle_multiple_seconded_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerConnected( - peer.clone(), + *peer, ObservedRole::Full, ValidationVersion::V1.into(), None, @@ -2449,7 +2448,7 @@ fn handle_multiple_seconded_statements() { handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerViewChange(peer.clone(), view![relay_parent_hash]), + NetworkBridgeEvent::PeerViewChange(*peer, view![relay_parent_hash]), ), }) .await; @@ -2470,13 +2469,13 @@ fn handle_multiple_seconded_statements() { .map(|i| { if i == 0 { TopologyPeerInfo { - peer_ids: vec![peer_a.clone()], + peer_ids: vec![peer_a], validator_index: ValidatorIndex(0), discovery_id: AuthorityPair::generate().0.public(), } } else if i == 1 { TopologyPeerInfo { - peer_ids: vec![peer_b.clone()], + peer_ids: vec![peer_b], validator_index: ValidatorIndex(1), discovery_id: AuthorityPair::generate().0.public(), } @@ -2489,7 +2488,7 @@ fn handle_multiple_seconded_statements() { } else if (i - 2) % dim == 0 { let lucky_index = ((i - 2) / dim) - 1; TopologyPeerInfo { - peer_ids: vec![lucky_peers[lucky_index].clone()], + peer_ids: vec![lucky_peers[lucky_index]], validator_index: ValidatorIndex(i as _), discovery_id: AuthorityPair::generate().0.public(), } @@ -2566,7 +2565,7 @@ fn handle_multiple_seconded_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_a.clone(), + peer_a, Versioned::V1(protocol_v1::StatementDistributionMessage::Statement( relay_parent_hash, statement.clone().into(), @@ -2618,7 +2617,7 @@ fn handle_multiple_seconded_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_b.clone(), + peer_b, Versioned::V1(protocol_v1::StatementDistributionMessage::Statement( relay_parent_hash, statement.clone().into(), @@ -2667,7 +2666,7 @@ fn handle_multiple_seconded_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_a.clone(), + peer_a, Versioned::V1(protocol_v1::StatementDistributionMessage::Statement( relay_parent_hash, statement.clone().into(), @@ -2718,7 +2717,7 @@ fn handle_multiple_seconded_statements() { .send(FromOrchestra::Communication { msg: StatementDistributionMessage::NetworkBridgeUpdate( NetworkBridgeEvent::PeerMessage( - peer_b.clone(), + peer_b, Versioned::V1(protocol_v1::StatementDistributionMessage::Statement( relay_parent_hash, statement.clone().into(), diff --git a/node/service/src/tests.rs b/node/service/src/tests.rs index 95d5765bad45..86119662d9bc 100644 --- a/node/service/src/tests.rs +++ b/node/service/src/tests.rs @@ -87,7 +87,7 @@ fn test_harness>( None, ); - let target_hash = case_vars.target_block.clone(); + let target_hash = case_vars.target_block; let selection_process = async move { let best = select_relay_chain .finality_target_with_longest_chain(target_hash, None) @@ -106,8 +106,7 @@ fn test_harness>( let _overseer = test_fut.await; }, selection_process, - )) - .1; + )); } async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages { @@ -241,7 +240,7 @@ impl ChainBuilder { builder } - pub fn add_block<'a>(&'a mut self, hash: Hash, parent_hash: Hash, number: u32) -> &'a mut Self { + pub fn add_block(&mut self, hash: Hash, parent_hash: Hash, number: u32) -> &mut Self { assert!(number != 0, "cannot add duplicate genesis block"); assert!(hash != Self::GENESIS_HASH, "cannot add block with genesis hash"); assert!( @@ -252,12 +251,7 @@ impl ChainBuilder { self.add_block_inner(hash, parent_hash, number) } - fn add_block_inner<'a>( - &'a mut self, - hash: Hash, - parent_hash: Hash, - number: u32, - ) -> &'a mut Self { + fn add_block_inner(&mut self, hash: Hash, parent_hash: Hash, number: u32) -> &mut Self { let header = ChainBuilder::make_header(parent_hash, number); assert!( self.0.blocks_by_hash.insert(hash, header).is_none(), @@ -360,7 +354,7 @@ async fn test_skeleton( )) => { assert_eq!(target_block_hash, target_hash, "TestIntegrity: target hashes always match. qed"); - tx.send(best_chain_containing_block.clone()).unwrap(); + tx.send(best_chain_containing_block).unwrap(); } ); diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index 4fc3f82eb4a9..1313b7b90469 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -210,7 +210,7 @@ pub fn run_validator_node( .expect("could not create Polkadot test service"); let overseer_handle = overseer_handle.expect("test node must have an overseer handle"); - let peer_id = network.local_peer_id().clone(); + let peer_id = network.local_peer_id(); let addr = MultiaddrWithPeerId { multiaddr, peer_id }; PolkadotTestNode { task_manager, client, overseer_handle, addr, rpc_handlers } @@ -242,7 +242,7 @@ pub fn run_collator_node( .expect("could not create Polkadot test service"); let overseer_handle = overseer_handle.expect("test node must have an overseer handle"); - let peer_id = network.local_peer_id().clone(); + let peer_id = network.local_peer_id(); let addr = MultiaddrWithPeerId { multiaddr, peer_id }; PolkadotTestNode { task_manager, client, overseer_handle, addr, rpc_handlers } @@ -273,7 +273,7 @@ impl PolkadotTestNode { ) -> Result<(), RpcTransactionError> { let sudo = SudoCall::sudo { call: Box::new(call.into()) }; - let extrinsic = construct_extrinsic(&*self.client, sudo, caller, nonce); + let extrinsic = construct_extrinsic(&self.client, sudo, caller, nonce); self.rpc_handlers.send_transaction(extrinsic.into()).await.map(drop) } @@ -283,7 +283,7 @@ impl PolkadotTestNode { function: impl Into, caller: Sr25519Keyring, ) -> Result { - let extrinsic = construct_extrinsic(&*self.client, function, caller, 0); + let extrinsic = construct_extrinsic(&self.client, function, caller, 0); self.rpc_handlers.send_transaction(extrinsic.into()).await } diff --git a/runtime/common/src/auctions.rs b/runtime/common/src/auctions.rs index 901c9c27da28..9c2bb04b9c8e 100644 --- a/runtime/common/src/auctions.rs +++ b/runtime/common/src/auctions.rs @@ -793,7 +793,7 @@ mod tests { if leases.contains_key(&(para, period)) { return Err(LeaseError::AlreadyLeased) } - leases.insert((para, period), LeaseData { leaser: leaser.clone(), amount }); + leases.insert((para, period), LeaseData { leaser: *leaser, amount }); } Ok(()) }) @@ -1391,7 +1391,7 @@ mod tests { (1, 2.into(), 53, SlotRange::TwoTwo), (5, 3.into(), 1, SlotRange::ThreeThree), ]; - assert_eq!(Auctions::calculate_winners(winning.clone()), winners); + assert_eq!(Auctions::calculate_winners(winning), winners); winning[SlotRange::ZeroOne as u8 as usize] = Some((4, 10.into(), 3)); let winners = vec![ @@ -1399,11 +1399,11 @@ mod tests { (1, 2.into(), 53, SlotRange::TwoTwo), (5, 3.into(), 1, SlotRange::ThreeThree), ]; - assert_eq!(Auctions::calculate_winners(winning.clone()), winners); + assert_eq!(Auctions::calculate_winners(winning), winners); winning[SlotRange::ZeroThree as u8 as usize] = Some((1, 100.into(), 100)); let winners = vec![(1, 100.into(), 100, SlotRange::ZeroThree)]; - assert_eq!(Auctions::calculate_winners(winning.clone()), winners); + assert_eq!(Auctions::calculate_winners(winning), winners); } #[test] diff --git a/runtime/common/src/crowdloan/mod.rs b/runtime/common/src/crowdloan/mod.rs index 1db046c52701..0303808e0747 100644 --- a/runtime/common/src/crowdloan/mod.rs +++ b/runtime/common/src/crowdloan/mod.rs @@ -970,16 +970,16 @@ mod tests { ENDING_PERIOD.with(|p| *p.borrow_mut() = ending_period); } fn auction() -> Option<(u64, u64)> { - AUCTION.with(|p| p.borrow().clone()) + AUCTION.with(|p| *p.borrow()) } fn ending_period() -> u64 { - ENDING_PERIOD.with(|p| p.borrow().clone()) + ENDING_PERIOD.with(|p| *p.borrow()) } fn bids() -> Vec { BIDS_PLACED.with(|p| p.borrow().clone()) } fn vrf_delay() -> u64 { - VRF_DELAY.with(|p| p.borrow().clone()) + VRF_DELAY.with(|p| *p.borrow()) } fn set_vrf_delay(delay: u64) { VRF_DELAY.with(|p| *p.borrow_mut() = delay); diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index 3573ec3dc42b..ff529143c509 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -140,26 +140,24 @@ mod tests { // F * (B + msg_length * M) // message_length = 1 - let result: u128 = TestFeeTracker::get_fee_factor(id.clone()).saturating_mul_int(b + m); + let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + m); assert_eq!( - TestExponentialPrice::price_for_parachain_delivery(id.clone(), &Xcm(vec![])), + TestExponentialPrice::price_for_parachain_delivery(id, &Xcm(vec![])), (FeeAssetId::get(), result).into() ); // message size = 2 - let result: u128 = - TestFeeTracker::get_fee_factor(id.clone()).saturating_mul_int(b + (2 * m)); + let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (2 * m)); assert_eq!( - TestExponentialPrice::price_for_parachain_delivery(id.clone(), &Xcm(vec![ClearOrigin])), + TestExponentialPrice::price_for_parachain_delivery(id, &Xcm(vec![ClearOrigin])), (FeeAssetId::get(), result).into() ); // message size = 4 - let result: u128 = - TestFeeTracker::get_fee_factor(id.clone()).saturating_mul_int(b + (4 * m)); + let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (4 * m)); assert_eq!( TestExponentialPrice::price_for_parachain_delivery( - id.clone(), + id, &Xcm(vec![SetAppendix(Xcm(vec![ClearOrigin]))]) ), (FeeAssetId::get(), result).into() diff --git a/runtime/parachains/src/builder.rs b/runtime/parachains/src/builder.rs index 892e934e6dfc..3f95b2087e6c 100644 --- a/runtime/parachains/src/builder.rs +++ b/runtime/parachains/src/builder.rs @@ -377,8 +377,8 @@ impl BenchBuilder { fn signing_context(&self) -> SigningContext { SigningContext { - parent_hash: Self::header(self.block_number.clone()).hash(), - session_index: self.session.clone(), + parent_hash: Self::header(self.block_number).hash(), + session_index: self.session, } } @@ -408,7 +408,7 @@ impl BenchBuilder { } let block_number = BlockNumberFor::::from(block); - let header = Self::header(block_number.clone()); + let header = Self::header(block_number); frame_system::Pallet::::reset_events(); frame_system::Pallet::::initialize( @@ -464,13 +464,13 @@ impl BenchBuilder { for (seed, _) in concluding_cores.iter() { // make sure the candidates that will be concluding are marked as pending availability. - let (para_id, core_idx, group_idx) = self.create_indexes(seed.clone()); + let (para_id, core_idx, group_idx) = self.create_indexes(*seed); Self::add_availability( para_id, core_idx, group_idx, Self::validator_availability_votes_yes(validators.len()), - CandidateHash(H256::from(byte32_slice_from(seed.clone()))), + CandidateHash(H256::from(byte32_slice_from(*seed))), ); } @@ -496,11 +496,11 @@ impl BenchBuilder { .iter() .map(|(seed, num_votes)| { assert!(*num_votes <= validators.len() as u32); - let (para_id, _core_idx, group_idx) = self.create_indexes(seed.clone()); + let (para_id, _core_idx, group_idx) = self.create_indexes(*seed); // This generates a pair and adds it to the keystore, returning just the public. let collator_public = CollatorId::generate_pair(None); - let header = Self::header(self.block_number.clone()); + let header = Self::header(self.block_number); let relay_parent = header.hash(); let head_data = Self::mock_head_data(); let persisted_validation_data_hash = PersistedValidationData:: { @@ -563,7 +563,7 @@ impl BenchBuilder { let public = validators.get(*val_idx).unwrap(); let sig = UncheckedSigned::::benchmark_sign( public, - CompactStatement::Valid(candidate_hash.clone()), + CompactStatement::Valid(candidate_hash), &self.signing_context(), *val_idx, ) @@ -632,14 +632,14 @@ impl BenchBuilder { } else { DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) }; - let data = dispute_statement.payload_data(candidate_hash.clone(), session); + let data = dispute_statement.payload_data(candidate_hash, session); let statement_sig = validator_public.sign(&data).unwrap(); (dispute_statement, ValidatorIndex(validator_index), statement_sig) }) .collect(); - DisputeStatementSet { candidate_hash: candidate_hash.clone(), session, statements } + DisputeStatementSet { candidate_hash: candidate_hash, session, statements } }) .collect() } @@ -702,7 +702,7 @@ impl BenchBuilder { bitfields, backed_candidates, disputes, - parent_header: Self::header(builder.block_number.clone()), + parent_header: Self::header(builder.block_number), }, _session: target_session, _block_number: builder.block_number, diff --git a/runtime/parachains/src/disputes/tests.rs b/runtime/parachains/src/disputes/tests.rs index acdba343274c..0757084084f6 100644 --- a/runtime/parachains/src/disputes/tests.rs +++ b/runtime/parachains/src/disputes/tests.rs @@ -377,7 +377,6 @@ fn test_initializer_on_new_session() { let mock_genesis_config = MockGenesisConfig { configuration: crate::configuration::GenesisConfig { config: HostConfiguration { dispute_period, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -386,13 +385,13 @@ fn test_initializer_on_new_session() { 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); + Pallet::::note_included(0, candidate_hash, 0); + Pallet::::note_included(1, candidate_hash, 1); + Pallet::::note_included(2, candidate_hash, 2); + Pallet::::note_included(3, candidate_hash, 3); + Pallet::::note_included(4, candidate_hash, 4); + Pallet::::note_included(5, candidate_hash, 5); + Pallet::::note_included(6, candidate_hash, 5); run_to_block(7, |b| { // a new session at each block @@ -465,7 +464,7 @@ fn test_provide_multi_dispute_is_providing() { let inclusion_parent = sp_core::H256::repeat_byte(0xff); let session = 1; let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( @@ -481,12 +480,8 @@ fn test_provide_multi_dispute_is_providing() { DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ], @@ -499,7 +494,7 @@ fn test_provide_multi_dispute_is_providing() { .map(CheckedDisputeStatementSet::unchecked_from_unchecked) .collect() ), - vec![(1, candidate_hash.clone())], + vec![(1, candidate_hash)], ); }) } @@ -528,31 +523,23 @@ fn test_disputes_with_missing_backing_votes_are_rejected() { let session = 1; let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ], @@ -590,31 +577,23 @@ fn test_freeze_on_note_included() { // v0 votes for 3 let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 3, statements: vec![ ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 3 } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 3 } + .signing_payload(), ), ), ( @@ -636,7 +615,7 @@ fn test_freeze_on_note_included() { ) .is_ok()); - Pallet::::note_included(3, candidate_hash.clone(), 3); + Pallet::::note_included(3, candidate_hash, 3); assert_eq!(Frozen::::get(), Some(2)); }); } @@ -663,31 +642,23 @@ fn test_freeze_provided_against_supermajority_for_included() { // v0 votes for 3 let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( @@ -702,7 +673,7 @@ fn test_freeze_provided_against_supermajority_for_included() { ], }]; - Pallet::::note_included(3, candidate_hash.clone(), 3); + Pallet::::note_included(3, candidate_hash, 3); assert!(Pallet::::process_checked_multi_dispute_data( &stmts .into_iter() @@ -744,43 +715,31 @@ fn test_freeze_provided_against_byzantine_threshold_for_included() { // A byzantine threshold of INVALID let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(2), v2.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( @@ -796,7 +755,7 @@ fn test_freeze_provided_against_byzantine_threshold_for_included() { }]; // Include the candidate and import the votes - Pallet::::note_included(3, candidate_hash.clone(), 3); + Pallet::::note_included(3, candidate_hash, 3); assert!(Pallet::::process_checked_multi_dispute_data( &stmts .into_iter() @@ -813,43 +772,31 @@ fn test_freeze_provided_against_byzantine_threshold_for_included() { // And generate enough votes to reach supermajority of invalid votes let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(3), v3.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(4), v4.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(5), v5.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ], @@ -922,31 +869,23 @@ mod unconfirmed_disputes { // v0 votes for 4, v1 votes against 4. DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 4, statements: vec![ ( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 4, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session: 4 } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(3), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 4, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 4 } + .signing_payload(), ), ), ], @@ -1037,7 +976,7 @@ fn test_provide_multi_dispute_success_and_other() { // v0 and v1 vote for 3, v6 votes against let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( @@ -1053,24 +992,16 @@ fn test_provide_multi_dispute_success_and_other() { DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(2), v6.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(3), v1.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session: 3 } + .signing_payload(), ), ), ], @@ -1080,29 +1011,25 @@ fn test_provide_multi_dispute_success_and_other() { assert_ok!( Pallet::::process_checked_multi_dispute_data(&stmts), - vec![(3, candidate_hash.clone())], + vec![(3, candidate_hash)], ); // v3 votes against 3 and for 5, v2 and v6 vote against 5. let stmts = vec![ DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 3, statements: vec![( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(5), v3.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 3 } + .signing_payload(), ), )], }, DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 5, statements: vec![ ( @@ -1118,24 +1045,16 @@ fn test_provide_multi_dispute_success_and_other() { DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(6), v2.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 5 } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(2), v6.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 5 } + .signing_payload(), ), ), ], @@ -1145,23 +1064,19 @@ fn test_provide_multi_dispute_success_and_other() { let stmts = filter_dispute_set(stmts); assert_ok!( Pallet::::process_checked_multi_dispute_data(&stmts), - vec![(5, candidate_hash.clone())], + vec![(5, candidate_hash)], ); // v2 votes for 3 let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 3, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(6), v2.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session: 3 } + .signing_payload(), ), )], }]; @@ -1171,74 +1086,54 @@ fn test_provide_multi_dispute_success_and_other() { let stmts = vec![ // 0, 4, and 5 vote against 5 DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 5, statements: vec![ ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 5 } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v4.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 5 } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(4), v5.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session: 5 } + .signing_payload(), ), ), ], }, // 4 and 5 vote for 3 DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 3, statements: vec![ ( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(1), v4.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session: 3 } + .signing_payload(), ), ), ( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(4), v5.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session: 3 } + .signing_payload(), ), ), ], @@ -1252,7 +1147,7 @@ fn test_provide_multi_dispute_success_and_other() { vec![ ( 5, - candidate_hash.clone(), + candidate_hash, DisputeState { validators_for: bitvec![u8, BitOrderLsb0; 0, 0, 0, 0, 0, 1, 0], validators_against: bitvec![u8, BitOrderLsb0; 1, 1, 1, 0, 1, 0, 1], @@ -1262,7 +1157,7 @@ fn test_provide_multi_dispute_success_and_other() { ), ( 3, - candidate_hash.clone(), + candidate_hash, DisputeState { validators_for: bitvec![u8, BitOrderLsb0; 1, 1, 0, 1, 1, 0, 1], validators_against: bitvec![u8, BitOrderLsb0; 0, 0, 1, 0, 0, 1, 0], @@ -1273,9 +1168,9 @@ fn test_provide_multi_dispute_success_and_other() { ] ); - assert!(!Pallet::::concluded_invalid(3, candidate_hash.clone())); - assert!(!Pallet::::concluded_invalid(4, candidate_hash.clone())); - assert!(Pallet::::concluded_invalid(5, candidate_hash.clone())); + assert!(!Pallet::::concluded_invalid(3, candidate_hash)); + assert!(!Pallet::::concluded_invalid(4, candidate_hash)); + assert!(Pallet::::concluded_invalid(5, candidate_hash)); // Ensure the `reward_validator` function was correctly called assert_eq!( @@ -1372,7 +1267,7 @@ fn test_punish_post_conclusion() { let session = 3; let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( @@ -1388,60 +1283,40 @@ fn test_punish_post_conclusion() { DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v4.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(2), v6.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(6), v2.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(4), v5.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(5), v3.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( @@ -1469,7 +1344,7 @@ fn test_punish_post_conclusion() { // someone reveals 3 backing vote, 6 votes against let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( @@ -1485,12 +1360,8 @@ fn test_punish_post_conclusion() { DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(6), v2.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ], @@ -1600,37 +1471,28 @@ fn test_check_signature() { 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_2 = + DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(inclusion_parent)); + let wrong_statement_2 = + DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(wrong_inclusion_parent)); let statement_3 = - DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent.clone())); - let wrong_statement_3 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid( - wrong_inclusion_parent.clone(), - )); + DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)); + let wrong_statement_3 = + DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(wrong_inclusion_parent)); 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_1 = validator_id + .sign(&ExplicitDisputeStatement { valid: true, candidate_hash, session }.signing_payload()); + let signed_2 = validator_id.sign(&CompactStatement::Seconded(candidate_hash).signing_payload( + &SigningContext { session_index: session, parent_hash: inclusion_parent }, + )); + let signed_3 = validator_id.sign(&CompactStatement::Valid(candidate_hash).signing_payload( + &SigningContext { session_index: session, parent_hash: inclusion_parent }, + )); + let signed_4 = validator_id.sign(&ApprovalVote(candidate_hash).signing_payload(session)); let signed_5 = validator_id.sign( - &ExplicitDisputeStatement { valid: false, candidate_hash: candidate_hash.clone(), session } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session }.signing_payload(), ); assert!(check_signature( @@ -2007,9 +1869,8 @@ fn deduplication_and_sorting_works() { c_hash: &CandidateHash, valid, session| { - let payload = - ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session } - .signing_payload(); + let payload = ExplicitDisputeStatement { valid, candidate_hash: *c_hash, session } + .signing_payload(); let sig = validator.sign(&payload); (DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), vidx, sig.clone()) }; @@ -2031,24 +1892,24 @@ fn deduplication_and_sorting_works() { let mut disputes = vec![ DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), + candidate_hash: candidate_hash_b, session: 2, statements: vec![explicit_triple_b.clone(), explicit_triple_b_bad.clone()], }, // same session as above DisputeStatementSet { - candidate_hash: candidate_hash_c.clone(), + candidate_hash: candidate_hash_c, session: 2, statements: vec![explicit_triple_c, explicit_triple_c_bad], }, // the duplicate set DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), + candidate_hash: candidate_hash_b, session: 2, statements: vec![explicit_triple_b.clone(), explicit_triple_b_bad.clone()], }, DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), + candidate_hash: candidate_hash_a, session: 1, statements: vec![explicit_triple_a, explicit_triple_a_bad], }, @@ -2116,19 +1977,11 @@ fn filter_removes_duplicates_within_set() { 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 = + ExplicitDisputeStatement { valid: true, candidate_hash, session: 1 }.signing_payload(); - let payload_against = ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 1, - } - .signing_payload(); + let payload_against = + ExplicitDisputeStatement { valid: false, candidate_hash, session: 1 }.signing_payload(); let sig_a = v0.sign(&payload); let sig_b = v0.sign(&payload); @@ -2136,7 +1989,7 @@ fn filter_removes_duplicates_within_set() { let sig_d = v1.sign(&payload_against); let statements = DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 1, statements: vec![ ( @@ -2172,7 +2025,7 @@ fn filter_removes_duplicates_within_set() { assert_eq!( statements, Some(CheckedDisputeStatementSet::unchecked_from_unchecked(DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 1, statements: vec![ ( @@ -2217,7 +2070,7 @@ fn filter_bad_signatures_correctly_detects_single_sided() { 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 } + ExplicitDisputeStatement { valid, candidate_hash: *c_hash, session: 1 } .signing_payload() }; @@ -2228,7 +2081,7 @@ fn filter_bad_signatures_correctly_detects_single_sided() { let sig_1 = v1.sign(&payload_a_bad); let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), + candidate_hash: candidate_hash_a, session: 1, statements: vec![ ( @@ -2262,17 +2115,13 @@ fn filter_removes_session_out_of_bounds() { 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 = + ExplicitDisputeStatement { valid: true, candidate_hash, session: 1 }.signing_payload(); let sig_a = v0.sign(&payload); let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session: 100, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), @@ -2297,7 +2146,6 @@ fn filter_removes_concluded_ancient() { dispute_post_conclusion_acceptance_period, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -2335,26 +2183,20 @@ fn filter_removes_concluded_ancient() { }, ); - let payload_a = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); + let payload_a = + ExplicitDisputeStatement { valid: true, candidate_hash: candidate_hash_a, session: 1 } + .signing_payload(); - let payload_b = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_b.clone(), - session: 1, - } - .signing_payload(); + let payload_b = + ExplicitDisputeStatement { valid: true, candidate_hash: candidate_hash_b, 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(), + candidate_hash: candidate_hash_a, session: 1, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), @@ -2363,7 +2205,7 @@ fn filter_removes_concluded_ancient() { )], }, DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), + candidate_hash: candidate_hash_b, session: 1, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), @@ -2378,7 +2220,7 @@ fn filter_removes_concluded_ancient() { assert_eq!( statements, vec![CheckedDisputeStatementSet::unchecked_from_unchecked(DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), + candidate_hash: candidate_hash_b, session: 1, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), @@ -2408,19 +2250,13 @@ fn filter_removes_duplicate_statements_sets() { 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 = + ExplicitDisputeStatement { valid: true, candidate_hash: candidate_hash_a, session: 1 } + .signing_payload(); - let payload_against = ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); + let payload_against = + ExplicitDisputeStatement { valid: false, candidate_hash: candidate_hash_a, session: 1 } + .signing_payload(); let sig_a = v0.sign(&payload); let sig_a_against = v1.sign(&payload_against); @@ -2440,12 +2276,12 @@ fn filter_removes_duplicate_statements_sets() { let mut sets = vec![ DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), + candidate_hash: candidate_hash_a, session: 1, statements: statements.clone(), }, DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), + candidate_hash: candidate_hash_a, session: 1, statements: statements.clone(), }, @@ -2459,11 +2295,7 @@ fn filter_removes_duplicate_statements_sets() { assert_eq!( sets, - vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements, - }] + vec![DisputeStatementSet { candidate_hash: candidate_hash_a, session: 1, statements }] ); }) } @@ -2480,17 +2312,14 @@ fn filter_ignores_single_sided() { 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 = + ExplicitDisputeStatement { valid: true, candidate_hash: candidate_hash_a, session: 1 } + .signing_payload(); let sig_a = v0.sign(&payload); let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), + candidate_hash: candidate_hash_a, session: 1, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), @@ -2517,17 +2346,14 @@ fn import_ignores_single_sided() { 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 = + ExplicitDisputeStatement { valid: true, candidate_hash: candidate_hash_a, session: 1 } + .signing_payload(); let sig_a = v0.sign(&payload); let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), + candidate_hash: candidate_hash_a, session: 1, statements: vec![( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), diff --git a/runtime/parachains/src/inclusion/tests.rs b/runtime/parachains/src/inclusion/tests.rs index 59f5e9414d0a..3b4d7a7df357 100644 --- a/runtime/parachains/src/inclusion/tests.rs +++ b/runtime/parachains/src/inclusion/tests.rs @@ -68,10 +68,7 @@ pub(crate) fn genesis_config(paras: Vec<(ParaId, ParaKind)>) -> MockGenesisConfi .collect(), ..Default::default() }, - configuration: configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: configuration::GenesisConfig { config: default_config() }, ..Default::default() } } diff --git a/runtime/parachains/src/paras/mod.rs b/runtime/parachains/src/paras/mod.rs index 4570bb2b13bd..6089fe2ba3b8 100644 --- a/runtime/parachains/src/paras/mod.rs +++ b/runtime/parachains/src/paras/mod.rs @@ -259,7 +259,7 @@ impl ParaPastCodeMeta { // of the para. #[cfg(test)] fn most_recent_change(&self) -> Option { - self.upgrade_times.last().map(|x| x.expected_at.clone()) + self.upgrade_times.last().map(|x| x.expected_at) } // prunes all code upgrade logs occurring at or before `max`. diff --git a/runtime/parachains/src/paras/tests.rs b/runtime/parachains/src/paras/tests.rs index 4a3be6d7d50e..a9b51fe2b45e 100644 --- a/runtime/parachains/src/paras/tests.rs +++ b/runtime/parachains/src/paras/tests.rs @@ -280,7 +280,6 @@ fn para_past_code_pruning_in_initialize() { paras: GenesisConfig { paras, ..Default::default() }, configuration: crate::configuration::GenesisConfig { config: HostConfiguration { code_retention_period, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -333,7 +332,6 @@ fn note_new_head_sets_head() { paras: GenesisConfig { paras, ..Default::default() }, configuration: crate::configuration::GenesisConfig { config: HostConfiguration { code_retention_period, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -375,7 +373,6 @@ fn note_past_code_sets_up_pruning_correctly() { paras: GenesisConfig { paras, ..Default::default() }, configuration: crate::configuration::GenesisConfig { config: HostConfiguration { code_retention_period, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -424,7 +421,6 @@ fn code_upgrade_applied_after_delay() { validation_upgrade_cooldown, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -537,7 +533,6 @@ fn code_upgrade_applied_after_delay_even_when_late() { validation_upgrade_cooldown, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -620,7 +615,6 @@ fn submit_code_change_when_not_allowed_is_err() { validation_upgrade_cooldown, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -691,7 +685,6 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { validation_upgrade_cooldown, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -757,7 +750,6 @@ fn full_parachain_cleanup_storage() { thread_availability_period: 1, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -1013,7 +1005,6 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { validation_upgrade_delay, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -1104,7 +1095,6 @@ fn pvf_check_coalescing_onboarding_and_upgrade() { paras: GenesisConfig { paras, ..Default::default() }, configuration: crate::configuration::GenesisConfig { config: HostConfiguration { validation_upgrade_delay, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -1169,7 +1159,6 @@ fn pvf_check_onboarding_reject_on_expiry() { let genesis_config = MockGenesisConfig { configuration: crate::configuration::GenesisConfig { config: HostConfiguration { pvf_voting_ttl, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -1569,7 +1558,6 @@ fn add_trusted_validation_code_insta_approval() { minimum_validation_upgrade_delay, ..Default::default() }, - ..Default::default() }, ..Default::default() }; @@ -1611,7 +1599,6 @@ fn add_trusted_validation_code_enacts_existing_pvf_vote() { minimum_validation_upgrade_delay, ..Default::default() }, - ..Default::default() }, ..Default::default() }; diff --git a/runtime/parachains/src/paras_inherent/tests.rs b/runtime/parachains/src/paras_inherent/tests.rs index faf52b555ba3..4de12bcc91b7 100644 --- a/runtime/parachains/src/paras_inherent/tests.rs +++ b/runtime/parachains/src/paras_inherent/tests.rs @@ -155,43 +155,31 @@ mod enter { let generate_votes = |session: u32, candidate_hash: CandidateHash| { // v0 votes for 3 vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), + candidate_hash, session, statements: vec![ ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(0), v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload(), ), ), ( DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), ValidatorIndex(1), v1.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), + &ExplicitDisputeStatement { valid: true, candidate_hash, session } + .signing_payload(), ), ), ], @@ -202,7 +190,7 @@ mod enter { }; let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - let statements = generate_votes(3, candidate_hash.clone()); + let statements = generate_votes(3, candidate_hash); set_scrapable_on_chain_disputes::(3, statements); assert_matches!(pallet::Pallet::::on_chain_votes(), Some(ScrapedOnChainVotes { session, @@ -221,7 +209,7 @@ mod enter { }); let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(2)); - let statements = generate_votes(7, candidate_hash.clone()); + let statements = generate_votes(7, candidate_hash); set_scrapable_on_chain_disputes::(7, statements); assert_matches!(pallet::Pallet::::on_chain_votes(), Some(ScrapedOnChainVotes { session, @@ -1330,7 +1318,7 @@ mod sanitizers { let mut set = std::collections::HashSet::new(); for (idx, backed_candidate) in backed_candidates.iter().enumerate() { if idx & 0x01 == 0 { - set.insert(backed_candidate.hash().clone()); + set.insert(backed_candidate.hash()); } } set diff --git a/runtime/parachains/src/scheduler/tests.rs b/runtime/parachains/src/scheduler/tests.rs index c4830f4bf253..cc2aee357231 100644 --- a/runtime/parachains/src/scheduler/tests.rs +++ b/runtime/parachains/src/scheduler/tests.rs @@ -116,10 +116,7 @@ fn default_config() -> HostConfiguration { #[test] fn add_parathread_claim_works() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -200,7 +197,7 @@ fn cannot_add_claim_when_no_parathread_cores() { config }; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config, ..Default::default() }, + configuration: crate::configuration::GenesisConfig { config }, ..Default::default() }; @@ -224,10 +221,7 @@ fn cannot_add_claim_when_no_parathread_cores() { #[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() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; let max_parathread_retries = default_config().parathread_retries; @@ -326,10 +320,7 @@ fn session_change_prunes_cores_beyond_retries_and_those_from_non_live_parathread #[test] fn session_change_shuffles_validators() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -384,10 +375,7 @@ fn session_change_takes_only_max_per_core() { }; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..Default::default() }; @@ -432,10 +420,7 @@ fn session_change_takes_only_max_per_core() { #[test] fn schedule_schedules() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -557,10 +542,7 @@ fn schedule_schedules() { #[test] fn schedule_schedules_including_just_freed() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -733,10 +715,7 @@ fn schedule_schedules_including_just_freed() { #[test] fn schedule_clears_availability_cores() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -839,10 +818,7 @@ fn schedule_rotates_groups() { let parathread_cores = config.parathread_cores; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..Default::default() }; @@ -911,10 +887,7 @@ 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() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -959,10 +932,7 @@ fn parathread_claims_are_pruned_after_retries() { #[test] fn availability_predicate_works() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -1067,10 +1037,7 @@ fn next_up_on_available_uses_next_scheduled_or_none_for_thread() { config.parathread_cores = 1; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..Default::default() }; @@ -1139,10 +1106,7 @@ fn next_up_on_time_out_reuses_claim_if_nothing_queued() { config.parathread_cores = 1; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..Default::default() }; @@ -1217,10 +1181,7 @@ fn next_up_on_available_is_parachain_always() { config.parathread_cores = 0; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..Default::default() }; @@ -1271,10 +1232,7 @@ fn next_up_on_time_out_is_parachain_always() { config.parathread_cores = 0; let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..Default::default() }; @@ -1322,10 +1280,7 @@ fn next_up_on_time_out_is_parachain_always() { #[test] fn session_change_requires_reschedule_dropping_removed_paras() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; @@ -1399,10 +1354,7 @@ fn session_change_requires_reschedule_dropping_removed_paras() { #[test] fn parathread_claims_are_pruned_after_deregistration() { let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: crate::configuration::GenesisConfig { config: default_config() }, ..Default::default() }; diff --git a/runtime/parachains/src/session_info/tests.rs b/runtime/parachains/src/session_info/tests.rs index 63226fb7cf81..c4475526d58f 100644 --- a/runtime/parachains/src/session_info/tests.rs +++ b/runtime/parachains/src/session_info/tests.rs @@ -71,10 +71,7 @@ fn default_config() -> HostConfiguration { fn genesis_config() -> MockGenesisConfig { MockGenesisConfig { - configuration: configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, + configuration: configuration::GenesisConfig { config: default_config() }, ..Default::default() } } diff --git a/runtime/parachains/src/ump_tests.rs b/runtime/parachains/src/ump_tests.rs index 424aa2a4d032..22aee31043a2 100644 --- a/runtime/parachains/src/ump_tests.rs +++ b/runtime/parachains/src/ump_tests.rs @@ -523,21 +523,21 @@ fn overweight_queue_works() { assert_last_events( [ pallet_message_queue::Event::::Processed { - id: hash_1.clone(), + id: hash_1, origin: Ump(UmpQueueId::Para(para_a)), weight_used: Weight::from_parts(301, 301), success: true, } .into(), pallet_message_queue::Event::::OverweightEnqueued { - id: hash_2.clone(), + id: hash_2, origin: Ump(UmpQueueId::Para(para_a)), page_index: 0, message_index: 1, } .into(), pallet_message_queue::Event::::OverweightEnqueued { - id: hash_3.clone(), + id: hash_3, origin: Ump(UmpQueueId::Para(para_a)), page_index: 0, message_index: 2, diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index ea629f189dc8..963df0aa0303 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -114,5 +114,6 @@ cargo-clippy: - .docker-env - .test-refs script: + - echo $RUSTFLAGS - cargo version && cargo clippy --version - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --locked --all-targets + - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy -q --locked --all-targets --workspace diff --git a/statement-table/src/generic.rs b/statement-table/src/generic.rs index 9aa445becce0..161a06ef161a 100644 --- a/statement-table/src/generic.rs +++ b/statement-table/src/generic.rs @@ -723,7 +723,7 @@ mod tests { // authority 2 votes for validity on 1's candidate. let bad_validity_vote = SignedStatement { - statement: Statement::Valid(candidate_a_digest.clone()), + statement: Statement::Valid(candidate_a_digest), signature: Signature(2), sender: AuthorityId(2), }; @@ -794,7 +794,7 @@ mod tests { assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let extra_vote = SignedStatement { - statement: Statement::Valid(candidate_digest.clone()), + statement: Statement::Valid(candidate_digest), signature: Signature(1), sender: AuthorityId(1), }; @@ -864,7 +864,7 @@ mod tests { assert!(table.attested_candidate(&candidate_digest, &context).is_none()); let vote = SignedStatement { - statement: Statement::Valid(candidate_digest.clone()), + statement: Statement::Valid(candidate_digest), signature: Signature(2), sender: AuthorityId(2), }; @@ -923,7 +923,7 @@ mod tests { assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let vote = SignedStatement { - statement: Statement::Valid(candidate_digest.clone()), + statement: Statement::Valid(candidate_digest), signature: Signature(2), sender: AuthorityId(2), }; diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index f42eb987876a..6ff9f1d893c8 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -46,10 +46,8 @@ fn report_outcome_notify_works() { (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); - let mut message = Xcm(vec![TransferAsset { - assets: (Here, SEND_AMOUNT).into(), - beneficiary: sender.clone(), - }]); + let mut message = + Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); let call = pallet_test_notifier::Call::notification_received { query_id: 0, response: Default::default(), @@ -71,7 +69,7 @@ fn report_outcome_notify_works() { query_id: 0, max_weight: Weight::from_parts(1_000_000, 1_000_000), })])), - TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender.clone() }, + TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }, ]) ); let querier: MultiLocation = Here.into(); @@ -79,7 +77,7 @@ fn report_outcome_notify_works() { responder: MultiLocation::from(Parachain(PARA_ID)).into(), maybe_notify: Some((4, 2)), timeout: 100, - maybe_match_querier: Some(querier.clone().into()), + maybe_match_querier: Some(querier.into()), }; assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); @@ -123,10 +121,8 @@ fn report_outcome_works() { (ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); - let mut message = Xcm(vec![TransferAsset { - assets: (Here, SEND_AMOUNT).into(), - beneficiary: sender.clone(), - }]); + let mut message = + Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); new_test_ext_with_balances(balances).execute_with(|| { XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into_location(), 100).unwrap(); assert_eq!( @@ -137,7 +133,7 @@ fn report_outcome_works() { query_id: 0, max_weight: Weight::zero(), })])), - TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender.clone() }, + TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }, ]) ); let querier: MultiLocation = Here.into(); @@ -145,7 +141,7 @@ fn report_outcome_works() { responder: MultiLocation::from(Parachain(PARA_ID)).into(), maybe_notify: None, timeout: 100, - maybe_match_querier: Some(querier.clone().into()), + maybe_match_querier: Some(querier.into()), }; assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); @@ -187,13 +183,13 @@ fn custom_querier_works() { let querier: MultiLocation = (Parent, AccountId32 { network: None, id: ALICE.into() }).into(); - let r = TestNotifier::prepare_new_query(RuntimeOrigin::signed(ALICE), querier.clone()); + let r = TestNotifier::prepare_new_query(RuntimeOrigin::signed(ALICE), querier); assert_eq!(r, Ok(())); let status = QueryStatus::Pending { responder: MultiLocation::from(AccountId32 { network: None, id: ALICE.into() }).into(), maybe_notify: None, timeout: 100, - maybe_match_querier: Some(querier.clone().into()), + maybe_match_querier: Some(querier.into()), }; assert_eq!(crate::Queries::::iter().collect::>(), vec![(0, status)]); @@ -218,7 +214,7 @@ fn custom_querier_works() { RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier { origin: AccountId32 { network: None, id: ALICE.into() }.into(), query_id: 0, - expected_querier: querier.clone(), + expected_querier: querier, maybe_actual_querier: None, }), ); @@ -244,7 +240,7 @@ fn custom_querier_works() { RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier { origin: AccountId32 { network: None, id: ALICE.into() }.into(), query_id: 0, - expected_querier: querier.clone(), + expected_querier: querier, maybe_actual_querier: Some(MultiLocation::here()), }), ); @@ -293,7 +289,7 @@ fn send_works() { ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), ClearOrigin, buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: sender.clone() }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, ]); let versioned_dest = Box::new(RelayLocation::get().into()); @@ -303,7 +299,7 @@ fn send_works() { versioned_dest, versioned_message )); - let sent_message = Xcm(Some(DescendOrigin(sender.clone().try_into().unwrap())) + let sent_message = Xcm(Some(DescendOrigin(sender.try_into().unwrap())) .into_iter() .chain(message.0.clone().into_iter()) .collect()); @@ -337,7 +333,7 @@ fn send_fails_when_xcm_router_blocks() { let message = Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), buy_execution((Parent, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: sender.clone() }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, ]); assert_noop!( XcmPallet::send( @@ -367,7 +363,7 @@ fn teleport_assets_works() { assert_ok!(XcmPallet::teleport_assets( RuntimeOrigin::signed(ALICE), Box::new(RelayLocation::get().into()), - Box::new(dest.clone().into()), + Box::new(dest.into()), Box::new((Here, SEND_AMOUNT).into()), 0, )); @@ -410,7 +406,7 @@ fn limited_teleport_assets_works() { assert_ok!(XcmPallet::limited_teleport_assets( RuntimeOrigin::signed(ALICE), Box::new(RelayLocation::get().into()), - Box::new(dest.clone().into()), + Box::new(dest.into()), Box::new((Here, SEND_AMOUNT).into()), 0, WeightLimit::Limited(Weight::from_parts(5000, 5000)), @@ -454,7 +450,7 @@ fn unlimited_teleport_assets_works() { assert_ok!(XcmPallet::limited_teleport_assets( RuntimeOrigin::signed(ALICE), Box::new(RelayLocation::get().into()), - Box::new(dest.clone().into()), + Box::new(dest.into()), Box::new((Here, SEND_AMOUNT).into()), 0, WeightLimit::Unlimited, @@ -496,7 +492,7 @@ fn reserve_transfer_assets_works() { assert_ok!(XcmPallet::reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), - Box::new(dest.clone().into()), + Box::new(dest.into()), Box::new((Here, SEND_AMOUNT).into()), 0, )); @@ -543,7 +539,7 @@ fn limited_reserve_transfer_assets_works() { assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), - Box::new(dest.clone().into()), + Box::new(dest.into()), Box::new((Here, SEND_AMOUNT).into()), 0, WeightLimit::Limited(Weight::from_parts(5000, 5000)), @@ -591,7 +587,7 @@ fn unlimited_reserve_transfer_assets_works() { assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), - Box::new(dest.clone().into()), + Box::new(dest.into()), Box::new((Here, SEND_AMOUNT).into()), 0, WeightLimit::Unlimited, @@ -670,7 +666,7 @@ fn trapped_assets_can_be_claimed() { // This will make an error. Trap(0), // This would succeed, but we never get to it. - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]))), weight )); @@ -678,12 +674,12 @@ fn trapped_assets_can_be_claimed() { Junction::AccountId32 { network: None, id: ALICE.into() }.into(); let trapped = AssetTraps::::iter().collect::>(); let vma = VersionedMultiAssets::from(MultiAssets::from((Here, SEND_AMOUNT))); - let hash = BlakeTwo256::hash_of(&(source.clone(), vma.clone())); + let hash = BlakeTwo256::hash_of(&(source, vma.clone())); assert_eq!( last_events(2), vec![ RuntimeEvent::XcmPallet(crate::Event::AssetsTrapped { - hash: hash.clone(), + hash, origin: source, assets: vma }), @@ -704,7 +700,7 @@ fn trapped_assets_can_be_claimed() { Box::new(VersionedXcm::from(Xcm(vec![ ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, buy_execution((Here, SEND_AMOUNT)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, ]))), weight )); @@ -742,25 +738,22 @@ fn basic_subscription_works() { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()), + Box::new(remote.into()), )); assert_eq!( Queries::::iter().collect::>(), - vec![( - 0, - QueryStatus::VersionNotifier { origin: remote.clone().into(), is_active: false } - )] + vec![(0, QueryStatus::VersionNotifier { origin: remote.into(), is_active: false })] ); assert_eq!( VersionNotifiers::::iter().collect::>(), - vec![(XCM_VERSION, remote.clone().into(), 0)] + vec![(XCM_VERSION, remote.into(), 0)] ); assert_eq!( take_sent_xcm(), vec![( - remote.clone(), + remote, Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), ),] ); @@ -790,27 +783,27 @@ fn subscriptions_increment_id() { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()), + Box::new(remote.into()), )); let remote2: MultiLocation = Parachain(1001).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote2.clone().into()), + Box::new(remote2.into()), )); assert_eq!( take_sent_xcm(), vec![ ( - remote.clone(), + remote, Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), ), ( - remote2.clone(), + remote2, Xcm(vec![SubscribeVersion { query_id: 1, max_response_weight: Weight::zero() @@ -827,12 +820,12 @@ fn double_subscription_fails() { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()), + Box::new(remote.into()), )); assert_noop!( XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()) + Box::new(remote.into()) ), Error::::AlreadySubscribed, ); @@ -845,16 +838,16 @@ fn unsubscribe_works() { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()), + Box::new(remote.into()), )); assert_ok!(XcmPallet::force_unsubscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()) + Box::new(remote.into()) )); assert_noop!( XcmPallet::force_unsubscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()) + Box::new(remote.into()) ), Error::::NoSubscription, ); @@ -863,13 +856,13 @@ fn unsubscribe_works() { take_sent_xcm(), vec![ ( - remote.clone(), + remote, Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), ), - (remote.clone(), Xcm(vec![UnsubscribeVersion]),), + (remote, Xcm(vec![UnsubscribeVersion]),), ] ); }); @@ -886,7 +879,7 @@ fn subscription_side_works() { let message = Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]); let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote.clone(), message, hash, weight); + let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); let instr = QueryResponse { @@ -895,7 +888,7 @@ fn subscription_side_works() { response: Response::Version(1), querier: None, }; - assert_eq!(take_sent_xcm(), vec![(remote.clone(), Xcm(vec![instr]))]); + assert_eq!(take_sent_xcm(), vec![(remote, Xcm(vec![instr]))]); // A runtime upgrade which doesn't alter the version sends no notifications. CurrentMigration::::put(VersionMigrationStage::default()); @@ -914,7 +907,7 @@ fn subscription_side_works() { response: Response::Version(2), querier: None, }; - assert_eq!(take_sent_xcm(), vec![(remote.clone(), Xcm(vec![instr]))]); + assert_eq!(take_sent_xcm(), vec![(remote, Xcm(vec![instr]))]); }); } @@ -1004,7 +997,7 @@ fn subscriber_side_subscription_works() { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), - Box::new(remote.clone().into()), + Box::new(remote.into()), )); take_sent_xcm(); @@ -1021,7 +1014,7 @@ fn subscriber_side_subscription_works() { }, ]); let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote.clone(), message, hash, weight); + let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); assert_eq!(take_sent_xcm(), vec![]); @@ -1039,7 +1032,7 @@ fn subscriber_side_subscription_works() { }, ]); let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote.clone(), message, hash, weight); + let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); // This message can now be sent to remote as it's v2. @@ -1068,7 +1061,7 @@ fn auto_subscription_works() { ); assert_eq!(XcmPallet::wrap_version(&remote_v2, msg_v3.clone()), Err(())); - let expected = vec![(remote_v2.clone().into(), 2)]; + let expected = vec![(remote_v2.into(), 2)]; assert_eq!(VersionDiscoveryQueue::::get().into_inner(), expected); assert_eq!( @@ -1077,14 +1070,14 @@ fn auto_subscription_works() { ); assert_eq!(XcmPallet::wrap_version(&remote_v3, msg_v3.clone()), Err(())); - let expected = vec![(remote_v2.clone().into(), 2), (remote_v3.clone().into(), 2)]; + let expected = vec![(remote_v2.into(), 2), (remote_v3.into(), 2)]; assert_eq!(VersionDiscoveryQueue::::get().into_inner(), expected); XcmPallet::on_initialize(1); assert_eq!( take_sent_xcm(), vec![( - remote_v3.clone(), + remote_v3, Xcm(vec![SubscribeVersion { query_id: 0, max_response_weight: Weight::zero() }]), )] ); @@ -1102,7 +1095,7 @@ fn auto_subscription_works() { }, ]); let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote_v3.clone(), message, hash, weight); + let r = XcmExecutor::::execute_xcm(remote_v3, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); // V2 messages can be sent to remote_v3 under XCM v3. @@ -1120,7 +1113,7 @@ fn auto_subscription_works() { assert_eq!( take_sent_xcm(), vec![( - remote_v2.clone(), + remote_v2, Xcm(vec![SubscribeVersion { query_id: 1, max_response_weight: Weight::zero() }]), )] ); @@ -1138,7 +1131,7 @@ fn auto_subscription_works() { }, ]); let hash = fake_message_hash(&message); - let r = XcmExecutor::::execute_xcm(remote_v2.clone(), message, hash, weight); + let r = XcmExecutor::::execute_xcm(remote_v2, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); // v3 messages cannot be sent to remote_v2... diff --git a/xcm/xcm-builder/src/asset_conversion.rs b/xcm/xcm-builder/src/asset_conversion.rs index 2fe26e8cd1e3..a246436a9d6d 100644 --- a/xcm/xcm-builder/src/asset_conversion.rs +++ b/xcm/xcm-builder/src/asset_conversion.rs @@ -286,11 +286,11 @@ mod tests { struct ClassInstanceIdConverter; impl MaybeEquivalence for ClassInstanceIdConverter { fn convert(value: &AssetInstance) -> Option { - value.clone().try_into().ok() + (*value).try_into().ok() } fn convert_back(value: &ClassInstanceId) -> Option { - Some(AssetInstance::from(value.clone())) + Some(AssetInstance::from(*value)) } } diff --git a/xcm/xcm-builder/src/tests/assets.rs b/xcm/xcm-builder/src/tests/assets.rs index dbcb731a1bda..e1d61a9d1c6d 100644 --- a/xcm/xcm-builder/src/tests/assets.rs +++ b/xcm/xcm-builder/src/tests/assets.rs @@ -147,10 +147,7 @@ fn reserve_transfer_should_work() { let message = Xcm(vec![TransferReserveAsset { assets: (Here, 100u128).into(), dest: Parachain(2).into(), - xcm: Xcm::<()>(vec![DepositAsset { - assets: AllCounted(1).into(), - beneficiary: three.clone(), - }]), + xcm: Xcm::<()>(vec![DepositAsset { assets: AllCounted(1).into(), beneficiary: three }]), }]); let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm( diff --git a/xcm/xcm-builder/src/tests/bridging/mod.rs b/xcm/xcm-builder/src/tests/bridging/mod.rs index 2b5de62975ee..45630dbfc248 100644 --- a/xcm/xcm-builder/src/tests/bridging/mod.rs +++ b/xcm/xcm-builder/src/tests/bridging/mod.rs @@ -155,7 +155,7 @@ fn price( d: &InteriorMultiLocation, m: &Xcm<()>, ) -> Result { - Ok(validate_export::(n, c, s.clone(), d.clone(), m.clone())?.1) + Ok(validate_export::(n, c, *s, *d, m.clone())?.1) } fn deliver( @@ -205,7 +205,7 @@ impl, Remote: Get, RemoteExporter: ExportXcm> S // though it is `Remote`. ExecutorUniversalLocation::set(Remote::get()); let origin = Local::get().relative_to(&Remote::get()); - AllowUnpaidFrom::set(vec![origin.clone()]); + AllowUnpaidFrom::set(vec![origin]); set_exporter_override(price::, deliver::); // The we execute it: let mut id = fake_id(); @@ -255,7 +255,7 @@ impl, Remote: Get, RemoteExporter: ExportXcm> S // though it is `Remote`. ExecutorUniversalLocation::set(Remote::get()); let origin = Local::get().relative_to(&Remote::get()); - AllowPaidFrom::set(vec![origin.clone()]); + AllowPaidFrom::set(vec![origin]); set_exporter_override(price::, deliver::); // Then we execute it: let mut id = fake_id(); diff --git a/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs b/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 6870413c38d5..7593ea5f17c0 100644 --- a/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs +++ b/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs @@ -113,7 +113,7 @@ fn sending_to_bridged_chain_without_funds_fails() { let dest: MultiLocation = (Parent, Parent, Remote::get()).into(); // Routing won't work if we don't have enough funds. assert_eq!( - send_xcm::(dest.clone(), Xcm(vec![Trap(1)])), + send_xcm::(dest, Xcm(vec![Trap(1)])), Err(SendError::Transport("Error executing")), ); } @@ -188,7 +188,7 @@ fn sending_to_parachain_of_bridged_chain_without_funds_fails() { let dest: MultiLocation = (Parent, Parent, Remote::get(), Parachain(100)).into(); // Routing won't work if we don't have enough funds. assert_eq!( - send_xcm::(dest.clone(), Xcm(vec![Trap(1)])), + send_xcm::(dest, Xcm(vec![Trap(1)])), Err(SendError::Transport("Error executing")), ); } diff --git a/xcm/xcm-builder/src/tests/mock.rs b/xcm/xcm-builder/src/tests/mock.rs index aea780b84367..9be034596f43 100644 --- a/xcm/xcm-builder/src/tests/mock.rs +++ b/xcm/xcm-builder/src/tests/mock.rs @@ -254,7 +254,7 @@ impl TransactAsset for TestAssetTransactor { who: &MultiLocation, _context: &XcmContext, ) -> Result<(), XcmError> { - add_asset(who.clone(), what.clone()); + add_asset(*who, what.clone()); Ok(()) } @@ -515,7 +515,7 @@ pub fn disallow_unlock( pub fn unlock_allowed(unlocker: &MultiLocation, asset: &MultiAsset, owner: &MultiLocation) -> bool { ALLOWED_UNLOCKS.with(|l| { l.borrow_mut() - .get(&(owner.clone(), unlocker.clone())) + .get(&(*owner, *unlocker)) .map_or(false, |x| x.contains_asset(asset)) }) } @@ -550,7 +550,7 @@ pub fn request_unlock_allowed( ) -> bool { ALLOWED_REQUEST_UNLOCKS.with(|l| { l.borrow_mut() - .get(&(owner.clone(), locker.clone())) + .get(&(*owner, *locker)) .map_or(false, |x| x.contains_asset(asset)) }) } @@ -560,11 +560,11 @@ impl Enact for TestTicket { fn enact(self) -> Result<(), LockError> { match &self.0 { LockTraceItem::Lock { unlocker, asset, owner } => - allow_unlock(unlocker.clone(), asset.clone(), owner.clone()), + allow_unlock(*unlocker, asset.clone(), *owner), LockTraceItem::Unlock { unlocker, asset, owner } => - disallow_unlock(unlocker.clone(), asset.clone(), owner.clone()), + disallow_unlock(*unlocker, asset.clone(), *owner), LockTraceItem::Reduce { locker, asset, owner } => - disallow_request_unlock(locker.clone(), asset.clone(), owner.clone()), + disallow_request_unlock(*locker, asset.clone(), *owner), _ => {}, } LOCK_TRACE.with(move |l| l.borrow_mut().push(self.0)); @@ -583,7 +583,7 @@ impl AssetLock for TestAssetLock { asset: MultiAsset, owner: MultiLocation, ) -> Result { - ensure!(assets(owner.clone()).contains_asset(&asset), LockError::AssetNotOwned); + ensure!(assets(owner).contains_asset(&asset), LockError::AssetNotOwned); Ok(TestTicket(LockTraceItem::Lock { unlocker, asset, owner })) } @@ -601,7 +601,7 @@ impl AssetLock for TestAssetLock { asset: MultiAsset, owner: MultiLocation, ) -> Result<(), LockError> { - allow_request_unlock(locker.clone(), asset.clone(), owner.clone()); + allow_request_unlock(locker, asset.clone(), owner); let item = LockTraceItem::Note { locker, asset, owner }; LOCK_TRACE.with(move |l| l.borrow_mut().push(item)); Ok(()) diff --git a/xcm/xcm-builder/src/tests/transacting.rs b/xcm/xcm-builder/src/tests/transacting.rs index ccb2c23d19fd..743ad7039f7f 100644 --- a/xcm/xcm-builder/src/tests/transacting.rs +++ b/xcm/xcm-builder/src/tests/transacting.rs @@ -66,11 +66,11 @@ fn transacting_should_refund_weight() { #[test] fn paid_transacting_should_refund_payment_for_unused_weight() { let one: MultiLocation = AccountIndex64 { index: 1, network: None }.into(); - AllowPaidFrom::set(vec![one.clone()]); + AllowPaidFrom::set(vec![one]); add_asset(AccountIndex64 { index: 1, network: None }, (Parent, 200u128)); WeightPrice::set((Parent.into(), 1_000_000_000_000, 1024 * 1024)); - let origin = one.clone(); + let origin = one; let fees = (Parent, 200u128).into(); let message = Xcm::(vec![ WithdrawAsset((Parent, 200u128).into()), // enough for 200 units of weight. @@ -84,7 +84,7 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { .into(), }, RefundSurplus, - DepositAsset { assets: AllCounted(1).into(), beneficiary: one.clone() }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: one }, ]); let hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(100, 100); diff --git a/xcm/xcm-builder/src/tests/version_subscriptions.rs b/xcm/xcm-builder/src/tests/version_subscriptions.rs index 434c92202c83..44ab7d34c51b 100644 --- a/xcm/xcm-builder/src/tests/version_subscriptions.rs +++ b/xcm/xcm-builder/src/tests/version_subscriptions.rs @@ -59,7 +59,7 @@ fn version_subscription_instruction_should_work() { let hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(20, 20); let r = XcmExecutor::::execute_xcm_in_credit( - origin.clone(), + origin, message, hash, weight_limit, @@ -124,7 +124,7 @@ fn version_unsubscription_instruction_should_work() { let hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(20, 20); let r = XcmExecutor::::execute_xcm_in_credit( - origin.clone(), + origin, message, hash, weight_limit, diff --git a/xcm/xcm-simulator/fuzzer/src/parachain.rs b/xcm/xcm-simulator/fuzzer/src/parachain.rs index 26379ed8dc8e..3d0b1c82f691 100644 --- a/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -238,7 +238,7 @@ pub mod mock_msg_queue { Ok(xcm) => { let location = MultiLocation::new(1, X1(Parachain(sender.into()))); match T::XcmExecutor::execute_xcm(location, xcm, message_hash, max_weight) { - Outcome::Error(e) => (Err(e.clone()), Event::Fail(Some(hash), e)), + Outcome::Error(e) => (Err(e), Event::Fail(Some(hash), e)), Outcome::Complete(w) => (Ok(w), Event::Success(Some(hash))), // As far as the caller is concerned, this was dispatched without error, so // we just report the weight used. @@ -262,7 +262,7 @@ pub mod mock_msg_queue { let _ = XcmpMessageFormat::decode(&mut data_ref) .expect("Simulator encodes with versioned xcm format; qed"); - let mut remaining_fragments = &data_ref[..]; + let mut remaining_fragments = data_ref; while !remaining_fragments.is_empty() { if let Ok(xcm) = VersionedXcm::::decode(&mut remaining_fragments) From d73503cc2351ffec047a4912ecdb3e1eab5f46aa Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 16 Aug 2023 16:26:41 +0200 Subject: [PATCH 26/45] [Polkadot] 28 days as conviction voting period (#7595) * Use 28 days for conviction vote locking Signed-off-by: Oliver Tale-Yazdi * Remove unused dependency profile Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- Cargo.toml | 1 - runtime/polkadot/src/governance/mod.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44cf027e35b3..dc42123a9f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -166,7 +166,6 @@ crossbeam-deque = { opt-level = 3 } crypto-mac = { opt-level = 3 } curve25519-dalek = { opt-level = 3 } ed25519-dalek = { opt-level = 3 } -flate2 = { opt-level = 3 } futures-channel = { opt-level = 3 } hash-db = { opt-level = 3 } hashbrown = { opt-level = 3 } diff --git a/runtime/polkadot/src/governance/mod.rs b/runtime/polkadot/src/governance/mod.rs index 4cd9eeacd845..870d143dbaf0 100644 --- a/runtime/polkadot/src/governance/mod.rs +++ b/runtime/polkadot/src/governance/mod.rs @@ -35,7 +35,7 @@ mod tracks; pub use tracks::TracksInfo; parameter_types! { - pub const VoteLockingPeriod: BlockNumber = 7 * DAYS; + pub const VoteLockingPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1); } impl pallet_conviction_voting::Config for Runtime { From 91e127953c9bb51f6bc2f8779376fc672e995c30 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Wed, 16 Aug 2023 17:31:57 -0300 Subject: [PATCH 27/45] bump zombienet to `v1.3.65` (#7631) * bump zombienet version * remove workaround, zombienet collators cmd bug fixed in latest version * add env var to run in ci * add env var to run in ci --- .gitlab-ci.yml | 6 +++--- .../test-parachains/adder/collator/src/main.rs | 6 +----- .../test-parachains/undying/collator/src/main.rs | 6 +----- scripts/ci/gitlab/pipeline/zombienet.yml | 13 ++++++++++++- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5a84bbfeba85..b2d91e61da94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,12 +33,12 @@ variables: GIT_STRATEGY: fetch GIT_DEPTH: 100 CI_SERVER_NAME: "GitLab CI" - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] BUILDAH_IMAGE: "quay.io/buildah/stable:v1.29" BUILDAH_COMMAND: "buildah --storage-driver overlay2" DOCKER_OS: "debian:stretch" ARCH: "x86_64" - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.55" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.65" default: cache: {} @@ -233,7 +233,7 @@ include: file: /common/timestamp.yml - project: parity/infrastructure/ci_cd/shared ref: main - file: /common/ci-unified.yml + file: /common/ci-unified.yml #### stage: .post diff --git a/parachain/test-parachains/adder/collator/src/main.rs b/parachain/test-parachains/adder/collator/src/main.rs index de1b37b50dab..ac135a2702a5 100644 --- a/parachain/test-parachains/adder/collator/src/main.rs +++ b/parachain/test-parachains/adder/collator/src/main.rs @@ -21,7 +21,6 @@ use polkadot_node_primitives::CollationGenerationConfig; use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage}; use polkadot_primitives::Id as ParaId; use sc_cli::{Error as SubstrateCliError, SubstrateCli}; -use sc_service::Role; use sp_core::hexdisplay::HexDisplay; use test_parachain_adder_collator::Collator; @@ -54,12 +53,9 @@ fn main() -> Result<()> { ) })?; - runner.run_node_until_exit(|mut config| async move { + runner.run_node_until_exit(|config| async move { let collator = Collator::new(); - // Zombienet is spawning all collators currently with the same CLI, this means it - // sets `--validator` and this is wrong here. - config.role = Role::Full; let full_node = polkadot_service::build_full( config, polkadot_service::NewFullParams { diff --git a/parachain/test-parachains/undying/collator/src/main.rs b/parachain/test-parachains/undying/collator/src/main.rs index 79420dbbc9d5..ac889d7a00e0 100644 --- a/parachain/test-parachains/undying/collator/src/main.rs +++ b/parachain/test-parachains/undying/collator/src/main.rs @@ -21,7 +21,6 @@ use polkadot_node_primitives::CollationGenerationConfig; use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage}; use polkadot_primitives::Id as ParaId; use sc_cli::{Error as SubstrateCliError, SubstrateCli}; -use sc_service::Role; use sp_core::hexdisplay::HexDisplay; use test_parachain_undying_collator::Collator; @@ -54,12 +53,9 @@ fn main() -> Result<()> { ) })?; - runner.run_node_until_exit(|mut config| async move { + runner.run_node_until_exit(|config| async move { let collator = Collator::new(cli.run.pov_size, cli.run.pvf_complexity); - // Zombienet is spawning all collators currently with the same CLI, this means it - // sets `--validator` and this is wrong here. - config.role = Role::Full; let full_node = polkadot_service::build_full( config, polkadot_service::NewFullParams { diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml index cc4a7eb2ccc1..d7a12ad0723f 100644 --- a/scripts/ci/gitlab/pipeline/zombienet.yml +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -12,6 +12,7 @@ zombienet-tests-parachains-smoke-test: - job: publish-malus-image - job: publish-test-collators-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/smoke" before_script: - echo "Zombie-net Tests Config" @@ -42,6 +43,7 @@ zombienet-tests-parachains-pvf: - job: publish-polkadot-debug-image - job: publish-test-collators-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" before_script: - echo "Zombie-net Tests Config" @@ -73,6 +75,7 @@ zombienet-tests-parachains-disputes: - job: publish-test-collators-image - job: publish-malus-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" before_script: - echo "Zombie-net Tests Config" @@ -104,6 +107,7 @@ zombienet-tests-parachains-disputes-garbage-candidate: - job: publish-test-collators-image - job: publish-malus-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" before_script: - echo "Zombie-net Tests Config" @@ -135,6 +139,7 @@ zombienet-tests-parachains-disputes-past-session: - job: publish-test-collators-image - job: publish-malus-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" before_script: - echo "Zombie-net Tests Config" @@ -167,6 +172,7 @@ zombienet-test-parachains-upgrade-smoke-test: - job: publish-malus-image - job: publish-test-collators-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/smoke" before_script: - echo "ZombieNet Tests Config" @@ -197,6 +203,7 @@ zombienet-tests-misc-paritydb: - job: publish-test-collators-image artifacts: true variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/misc" before_script: - echo "Zombie-net Tests Config" @@ -227,7 +234,8 @@ zombienet-tests-misc-upgrade-node: - job: build-linux-stable artifacts: true variables: - GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/misc" + RUN_IN_CONTAINER: "1" + GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/misc" before_script: - echo "Zombie-net Tests Config" - echo "${ZOMBIENET_IMAGE_NAME}" @@ -258,6 +266,7 @@ zombienet-tests-malus-dispute-valid: - job: publish-malus-image - job: publish-test-collators-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/node/malus/integrationtests" before_script: - echo "Zombie-net Tests Config" @@ -288,6 +297,7 @@ zombienet-tests-deregister-register-validator: - job: publish-polkadot-debug-image artifacts: true variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/smoke" before_script: - echo "Zombie-net Tests Config" @@ -315,6 +325,7 @@ zombienet-tests-beefy-and-mmr: needs: - job: publish-polkadot-debug-image variables: + RUN_IN_CONTAINER: "1" GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/functional" before_script: - echo "Zombie-net Tests Config" From d74c60b6489f31f437edb1a19de0d0f6b8ad432e Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 17 Aug 2023 15:57:38 +1000 Subject: [PATCH 28/45] cli: remove deprecated try-runtime subcommand (also companion for #14731) (#7599) * remove try-runtime-cli * fix ci pipeline * fix link * remove chain var * build runtime with try-runtime feature * use main branch * pin to commit * fix build * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 368 +++++++++++++-------------- cli/src/cli.rs | 9 +- cli/src/command.rs | 64 +---- scripts/ci/gitlab/pipeline/check.yml | 6 +- 4 files changed, 194 insertions(+), 253 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50e6128a7f0a..9073a8fb6297 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -778,7 +778,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "hash-db", "log", @@ -2831,7 +2831,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", ] @@ -2854,7 +2854,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-support-procedural", @@ -2879,7 +2879,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "Inflector", "array-bytes", @@ -2927,7 +2927,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2938,7 +2938,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2955,7 +2955,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -2984,7 +2984,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-recursion", "futures", @@ -3005,7 +3005,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "aquamarine", "bitflags 1.3.2", @@ -3043,7 +3043,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "Inflector", "cfg-expr", @@ -3061,7 +3061,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3073,7 +3073,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro2", "quote", @@ -3083,7 +3083,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-executive", @@ -3110,7 +3110,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -3123,7 +3123,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "cfg-if", "frame-support", @@ -3142,7 +3142,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -3157,7 +3157,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "sp-api", @@ -3166,7 +3166,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "parity-scale-codec", @@ -3341,7 +3341,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "chrono", "frame-election-provider-support", @@ -5345,7 +5345,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "log", @@ -5364,7 +5364,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "anyhow", "jsonrpsee", @@ -5901,7 +5901,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5916,7 +5916,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -5932,7 +5932,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -5946,7 +5946,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5970,7 +5970,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "aquamarine", "docify", @@ -5992,7 +5992,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -6011,7 +6011,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6026,7 +6026,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -6045,7 +6045,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -6069,7 +6069,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6087,7 +6087,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6106,7 +6106,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6123,7 +6123,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6140,7 +6140,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6158,7 +6158,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6181,7 +6181,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6194,7 +6194,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6213,7 +6213,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "docify", "frame-benchmarking", @@ -6232,7 +6232,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6255,7 +6255,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6271,7 +6271,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6291,7 +6291,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6325,7 +6325,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6344,7 +6344,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6361,7 +6361,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6377,7 +6377,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6393,7 +6393,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -6412,7 +6412,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6432,7 +6432,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6443,7 +6443,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -6460,7 +6460,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6484,7 +6484,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6501,7 +6501,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6516,7 +6516,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6534,7 +6534,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6549,7 +6549,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6568,7 +6568,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "docify", "frame-benchmarking", @@ -6586,7 +6586,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -6607,7 +6607,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6623,7 +6623,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6641,7 +6641,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6664,7 +6664,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6675,7 +6675,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "log", "sp-arithmetic", @@ -6684,7 +6684,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "sp-api", @@ -6693,7 +6693,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6710,7 +6710,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6725,7 +6725,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6743,7 +6743,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6762,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-support", "frame-system", @@ -6778,7 +6778,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6794,7 +6794,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6806,7 +6806,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6823,7 +6823,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6838,7 +6838,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6854,7 +6854,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6869,7 +6869,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-benchmarking", "frame-support", @@ -10031,7 +10031,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "log", "sp-core", @@ -10042,7 +10042,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "futures", @@ -10070,7 +10070,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "futures-timer", @@ -10093,7 +10093,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10108,7 +10108,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10127,7 +10127,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10138,7 +10138,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "chrono", @@ -10177,7 +10177,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "fnv", "futures", @@ -10203,7 +10203,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "hash-db", "kvdb", @@ -10229,7 +10229,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "futures", @@ -10254,7 +10254,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "fork-tree", @@ -10290,7 +10290,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "jsonrpsee", @@ -10312,7 +10312,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "async-channel", @@ -10346,7 +10346,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "jsonrpsee", @@ -10365,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10378,7 +10378,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ahash 0.8.3", "array-bytes", @@ -10419,7 +10419,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "finality-grandpa", "futures", @@ -10439,7 +10439,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "futures", @@ -10462,7 +10462,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -10484,7 +10484,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10496,7 +10496,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "anyhow", "cfg-if", @@ -10513,7 +10513,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ansi_term", "futures", @@ -10529,7 +10529,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -10543,7 +10543,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "async-channel", @@ -10584,7 +10584,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-channel", "cid", @@ -10604,7 +10604,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "bitflags 1.3.2", @@ -10621,7 +10621,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ahash 0.8.3", "futures", @@ -10639,7 +10639,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "async-channel", @@ -10660,7 +10660,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "async-channel", @@ -10694,7 +10694,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "futures", @@ -10712,7 +10712,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "bytes", @@ -10746,7 +10746,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10755,7 +10755,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "jsonrpsee", @@ -10786,7 +10786,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10805,7 +10805,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "http", "jsonrpsee", @@ -10820,7 +10820,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "futures", @@ -10848,7 +10848,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "directories", @@ -10912,7 +10912,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "log", "parity-scale-codec", @@ -10923,7 +10923,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "clap 4.3.19", "fs4", @@ -10937,7 +10937,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10956,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "libc", @@ -10975,7 +10975,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "chrono", "futures", @@ -10994,7 +10994,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ansi_term", "atty", @@ -11023,7 +11023,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11034,7 +11034,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "futures", @@ -11060,7 +11060,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "futures", @@ -11076,7 +11076,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-channel", "futures", @@ -11660,7 +11660,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "hash-db", "log", @@ -11681,7 +11681,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "Inflector", "blake2", @@ -11695,7 +11695,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "scale-info", @@ -11708,7 +11708,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "integer-sqrt", "num-traits", @@ -11722,7 +11722,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "scale-info", @@ -11735,7 +11735,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "sp-api", "sp-inherents", @@ -11746,7 +11746,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "log", @@ -11764,7 +11764,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "futures", @@ -11779,7 +11779,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "parity-scale-codec", @@ -11796,7 +11796,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "parity-scale-codec", @@ -11815,7 +11815,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11834,7 +11834,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "finality-grandpa", "log", @@ -11852,7 +11852,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "scale-info", @@ -11864,7 +11864,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11911,7 +11911,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "blake2b_simd", "byteorder", @@ -11924,7 +11924,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "quote", "sp-core-hashing", @@ -11934,7 +11934,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11943,7 +11943,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro2", "quote", @@ -11953,7 +11953,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "environmental", "parity-scale-codec", @@ -11964,7 +11964,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "serde_json", "sp-api", @@ -11975,7 +11975,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11989,7 +11989,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "bytes", "ed25519", @@ -12014,7 +12014,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "lazy_static", "sp-core", @@ -12025,7 +12025,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -12037,7 +12037,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "thiserror", "zstd 0.12.4", @@ -12046,7 +12046,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -12057,7 +12057,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12075,7 +12075,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "scale-info", @@ -12089,7 +12089,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "sp-api", "sp-core", @@ -12099,7 +12099,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "backtrace", "lazy_static", @@ -12109,7 +12109,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "rustc-hash", "serde", @@ -12119,7 +12119,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "either", "hash256-std-hasher", @@ -12141,7 +12141,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12159,7 +12159,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "Inflector", "proc-macro-crate", @@ -12171,7 +12171,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "scale-info", @@ -12186,7 +12186,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -12200,7 +12200,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "hash-db", "log", @@ -12221,7 +12221,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -12245,12 +12245,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12263,7 +12263,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "parity-scale-codec", @@ -12276,7 +12276,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "sp-std", @@ -12288,7 +12288,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "sp-api", "sp-runtime", @@ -12297,7 +12297,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "parity-scale-codec", @@ -12312,7 +12312,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ahash 0.8.3", "hash-db", @@ -12335,7 +12335,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12352,7 +12352,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12363,7 +12363,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12376,7 +12376,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "parity-scale-codec", "scale-info", @@ -12617,12 +12617,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12641,7 +12641,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "hyper", "log", @@ -12653,7 +12653,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "jsonrpsee", @@ -12666,7 +12666,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -12683,7 +12683,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "array-bytes", "async-trait", @@ -12709,7 +12709,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12719,7 +12719,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12730,7 +12730,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "ansi_term", "build-helper", @@ -13638,7 +13638,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#e53cf32cce1f1f9416e09183b2b0dbdb0a50367d" +source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" dependencies = [ "async-trait", "clap 4.3.19", diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 696d381962b6..66205902b79d 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -55,12 +55,9 @@ pub enum Subcommand { /// capabilities of running a validator. HostPerfCheck, - /// Try some command against runtime state. - #[cfg(feature = "try-runtime")] - TryRuntime(try_runtime_cli::TryRuntimeCmd), - - /// Try some command against runtime state. Note: `try-runtime` feature must be enabled. - #[cfg(not(feature = "try-runtime"))] + /// Try-runtime has migrated to a standalone CLI + /// (). The subcommand exists as a stub and + /// deprecation notice. It will be removed entirely some time after Janurary 2024. TryRuntime, /// Key management CLI utilities diff --git a/cli/src/command.rs b/cli/src/command.rs index dd76ed558695..0fbeafb99a07 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -531,68 +531,12 @@ pub fn run() -> Result<()> { }, Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), #[cfg(feature = "try-runtime")] - Some(Subcommand::TryRuntime(cmd)) => { - use sc_service::TaskManager; - use try_runtime_cli::block_building_info::timestamp_with_babe_info; - - let runner = cli.create_runner(cmd)?; - let chain_spec = &runner.config().chain_spec; - set_default_ss58_version(chain_spec); - - let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry); - let task_manager = TaskManager::new(runner.config().tokio_handle.clone(), *registry) - .map_err(|e| Error::SubstrateService(sc_service::Error::Prometheus(e)))?; - - ensure_dev(chain_spec).map_err(Error::Other)?; - - #[cfg(feature = "kusama-native")] - if chain_spec.is_kusama() { - return runner.async_run(|_| { - Ok(( - cmd.run::( - Some(timestamp_with_babe_info(service::kusama_runtime_constants::time::MILLISECS_PER_BLOCK)) - ) - .map_err(Error::SubstrateCli), - task_manager, - )) - }) - } - - #[cfg(feature = "westend-native")] - if chain_spec.is_westend() { - return runner.async_run(|_| { - Ok(( - cmd.run::( - Some(timestamp_with_babe_info(service::westend_runtime_constants::time::MILLISECS_PER_BLOCK)) - ) - .map_err(Error::SubstrateCli), - task_manager, - )) - }) - } - // else we assume it is polkadot. - #[cfg(feature = "polkadot-native")] - { - return runner.async_run(|_| { - Ok(( - cmd.run::( - Some(timestamp_with_babe_info(service::polkadot_runtime_constants::time::MILLISECS_PER_BLOCK)) - ) - .map_err(Error::SubstrateCli), - task_manager, - )) - }) - } - #[cfg(not(feature = "polkadot-native"))] - panic!("No runtime feature (polkadot, kusama, westend, rococo) is enabled") - }, + Some(Subcommand::TryRuntime) => Err(try_runtime_cli::DEPRECATION_NOTICE.to_owned().into()), #[cfg(not(feature = "try-runtime"))] - Some(Subcommand::TryRuntime) => Err(Error::Other( - "TryRuntime wasn't enabled when building the node. \ + Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \ You can enable it with `--features try-runtime`." - .into(), - ) - .into()), + .to_owned() + .into()), Some(Subcommand::ChainInfo(cmd)) => { let runner = cli.create_runner(cmd)?; Ok(runner.sync_run(|config| cmd.run::(&config))?) diff --git a/scripts/ci/gitlab/pipeline/check.yml b/scripts/ci/gitlab/pipeline/check.yml index a9076c9318cd..9b2ad5e73833 100644 --- a/scripts/ci/gitlab/pipeline/check.yml +++ b/scripts/ci/gitlab/pipeline/check.yml @@ -62,10 +62,10 @@ check-try-runtime: - | export RUST_LOG=remote-ext=debug,runtime=debug echo "---------- Running try-runtime for ${NETWORK} ----------" - time cargo build --release --locked -p "$NETWORK"-runtime - time cargo run --locked --release --features try-runtime try-runtime \ + time cargo install --locked --git https://github.com/paritytech/try-runtime-cli --rev a93c9b5abe5d31a4cf1936204f7e5c489184b521 + time cargo build --release --locked -p "$NETWORK"-runtime --features try-runtime + time try-runtime \ --runtime ./target/release/wbuild/"$NETWORK"-runtime/target/wasm32-unknown-unknown/release/"$NETWORK"_runtime.wasm \ - --chain=${NETWORK}-dev \ on-runtime-upgrade --checks=pre-and-post live --uri wss://${NETWORK}-try-runtime-node.parity-chains.parity.io:443 check-runtime-migration-polkadot: From eb7078cc9917f5696313ffb2b989572f2e5f4ec6 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 17 Aug 2023 13:06:39 +0200 Subject: [PATCH 29/45] Polkadot gets topic-based message IDs (#7301) * Polkadot gets topics * Formatting * Fixes --------- Co-authored-by: Keith Yeung --- runtime/polkadot/src/xcm_config.rs | 12 ++++++------ xcm/src/v3/junction.rs | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/runtime/polkadot/src/xcm_config.rs b/runtime/polkadot/src/xcm_config.rs index faae2e1d2619..b2e09b1453af 100644 --- a/runtime/polkadot/src/xcm_config.rs +++ b/runtime/polkadot/src/xcm_config.rs @@ -43,8 +43,8 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, - WeightInfoBounds, WithComputedOrigin, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::traits::WithOriginFilter; @@ -120,14 +120,14 @@ parameter_types! { /// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our /// individual routers. -pub type XcmRouter = ( +pub type XcmRouter = WithUniqueTopic<( // Only one router so far - use DMP to communicate with child parachains. ChildParachainRouter< Runtime, XcmPallet, ExponentialPrice, >, -); +)>; parameter_types! { pub const Dot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); @@ -153,7 +153,7 @@ match_types! { } /// The barriers one of which must be passed for an XCM message to be executed. -pub type Barrier = ( +pub type Barrier = TrailingSetTopicAsId<( // Weight that is paid for may be consumed. TakeWeightCredit, // Expected responses are OK. @@ -170,7 +170,7 @@ pub type Barrier = ( UniversalLocation, ConstU32<8>, >, -); +)>; /// A call filter for the XCM Transact instruction. This is a temporary measure until we /// properly account for proof size weights. diff --git a/xcm/src/v3/junction.rs b/xcm/src/v3/junction.rs index ae66e2b33364..b5dd5bc7c88f 100644 --- a/xcm/src/v3/junction.rs +++ b/xcm/src/v3/junction.rs @@ -288,6 +288,7 @@ pub enum Junction { /// An instanced, indexed pallet that forms a constituent part of the context. /// /// Generally used when the context is a Frame-based chain. + // TODO XCMv4 inner should be `Compact`. PalletInstance(u8), /// A non-descript index within the context location. /// From 046c43b97e46bc843fab277a497504275a5f5407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 17 Aug 2023 13:26:44 +0200 Subject: [PATCH 30/45] Companion for Substrate#14612 (#7536) * Companion for reworking the storage transaction cache * Cargo lock * Fixes * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 372 +++++++++--------- node/service/Cargo.toml | 1 - node/service/src/lib.rs | 14 +- utils/staking-miner/Cargo.toml | 2 +- utils/staking-miner/src/dry_run.rs | 2 +- utils/staking-miner/src/emergency_solution.rs | 2 +- utils/staking-miner/src/main.rs | 11 +- utils/staking-miner/src/monitor.rs | 2 +- utils/staking-miner/src/prelude.rs | 4 +- 9 files changed, 200 insertions(+), 210 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9073a8fb6297..0cf0541fa5f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -778,7 +778,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "hash-db", "log", @@ -2831,7 +2831,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", ] @@ -2854,7 +2854,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-support-procedural", @@ -2879,7 +2879,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "Inflector", "array-bytes", @@ -2927,7 +2927,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2938,7 +2938,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2955,7 +2955,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -2984,7 +2984,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-recursion", "futures", @@ -2996,6 +2996,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-state-machine", "spinners", "substrate-rpc-client", "tokio", @@ -3005,7 +3006,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "aquamarine", "bitflags 1.3.2", @@ -3043,7 +3044,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "Inflector", "cfg-expr", @@ -3061,7 +3062,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3073,7 +3074,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro2", "quote", @@ -3083,7 +3084,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-executive", @@ -3110,7 +3111,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -3123,7 +3124,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "cfg-if", "frame-support", @@ -3142,7 +3143,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -3157,7 +3158,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "sp-api", @@ -3166,7 +3167,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "parity-scale-codec", @@ -3341,7 +3342,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "chrono", "frame-election-provider-support", @@ -5345,7 +5346,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "log", @@ -5364,7 +5365,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "anyhow", "jsonrpsee", @@ -5901,7 +5902,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -5916,7 +5917,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -5932,7 +5933,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -5946,7 +5947,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -5970,7 +5971,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "aquamarine", "docify", @@ -5992,7 +5993,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -6011,7 +6012,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6026,7 +6027,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -6045,7 +6046,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -6069,7 +6070,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6087,7 +6088,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6106,7 +6107,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6123,7 +6124,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6140,7 +6141,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6158,7 +6159,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6181,7 +6182,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6194,7 +6195,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6213,7 +6214,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "docify", "frame-benchmarking", @@ -6232,7 +6233,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6255,7 +6256,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6271,7 +6272,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6291,7 +6292,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6309,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6325,7 +6326,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6344,7 +6345,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6361,7 +6362,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6377,7 +6378,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6393,7 +6394,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -6412,7 +6413,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6432,7 +6433,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6443,7 +6444,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -6460,7 +6461,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6484,7 +6485,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6501,7 +6502,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6516,7 +6517,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6534,7 +6535,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6549,7 +6550,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6568,7 +6569,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "docify", "frame-benchmarking", @@ -6586,7 +6587,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -6607,7 +6608,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6623,7 +6624,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6641,7 +6642,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6664,7 +6665,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6675,7 +6676,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "log", "sp-arithmetic", @@ -6684,7 +6685,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "sp-api", @@ -6693,7 +6694,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6710,7 +6711,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6725,7 +6726,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6743,7 +6744,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6763,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", "frame-system", @@ -6778,7 +6779,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6794,7 +6795,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6806,7 +6807,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6823,7 +6824,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6838,7 +6839,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6854,7 +6855,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6869,7 +6870,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-benchmarking", "frame-support", @@ -8590,7 +8591,6 @@ dependencies = [ "sp-storage", "sp-timestamp", "sp-transaction-pool", - "sp-trie", "sp-version", "sp-weights", "substrate-prometheus-endpoint", @@ -10031,7 +10031,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "log", "sp-core", @@ -10042,7 +10042,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "futures", @@ -10070,7 +10070,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "futures-timer", @@ -10093,7 +10093,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10108,7 +10108,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10127,7 +10127,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10138,7 +10138,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "chrono", @@ -10177,7 +10177,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "fnv", "futures", @@ -10203,7 +10203,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "hash-db", "kvdb", @@ -10229,7 +10229,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "futures", @@ -10254,7 +10254,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "fork-tree", @@ -10290,7 +10290,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "jsonrpsee", @@ -10312,7 +10312,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "async-channel", @@ -10346,7 +10346,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "jsonrpsee", @@ -10365,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10378,7 +10378,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ahash 0.8.3", "array-bytes", @@ -10419,7 +10419,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "finality-grandpa", "futures", @@ -10439,7 +10439,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "futures", @@ -10462,7 +10462,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -10484,7 +10484,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10496,7 +10496,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "anyhow", "cfg-if", @@ -10513,7 +10513,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ansi_term", "futures", @@ -10529,7 +10529,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -10543,7 +10543,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "async-channel", @@ -10584,7 +10584,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-channel", "cid", @@ -10604,7 +10604,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "bitflags 1.3.2", @@ -10621,7 +10621,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ahash 0.8.3", "futures", @@ -10639,7 +10639,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "async-channel", @@ -10660,7 +10660,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "async-channel", @@ -10694,7 +10694,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "futures", @@ -10712,7 +10712,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "bytes", @@ -10746,7 +10746,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10755,7 +10755,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "jsonrpsee", @@ -10786,7 +10786,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10805,7 +10805,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "http", "jsonrpsee", @@ -10820,7 +10820,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "futures", @@ -10848,7 +10848,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "directories", @@ -10912,7 +10912,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "log", "parity-scale-codec", @@ -10923,7 +10923,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "clap 4.3.19", "fs4", @@ -10937,7 +10937,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10956,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "libc", @@ -10975,7 +10975,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "chrono", "futures", @@ -10994,7 +10994,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ansi_term", "atty", @@ -11023,7 +11023,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11034,7 +11034,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "futures", @@ -11060,7 +11060,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "futures", @@ -11076,7 +11076,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-channel", "futures", @@ -11660,7 +11660,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "hash-db", "log", @@ -11681,7 +11681,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "Inflector", "blake2", @@ -11695,7 +11695,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11708,7 +11708,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "integer-sqrt", "num-traits", @@ -11722,7 +11722,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11735,7 +11735,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "sp-api", "sp-inherents", @@ -11746,7 +11746,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "log", @@ -11764,7 +11764,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "futures", @@ -11779,7 +11779,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "parity-scale-codec", @@ -11796,7 +11796,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "parity-scale-codec", @@ -11815,7 +11815,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11834,7 +11834,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "finality-grandpa", "log", @@ -11852,7 +11852,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11864,7 +11864,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11911,7 +11911,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "blake2b_simd", "byteorder", @@ -11924,7 +11924,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "quote", "sp-core-hashing", @@ -11934,7 +11934,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11943,7 +11943,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro2", "quote", @@ -11953,7 +11953,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "environmental", "parity-scale-codec", @@ -11964,7 +11964,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "serde_json", "sp-api", @@ -11975,7 +11975,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11989,7 +11989,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "bytes", "ed25519", @@ -12014,7 +12014,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "lazy_static", "sp-core", @@ -12025,7 +12025,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -12037,7 +12037,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "thiserror", "zstd 0.12.4", @@ -12046,7 +12046,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -12057,7 +12057,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12075,7 +12075,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12089,7 +12089,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "sp-api", "sp-core", @@ -12099,7 +12099,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "backtrace", "lazy_static", @@ -12109,7 +12109,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "rustc-hash", "serde", @@ -12119,7 +12119,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "either", "hash256-std-hasher", @@ -12141,7 +12141,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12159,7 +12159,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "Inflector", "proc-macro-crate", @@ -12171,7 +12171,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12186,7 +12186,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -12200,7 +12200,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "hash-db", "log", @@ -12221,7 +12221,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", @@ -12245,12 +12245,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12263,7 +12263,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "parity-scale-codec", @@ -12276,7 +12276,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "sp-std", @@ -12288,7 +12288,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "sp-api", "sp-runtime", @@ -12297,7 +12297,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "parity-scale-codec", @@ -12312,7 +12312,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ahash 0.8.3", "hash-db", @@ -12335,7 +12335,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12352,7 +12352,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12363,7 +12363,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12376,7 +12376,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12476,9 +12476,9 @@ dependencies = [ "signal-hook", "signal-hook-tokio", "sp-core", - "sp-io", "sp-npos-elections", "sp-runtime", + "sp-state-machine", "sp-version", "sub-tokens", "thiserror", @@ -12617,12 +12617,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12641,7 +12641,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "hyper", "log", @@ -12653,7 +12653,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "jsonrpsee", @@ -12666,7 +12666,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -12683,7 +12683,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "array-bytes", "async-trait", @@ -12709,7 +12709,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12719,7 +12719,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12730,7 +12730,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "ansi_term", "build-helper", @@ -13638,7 +13638,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#aa70241b841b96a3cfd3580a3d378a6d3d01b1ec" +source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", "clap 4.3.19", diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml index 48e4633aa5e3..8cd9e4434bbd 100644 --- a/node/service/Cargo.toml +++ b/node/service/Cargo.toml @@ -53,7 +53,6 @@ sp-session = { git = "https://github.com/paritytech/substrate", branch = "master sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 3a850c46279a..2e46bf7329e2 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -56,7 +56,6 @@ use { sc_client_api::BlockBackend, sc_transaction_pool_api::OffchainTransactionPoolFactory, sp_core::traits::SpawnNamed, - sp_trie::PrefixedMemoryDB, }; use polkadot_node_subsystem_util::database::Database; @@ -475,7 +474,7 @@ fn new_partial( FullClient, FullBackend, ChainSelection, - sc_consensus::DefaultImportQueue, + sc_consensus::DefaultImportQueue, sc_transaction_pool::FullPool, ( impl Fn( @@ -1321,15 +1320,8 @@ macro_rules! chain_ops { pub fn new_chain_ops( config: &mut Configuration, jaeger_agent: Option, -) -> Result< - ( - Arc, - Arc, - sc_consensus::BasicQueue>, - TaskManager, - ), - Error, -> { +) -> Result<(Arc, Arc, sc_consensus::BasicQueue, TaskManager), Error> +{ config.keystore = service::config::KeystoreConfig::InMemory; if config.chain_spec.is_rococo() || diff --git a/utils/staking-miner/Cargo.toml b/utils/staking-miner/Cargo.toml index 05b0ddefaee9..f63425bb74e4 100644 --- a/utils/staking-miner/Cargo.toml +++ b/utils/staking-miner/Cargo.toml @@ -25,7 +25,7 @@ remote-externalities = { git = "https://github.com/paritytech/substrate", branch signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-npos-elections = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/utils/staking-miner/src/dry_run.rs b/utils/staking-miner/src/dry_run.rs index 4d09306a6ef5..7e46f630a1f5 100644 --- a/utils/staking-miner/src/dry_run.rs +++ b/utils/staking-miner/src/dry_run.rs @@ -120,7 +120,7 @@ macro_rules! dry_run_cmd_for { ($runtime:ident) => { paste::paste! { } else { Default::default() }; - let mut ext = crate::create_election_ext::(rpc.clone(), config.at, pallets).await?; + let mut ext = crate::create_election_ext::(rpc.clone(), config.at, pallets).await?; if config.force_snapshot { force_create_snapshot::(&mut ext)?; }; diff --git a/utils/staking-miner/src/emergency_solution.rs b/utils/staking-miner/src/emergency_solution.rs index 85487f7e40df..9ea9f90756e2 100644 --- a/utils/staking-miner/src/emergency_solution.rs +++ b/utils/staking-miner/src/emergency_solution.rs @@ -28,7 +28,7 @@ macro_rules! emergency_solution_cmd_for { ($runtime:ident) => { paste::paste! { ) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> { use $crate::[<$runtime _runtime_exports>]::*; - let mut ext = crate::create_election_ext::(client, config.at, vec![]).await?; + let mut ext = crate::create_election_ext::(client, config.at, vec![]).await?; let raw_solution = crate::mine_with::(&config.solver, &mut ext, false)?; ext.execute_with(|| { diff --git a/utils/staking-miner/src/main.rs b/utils/staking-miner/src/main.rs index a4c496998ed9..90b2c7366a1b 100644 --- a/utils/staking-miner/src/main.rs +++ b/utils/staking-miner/src/main.rs @@ -56,7 +56,6 @@ use runtime_versions::RuntimeVersions; use signal_hook::consts::signal::*; use signal_hook_tokio::Signals; use sp_npos_elections::BalancingConfig; -use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; use std::{ops::Deref, sync::Arc, time::Duration}; use tracing_subscriber::{fmt, EnvFilter}; @@ -295,15 +294,13 @@ frame_support::parameter_types! { /// Build the Ext at hash with all the data of `ElectionProviderMultiPhase` and any additional /// pallets. -async fn create_election_ext( +async fn create_election_ext( client: SharedRpcClient, - at: Option, + at: Option, additional: Vec, ) -> Result> where T: EPM::Config, - B: BlockT + DeserializeOwned, - B::Header: DeserializeOwned, { use frame_support::{storage::generator::StorageMap, traits::PalletInfo}; use sp_core::hashing::twox_128; @@ -312,7 +309,7 @@ where .expect("Pallet always has name; qed.") .to_string()]; pallets.extend(additional); - Builder::::new() + Builder::::new() .mode(Mode::Online(OnlineConfig { transport: Transport::Uri(client.uri().to_owned()), at, @@ -323,7 +320,7 @@ where })) .build() .await - .map_err(|why| Error::RemoteExternalities(why)) + .map_err(|why| Error::::RemoteExternalities(why)) .map(|rx| rx.inner_ext) } diff --git a/utils/staking-miner/src/monitor.rs b/utils/staking-miner/src/monitor.rs index e578e1c83544..607ecb6baa42 100644 --- a/utils/staking-miner/src/monitor.rs +++ b/utils/staking-miner/src/monitor.rs @@ -259,7 +259,7 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! { let _lock = submit_lock.lock().await; - let mut ext = match crate::create_election_ext::(rpc.clone(), Some(hash), vec![]).await { + let mut ext = match crate::create_election_ext::(rpc.clone(), Some(hash), vec![]).await { Ok(ext) => ext, Err(err) => { log::debug!(target: LOG_TARGET, "Skipping block {}; {}", at.number, err); diff --git a/utils/staking-miner/src/prelude.rs b/utils/staking-miner/src/prelude.rs index db029de881c9..fb701ece2384 100644 --- a/utils/staking-miner/src/prelude.rs +++ b/utils/staking-miner/src/prelude.rs @@ -32,6 +32,8 @@ pub type Nonce = core_primitives::Nonce; pub type Hash = core_primitives::Hash; /// The header type. We re-export it here, but we can easily get it from block as well. pub type Header = core_primitives::Header; +/// The block type. +pub type Block = core_primitives::Block; pub use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -44,7 +46,7 @@ pub const LOG_TARGET: &str = "staking-miner"; pub use pallet_election_provider_multi_phase as EPM; /// The externalities type. -pub type Ext = sp_io::TestExternalities; +pub type Ext = sp_state_machine::TestExternalities>; /// The key pair type being used. We "strongly" assume sr25519 for simplicity. pub type Pair = sp_core::sr25519::Pair; From 56d45fe3f34b895e6f94b05d6fea278497527cf5 Mon Sep 17 00:00:00 2001 From: eskimor Date: Thu, 17 Aug 2023 14:52:23 +0200 Subject: [PATCH 31/45] Parathreads Feature Branch (#6969) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First baby steps * Split scheduler into several modules * Towards a more modular approach for scheduling * move free_cores; IntoInterator -> BTreeMap * Move clear() * Move more functions out of scheduler * Change weight composition * More abstraction * Further refactor * clippy * fmt * fix test-runtime * Add parathreads pallet to construct_runtime! * Make all runtimes use (Parachains, Parathreads) scheduling * Delete commented out code * Remove parathreads scheduler from westend, rococo, and kusama * fix rococo, westend, and kusama config * Revert "fix rococo, westend, and kusama config" This reverts commit 3ef951d7d3b8f171ce3a2a42c948ac6742772bee. * Revert "Remove parathreads scheduler from westend, rococo, and kusama" This reverts commit 664bafab512f29546c72ba5ceb4255e41298dc3b. * Remove CoreIndex from free_cores * Remove unnecessary struct for parathreads * parathreads provider take 1 * Comment out parathread tests * Pop into lookahead * fmt * Fill lookahead with two entries for parachains * fmt * Current stage * Towards ab parathreads * no AB use * Make tests typecheck * quick hack to set scheduling lookahead to 1 * Fix scheduler tests * fix paras_inherent tests * misc * Update more of a test * cfg(test) * some cleanup * Undo paras_inherent changes * Adjust paras inherent tests * Undo changes to v2 primitives * Undo v2 mod changes to tests * minor * Remove parathreads assigner and pallet * minor * minor * more cleanup * fmt * minor * minor * minor * Remove on_new_session from assignment provider * Make adder collator integration test pass * disable failing unit tests * minor * minor * re-enable one unit test * minor * handle retries, add concluded para to pop interface * comment out unused code * Remove core_para from interface * Remove first claimqueue element on clear if None instead removing all Nones * Move claimqueue get out of loop * Use VecDeque instead of Ved in ClaimQueue * Make occupied() AB ready(?) * handle freed disputed in clear_and_fill_claimqueue * clear_and_fill_claimqueue returns scheduled Vec * Rename and minor refactor * return position of assignment taken from claimqueue * minor * Fix session boundary parachains number change + extended test * Fix runtimes * Fix polkadot runtime * Remove polkadot pallet from benchmarks * fix test runtime * Add storage migration * Minor refactor * Minor * migratin typechecks * Add migration to runtimes * Towards modular scheduling II (#6568) * Add post migration check * pebkac * Disable migrations but mine * Revert "Disable migrations but mine" This reverts commit 4fa5c5a370c199944a7e0926f50b08626bfbad4c. * Move scheduler migration * Revert "Move scheduler migration" This reverts commit a16b1659a907950bae048a9f7010f2aa76e02b6d. * Fix migration * cleanup * Don't lose retries value anymore * comment out test function * Remove retries value from Assignment again * minor * Make collator for parathreads optional * data type refactor * update scheduler tests * Change test function cfg * comment out test function * Try cfg(test) only * fix cfg flags * Add get_max_retries function to provider interface (#7047) * Fix merge commit * pebkac * fix merge * update cargo.lock * fix merge * fix merge * Use btreemap instead of vec, fix scheduler calls. * Use imported `ScheduledCore` * Remove unused import in inclusion tests * Use keys() instead of mapping over a BTreeMap * Fix migrations for parachains scheduler * Use BlockNumberFor everywhere in scheduler * Add on demand assignment provider pallet (#7110) * Address some PR comments * minor * more cleanup * find_map and timeout availability fixes * Change default scheduling_lookahead to 1 * Add on demand assignment provider pallet * Move test-runtime to new assignment provider * Run cargo format on scheduler tests * minor * Mutate cores in single loop * timeout predicate simplification * claimqueue desired size fix * Replace expect by ok_or * More improvements * Fix push back order and next_up_on_timeout * minor * session change docs * Add pre_new_session call to hand pre session updates * Remove sc_network dependency and PeerId from unnecessary data structures * Remove unnecessary peer_ids * Add OnDemandOrdering proxy (#7156) * Add OnDemandBidding proxy * Fix names * OnDemandAssigner for rococo only * Check PeerId in collator protocol before fetching collation * On occupied, remove non occupied cores from the claimqueue front and refill * Add missing docs * Comment out unused field * fix ScheduledCore in tests * Fix the fix * pebkac * fmt * Fix occupied dropping * Remove double import * ScheduledCore fixes * Readd sc-network dep * pebkac * OpaquePeerId -> PeerId in can_collate interface * Cargo.lock update for interface change * Remove checks not needed anymore? * Drop occupied core on session change if it would time out after the new session * Add on demand assignment provider pallet * Move test-runtime to new assignment provider * Run cargo format on scheduler tests * Add OnDemandOrdering proxy (#7156) * Add OnDemandBidding proxy * Fix names * OnDemandAssigner for rococo only * Remove unneeded config values * Update comments * Use and_then for queue position * Return the max size of the spot queue on error * Add comments to add_parathread_entry * Add module comments * Add log for when can_collate fails * Change assigner queue type to `Assignment` * Update assignment provider tests * More logs * Remove unused keyring import * disable can_collate * comment out can_collate * Can collate first checks set if empty * Move can_collate call to collation advertisement * Fix backing test * map to loop * Remove obsolete check * Move invalid collation test from backing to collator-protocol * fix unused imports * fix test * fix Debug derivation * Increase time limit on zombienet predicates * Increase zombienet timeout * Minor * Address some PR comments * Address PR comments * Comment out failing assert due to on-demand assigner missing * remove collator_restrictions info from backing * Move can_collate to ActiveParas * minor * minor * Update weight information for on demand config * Add ttl to parasentry * Fix tests missing parasentry ttl * Adjust scheduler tests to use ttl default values * Use match instead of if let for ttl drop * Use RuntimeDebug trait for `ParasEntry` fields * Add comments to on demand assignment pallet * Fix spot traffic calculation * Revert runtimedebug changes to primitives * Remove runtimedebug derivation from `ParasEntry` * Mention affinity in pallet level docs * Use RuntimeDebug trait for ParasEntry child types * Remove collator restrictions * Fix primitive versioning and other merge issues * Fix tests post merge * Fix node side tests * Edit parascheduler migration for clarity * Move parascheduler migration up to next release * Remove vestiges from merge * Fix tests * Refactor ttl handling * Remove unused things from scheduler tests * Move on demand assigner to own directory * Update documentation * Remove unused sc-network dependency in primitives Was used for collator restrictions * Remove unused import * Reenable scheduler test * Remove unused storage value * Enable timeout predicate test and fix fn Turns out that the issue with the compiler is fixed and we can now use impl Trait in the manner used here. * Remove unused imports * Add benchmarking entry for perbill in config * Correct typo * Address review comments * Log out errors when calculating spot traffic. * Change parascheduler's log target name * Update scheduler_common documentation * Use mutate for affinity fns, add tests * Add another on demand affinity test * Unify parathreads and parachains in HostConfig (take 2) (#7452) * Unify parathreads and parachains in HostConfig * Fixed missed occurences * Remove commented out lines * `HostConfiguration v7` * Fix version check * Add `MigrateToV7` to `Unreleased` * fmt * fmt * Fix compilation errors after the rebase * Update runtime/parachains/src/scheduler/tests.rs Co-authored-by: Anton Vilhelm Ásgeirsson * Update runtime/parachains/src/scheduler/tests.rs Co-authored-by: Anton Vilhelm Ásgeirsson * fmt * Fix migration test * Fix tests * Remove unneeded assert from tests * parathread_cores -> on_demand_cores; parathread_retries -> on_demand_retries * Fix a compilation error in tests * Remove unused `use` * update colander image version --------- Co-authored-by: alexgparity Co-authored-by: Anton Vilhelm Ásgeirsson Co-authored-by: Javier Viola * Fix branch after merge with master * Refactor out duplicate checks into a helper fn * Fix tests post merge * Rename add_parathread_assignment, add test * Update docs * Remove unused on_finalize function * Add weight info to on demand pallet * Update runtime/parachains/src/configuration.rs Co-authored-by: Tsvetomir Dimitrov * Update runtime/parachains/src/scheduler_common/mod.rs Co-authored-by: Tsvetomir Dimitrov * Update runtime/parachains/src/assigner_on_demand/mod.rs Co-authored-by: Tsvetomir Dimitrov * Add benchmarking to on demand pallet * Make place_order test check for success * Add on demand benchmarks * Add local test weights to rococo runtime * Modify TTL drop behaviour to not skip claims Previous behaviour would jump a new claim from the assignment provider ahead in the claimqueue, assuming lookahead is larger than 1. * Refactor ttl test to test claimqueue order * Disable place_order ext. when no on_demand cores * Use default genesis config for benchmark tests * Refactor config builder param * Move lifecycle test from scheduler to on demand * Remove unneeded lifecycle test Paras module via the parachain assignment provider doesn't provide new assignments if a parachain loses it's lease. The on demand assignment provider doesn't provide an assignment that is not a parathread. * Re enable validator shuffle test * More realistic weights for place_order * Remove redundant import * Fix backwards compatibility (hopefully) * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=rococo --target_dir=polkadot --pallet=runtime_parachains::assigner_on_demand * Fix tests. * Fix off-by-one. * Re enable claimqueue fills test * Re enable schedule_rotates_groups test * Fix fill_claimqueue_fills test * Re enable next_up_on_timeout test, move fn * Do not pop from assignment provider when retrying * Fix tests missing collator in scheduledcore * Add comment about timeout predicate. * Rename parasentry retries to availability timeouts * Re enable schedule_schedules... test * Refactor prune retried test to new scheduler * Have all scheduler tests use genesis_cfg fn * Update docs * Update copyright notices on new files * Rename is_parachain_core to is_bulk_core * Remove erroneous TODO * Simplify import * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=rococo --target_dir=polkadot --pallet=runtime_parachains::configuration * Revert AdvertiseCollation order shuffle * Refactor place_order into keepalive and allowdeath * Revert rename of hrmp max inbound channels parachain encompasses both on demand and slot auction / bulk. * Restore availability_timeout_predicate function * Clean up leftover comments * Update runtime/parachains/src/scheduler/tests.rs Co-authored-by: Tsvetomir Dimitrov * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=westend --target_dir=polkadot --pallet=runtime_parachains::configuration --------- Co-authored-by: alexgparity Co-authored-by: alexgparity <115470171+alexgparity@users.noreply.github.com> Co-authored-by: Tsvetomir Dimitrov Co-authored-by: Javier Viola Co-authored-by: eskimor Co-authored-by: command-bot <> * On Demand - update weights and small nits (#7605) * Remove collator restriction test in inclusion On demand parachains won't have collator restrictions implemented in this way but will instead use a preferred collator registered to a `ParaId` in `paras_registrar`. * Remove redundant config guard for test fns * Update weights * Update WeightInfo for on_demand assigner * Unify assignment provider parameters into one call (#7606) * Combine assignmentprovider params into one fn call * Move scheduler_common to a module under scheduler * Fix ttl handling in benchmark builder * Run cargo format * Remove obsolete test. * Small improvement. * Use same migration pattern as config module * Remove old TODO * Change log target name for assigner on demand * Fix migration * Fix clippy warnings * Add HostConfiguration storage migration to V8 * Add `MigrateToV8` to unreleased migrations for all runtimes * Fix storage version check for config v8 * Set `StorageVersion` to 8 in `MigrateToV8` * Remove dups. * Update primitives/src/v5/mod.rs Co-authored-by: Bastian Köcher --------- Co-authored-by: alexgparity Co-authored-by: alexgparity <115470171+alexgparity@users.noreply.github.com> Co-authored-by: antonva Co-authored-by: Tsvetomir Dimitrov Co-authored-by: Anton Vilhelm Ásgeirsson Co-authored-by: Javier Viola Co-authored-by: eskimor Co-authored-by: Bastian Köcher --- node/core/backing/src/lib.rs | 42 +- node/core/backing/src/tests.rs | 120 +- .../src/validator_side/mod.rs | 1 + node/service/src/chain_spec.rs | 5 +- node/test/service/src/chain_spec.rs | 3 +- primitives/src/lib.rs | 3 +- primitives/src/v5/mod.rs | 75 +- runtime/kusama/src/lib.rs | 10 +- .../runtime_parachains_configuration.rs | 120 +- runtime/parachains/src/assigner.rs | 111 ++ .../src/assigner_on_demand/benchmarking.rs | 109 ++ .../src/assigner_on_demand/mock_helpers.rs | 86 ++ .../parachains/src/assigner_on_demand/mod.rs | 614 +++++++++ .../src/assigner_on_demand/tests.rs | 558 ++++++++ runtime/parachains/src/assigner_parachains.rs | 70 + runtime/parachains/src/builder.rs | 39 +- runtime/parachains/src/configuration.rs | 239 ++-- .../src/configuration/benchmarking.rs | 2 + .../parachains/src/configuration/migration.rs | 1 + .../src/configuration/migration/v7.rs | 97 +- .../src/configuration/migration/v8.rs | 319 +++++ runtime/parachains/src/configuration/tests.rs | 52 +- runtime/parachains/src/dmp.rs | 5 +- runtime/parachains/src/hrmp.rs | 12 +- runtime/parachains/src/hrmp/tests.rs | 18 +- runtime/parachains/src/inclusion/mod.rs | 48 +- runtime/parachains/src/inclusion/tests.rs | 91 +- runtime/parachains/src/initializer.rs | 3 + runtime/parachains/src/lib.rs | 3 + runtime/parachains/src/mock.rs | 29 +- runtime/parachains/src/paras/tests.rs | 3 +- runtime/parachains/src/paras_inherent/mod.rs | 26 +- .../parachains/src/paras_inherent/tests.rs | 44 +- runtime/parachains/src/runtime_api_impl/v5.rs | 101 +- runtime/parachains/src/scheduler.rs | 890 ++++++------ runtime/parachains/src/scheduler/common.rs | 98 ++ runtime/parachains/src/scheduler/migration.rs | 170 +++ runtime/parachains/src/scheduler/tests.rs | 1198 +++++++++-------- runtime/parachains/src/session_info/tests.rs | 2 +- runtime/polkadot/src/lib.rs | 10 +- .../runtime_parachains_configuration.rs | 170 +-- runtime/rococo/src/lib.rs | 34 +- runtime/rococo/src/weights/mod.rs | 1 + .../runtime_parachains_assigner_on_demand.rs | 91 ++ .../runtime_parachains_configuration.rs | 168 +-- runtime/test-runtime/src/lib.rs | 8 +- runtime/westend/src/lib.rs | 10 +- .../runtime_parachains_configuration.rs | 120 +- scripts/ci/gitlab/pipeline/zombienet.yml | 2 +- .../0003-parachains-garbage-candidate.zndsl | 2 +- zombienet_tests/misc/0003-parathreads.toml | 32 + .../smoke/0001-parachains-smoke-test.zndsl | 2 +- .../0002-parachains-upgrade-smoke-test.zndsl | 2 +- 53 files changed, 4196 insertions(+), 1873 deletions(-) create mode 100644 runtime/parachains/src/assigner.rs create mode 100644 runtime/parachains/src/assigner_on_demand/benchmarking.rs create mode 100644 runtime/parachains/src/assigner_on_demand/mock_helpers.rs create mode 100644 runtime/parachains/src/assigner_on_demand/mod.rs create mode 100644 runtime/parachains/src/assigner_on_demand/tests.rs create mode 100644 runtime/parachains/src/assigner_parachains.rs create mode 100644 runtime/parachains/src/configuration/migration/v8.rs create mode 100644 runtime/parachains/src/scheduler/common.rs create mode 100644 runtime/parachains/src/scheduler/migration.rs create mode 100644 runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs create mode 100644 zombienet_tests/misc/0003-parathreads.toml diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index 0abfbfad7657..ccfbb4e5145f 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -48,7 +48,7 @@ use polkadot_node_subsystem_util::{ request_validators, Validator, }; use polkadot_primitives::{ - BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, CollatorId, + BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, PvfExecTimeoutKind, SigningContext, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, }; @@ -354,7 +354,7 @@ async fn handle_active_leaves_update( let group_index = group_rotation_info.group_for_core(core_index, n_cores); if let Some(g) = validator_groups.get(group_index.0 as usize) { if validator.as_ref().map_or(false, |v| g.contains(&v.index())) { - assignment = Some((scheduled.para_id, scheduled.collator)); + assignment = Some(scheduled.para_id); } groups.insert(scheduled.para_id, g.clone()); } @@ -363,15 +363,15 @@ async fn handle_active_leaves_update( let table_context = TableContext { groups, validators, validator }; - let (assignment, required_collator) = match assignment { + let assignment = match assignment { None => { assignments_span.add_string_tag("assigned", "false"); - (None, None) + None }, - Some((assignment, required_collator)) => { + Some(assignment) => { assignments_span.add_string_tag("assigned", "true"); assignments_span.add_para_id(assignment); - (Some(assignment), required_collator) + Some(assignment) }, }; @@ -381,7 +381,6 @@ async fn handle_active_leaves_update( let job = CandidateBackingJob { parent, assignment, - required_collator, issued_statements: HashSet::new(), awaiting_validation: HashSet::new(), fallbacks: HashMap::new(), @@ -412,8 +411,6 @@ struct CandidateBackingJob { parent: Hash, /// The `ParaId` assigned to this validator assignment: Option, - /// The collator required to author the candidate, if any. - required_collator: Option, /// Spans for all candidates that are not yet backable. unbacked_candidates: HashMap, /// We issued `Seconded`, `Valid` or `Invalid` statements on about these candidates. @@ -913,21 +910,6 @@ impl CandidateBackingJob { candidate: &CandidateReceipt, pov: Arc, ) -> Result<(), Error> { - // Check that candidate is collated by the right collator. - if self - .required_collator - .as_ref() - .map_or(false, |c| c != &candidate.descriptor().collator) - { - // Break cycle - bounded as there is only one candidate to - // second per block. - ctx.send_unbounded_message(CollatorProtocolMessage::Invalid( - self.parent, - candidate.clone(), - )); - return Ok(()) - } - let candidate_hash = candidate.hash(); let mut span = self.get_unbacked_validation_child( root_span, @@ -1171,8 +1153,6 @@ impl CandidateBackingJob { return Ok(()) } - let descriptor = attesting.candidate.descriptor().clone(); - gum::debug!( target: LOG_TARGET, candidate_hash = ?candidate_hash, @@ -1180,16 +1160,6 @@ impl CandidateBackingJob { "Kicking off validation", ); - // Check that candidate is collated by the right collator. - if self.required_collator.as_ref().map_or(false, |c| c != &descriptor.collator) { - // If not, we've got the statement in the table but we will - // not issue validation work for it. - // - // Act as though we've issued a statement. - self.issued_statements.insert(candidate_hash); - return Ok(()) - } - let bg_sender = ctx.sender().clone(); let pov = PoVData::FetchFromValidator { from_validator: attesting.from_validator, diff --git a/node/core/backing/src/tests.rs b/node/core/backing/src/tests.rs index 4be7516c58b4..1a2c044ccc66 100644 --- a/node/core/backing/src/tests.rs +++ b/node/core/backing/src/tests.rs @@ -31,8 +31,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - CandidateDescriptor, CollatorId, GroupRotationInfo, HeadData, PersistedValidationData, - PvfExecTimeoutKind, ScheduledCore, + CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, PvfExecTimeoutKind, + ScheduledCore, }; use sp_application_crypto::AppCrypto; use sp_keyring::Sr25519Keyring; @@ -98,14 +98,10 @@ impl Default for TestState { let group_rotation_info = GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 100, now: 1 }; - let thread_collator: CollatorId = Sr25519Keyring::Two.public().into(); let availability_cores = vec![ CoreState::Scheduled(ScheduledCore { para_id: chain_a, collator: None }), CoreState::Scheduled(ScheduledCore { para_id: chain_b, collator: None }), - CoreState::Scheduled(ScheduledCore { - para_id: thread_a, - collator: Some(thread_collator.clone()), - }), + CoreState::Scheduled(ScheduledCore { para_id: thread_a, collator: None }), ]; let mut head_data = HashMap::new(); @@ -1186,116 +1182,6 @@ fn backing_works_after_failed_validation() { }); } -// Test that a `CandidateBackingMessage::Second` issues validation work -// and in case validation is successful issues a `StatementDistributionMessage`. -#[test] -fn backing_doesnt_second_wrong_collator() { - let mut test_state = TestState::default(); - test_state.availability_cores[0] = CoreState::Scheduled(ScheduledCore { - para_id: ParaId::from(1), - collator: Some(Sr25519Keyring::Bob.public().into()), - }); - - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - - let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); - - let pov_hash = pov.hash(); - let candidate = TestCandidateBuilder { - para_id: test_state.chain_ids[0], - relay_parent: test_state.relay_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone()), - } - .build(); - - let second = CandidateBackingMessage::Second( - test_state.relay_parent, - candidate.to_plain(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol( - CollatorProtocolMessage::Invalid(parent, c) - ) if parent == test_state.relay_parent && c == candidate.to_plain() => { - } - ); - - virtual_overseer - .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::stop_work(test_state.relay_parent), - ))) - .await; - virtual_overseer - }); -} - -#[test] -fn validation_work_ignores_wrong_collator() { - let mut test_state = TestState::default(); - test_state.availability_cores[0] = CoreState::Scheduled(ScheduledCore { - para_id: ParaId::from(1), - collator: Some(Sr25519Keyring::Bob.public().into()), - }); - - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; - - let pov_hash = pov.hash(); - - let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); - - let candidate_a = TestCandidateBuilder { - para_id: test_state.chain_ids[0], - relay_parent: test_state.relay_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone()), - } - .build(); - - let public2 = Keystore::sr25519_generate_new( - &*test_state.keystore, - ValidatorId::ID, - Some(&test_state.validators[2].to_seed()), - ) - .expect("Insert key into keystore"); - let seconding = SignedFullStatement::sign( - &test_state.keystore, - Statement::Seconded(candidate_a.clone()), - &test_state.signing_context, - ValidatorIndex(2), - &public2.into(), - ) - .ok() - .flatten() - .expect("should be signed"); - - let statement = - CandidateBackingMessage::Statement(test_state.relay_parent, seconding.clone()); - - virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - - // The statement will be ignored because it has the wrong collator. - virtual_overseer - .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::stop_work(test_state.relay_parent), - ))) - .await; - virtual_overseer - }); -} - #[test] fn candidate_backing_reorders_votes() { use sp_core::Encode; diff --git a/node/network/collator-protocol/src/validator_side/mod.rs b/node/network/collator-protocol/src/validator_side/mod.rs index b455285332be..f87a14971e8a 100644 --- a/node/network/collator-protocol/src/validator_side/mod.rs +++ b/node/network/collator-protocol/src/validator_side/mod.rs @@ -921,6 +921,7 @@ async fn process_incoming_peer_message( .span_per_relay_parent .get(&relay_parent) .map(|s| s.child("advertise-collation")); + if !state.view.contains(&relay_parent) { gum::debug!( target: LOG_TARGET, diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index 87a8650c2ed6..7e2d9c470450 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -211,8 +211,7 @@ fn default_parachains_host_configuration( max_pov_size: MAX_POV_SIZE, max_head_data_size: 32 * 1024, group_rotation_frequency: 20, - chain_availability_period: 4, - thread_availability_period: 4, + paras_availability_period: 4, max_upward_queue_count: 8, max_upward_queue_size: 1024 * 1024, max_downward_message_size: 1024 * 1024, @@ -223,10 +222,8 @@ fn default_parachains_host_configuration( hrmp_channel_max_capacity: 8, hrmp_channel_max_total_size: 8 * 1024, hrmp_max_parachain_inbound_channels: 4, - hrmp_max_parathread_inbound_channels: 4, hrmp_channel_max_message_size: 1024 * 1024, hrmp_max_parachain_outbound_channels: 4, - hrmp_max_parathread_outbound_channels: 4, hrmp_max_message_num_per_candidate: 5, dispute_period: 6, no_show_slots: 2, diff --git a/node/test/service/src/chain_spec.rs b/node/test/service/src/chain_spec.rs index 876bbb8806b4..9aadd7d203c0 100644 --- a/node/test/service/src/chain_spec.rs +++ b/node/test/service/src/chain_spec.rs @@ -175,8 +175,7 @@ fn polkadot_testnet_genesis( max_pov_size: MAX_POV_SIZE, max_head_data_size: 32 * 1024, group_rotation_frequency: 20, - chain_availability_period: 4, - thread_availability_period: 4, + paras_availability_period: 4, no_show_slots: 10, minimum_validation_upgrade_delay: 5, ..Default::default() diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 1c8ef1eae73b..3680cb857e66 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -56,7 +56,8 @@ pub use v5::{ UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, ValidityError, ASSIGNMENT_KEY_TYPE_ID, LOWEST_PUBLIC_ID, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, - MAX_POV_SIZE, PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, + MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, + PARACHAIN_KEY_TYPE_ID, }; #[cfg(feature = "std")] diff --git a/primitives/src/v5/mod.rs b/primitives/src/v5/mod.rs index bdd10e623190..c973bb05bb48 100644 --- a/primitives/src/v5/mod.rs +++ b/primitives/src/v5/mod.rs @@ -385,6 +385,11 @@ pub const MAX_HEAD_DATA_SIZE: u32 = 1 * 1024 * 1024; // NOTE: This value is used in the runtime so be careful when changing it. pub const MAX_POV_SIZE: u32 = 5 * 1024 * 1024; +/// Default queue size we use for the on-demand order book. +/// +/// Can be adjusted in configuration. +pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000; + // The public key of a keypair used by a validator for determining assignments /// to approve included parachain candidates. mod assignment_app { @@ -809,28 +814,70 @@ impl TypeIndex for GroupIndex { } /// A claim on authoring the next block for a given parathread. -#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(PartialEq))] -pub struct ParathreadClaim(pub Id, pub CollatorId); +#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)] +pub struct ParathreadClaim(pub Id, pub Option); /// An entry tracking a claim to ensure it does not pass the maximum number of retries. -#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(PartialEq))] +#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)] pub struct ParathreadEntry { /// The claim. pub claim: ParathreadClaim, - /// Number of retries. + /// Number of retries pub retries: u32, } +/// An assignment for a parachain scheduled to be backed and included in a relay chain block. +#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebug)] +pub struct Assignment { + /// Assignment's ParaId + pub para_id: Id, +} + +impl Assignment { + /// Create a new `Assignment`. + pub fn new(para_id: Id) -> Self { + Self { para_id } + } +} + +/// An entry tracking a paras +#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)] +pub struct ParasEntry { + /// The `Assignment` + pub assignment: Assignment, + /// The number of times the entry has timed out in availability. + pub availability_timeouts: u32, + /// The block height where this entry becomes invalid. + pub ttl: N, +} + +impl ParasEntry { + /// Return `Id` from the underlying `Assignment`. + pub fn para_id(&self) -> Id { + self.assignment.para_id + } + + /// Create a new `ParasEntry`. + pub fn new(assignment: Assignment, now: N) -> Self { + ParasEntry { assignment, availability_timeouts: 0, ttl: now } + } +} + /// What is occupying a specific availability core. #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(PartialEq))] -pub enum CoreOccupied { - /// A parathread. - Parathread(ParathreadEntry), - /// A parachain. - Parachain, +pub enum CoreOccupied { + /// The core is not occupied. + Free, + /// A paras. + Paras(ParasEntry), +} + +impl CoreOccupied { + /// Is core free? + pub fn is_free(&self) -> bool { + matches!(self, Self::Free) + } } /// A helper data-type for tracking validator-group rotations. @@ -962,7 +1009,9 @@ impl OccupiedCore { pub struct ScheduledCore { /// The ID of a para scheduled. pub para_id: Id, - /// The collator required to author the block, if any. + /// DEPRECATED: see: https://github.com/paritytech/polkadot/issues/7575 + /// + /// Will be removed in a future version. pub collator: Option, } @@ -992,7 +1041,7 @@ impl CoreState { pub fn para_id(&self) -> Option { match self { Self::Occupied(ref core) => Some(core.para_id()), - Self::Scheduled(ScheduledCore { para_id, .. }) => Some(*para_id), + Self::Scheduled(core) => Some(core.para_id), Self::Free => None, } } diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 0248b02e12f6..ae1925e898a2 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -39,6 +39,7 @@ use scale_info::TypeInfo; use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; use runtime_parachains::{ + assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, @@ -1166,7 +1167,11 @@ impl parachains_paras_inherent::Config for Runtime { type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; } -impl parachains_scheduler::Config for Runtime {} +impl parachains_scheduler::Config for Runtime { + type AssignmentProvider = ParaAssignmentProvider; +} + +impl parachains_assigner_parachains::Config for Runtime {} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; @@ -1470,6 +1475,7 @@ construct_runtime! { ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event} = 62, ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63, + ParaAssignmentProvider: parachains_assigner_parachains::{Pallet, Storage} = 64, // Parachain Onboarding Pallets. Start indices at 70 to leave room. Registrar: paras_registrar::{Pallet, Call, Storage, Event} = 70, @@ -1538,6 +1544,8 @@ pub mod migrations { >, pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, + parachains_scheduler::migration::v1::MigrateToV1, + parachains_configuration::migration::v8::MigrateToV8, ); } diff --git a/runtime/kusama/src/weights/runtime_parachains_configuration.rs b/runtime/kusama/src/weights/runtime_parachains_configuration.rs index 077e9409076d..22609209c733 100644 --- a/runtime/kusama/src/weights/runtime_parachains_configuration.rs +++ b/runtime/kusama/src/weights/runtime_parachains_configuration.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("kusama-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=kusama-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::configuration // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_parachains::configuration +// --chain=kusama-dev // --header=./file_header.txt -// --output=./runtime/kusama/src/weights/runtime_parachains_configuration.rs +// --output=./runtime/kusama/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,56 +48,56 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::configuration`. pub struct WeightInfo(PhantomData); impl runtime_parachains::configuration::WeightInfo for WeightInfo { - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_448_000 picoseconds. - Weight::from_parts(9_847_000, 0) + // Minimum execution time: 9_186_000 picoseconds. + Weight::from_parts(9_567_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_493_000 picoseconds. - Weight::from_parts(9_882_000, 0) + // Minimum execution time: 9_388_000 picoseconds. + Weight::from_parts(9_723_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_option_u32() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_512_000 picoseconds. - Weight::from_parts(9_883_000, 0) + // Minimum execution time: 9_264_000 picoseconds. + Weight::from_parts(9_477_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_hrmp_open_request_ttl() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -108,34 +106,50 @@ impl runtime_parachains::configuration::WeightInfo for Weight::from_parts(2_000_000_000_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_balance() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_452_000 picoseconds. - Weight::from_parts(9_821_000, 0) + // Minimum execution time: 9_282_000 picoseconds. + Weight::from_parts(9_641_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_executor_params() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 10_107_000 picoseconds. - Weight::from_parts(10_553_000, 0) + // Minimum execution time: 9_937_000 picoseconds. + Weight::from_parts(10_445_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_perbill() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_106_000 picoseconds. + Weight::from_parts(9_645_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/runtime/parachains/src/assigner.rs b/runtime/parachains/src/assigner.rs new file mode 100644 index 000000000000..55434da11f30 --- /dev/null +++ b/runtime/parachains/src/assigner.rs @@ -0,0 +1,111 @@ +// Copyright (C) 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 . + +//! The Polkadot multiplexing assignment provider. +//! Provides blockspace assignments for both bulk and on demand parachains. +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::{v5::Assignment, CoreIndex, Id as ParaId}; + +use crate::{ + configuration, paras, + scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, +}; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + configuration::Config + paras::Config { + type ParachainsAssignmentProvider: AssignmentProvider>; + type OnDemandAssignmentProvider: AssignmentProvider>; + } +} + +// Aliases to make the impl more readable. +type ParachainAssigner = ::ParachainsAssignmentProvider; +type OnDemandAssigner = ::OnDemandAssignmentProvider; + +impl Pallet { + // Helper fn for the AssignmentProvider implementation. + // Assumes that the first allocation of cores is to bulk parachains. + // This function will return false if there are no cores assigned to the bulk parachain + // assigner. + fn is_bulk_core(core_idx: &CoreIndex) -> bool { + let parachain_cores = + as AssignmentProvider>>::session_core_count(); + (0..parachain_cores).contains(&core_idx.0) + } +} + +impl AssignmentProvider> for Pallet { + fn session_core_count() -> u32 { + let parachain_cores = + as AssignmentProvider>>::session_core_count(); + let on_demand_cores = + as AssignmentProvider>>::session_core_count(); + + parachain_cores.saturating_add(on_demand_cores) + } + + /// Pops an `Assignment` from a specified `CoreIndex` + fn pop_assignment_for_core( + core_idx: CoreIndex, + concluded_para: Option, + ) -> Option { + if Pallet::::is_bulk_core(&core_idx) { + as AssignmentProvider>>::pop_assignment_for_core( + core_idx, + concluded_para, + ) + } else { + as AssignmentProvider>>::pop_assignment_for_core( + core_idx, + concluded_para, + ) + } + } + + fn push_assignment_for_core(core_idx: CoreIndex, assignment: Assignment) { + if Pallet::::is_bulk_core(&core_idx) { + as AssignmentProvider>>::push_assignment_for_core( + core_idx, assignment, + ) + } else { + as AssignmentProvider>>::push_assignment_for_core( + core_idx, assignment, + ) + } + } + + fn get_provider_config(core_idx: CoreIndex) -> AssignmentProviderConfig> { + if Pallet::::is_bulk_core(&core_idx) { + as AssignmentProvider>>::get_provider_config( + core_idx, + ) + } else { + as AssignmentProvider>>::get_provider_config( + core_idx, + ) + } + } +} diff --git a/runtime/parachains/src/assigner_on_demand/benchmarking.rs b/runtime/parachains/src/assigner_on_demand/benchmarking.rs new file mode 100644 index 000000000000..42ca94d5185f --- /dev/null +++ b/runtime/parachains/src/assigner_on_demand/benchmarking.rs @@ -0,0 +1,109 @@ +// Copyright (C) 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 . + +//! On demand assigner pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::{Pallet, *}; +use crate::{ + configuration::{HostConfiguration, Pallet as ConfigurationPallet}, + paras::{Pallet as ParasPallet, ParaGenesisArgs, ParaKind, ParachainsCache}, + shared::Pallet as ParasShared, +}; + +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; +use sp_runtime::traits::Bounded; + +use primitives::{ + HeadData, Id as ParaId, SessionIndex, ValidationCode, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, +}; + +// Constants for the benchmarking +const SESSION_INDEX: SessionIndex = 1; + +// Initialize a parathread for benchmarking. +pub fn init_parathread(para_id: ParaId) +where + T: Config + crate::paras::Config + crate::shared::Config, +{ + ParasShared::::set_session_index(SESSION_INDEX); + let mut config = HostConfiguration::default(); + config.on_demand_cores = 1; + ConfigurationPallet::::force_set_active_config(config); + let mut parachains = ParachainsCache::new(); + ParasPallet::::initialize_para_now( + &mut parachains, + para_id, + &ParaGenesisArgs { + para_kind: ParaKind::Parathread, + genesis_head: HeadData(vec![1, 2, 3, 4]), + validation_code: ValidationCode(vec![1, 2, 3, 4]), + }, + ); +} + +#[benchmarks] +mod benchmarks { + /// We want to fill the queue to the maximum, so exactly one more item fits. + const MAX_FILL_BENCH: u32 = ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE.saturating_sub(1); + + use super::*; + #[benchmark] + fn place_order_keep_alive(s: Linear<1, MAX_FILL_BENCH>) { + // Setup + let caller = whitelisted_caller(); + let para_id = ParaId::from(111u32); + init_parathread::(para_id); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + let assignment = Assignment::new(para_id); + + for _ in 0..s { + Pallet::::add_on_demand_assignment(assignment.clone(), QueuePushDirection::Back) + .unwrap(); + } + + #[extrinsic_call] + _(RawOrigin::Signed(caller.into()), BalanceOf::::max_value(), para_id) + } + + #[benchmark] + fn place_order_allow_death(s: Linear<1, MAX_FILL_BENCH>) { + // Setup + let caller = whitelisted_caller(); + let para_id = ParaId::from(111u32); + init_parathread::(para_id); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + let assignment = Assignment::new(para_id); + + for _ in 0..s { + Pallet::::add_on_demand_assignment(assignment.clone(), QueuePushDirection::Back) + .unwrap(); + } + + #[extrinsic_call] + _(RawOrigin::Signed(caller.into()), BalanceOf::::max_value(), para_id) + } + + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext( + crate::assigner_on_demand::mock_helpers::GenesisConfigBuilder::default().build() + ), + crate::mock::Test + ); +} diff --git a/runtime/parachains/src/assigner_on_demand/mock_helpers.rs b/runtime/parachains/src/assigner_on_demand/mock_helpers.rs new file mode 100644 index 000000000000..acfb24cbf194 --- /dev/null +++ b/runtime/parachains/src/assigner_on_demand/mock_helpers.rs @@ -0,0 +1,86 @@ +// Copyright (C) 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 . + +//! Helper functions for tests, also used in runtime-benchmarks. + +#![cfg(test)] + +use super::*; + +use crate::{ + mock::MockGenesisConfig, + paras::{ParaGenesisArgs, ParaKind}, +}; + +use primitives::{Balance, HeadData, ValidationCode}; + +pub fn default_genesis_config() -> MockGenesisConfig { + MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: crate::configuration::HostConfiguration { ..Default::default() }, + }, + ..Default::default() + } +} + +#[derive(Debug)] +pub struct GenesisConfigBuilder { + pub on_demand_cores: u32, + pub on_demand_base_fee: Balance, + pub on_demand_fee_variability: Perbill, + pub on_demand_max_queue_size: u32, + pub on_demand_target_queue_utilization: Perbill, + pub onboarded_on_demand_chains: Vec, +} + +impl Default for GenesisConfigBuilder { + fn default() -> Self { + Self { + on_demand_cores: 10, + on_demand_base_fee: 10_000, + on_demand_fee_variability: Perbill::from_percent(1), + on_demand_max_queue_size: 100, + on_demand_target_queue_utilization: Perbill::from_percent(25), + onboarded_on_demand_chains: vec![], + } + } +} + +impl GenesisConfigBuilder { + pub(super) fn build(self) -> MockGenesisConfig { + let mut genesis = default_genesis_config(); + let config = &mut genesis.configuration.config; + config.on_demand_cores = self.on_demand_cores; + config.on_demand_base_fee = self.on_demand_base_fee; + config.on_demand_fee_variability = self.on_demand_fee_variability; + config.on_demand_queue_max_size = self.on_demand_max_queue_size; + config.on_demand_target_queue_utilization = self.on_demand_target_queue_utilization; + + let paras = &mut genesis.paras.paras; + for para_id in self.onboarded_on_demand_chains { + paras.push(( + para_id, + ParaGenesisArgs { + genesis_head: HeadData::from(vec![0u8]), + validation_code: ValidationCode::from(vec![0u8]), + para_kind: ParaKind::Parathread, + }, + )) + } + + genesis + } +} diff --git a/runtime/parachains/src/assigner_on_demand/mod.rs b/runtime/parachains/src/assigner_on_demand/mod.rs new file mode 100644 index 000000000000..5a60201e4fa8 --- /dev/null +++ b/runtime/parachains/src/assigner_on_demand/mod.rs @@ -0,0 +1,614 @@ +// Copyright (C) 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 . + +//! The parachain on demand assignment module. +//! +//! Implements a mechanism for taking in orders for pay as you go (PAYG) or on demand +//! parachain (previously parathreads) assignments. This module is not handled by the +//! initializer but is instead instantiated in the `construct_runtime` macro. +//! +//! The module currently limits parallel execution of blocks from the same `ParaId` via +//! a core affinity mechanism. As long as there exists an affinity for a `CoreIndex` for +//! a specific `ParaId`, orders for blockspace for that `ParaId` will only be assigned to +//! that `CoreIndex`. This affinity mechanism can be removed if it can be shown that parallel +//! execution is valid. + +mod benchmarking; +mod mock_helpers; + +#[cfg(test)] +mod tests; + +use crate::{ + configuration, paras, + scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, +}; + +use frame_support::{ + pallet_prelude::*, + traits::{ + Currency, + ExistenceRequirement::{self, AllowDeath, KeepAlive}, + WithdrawReasons, + }, +}; +use frame_system::pallet_prelude::*; +use primitives::{v5::Assignment, CoreIndex, Id as ParaId}; +use sp_runtime::{ + traits::{One, SaturatedConversion}, + FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Saturating, +}; + +use sp_std::{collections::vec_deque::VecDeque, prelude::*}; + +const LOG_TARGET: &str = "runtime::parachains::assigner-on-demand"; + +pub use pallet::*; + +pub trait WeightInfo { + fn place_order_allow_death(s: u32) -> Weight; + fn place_order_keep_alive(s: u32) -> Weight; +} + +/// A weight info that is only suitable for testing. +pub struct TestWeightInfo; + +impl WeightInfo for TestWeightInfo { + fn place_order_allow_death(_: u32) -> Weight { + Weight::MAX + } + + fn place_order_keep_alive(_: u32) -> Weight { + Weight::MAX + } +} + +/// Keeps track of how many assignments a scheduler currently has at a specific `CoreIndex` for a +/// specific `ParaId`. +#[derive(Encode, Decode, Default, Clone, Copy, TypeInfo)] +#[cfg_attr(test, derive(PartialEq, Debug))] +pub struct CoreAffinityCount { + core_idx: CoreIndex, + count: u32, +} + +/// An indicator as to which end of the `OnDemandQueue` an assignment will be placed. +pub enum QueuePushDirection { + Back, + Front, +} + +/// Shorthand for the Balance type the runtime is using. +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +/// Errors that can happen during spot traffic calculation. +#[derive(PartialEq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum SpotTrafficCalculationErr { + /// The order queue capacity is at 0. + QueueCapacityIsZero, + /// The queue size is larger than the queue capacity. + QueueSizeLargerThanCapacity, + /// Arithmetic error during division, either division by 0 or over/underflow. + Division, +} + +#[frame_support::pallet] +pub mod pallet { + + use super::*; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + configuration::Config + paras::Config { + /// The runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The runtime's definition of a Currency. + type Currency: Currency; + + /// Something that provides the weight of this pallet. + type WeightInfo: WeightInfo; + + /// The default value for the spot traffic multiplier. + #[pallet::constant] + type TrafficDefaultValue: Get; + } + + /// Creates an empty spot traffic value if one isn't present in storage already. + #[pallet::type_value] + pub fn SpotTrafficOnEmpty() -> FixedU128 { + T::TrafficDefaultValue::get() + } + + /// Creates an empty on demand queue if one isn't present in storage already. + #[pallet::type_value] + pub fn OnDemandQueueOnEmpty() -> VecDeque { + VecDeque::new() + } + + /// Keeps track of the multiplier used to calculate the current spot price for the on demand + /// assigner. + #[pallet::storage] + pub(super) type SpotTraffic = + StorageValue<_, FixedU128, ValueQuery, SpotTrafficOnEmpty>; + + /// The order storage entry. Uses a VecDeque to be able to push to the front of the + /// queue from the scheduler on session boundaries. + #[pallet::storage] + pub type OnDemandQueue = + StorageValue<_, VecDeque, ValueQuery, OnDemandQueueOnEmpty>; + + /// Maps a `ParaId` to `CoreIndex` and keeps track of how many assignments the scheduler has in + /// it's lookahead. Keeping track of this affinity prevents parallel execution of the same + /// `ParaId` on two or more `CoreIndex`es. + #[pallet::storage] + pub(super) type ParaIdAffinity = + StorageMap<_, Twox256, ParaId, CoreAffinityCount, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// An order was placed at some spot price amount. + OnDemandOrderPlaced { para_id: ParaId, spot_price: BalanceOf }, + /// The value of the spot traffic multiplier changed. + SpotTrafficSet { traffic: FixedU128 }, + } + + #[pallet::error] + pub enum Error { + /// The `ParaId` supplied to the `place_order` call is not a valid `ParaThread`, making the + /// call is invalid. + InvalidParaId, + /// The order queue is full, `place_order` will not continue. + QueueFull, + /// The current spot price is higher than the max amount specified in the `place_order` + /// call, making it invalid. + SpotPriceHigherThanMaxAmount, + /// There are no on demand cores available. `place_order` will not add anything to the + /// queue. + NoOnDemandCores, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_now: BlockNumberFor) -> Weight { + let config = >::config(); + // Calculate spot price multiplier and store it. + let old_traffic = SpotTraffic::::get(); + match Self::calculate_spot_traffic( + old_traffic, + config.on_demand_queue_max_size, + Self::queue_size(), + config.on_demand_target_queue_utilization, + config.on_demand_fee_variability, + ) { + Ok(new_traffic) => { + // Only update storage on change + if new_traffic != old_traffic { + SpotTraffic::::set(new_traffic); + Pallet::::deposit_event(Event::::SpotTrafficSet { + traffic: new_traffic, + }); + return T::DbWeight::get().reads_writes(2, 1) + } + }, + Err(SpotTrafficCalculationErr::QueueCapacityIsZero) => { + log::debug!( + target: LOG_TARGET, + "Error calculating spot traffic: The order queue capacity is at 0." + ); + }, + Err(SpotTrafficCalculationErr::QueueSizeLargerThanCapacity) => { + log::debug!( + target: LOG_TARGET, + "Error calculating spot traffic: The queue size is larger than the queue capacity." + ); + }, + Err(SpotTrafficCalculationErr::Division) => { + log::debug!( + target: LOG_TARGET, + "Error calculating spot traffic: Arithmetic error during division, either division by 0 or over/underflow." + ); + }, + }; + T::DbWeight::get().reads_writes(2, 0) + } + } + + #[pallet::call] + impl Pallet { + /// Create a single on demand core order. + /// Will use the spot price for the current block and will reap the account if needed. + /// + /// Parameters: + /// - `origin`: The sender of the call, funds will be withdrawn from this account. + /// - `max_amount`: The maximum balance to withdraw from the origin to place an order. + /// - `para_id`: A `ParaId` the origin wants to provide blockspace for. + /// + /// Errors: + /// - `InsufficientBalance`: from the Currency implementation + /// - `InvalidParaId` + /// - `QueueFull` + /// - `SpotPriceHigherThanMaxAmount` + /// - `NoOnDemandCores` + /// + /// Events: + /// - `SpotOrderPlaced` + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::place_order_allow_death(OnDemandQueue::::get().len() as u32))] + pub fn place_order_allow_death( + origin: OriginFor, + max_amount: BalanceOf, + para_id: ParaId, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + Pallet::::do_place_order(sender, max_amount, para_id, AllowDeath) + } + + /// Same as the [`place_order_allow_death`] call , but with a check that placing the order + /// will not reap the account. + /// + /// Parameters: + /// - `origin`: The sender of the call, funds will be withdrawn from this account. + /// - `max_amount`: The maximum balance to withdraw from the origin to place an order. + /// - `para_id`: A `ParaId` the origin wants to provide blockspace for. + /// + /// Errors: + /// - `InsufficientBalance`: from the Currency implementation + /// - `InvalidParaId` + /// - `QueueFull` + /// - `SpotPriceHigherThanMaxAmount` + /// - `NoOnDemandCores` + /// + /// Events: + /// - `SpotOrderPlaced` + #[pallet::call_index(1)] + #[pallet::weight(::WeightInfo::place_order_keep_alive(OnDemandQueue::::get().len() as u32))] + pub fn place_order_keep_alive( + origin: OriginFor, + max_amount: BalanceOf, + para_id: ParaId, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + Pallet::::do_place_order(sender, max_amount, para_id, KeepAlive) + } + } +} + +impl Pallet +where + BalanceOf: FixedPointOperand, +{ + /// Helper function for `place_order_*` calls. Used to differentiate between placing orders + /// with a keep alive check or to allow the account to be reaped. + /// + /// Parameters: + /// - `sender`: The sender of the call, funds will be withdrawn from this account. + /// - `max_amount`: The maximum balance to withdraw from the origin to place an order. + /// - `para_id`: A `ParaId` the origin wants to provide blockspace for. + /// - `existence_requirement`: Whether or not to ensure that the account will not be reaped. + /// + /// Errors: + /// - `InsufficientBalance`: from the Currency implementation + /// - `InvalidParaId` + /// - `QueueFull` + /// - `SpotPriceHigherThanMaxAmount` + /// - `NoOnDemandCores` + /// + /// Events: + /// - `SpotOrderPlaced` + fn do_place_order( + sender: ::AccountId, + max_amount: BalanceOf, + para_id: ParaId, + existence_requirement: ExistenceRequirement, + ) -> DispatchResult { + let config = >::config(); + + // Are there any schedulable cores in this session + ensure!(config.on_demand_cores > 0, Error::::NoOnDemandCores); + + // Traffic always falls back to 1.0 + let traffic = SpotTraffic::::get(); + + // Calculate spot price + let spot_price: BalanceOf = + traffic.saturating_mul_int(config.on_demand_base_fee.saturated_into::>()); + + // Is the current price higher than `max_amount` + ensure!(spot_price.le(&max_amount), Error::::SpotPriceHigherThanMaxAmount); + + // Charge the sending account the spot price + T::Currency::withdraw(&sender, spot_price, WithdrawReasons::FEE, existence_requirement)?; + + let assignment = Assignment::new(para_id); + + let res = Pallet::::add_on_demand_assignment(assignment, QueuePushDirection::Back); + + match res { + Ok(_) => { + Pallet::::deposit_event(Event::::OnDemandOrderPlaced { para_id, spot_price }); + return Ok(()) + }, + Err(err) => return Err(err), + } + } + + /// The spot price multiplier. This is based on the transaction fee calculations defined in: + /// https://research.web3.foundation/Polkadot/overview/token-economics#setting-transaction-fees + /// + /// Parameters: + /// - `traffic`: The previously calculated multiplier, can never go below 1.0. + /// - `queue_capacity`: The max size of the order book. + /// - `queue_size`: How many orders are currently in the order book. + /// - `target_queue_utilisation`: How much of the queue_capacity should be ideally occupied, + /// expressed in percentages(perbill). + /// - `variability`: A variability factor, i.e. how quickly the spot price adjusts. This number + /// can be chosen by p/(k*(1-s)) where p is the desired ratio increase in spot price over k + /// number of blocks. s is the target_queue_utilisation. A concrete example: v = + /// 0.05/(20*(1-0.25)) = 0.0033. + /// + /// Returns: + /// - A `FixedU128` in the range of `Config::TrafficDefaultValue` - `FixedU128::MAX` on + /// success. + /// + /// Errors: + /// - `SpotTrafficCalculationErr::QueueCapacityIsZero` + /// - `SpotTrafficCalculationErr::QueueSizeLargerThanCapacity` + /// - `SpotTrafficCalculationErr::Division` + pub(crate) fn calculate_spot_traffic( + traffic: FixedU128, + queue_capacity: u32, + queue_size: u32, + target_queue_utilisation: Perbill, + variability: Perbill, + ) -> Result { + // Return early if queue has no capacity. + if queue_capacity == 0 { + return Err(SpotTrafficCalculationErr::QueueCapacityIsZero) + } + + // Return early if queue size is greater than capacity. + if queue_size > queue_capacity { + return Err(SpotTrafficCalculationErr::QueueSizeLargerThanCapacity) + } + + // (queue_size / queue_capacity) - target_queue_utilisation + let queue_util_ratio = FixedU128::from_rational(queue_size.into(), queue_capacity.into()); + let positive = queue_util_ratio >= target_queue_utilisation.into(); + let queue_util_diff = queue_util_ratio.max(target_queue_utilisation.into()) - + queue_util_ratio.min(target_queue_utilisation.into()); + + // variability * queue_util_diff + let var_times_qud = queue_util_diff.saturating_mul(variability.into()); + + // variability^2 * queue_util_diff^2 + let var_times_qud_pow = var_times_qud.saturating_mul(var_times_qud); + + // (variability^2 * queue_util_diff^2)/2 + let div_by_two: FixedU128; + match var_times_qud_pow.const_checked_div(2.into()) { + Some(dbt) => div_by_two = dbt, + None => return Err(SpotTrafficCalculationErr::Division), + } + + // traffic * (1 + queue_util_diff) + div_by_two + if positive { + let new_traffic = queue_util_diff + .saturating_add(div_by_two) + .saturating_add(One::one()) + .saturating_mul(traffic); + Ok(new_traffic.max(::TrafficDefaultValue::get())) + } else { + let new_traffic = queue_util_diff.saturating_sub(div_by_two).saturating_mul(traffic); + Ok(new_traffic.max(::TrafficDefaultValue::get())) + } + } + + /// Adds an assignment to the on demand queue. + /// + /// Paramenters: + /// - `assignment`: The on demand assignment to add to the queue. + /// - `location`: Whether to push this entry to the back or the front of the queue. Pushing an + /// entry to the front of the queue is only used when the scheduler wants to push back an + /// entry it has already popped. + /// Returns: + /// - The unit type on success. + /// + /// Errors: + /// - `InvalidParaId` + /// - `QueueFull` + pub fn add_on_demand_assignment( + assignment: Assignment, + location: QueuePushDirection, + ) -> Result<(), DispatchError> { + // Only parathreads are valid paraids for on the go parachains. + ensure!(>::is_parathread(assignment.para_id), Error::::InvalidParaId); + + let config = >::config(); + + OnDemandQueue::::try_mutate(|queue| { + // Abort transaction if queue is too large + ensure!(Self::queue_size() < config.on_demand_queue_max_size, Error::::QueueFull); + match location { + QueuePushDirection::Back => queue.push_back(assignment), + QueuePushDirection::Front => queue.push_front(assignment), + }; + Ok(()) + }) + } + + /// Get the size of the on demand queue. + /// + /// Returns: + /// - The size of the on demand queue. + fn queue_size() -> u32 { + let config = >::config(); + match OnDemandQueue::::get().len().try_into() { + Ok(size) => return size, + Err(_) => { + log::debug!( + target: LOG_TARGET, + "Failed to fetch the on demand queue size, returning the max size." + ); + return config.on_demand_queue_max_size + }, + } + } + + /// Getter for the order queue. + pub fn get_queue() -> VecDeque { + OnDemandQueue::::get() + } + + /// Getter for the affinity tracker. + pub fn get_affinity_map(para_id: ParaId) -> Option { + ParaIdAffinity::::get(para_id) + } + + /// Decreases the affinity of a `ParaId` to a specified `CoreIndex`. + /// Subtracts from the count of the `CoreAffinityCount` if an entry is found and the core_idx + /// matches. When the count reaches 0, the entry is removed. + /// A non-existant entry is a no-op. + fn decrease_affinity(para_id: ParaId, core_idx: CoreIndex) { + ParaIdAffinity::::mutate(para_id, |maybe_affinity| { + if let Some(affinity) = maybe_affinity { + if affinity.core_idx == core_idx { + let new_count = affinity.count.saturating_sub(1); + if new_count > 0 { + *maybe_affinity = Some(CoreAffinityCount { core_idx, count: new_count }); + } else { + *maybe_affinity = None; + } + } + } + }); + } + + /// Increases the affinity of a `ParaId` to a specified `CoreIndex`. + /// Adds to the count of the `CoreAffinityCount` if an entry is found and the core_idx matches. + /// A non-existant entry will be initialized with a count of 1 and uses the supplied + /// `CoreIndex`. + fn increase_affinity(para_id: ParaId, core_idx: CoreIndex) { + ParaIdAffinity::::mutate(para_id, |maybe_affinity| match maybe_affinity { + Some(affinity) => + if affinity.core_idx == core_idx { + *maybe_affinity = Some(CoreAffinityCount { + core_idx, + count: affinity.count.saturating_add(1), + }); + }, + None => { + *maybe_affinity = Some(CoreAffinityCount { core_idx, count: 1 }); + }, + }) + } +} + +impl AssignmentProvider> for Pallet { + fn session_core_count() -> u32 { + let config = >::config(); + config.on_demand_cores + } + + /// Take the next queued entry that is available for a given core index. + /// Invalidates and removes orders with a `para_id` that is not `ParaLifecycle::Parathread` + /// but only in [0..P] range slice of the order queue, where P is the element that is + /// removed from the order queue. + /// + /// Parameters: + /// - `core_idx`: The core index + /// - `previous_paraid`: Which paraid was previously processed on the requested core. Is None if + /// nothing was processed on the core. + fn pop_assignment_for_core( + core_idx: CoreIndex, + previous_para: Option, + ) -> Option { + // Only decrease the affinity of the previous para if it exists. + // A nonexistant `ParaId` indicates that the scheduler has not processed any + // `ParaId` this session. + if let Some(previous_para_id) = previous_para { + Pallet::::decrease_affinity(previous_para_id, core_idx) + } + + let mut queue: VecDeque = OnDemandQueue::::get(); + + let mut invalidated_para_id_indexes: Vec = vec![]; + + // Get the position of the next `ParaId`. Select either a valid `ParaId` that has an + // affinity to the same `CoreIndex` as the scheduler asks for or a valid `ParaId` with no + // affinity at all. + let pos = queue.iter().enumerate().position(|(index, assignment)| { + if >::is_parathread(assignment.para_id) { + match ParaIdAffinity::::get(&assignment.para_id) { + Some(affinity) => return affinity.core_idx == core_idx, + None => return true, + } + } + // Record no longer valid para_ids. + invalidated_para_id_indexes.push(index); + return false + }); + + // Collect the popped value. + let popped = pos.and_then(|p: usize| { + if let Some(assignment) = queue.remove(p) { + Pallet::::increase_affinity(assignment.para_id, core_idx); + return Some(assignment) + }; + None + }); + + // Only remove the invalid indexes *after* using the index. + // Removed in reverse order so that the indexes don't shift. + invalidated_para_id_indexes.iter().rev().for_each(|idx| { + queue.remove(*idx); + }); + + // Write changes to storage. + OnDemandQueue::::set(queue); + + popped + } + + /// Push an assignment back to the queue. + /// Typically used on session boundaries. + /// Parameters: + /// - `core_idx`: The core index + /// - `assignment`: The on demand assignment. + fn push_assignment_for_core(core_idx: CoreIndex, assignment: Assignment) { + Pallet::::decrease_affinity(assignment.para_id, core_idx); + // Skip the queue on push backs from scheduler + match Pallet::::add_on_demand_assignment(assignment, QueuePushDirection::Front) { + Ok(_) => {}, + Err(_) => {}, + } + } + + fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig> { + let config = >::config(); + AssignmentProviderConfig { + availability_period: config.paras_availability_period, + max_availability_timeouts: config.on_demand_retries, + ttl: config.on_demand_ttl, + } + } +} diff --git a/runtime/parachains/src/assigner_on_demand/tests.rs b/runtime/parachains/src/assigner_on_demand/tests.rs new file mode 100644 index 000000000000..8041179cd90c --- /dev/null +++ b/runtime/parachains/src/assigner_on_demand/tests.rs @@ -0,0 +1,558 @@ +// Copyright (C) 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::{ + assigner_on_demand::{mock_helpers::GenesisConfigBuilder, Error}, + initializer::SessionChangeNotification, + mock::{ + new_test_ext, Balances, OnDemandAssigner, Paras, ParasShared, RuntimeOrigin, Scheduler, + System, Test, + }, + paras::{ParaGenesisArgs, ParaKind}, +}; +use frame_support::{assert_noop, assert_ok, error::BadOrigin}; +use pallet_balances::Error as BalancesError; +use primitives::{ + v5::{Assignment, ValidationCode}, + BlockNumber, SessionIndex, +}; +use sp_std::collections::btree_map::BTreeMap; + +fn schedule_blank_para(id: ParaId, parakind: ParaKind) { + let validation_code: ValidationCode = vec![1, 2, 3].into(); + assert_ok!(Paras::schedule_para_initialize( + id, + ParaGenesisArgs { + genesis_head: Vec::new().into(), + validation_code: validation_code.clone(), + para_kind: parakind, + } + )); + + assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), validation_code)); +} + +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::update_claimqueue(BTreeMap::new(), b + 1); + } +} + +#[test] +fn spot_traffic_capacity_zero_returns_none() { + match OnDemandAssigner::calculate_spot_traffic( + FixedU128::from(u128::MAX), + 0u32, + u32::MAX, + Perbill::from_percent(100), + Perbill::from_percent(1), + ) { + Ok(_) => panic!("Error"), + Err(e) => assert_eq!(e, SpotTrafficCalculationErr::QueueCapacityIsZero), + }; +} + +#[test] +fn spot_traffic_queue_size_larger_than_capacity_returns_none() { + match OnDemandAssigner::calculate_spot_traffic( + FixedU128::from(u128::MAX), + 1u32, + 2u32, + Perbill::from_percent(100), + Perbill::from_percent(1), + ) { + Ok(_) => panic!("Error"), + Err(e) => assert_eq!(e, SpotTrafficCalculationErr::QueueSizeLargerThanCapacity), + } +} + +#[test] +fn spot_traffic_calculation_identity() { + match OnDemandAssigner::calculate_spot_traffic( + FixedU128::from_u32(1), + 1000, + 100, + Perbill::from_percent(10), + Perbill::from_percent(3), + ) { + Ok(res) => { + assert_eq!(res, FixedU128::from_u32(1)) + }, + _ => (), + } +} + +#[test] +fn spot_traffic_calculation_u32_max() { + match OnDemandAssigner::calculate_spot_traffic( + FixedU128::from_u32(1), + u32::MAX, + u32::MAX, + Perbill::from_percent(100), + Perbill::from_percent(3), + ) { + Ok(res) => { + assert_eq!(res, FixedU128::from_u32(1)) + }, + _ => panic!("Error"), + }; +} + +#[test] +fn spot_traffic_calculation_u32_traffic_max() { + match OnDemandAssigner::calculate_spot_traffic( + FixedU128::from(u128::MAX), + u32::MAX, + u32::MAX, + Perbill::from_percent(1), + Perbill::from_percent(1), + ) { + Ok(res) => assert_eq!(res, FixedU128::from(u128::MAX)), + _ => panic!("Error"), + }; +} + +#[test] +fn sustained_target_increases_spot_traffic() { + let mut traffic = FixedU128::from_u32(1u32); + for _ in 0..50 { + traffic = OnDemandAssigner::calculate_spot_traffic( + traffic, + 100, + 12, + Perbill::from_percent(10), + Perbill::from_percent(100), + ) + .unwrap() + } + assert_eq!(traffic, FixedU128::from_inner(2_718_103_312_071_174_015u128)) +} + +#[test] +fn spot_traffic_can_decrease() { + let traffic = FixedU128::from_u32(100u32); + match OnDemandAssigner::calculate_spot_traffic( + traffic, + 100u32, + 0u32, + Perbill::from_percent(100), + Perbill::from_percent(100), + ) { + Ok(new_traffic) => + assert_eq!(new_traffic, FixedU128::from_inner(50_000_000_000_000_000_000u128)), + _ => panic!("Error"), + } +} + +#[test] +fn spot_traffic_decreases_over_time() { + let mut traffic = FixedU128::from_u32(100u32); + for _ in 0..5 { + traffic = OnDemandAssigner::calculate_spot_traffic( + traffic, + 100u32, + 0u32, + Perbill::from_percent(100), + Perbill::from_percent(100), + ) + .unwrap(); + println!("{traffic}"); + } + assert_eq!(traffic, FixedU128::from_inner(3_125_000_000_000_000_000u128)) +} + +#[test] +fn place_order_works() { + let alice = 1u64; + let amt = 10_000_000u128; + let para_id = ParaId::from(111); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // Initialize the parathread and wait for it to be ready. + schedule_blank_para(para_id, ParaKind::Parathread); + + assert!(!Paras::is_parathread(para_id)); + + run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None }); + + assert!(Paras::is_parathread(para_id)); + + // Does not work unsigned + assert_noop!( + OnDemandAssigner::place_order_allow_death(RuntimeOrigin::none(), amt, para_id), + BadOrigin + ); + + // Does not work with max_amount lower than fee + let low_max_amt = 1u128; + assert_noop!( + OnDemandAssigner::place_order_allow_death( + RuntimeOrigin::signed(alice), + low_max_amt, + para_id, + ), + Error::::SpotPriceHigherThanMaxAmount, + ); + + // Does not work with insufficient balance + assert_noop!( + OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id), + BalancesError::::InsufficientBalance + ); + + // Works + Balances::make_free_balance_be(&alice, amt); + run_to_block(101, |n| if n == 101 { Some(Default::default()) } else { None }); + assert_ok!(OnDemandAssigner::place_order_allow_death( + RuntimeOrigin::signed(alice), + amt, + para_id + )); + }); +} + +#[test] +fn place_order_keep_alive_keeps_alive() { + let alice = 1u64; + let amt = 1u128; // The same as crate::mock's EXISTENTIAL_DEPOSIT + let max_amt = 10_000_000u128; + let para_id = ParaId::from(111); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // Initialize the parathread and wait for it to be ready. + schedule_blank_para(para_id, ParaKind::Parathread); + Balances::make_free_balance_be(&alice, amt); + + assert!(!Paras::is_parathread(para_id)); + run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None }); + assert!(Paras::is_parathread(para_id)); + + assert_noop!( + OnDemandAssigner::place_order_keep_alive( + RuntimeOrigin::signed(alice), + max_amt, + para_id + ), + BalancesError::::InsufficientBalance + ); + }); +} + +#[test] +fn add_on_demand_assignment_works() { + let para_a = ParaId::from(111); + let assignment = Assignment::new(para_a); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.on_demand_max_queue_size = 1; + new_test_ext(genesis.build()).execute_with(|| { + // Initialize the parathread and wait for it to be ready. + schedule_blank_para(para_a, ParaKind::Parathread); + + // `para_a` is not onboarded as a parathread yet. + assert_noop!( + OnDemandAssigner::add_on_demand_assignment( + assignment.clone(), + QueuePushDirection::Back + ), + Error::::InvalidParaId + ); + + assert!(!Paras::is_parathread(para_a)); + run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None }); + assert!(Paras::is_parathread(para_a)); + + // `para_a` is now onboarded as a valid parathread. + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment.clone(), + QueuePushDirection::Back + )); + + // Max queue size is 1, queue should be full. + assert_noop!( + OnDemandAssigner::add_on_demand_assignment(assignment, QueuePushDirection::Back), + Error::::QueueFull + ); + }); +} + +#[test] +fn spotqueue_push_directions() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + let para_a = ParaId::from(111); + let para_b = ParaId::from(222); + let para_c = ParaId::from(333); + + schedule_blank_para(para_a, ParaKind::Parathread); + schedule_blank_para(para_b, ParaKind::Parathread); + schedule_blank_para(para_c, ParaKind::Parathread); + + run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); + + let assignment_a = Assignment { para_id: para_a }; + let assignment_b = Assignment { para_id: para_b }; + let assignment_c = Assignment { para_id: para_c }; + + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a.clone(), + QueuePushDirection::Front + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_b.clone(), + QueuePushDirection::Front + )); + + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_c.clone(), + QueuePushDirection::Back + )); + + assert_eq!(OnDemandAssigner::queue_size(), 3); + assert_eq!( + OnDemandAssigner::get_queue(), + VecDeque::from(vec![assignment_b, assignment_a, assignment_c]) + ) + }); +} + +#[test] +fn affinity_changes_work() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + let para_a = ParaId::from(111); + schedule_blank_para(para_a, ParaKind::Parathread); + + run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); + + let assignment_a = Assignment { para_id: para_a }; + // There should be no affinity before starting. + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + + // Add enough assignments to the order queue. + for _ in 0..10 { + OnDemandAssigner::add_on_demand_assignment( + assignment_a.clone(), + QueuePushDirection::Front, + ) + .expect("Invalid paraid or queue full"); + } + + // There should be no affinity before the scheduler pops. + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None); + + // Affinity count is 1 after popping. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); + + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a)); + + // Affinity count is 1 after popping with a previous para. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); + assert_eq!(OnDemandAssigner::queue_size(), 8); + + for _ in 0..3 { + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None); + } + + // Affinity count is 4 after popping 3 times without a previous para. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4); + assert_eq!(OnDemandAssigner::queue_size(), 5); + + for _ in 0..5 { + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a)); + } + + // Affinity count should still be 4 but queue should be empty. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4); + assert_eq!(OnDemandAssigner::queue_size(), 0); + + // Pop 4 times and get to exactly 0 (None) affinity. + for _ in 0..4 { + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a)); + } + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + + // Decreasing affinity beyond 0 should still be None. + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a)); + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + }); +} + +#[test] +fn affinity_prohibits_parallel_scheduling() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + let para_a = ParaId::from(111); + let para_b = ParaId::from(222); + + schedule_blank_para(para_a, ParaKind::Parathread); + schedule_blank_para(para_b, ParaKind::Parathread); + + run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); + + let assignment_a = Assignment { para_id: para_a }; + let assignment_b = Assignment { para_id: para_b }; + + // There should be no affinity before starting. + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); + + // Add 2 assignments for para_a for every para_b. + OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back) + .expect("Invalid paraid or queue full"); + + OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back) + .expect("Invalid paraid or queue full"); + + OnDemandAssigner::add_on_demand_assignment(assignment_b.clone(), QueuePushDirection::Back) + .expect("Invalid paraid or queue full"); + + assert_eq!(OnDemandAssigner::queue_size(), 3); + + // Approximate having 1 core. + for _ in 0..3 { + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None); + } + + // Affinity on one core is meaningless. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); + assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); + assert_eq!( + OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx, + OnDemandAssigner::get_affinity_map(para_b).unwrap().core_idx + ); + + // Clear affinity + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a)); + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a)); + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_b)); + + // Add 2 assignments for para_a for every para_b. + OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back) + .expect("Invalid paraid or queue full"); + + OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back) + .expect("Invalid paraid or queue full"); + + OnDemandAssigner::add_on_demand_assignment(assignment_b.clone(), QueuePushDirection::Back) + .expect("Invalid paraid or queue full"); + + // Approximate having 2 cores. + for _ in 0..3 { + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None); + OnDemandAssigner::pop_assignment_for_core(CoreIndex(1), None); + } + + // Affinity should be the same as before, but on different cores. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); + assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx, CoreIndex(0)); + assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().core_idx, CoreIndex(1)); + }); +} + +#[test] +fn cannot_place_order_when_no_on_demand_cores() { + let mut genesis = GenesisConfigBuilder::default(); + genesis.on_demand_cores = 0; + let para_id = ParaId::from(10); + let alice = 1u64; + let amt = 10_000_000u128; + + new_test_ext(genesis.build()).execute_with(|| { + schedule_blank_para(para_id, ParaKind::Parathread); + Balances::make_free_balance_be(&alice, amt); + + assert!(!Paras::is_parathread(para_id)); + + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); + + assert!(Paras::is_parathread(para_id)); + + assert_noop!( + OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id), + Error::::NoOnDemandCores + ); + }); +} + +#[test] +fn on_demand_orders_cannot_be_popped_if_lifecycle_changes() { + let para_id = ParaId::from(10); + let assignment = Assignment { para_id }; + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // Register the para_id as a parathread + schedule_blank_para(para_id, ParaKind::Parathread); + + assert!(!Paras::is_parathread(para_id)); + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); + assert!(Paras::is_parathread(para_id)); + + // Add two assignments for a para_id with a valid lifecycle. + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment.clone(), + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment.clone(), + QueuePushDirection::Back + )); + + // First pop is fine + assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None) == Some(assignment)); + + // Deregister para + assert_ok!(Paras::schedule_para_cleanup(para_id)); + + // Run to new session and verify that para_id is no longer a valid parathread. + assert!(Paras::is_parathread(para_id)); + run_to_block(20, |n| if n == 20 { Some(Default::default()) } else { None }); + assert!(!Paras::is_parathread(para_id)); + + // Second pop should be None. + assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_id)) == None); + }); +} diff --git a/runtime/parachains/src/assigner_parachains.rs b/runtime/parachains/src/assigner_parachains.rs new file mode 100644 index 000000000000..9a6b970597d5 --- /dev/null +++ b/runtime/parachains/src/assigner_parachains.rs @@ -0,0 +1,70 @@ +// Copyright (C) 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 . + +//! The bulk (parachain slot auction) blockspace assignment provider. +//! This provider is tightly coupled with the configuration and paras modules. + +use crate::{ + configuration, paras, + scheduler::common::{AssignmentProvider, AssignmentProviderConfig}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +pub use pallet::*; +use primitives::{v5::Assignment, CoreIndex, Id as ParaId}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + configuration::Config + paras::Config {} +} + +impl AssignmentProvider> for Pallet { + fn session_core_count() -> u32 { + >::parachains().len() as u32 + } + + fn pop_assignment_for_core( + core_idx: CoreIndex, + _concluded_para: Option, + ) -> Option { + >::parachains() + .get(core_idx.0 as usize) + .copied() + .map(|para_id| Assignment::new(para_id)) + } + + /// Bulk assignment has no need to push the assignment back on a session change, + /// this is a no-op in the case of a bulk assignment slot. + fn push_assignment_for_core(_: CoreIndex, _: Assignment) {} + + fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig> { + let config = >::config(); + AssignmentProviderConfig { + availability_period: config.paras_availability_period, + // The next assignment already goes to the same [`ParaId`], no timeout tracking needed. + max_availability_timeouts: 0, + // The next assignment already goes to the same [`ParaId`], this can be any number + // that's high enough to clear the time it takes to clear backing/availability. + ttl: BlockNumberFor::::from(10u32), + } + } +} diff --git a/runtime/parachains/src/builder.rs b/runtime/parachains/src/builder.rs index 3f95b2087e6c..4921af5bedda 100644 --- a/runtime/parachains/src/builder.rs +++ b/runtime/parachains/src/builder.rs @@ -17,20 +17,22 @@ use crate::{ configuration, inclusion, initializer, paras, paras::ParaKind, - paras_inherent::{self}, - scheduler, session_info, shared, + paras_inherent, + scheduler::{self, common::AssignmentProviderConfig}, + session_info, shared, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use primitives::{ - collator_signature_payload, AvailabilityBitfield, BackedCandidate, CandidateCommitments, - CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, - CompactStatement, CoreIndex, CoreOccupied, DisputeStatement, DisputeStatementSet, GroupIndex, - HeadData, Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, - InvalidDisputeStatementKind, PersistedValidationData, SessionIndex, SigningContext, - UncheckedSigned, ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, - ValidityAttestation, + collator_signature_payload, + v5::{Assignment, ParasEntry}, + AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor, + CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement, + CoreIndex, CoreOccupied, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData, + Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, InvalidDisputeStatementKind, + PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned, + ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation, }; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -689,13 +691,22 @@ impl BenchBuilder { ); assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores as usize,); - // Mark all the used cores as occupied. We expect that their are + // Mark all the used cores as occupied. We expect that there are // `backed_and_concluding_cores` that are pending availability and that there are // `used_cores - backed_and_concluding_cores ` which are about to be disputed. - scheduler::AvailabilityCores::::set(vec![ - Some(CoreOccupied::Parachain); - used_cores as usize - ]); + let now = >::block_number() + One::one(); + let cores = (0..used_cores) + .into_iter() + .map(|i| { + let AssignmentProviderConfig { ttl, .. } = + scheduler::Pallet::::assignment_provider_config(CoreIndex(i)); + CoreOccupied::Paras(ParasEntry::new( + Assignment::new(ParaId::from(i as u32)), + now + ttl, + )) + }) + .collect(); + scheduler::AvailabilityCores::::set(cores); Bench:: { data: ParachainsInherentData { diff --git a/runtime/parachains/src/configuration.rs b/runtime/parachains/src/configuration.rs index 0631b280aadd..03d1ae420495 100644 --- a/runtime/parachains/src/configuration.rs +++ b/runtime/parachains/src/configuration.rs @@ -25,9 +25,9 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_parachain::primitives::{MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM}; use primitives::{ vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex, MAX_CODE_SIZE, - MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, + MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; -use sp_runtime::traits::Zero; +use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; #[cfg(test)] @@ -42,7 +42,7 @@ pub use pallet::*; const LOG_TARGET: &str = "runtime::configuration"; -/// All configuration of the runtime with respect to parachains and parathreads. +/// All configuration of the runtime with respect to paras. #[derive( Clone, Encode, @@ -113,10 +113,9 @@ pub struct HostConfiguration { /// been completed. /// /// Note, there are situations in which `expected_at` in the past. For example, if - /// [`chain_availability_period`] or [`thread_availability_period`] is less than the delay set - /// by this field or if PVF pre-check took more time than the delay. In such cases, the upgrade - /// is further at the earliest possible time determined by - /// [`minimum_validation_upgrade_delay`]. + /// [`paras_availability_period`] is less than the delay set by + /// this field or if PVF pre-check took more time than the delay. In such cases, the upgrade is + /// further at the earliest possible time determined by [`minimum_validation_upgrade_delay`]. /// /// The rationale for this delay has to do with relay-chain reversions. In case there is an /// invalid candidate produced with the new version of the code, then the relay-chain can @@ -143,8 +142,6 @@ pub struct HostConfiguration { pub max_downward_message_size: u32, /// The maximum number of outbound HRMP channels a parachain is allowed to open. pub hrmp_max_parachain_outbound_channels: u32, - /// The maximum number of outbound HRMP channels a parathread is allowed to open. - pub hrmp_max_parathread_outbound_channels: u32, /// The deposit that the sender should provide for opening an HRMP channel. pub hrmp_sender_deposit: Balance, /// The deposit that the recipient should provide for accepting opening an HRMP channel. @@ -155,8 +152,6 @@ pub struct HostConfiguration { pub hrmp_channel_max_total_size: u32, /// The maximum number of inbound HRMP channels a parachain is allowed to accept. pub hrmp_max_parachain_inbound_channels: u32, - /// The maximum number of inbound HRMP channels a parathread is allowed to accept. - pub hrmp_max_parathread_inbound_channels: u32, /// The maximum size of a message that could ever be put into an HRMP channel. /// /// This parameter affects the upper bound of size of `CandidateCommitments`. @@ -171,26 +166,34 @@ pub struct HostConfiguration { /// How long to keep code on-chain, in blocks. This should be sufficiently long that disputes /// have concluded. pub code_retention_period: BlockNumber, - /// The amount of execution cores to dedicate to parathread execution. - pub parathread_cores: u32, - /// The number of retries that a parathread author has to submit their block. - pub parathread_retries: u32, + /// The amount of execution cores to dedicate to on demand execution. + pub on_demand_cores: u32, + /// The number of retries that a on demand author has to submit their block. + pub on_demand_retries: u32, + /// The maximum queue size of the pay as you go module. + pub on_demand_queue_max_size: u32, + /// The target utilization of the spot price queue in percentages. + pub on_demand_target_queue_utilization: Perbill, + /// How quickly the fee rises in reaction to increased utilization. + /// The lower the number the slower the increase. + pub on_demand_fee_variability: Perbill, + /// The minimum amount needed to claim a slot in the spot pricing queue. + pub on_demand_base_fee: Balance, + /// The number of blocks an on demand claim stays in the scheduler's claimqueue before getting + /// cleared. This number should go reasonably higher than the number of blocks in the async + /// backing lookahead. + pub on_demand_ttl: BlockNumber, /// How often parachain groups should be rotated across parachains. /// /// Must be non-zero. pub group_rotation_frequency: BlockNumber, - /// The availability period, in blocks, for parachains. This is the amount of blocks + /// The availability period, in blocks. This is the amount of blocks /// after inclusion that validators have to make the block available and signal its /// availability to the chain. /// /// Must be at least 1. - pub chain_availability_period: BlockNumber, - /// The availability period, in blocks, for parathreads. Same as the - /// `chain_availability_period`, but a differing timeout due to differing requirements. - /// - /// Must be at least 1. - pub thread_availability_period: BlockNumber, - /// The amount of blocks ahead to schedule parachains and parathreads. + pub paras_availability_period: BlockNumber, + /// The amount of blocks ahead to schedule paras. pub scheduling_lookahead: u32, /// The maximum number of validators to have per core. /// @@ -237,8 +240,7 @@ pub struct HostConfiguration { /// To prevent that, we introduce the minimum number of blocks after which the upgrade can be /// scheduled. This number is controlled by this field. /// - /// This value should be greater than [`chain_availability_period`] and - /// [`thread_availability_period`]. + /// This value should be greater than [`paras_availability_period`]. pub minimum_validation_upgrade_delay: BlockNumber, } @@ -250,8 +252,7 @@ impl> Default for HostConfiguration> Default for HostConfiguration> Default for HostConfiguration> Default for HostConfiguration { /// `group_rotation_frequency` is set to zero. ZeroGroupRotationFrequency, - /// `chain_availability_period` is set to zero. - ZeroChainAvailabilityPeriod, - /// `thread_availability_period` is set to zero. - ZeroThreadAvailabilityPeriod, + /// `paras_availability_period` is set to zero. + ZeroParasAvailabilityPeriod, /// `no_show_slots` is set to zero. ZeroNoShowSlots, /// `max_code_size` exceeds the hard limit of `MAX_CODE_SIZE`. @@ -309,15 +311,10 @@ pub enum InconsistentError { MaxHeadDataSizeExceedHardLimit { max_head_data_size: u32 }, /// `max_pov_size` exceeds the hard limit of `MAX_POV_SIZE`. MaxPovSizeExceedHardLimit { max_pov_size: u32 }, - /// `minimum_validation_upgrade_delay` is less than `chain_availability_period`. + /// `minimum_validation_upgrade_delay` is less than `paras_availability_period`. MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod { minimum_validation_upgrade_delay: BlockNumber, - chain_availability_period: BlockNumber, - }, - /// `minimum_validation_upgrade_delay` is less than `thread_availability_period`. - MinimumValidationUpgradeDelayLessThanThreadAvailabilityPeriod { - minimum_validation_upgrade_delay: BlockNumber, - thread_availability_period: BlockNumber, + paras_availability_period: BlockNumber, }, /// `validation_upgrade_delay` is less than or equal 1. ValidationUpgradeDelayIsTooLow { validation_upgrade_delay: BlockNumber }, @@ -349,12 +346,8 @@ where return Err(ZeroGroupRotationFrequency) } - if self.chain_availability_period.is_zero() { - return Err(ZeroChainAvailabilityPeriod) - } - - if self.thread_availability_period.is_zero() { - return Err(ZeroThreadAvailabilityPeriod) + if self.paras_availability_period.is_zero() { + return Err(ZeroParasAvailabilityPeriod) } if self.no_show_slots.is_zero() { @@ -375,15 +368,10 @@ where return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size }) } - if self.minimum_validation_upgrade_delay <= self.chain_availability_period { + if self.minimum_validation_upgrade_delay <= self.paras_availability_period { return Err(MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod { minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(), - chain_availability_period: self.chain_availability_period.clone(), - }) - } else if self.minimum_validation_upgrade_delay <= self.thread_availability_period { - return Err(MinimumValidationUpgradeDelayLessThanThreadAvailabilityPeriod { - minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(), - thread_availability_period: self.thread_availability_period.clone(), + paras_availability_period: self.paras_availability_period.clone(), }) } @@ -442,6 +430,7 @@ pub trait WeightInfo { fn set_config_with_balance() -> Weight; fn set_hrmp_open_request_ttl() -> Weight; fn set_config_with_executor_params() -> Weight; + fn set_config_with_perbill() -> Weight; } pub struct TestWeightInfo; @@ -464,6 +453,9 @@ impl WeightInfo for TestWeightInfo { fn set_config_with_executor_params() -> Weight { Weight::MAX } + fn set_config_with_perbill() -> Weight { + Weight::MAX + } } #[frame_support::pallet] @@ -481,7 +473,8 @@ pub mod pallet { /// + /// v5-v6: (remove UMP dispatch queue) /// v6-v7: - const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); + /// v7-v8: + const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -626,29 +619,29 @@ pub mod pallet { }) } - /// Set the number of parathread execution cores. + /// Set the number of on demand execution cores. #[pallet::call_index(6)] #[pallet::weight(( T::WeightInfo::set_config_with_u32(), DispatchClass::Operational, ))] - pub fn set_parathread_cores(origin: OriginFor, new: u32) -> DispatchResult { + pub fn set_on_demand_cores(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.parathread_cores = new; + config.on_demand_cores = new; }) } - /// Set the number of retries for a particular parathread. + /// Set the number of retries for a particular on demand. #[pallet::call_index(7)] #[pallet::weight(( T::WeightInfo::set_config_with_u32(), DispatchClass::Operational, ))] - pub fn set_parathread_retries(origin: OriginFor, new: u32) -> DispatchResult { + pub fn set_on_demand_retries(origin: OriginFor, new: u32) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.parathread_retries = new; + config.on_demand_retries = new; }) } @@ -668,35 +661,19 @@ pub mod pallet { }) } - /// Set the availability period for parachains. + /// Set the availability period for paras. #[pallet::call_index(9)] #[pallet::weight(( T::WeightInfo::set_config_with_block_number(), DispatchClass::Operational, ))] - pub fn set_chain_availability_period( - origin: OriginFor, - new: BlockNumberFor, - ) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.chain_availability_period = new; - }) - } - - /// Set the availability period for parathreads. - #[pallet::call_index(10)] - #[pallet::weight(( - T::WeightInfo::set_config_with_block_number(), - DispatchClass::Operational, - ))] - pub fn set_thread_availability_period( + pub fn set_paras_availability_period( origin: OriginFor, new: BlockNumberFor, ) -> DispatchResult { ensure_root(origin)?; Self::schedule_config_update(|config| { - config.thread_availability_period = new; + config.paras_availability_period = new; }) } @@ -989,22 +966,6 @@ pub mod pallet { }) } - /// Sets the maximum number of inbound HRMP channels a parathread is allowed to accept. - #[pallet::call_index(35)] - #[pallet::weight(( - T::WeightInfo::set_config_with_u32(), - DispatchClass::Operational, - ))] - pub fn set_hrmp_max_parathread_inbound_channels( - origin: OriginFor, - new: u32, - ) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.hrmp_max_parathread_inbound_channels = new; - }) - } - /// Sets the maximum size of a message that could ever be put into an HRMP channel. #[pallet::call_index(36)] #[pallet::weight(( @@ -1034,22 +995,6 @@ pub mod pallet { }) } - /// Sets the maximum number of outbound HRMP channels a parathread is allowed to open. - #[pallet::call_index(38)] - #[pallet::weight(( - T::WeightInfo::set_config_with_u32(), - DispatchClass::Operational, - ))] - pub fn set_hrmp_max_parathread_outbound_channels( - origin: OriginFor, - new: u32, - ) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.hrmp_max_parathread_outbound_channels = new; - }) - } - /// Sets the maximum number of outbound HRMP messages can be sent by a candidate. #[pallet::call_index(39)] #[pallet::weight(( @@ -1139,6 +1084,72 @@ pub mod pallet { config.executor_params = new; }) } + + /// Set the on demand (parathreads) base fee. + #[pallet::call_index(47)] + #[pallet::weight(( + T::WeightInfo::set_config_with_balance(), + DispatchClass::Operational, + ))] + pub fn set_on_demand_base_fee(origin: OriginFor, new: Balance) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.on_demand_base_fee = new; + }) + } + + /// Set the on demand (parathreads) fee variability. + #[pallet::call_index(48)] + #[pallet::weight(( + T::WeightInfo::set_config_with_perbill(), + DispatchClass::Operational, + ))] + pub fn set_on_demand_fee_variability(origin: OriginFor, new: Perbill) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.on_demand_fee_variability = new; + }) + } + + /// Set the on demand (parathreads) queue max size. + #[pallet::call_index(49)] + #[pallet::weight(( + T::WeightInfo::set_config_with_option_u32(), + DispatchClass::Operational, + ))] + pub fn set_on_demand_queue_max_size(origin: OriginFor, new: u32) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.on_demand_queue_max_size = new; + }) + } + /// Set the on demand (parathreads) fee variability. + #[pallet::call_index(50)] + #[pallet::weight(( + T::WeightInfo::set_config_with_perbill(), + DispatchClass::Operational, + ))] + pub fn set_on_demand_target_queue_utilization( + origin: OriginFor, + new: Perbill, + ) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.on_demand_target_queue_utilization = new; + }) + } + /// Set the on demand (parathreads) ttl in the claimqueue. + #[pallet::call_index(51)] + #[pallet::weight(( + T::WeightInfo::set_config_with_block_number(), + DispatchClass::Operational + ))] + pub fn set_on_demand_ttl(origin: OriginFor, new: BlockNumberFor) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.on_demand_ttl = new; + }) + } } #[pallet::hooks] diff --git a/runtime/parachains/src/configuration/benchmarking.rs b/runtime/parachains/src/configuration/benchmarking.rs index ef8fafd91c96..d9d11ab56e49 100644 --- a/runtime/parachains/src/configuration/benchmarking.rs +++ b/runtime/parachains/src/configuration/benchmarking.rs @@ -47,6 +47,8 @@ benchmarks! { ExecutorParam::PvfExecTimeout(PvfExecTimeoutKind::Approval, 12_000), ][..])) + set_config_with_perbill {}: set_on_demand_fee_variability(RawOrigin::Root, Perbill::from_percent(100)) + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(Default::default()), diff --git a/runtime/parachains/src/configuration/migration.rs b/runtime/parachains/src/configuration/migration.rs index ae035abac505..4499b116462b 100644 --- a/runtime/parachains/src/configuration/migration.rs +++ b/runtime/parachains/src/configuration/migration.rs @@ -18,3 +18,4 @@ pub mod v6; pub mod v7; +pub mod v8; diff --git a/runtime/parachains/src/configuration/migration/v7.rs b/runtime/parachains/src/configuration/migration/v7.rs index 78a7cf9e4dc0..113651381207 100644 --- a/runtime/parachains/src/configuration/migration/v7.rs +++ b/runtime/parachains/src/configuration/migration/v7.rs @@ -23,13 +23,106 @@ use frame_support::{ weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; -use primitives::SessionIndex; +use primitives::{vstaging::AsyncBackingParams, Balance, ExecutorParams, SessionIndex}; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; use super::v6::V6HostConfiguration; -type V7HostConfiguration = configuration::HostConfiguration; + +#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, Clone)] +pub struct V7HostConfiguration { + pub max_code_size: u32, + pub max_head_data_size: u32, + pub max_upward_queue_count: u32, + pub max_upward_queue_size: u32, + pub max_upward_message_size: u32, + pub max_upward_message_num_per_candidate: u32, + pub hrmp_max_message_num_per_candidate: u32, + pub validation_upgrade_cooldown: BlockNumber, + pub validation_upgrade_delay: BlockNumber, + pub async_backing_params: AsyncBackingParams, + pub max_pov_size: u32, + pub max_downward_message_size: u32, + pub hrmp_max_parachain_outbound_channels: u32, + pub hrmp_max_parathread_outbound_channels: u32, + pub hrmp_sender_deposit: Balance, + pub hrmp_recipient_deposit: Balance, + pub hrmp_channel_max_capacity: u32, + pub hrmp_channel_max_total_size: u32, + pub hrmp_max_parachain_inbound_channels: u32, + pub hrmp_max_parathread_inbound_channels: u32, + pub hrmp_channel_max_message_size: u32, + pub executor_params: ExecutorParams, + pub code_retention_period: BlockNumber, + pub parathread_cores: u32, + pub parathread_retries: u32, + pub group_rotation_frequency: BlockNumber, + pub chain_availability_period: BlockNumber, + pub thread_availability_period: BlockNumber, + pub scheduling_lookahead: u32, + pub max_validators_per_core: Option, + pub max_validators: Option, + pub dispute_period: SessionIndex, + pub dispute_post_conclusion_acceptance_period: BlockNumber, + pub no_show_slots: u32, + pub n_delay_tranches: u32, + pub zeroth_delay_tranche_width: u32, + pub needed_approvals: u32, + pub relay_vrf_modulo_samples: u32, + pub pvf_voting_ttl: SessionIndex, + pub minimum_validation_upgrade_delay: BlockNumber, +} + +impl> Default for V7HostConfiguration { + fn default() -> Self { + Self { + async_backing_params: AsyncBackingParams { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, + group_rotation_frequency: 1u32.into(), + chain_availability_period: 1u32.into(), + thread_availability_period: 1u32.into(), + no_show_slots: 1u32.into(), + validation_upgrade_cooldown: Default::default(), + validation_upgrade_delay: 2u32.into(), + code_retention_period: Default::default(), + max_code_size: Default::default(), + max_pov_size: Default::default(), + max_head_data_size: Default::default(), + parathread_cores: Default::default(), + parathread_retries: Default::default(), + scheduling_lookahead: Default::default(), + max_validators_per_core: Default::default(), + max_validators: None, + dispute_period: 6, + dispute_post_conclusion_acceptance_period: 100.into(), + n_delay_tranches: Default::default(), + zeroth_delay_tranche_width: Default::default(), + needed_approvals: Default::default(), + relay_vrf_modulo_samples: Default::default(), + max_upward_queue_count: Default::default(), + max_upward_queue_size: Default::default(), + max_downward_message_size: Default::default(), + max_upward_message_size: Default::default(), + max_upward_message_num_per_candidate: Default::default(), + hrmp_sender_deposit: Default::default(), + hrmp_recipient_deposit: Default::default(), + hrmp_channel_max_capacity: Default::default(), + hrmp_channel_max_total_size: Default::default(), + hrmp_max_parachain_inbound_channels: Default::default(), + hrmp_max_parathread_inbound_channels: Default::default(), + hrmp_channel_max_message_size: Default::default(), + hrmp_max_parachain_outbound_channels: Default::default(), + hrmp_max_parathread_outbound_channels: Default::default(), + hrmp_max_message_num_per_candidate: Default::default(), + pvf_voting_ttl: 2u32.into(), + minimum_validation_upgrade_delay: 2.into(), + executor_params: Default::default(), + } + } +} mod v6 { use super::*; diff --git a/runtime/parachains/src/configuration/migration/v8.rs b/runtime/parachains/src/configuration/migration/v8.rs new file mode 100644 index 000000000000..7f7cc1cdefcd --- /dev/null +++ b/runtime/parachains/src/configuration/migration/v8.rs @@ -0,0 +1,319 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::configuration::{self, Config, Pallet}; +use frame_support::{ + pallet_prelude::*, + traits::{Defensive, StorageVersion}, + weights::Weight, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::SessionIndex; +use sp_runtime::Perbill; +use sp_std::vec::Vec; + +use frame_support::traits::OnRuntimeUpgrade; + +use super::v7::V7HostConfiguration; +type V8HostConfiguration = configuration::HostConfiguration; + +mod v7 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V7HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V7HostConfiguration>)>, + OptionQuery, + >; +} + +mod v8 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V8HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V8HostConfiguration>)>, + OptionQuery, + >; +} + +pub struct MigrateToV8(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for MigrateToV8 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV8"); + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV8 started"); + if StorageVersion::get::>() == 7 { + let weight_consumed = migrate_to_v8::(); + + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV8 executed successfully"); + StorageVersion::new(8).put::>(); + + weight_consumed + } else { + log::warn!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV8 should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade() for HostConfiguration MigrateToV8"); + ensure!( + StorageVersion::get::>() >= 8, + "Storage version should be >= 8 after the migration" + ); + + Ok(()) + } +} + +fn migrate_to_v8() -> Weight { + // Unusual formatting is justified: + // - make it easier to verify that fields assign what they supposed to assign. + // - this code is transient and will be removed after all migrations are done. + // - this code is important enough to optimize for legibility sacrificing consistency. + #[rustfmt::skip] + let translate = + |pre: V7HostConfiguration>| -> + V8HostConfiguration> + { + V8HostConfiguration { +max_code_size : pre.max_code_size, +max_head_data_size : pre.max_head_data_size, +max_upward_queue_count : pre.max_upward_queue_count, +max_upward_queue_size : pre.max_upward_queue_size, +max_upward_message_size : pre.max_upward_message_size, +max_upward_message_num_per_candidate : pre.max_upward_message_num_per_candidate, +hrmp_max_message_num_per_candidate : pre.hrmp_max_message_num_per_candidate, +validation_upgrade_cooldown : pre.validation_upgrade_cooldown, +validation_upgrade_delay : pre.validation_upgrade_delay, +max_pov_size : pre.max_pov_size, +max_downward_message_size : pre.max_downward_message_size, +hrmp_sender_deposit : pre.hrmp_sender_deposit, +hrmp_recipient_deposit : pre.hrmp_recipient_deposit, +hrmp_channel_max_capacity : pre.hrmp_channel_max_capacity, +hrmp_channel_max_total_size : pre.hrmp_channel_max_total_size, +hrmp_max_parachain_inbound_channels : pre.hrmp_max_parachain_inbound_channels, +hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels, +hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size, +code_retention_period : pre.code_retention_period, +on_demand_cores : pre.parathread_cores, +on_demand_retries : pre.parathread_retries, +group_rotation_frequency : pre.group_rotation_frequency, +paras_availability_period : pre.chain_availability_period, +scheduling_lookahead : pre.scheduling_lookahead, +max_validators_per_core : pre.max_validators_per_core, +max_validators : pre.max_validators, +dispute_period : pre.dispute_period, +dispute_post_conclusion_acceptance_period: pre.dispute_post_conclusion_acceptance_period, +no_show_slots : pre.no_show_slots, +n_delay_tranches : pre.n_delay_tranches, +zeroth_delay_tranche_width : pre.zeroth_delay_tranche_width, +needed_approvals : pre.needed_approvals, +relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples, +pvf_voting_ttl : pre.pvf_voting_ttl, +minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, +async_backing_params : pre.async_backing_params, +executor_params : pre.executor_params, +on_demand_queue_max_size : 10_000u32, +on_demand_base_fee : 10_000_000u128, +on_demand_fee_variability : Perbill::from_percent(3), +on_demand_target_queue_utilization : Perbill::from_percent(25), +on_demand_ttl : 5u32.into(), + } + }; + + let v7 = v7::ActiveConfig::::get() + .defensive_proof("Could not decode old config") + .unwrap_or_default(); + let v8 = translate(v7); + v8::ActiveConfig::::set(Some(v8)); + + // Allowed to be empty. + let pending_v7 = v7::PendingConfigs::::get().unwrap_or_default(); + let mut pending_v8 = Vec::new(); + + for (session, v7) in pending_v7.into_iter() { + let v8 = translate(v7); + pending_v8.push((session, v8)); + } + v8::PendingConfigs::::set(Some(pending_v8.clone())); + + let num_configs = (pending_v8.len() + 1) as u64; + T::DbWeight::get().reads_writes(num_configs, num_configs) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{new_test_ext, Test}; + + #[test] + fn v8_deserialized_from_actual_data() { + // Example how to get new `raw_config`: + // We'll obtain the raw_config at a specified a block + // Steps: + // 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate + // 2. Set these parameters: + // 2.1. selected state query: configuration; activeConfig(): + // PolkadotRuntimeParachainsConfigurationHostConfiguration + // 2.2. blockhash to query at: + // 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of + // the block) + // 2.3. Note the value of encoded storage key -> + // 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the + // referenced block. + // 2.4. You'll also need the decoded values to update the test. + // 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage + // 3.1 Enter the encoded storage key and you get the raw config. + + // This exceeds the maximal line width length, but that's fine, since this is not code and + // doesn't need to be read and also leaving it as one line allows to easily copy it. + let raw_config = + hex_literal::hex![" + 0000300000800000080000000000100000c8000005000000050000000200000002000000000000000000000000005000000010000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000000100000b004000000000000000000001027000080b2e60e80c3c9018096980000000000000000000000000005000000140000000400000001000000010100000000060000006400000002000000190000000000000002000000020000000200000005000000" + ]; + + let v8 = + V8HostConfiguration::::decode(&mut &raw_config[..]).unwrap(); + + // We check only a sample of the values here. If we missed any fields or messed up data + // types that would skew all the fields coming after. + assert_eq!(v8.max_code_size, 3_145_728); + assert_eq!(v8.validation_upgrade_cooldown, 2); + assert_eq!(v8.max_pov_size, 5_242_880); + assert_eq!(v8.hrmp_channel_max_message_size, 1_048_576); + assert_eq!(v8.n_delay_tranches, 25); + assert_eq!(v8.minimum_validation_upgrade_delay, 5); + assert_eq!(v8.group_rotation_frequency, 20); + assert_eq!(v8.on_demand_cores, 0); + assert_eq!(v8.on_demand_base_fee, 10_000_000); + } + + #[test] + fn test_migrate_to_v8() { + // Host configuration has lots of fields. However, in this migration we only remove one + // field. The most important part to check are a couple of the last fields. We also pick + // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and + // also their type. + // + // We specify only the picked fields and the rest should be provided by the `Default` + // implementation. That implementation is copied over between the two types and should work + // fine. + let v7 = V7HostConfiguration:: { + needed_approvals: 69, + thread_availability_period: 55, + hrmp_recipient_deposit: 1337, + max_pov_size: 1111, + chain_availability_period: 33, + minimum_validation_upgrade_delay: 20, + ..Default::default() + }; + + let mut pending_configs = Vec::new(); + pending_configs.push((100, v7.clone())); + pending_configs.push((300, v7.clone())); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v6 version in the state. + v7::ActiveConfig::::set(Some(v7)); + v7::PendingConfigs::::set(Some(pending_configs)); + + migrate_to_v8::(); + + let v8 = v8::ActiveConfig::::get().unwrap(); + let mut configs_to_check = v8::PendingConfigs::::get().unwrap(); + configs_to_check.push((0, v8.clone())); + + for (_, v7) in configs_to_check { + #[rustfmt::skip] + { + assert_eq!(v7.max_code_size , v8.max_code_size); + assert_eq!(v7.max_head_data_size , v8.max_head_data_size); + assert_eq!(v7.max_upward_queue_count , v8.max_upward_queue_count); + assert_eq!(v7.max_upward_queue_size , v8.max_upward_queue_size); + assert_eq!(v7.max_upward_message_size , v8.max_upward_message_size); + assert_eq!(v7.max_upward_message_num_per_candidate , v8.max_upward_message_num_per_candidate); + assert_eq!(v7.hrmp_max_message_num_per_candidate , v8.hrmp_max_message_num_per_candidate); + assert_eq!(v7.validation_upgrade_cooldown , v8.validation_upgrade_cooldown); + assert_eq!(v7.validation_upgrade_delay , v8.validation_upgrade_delay); + assert_eq!(v7.max_pov_size , v8.max_pov_size); + assert_eq!(v7.max_downward_message_size , v8.max_downward_message_size); + assert_eq!(v7.hrmp_max_parachain_outbound_channels , v8.hrmp_max_parachain_outbound_channels); + assert_eq!(v7.hrmp_sender_deposit , v8.hrmp_sender_deposit); + assert_eq!(v7.hrmp_recipient_deposit , v8.hrmp_recipient_deposit); + assert_eq!(v7.hrmp_channel_max_capacity , v8.hrmp_channel_max_capacity); + assert_eq!(v7.hrmp_channel_max_total_size , v8.hrmp_channel_max_total_size); + assert_eq!(v7.hrmp_max_parachain_inbound_channels , v8.hrmp_max_parachain_inbound_channels); + assert_eq!(v7.hrmp_channel_max_message_size , v8.hrmp_channel_max_message_size); + assert_eq!(v7.code_retention_period , v8.code_retention_period); + assert_eq!(v7.on_demand_cores , v8.on_demand_cores); + assert_eq!(v7.on_demand_retries , v8.on_demand_retries); + assert_eq!(v7.group_rotation_frequency , v8.group_rotation_frequency); + assert_eq!(v7.paras_availability_period , v8.paras_availability_period); + assert_eq!(v7.scheduling_lookahead , v8.scheduling_lookahead); + assert_eq!(v7.max_validators_per_core , v8.max_validators_per_core); + assert_eq!(v7.max_validators , v8.max_validators); + assert_eq!(v7.dispute_period , v8.dispute_period); + assert_eq!(v7.no_show_slots , v8.no_show_slots); + assert_eq!(v7.n_delay_tranches , v8.n_delay_tranches); + assert_eq!(v7.zeroth_delay_tranche_width , v8.zeroth_delay_tranche_width); + assert_eq!(v7.needed_approvals , v8.needed_approvals); + assert_eq!(v7.relay_vrf_modulo_samples , v8.relay_vrf_modulo_samples); + assert_eq!(v7.pvf_voting_ttl , v8.pvf_voting_ttl); + assert_eq!(v7.minimum_validation_upgrade_delay , v8.minimum_validation_upgrade_delay); + assert_eq!(v7.async_backing_params.allowed_ancestry_len, v8.async_backing_params.allowed_ancestry_len); + assert_eq!(v7.async_backing_params.max_candidate_depth , v8.async_backing_params.max_candidate_depth); + assert_eq!(v7.executor_params , v8.executor_params); + }; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression. + } + }); + } + + // Test that migration doesn't panic in case there're no pending configurations upgrades in + // pallet's storage. + #[test] + fn test_migrate_to_v8_no_pending() { + let v7 = V7HostConfiguration::::default(); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v6 version in the state. + v7::ActiveConfig::::set(Some(v7)); + // Ensure there're no pending configs. + v7::PendingConfigs::::set(None); + + // Shouldn't fail. + migrate_to_v8::(); + }); + } +} diff --git a/runtime/parachains/src/configuration/tests.rs b/runtime/parachains/src/configuration/tests.rs index 0c2b5a779cb5..b2a81894a939 100644 --- a/runtime/parachains/src/configuration/tests.rs +++ b/runtime/parachains/src/configuration/tests.rs @@ -216,11 +216,7 @@ fn invariants() { ); assert_err!( - Configuration::set_chain_availability_period(RuntimeOrigin::root(), 0), - Error::::InvalidNewValue - ); - assert_err!( - Configuration::set_thread_availability_period(RuntimeOrigin::root(), 0), + Configuration::set_paras_availability_period(RuntimeOrigin::root(), 0), Error::::InvalidNewValue ); assert_err!( @@ -229,17 +225,12 @@ fn invariants() { ); ActiveConfig::::put(HostConfiguration { - chain_availability_period: 10, - thread_availability_period: 8, + paras_availability_period: 10, minimum_validation_upgrade_delay: 11, ..Default::default() }); assert_err!( - Configuration::set_chain_availability_period(RuntimeOrigin::root(), 12), - Error::::InvalidNewValue - ); - assert_err!( - Configuration::set_thread_availability_period(RuntimeOrigin::root(), 12), + Configuration::set_paras_availability_period(RuntimeOrigin::root(), 12), Error::::InvalidNewValue ); assert_err!( @@ -291,11 +282,10 @@ fn setting_pending_config_members() { max_code_size: 100_000, max_pov_size: 1024, max_head_data_size: 1_000, - parathread_cores: 2, - parathread_retries: 5, + on_demand_cores: 2, + on_demand_retries: 5, group_rotation_frequency: 20, - chain_availability_period: 10, - thread_availability_period: 8, + paras_availability_period: 10, scheduling_lookahead: 3, max_validators_per_core: None, max_validators: None, @@ -316,14 +306,17 @@ fn setting_pending_config_members() { 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, pvf_voting_ttl: 3, minimum_validation_upgrade_delay: 20, executor_params: Default::default(), + on_demand_queue_max_size: 10_000u32, + on_demand_base_fee: 10_000_000u128, + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_ttl: 5u32, }; Configuration::set_validation_upgrade_cooldown( @@ -345,9 +338,9 @@ fn setting_pending_config_members() { Configuration::set_max_pov_size(RuntimeOrigin::root(), new_config.max_pov_size).unwrap(); Configuration::set_max_head_data_size(RuntimeOrigin::root(), new_config.max_head_data_size) .unwrap(); - Configuration::set_parathread_cores(RuntimeOrigin::root(), new_config.parathread_cores) + Configuration::set_on_demand_cores(RuntimeOrigin::root(), new_config.on_demand_cores) .unwrap(); - Configuration::set_parathread_retries(RuntimeOrigin::root(), new_config.parathread_retries) + Configuration::set_on_demand_retries(RuntimeOrigin::root(), new_config.on_demand_retries) .unwrap(); Configuration::set_group_rotation_frequency( RuntimeOrigin::root(), @@ -361,14 +354,9 @@ fn setting_pending_config_members() { new_config.minimum_validation_upgrade_delay, ) .unwrap(); - Configuration::set_chain_availability_period( + Configuration::set_paras_availability_period( RuntimeOrigin::root(), - new_config.chain_availability_period, - ) - .unwrap(); - Configuration::set_thread_availability_period( - RuntimeOrigin::root(), - new_config.thread_availability_period, + new_config.paras_availability_period, ) .unwrap(); Configuration::set_scheduling_lookahead( @@ -462,11 +450,6 @@ fn setting_pending_config_members() { new_config.hrmp_max_parachain_inbound_channels, ) .unwrap(); - Configuration::set_hrmp_max_parathread_inbound_channels( - RuntimeOrigin::root(), - new_config.hrmp_max_parathread_inbound_channels, - ) - .unwrap(); Configuration::set_hrmp_channel_max_message_size( RuntimeOrigin::root(), new_config.hrmp_channel_max_message_size, @@ -477,11 +460,6 @@ fn setting_pending_config_members() { new_config.hrmp_max_parachain_outbound_channels, ) .unwrap(); - Configuration::set_hrmp_max_parathread_outbound_channels( - RuntimeOrigin::root(), - new_config.hrmp_max_parathread_outbound_channels, - ) - .unwrap(); Configuration::set_hrmp_max_message_num_per_candidate( RuntimeOrigin::root(), new_config.hrmp_max_message_num_per_candidate, diff --git a/runtime/parachains/src/dmp.rs b/runtime/parachains/src/dmp.rs index b88475c980ef..e4a7d5e17465 100644 --- a/runtime/parachains/src/dmp.rs +++ b/runtime/parachains/src/dmp.rs @@ -94,8 +94,9 @@ impl fmt::Debug for ProcessedDownwardMessagesAcceptanceErr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use ProcessedDownwardMessagesAcceptanceErr::*; match *self { - AdvancementRule => - write!(fmt, "DMQ is not empty, but processed_downward_messages is 0",), + AdvancementRule => { + write!(fmt, "DMQ is not empty, but processed_downward_messages is 0",) + }, Underflow { processed_downward_messages, dmq_length } => write!( fmt, "processed_downward_messages = {}, but dmq_length is only {}", diff --git a/runtime/parachains/src/hrmp.rs b/runtime/parachains/src/hrmp.rs index 1be2fe57b1df..27f9fdab7684 100644 --- a/runtime/parachains/src/hrmp.rs +++ b/runtime/parachains/src/hrmp.rs @@ -1184,11 +1184,7 @@ impl Pallet { let egress_cnt = HrmpEgressChannelsIndex::::decode_len(&origin).unwrap_or(0) as u32; let open_req_cnt = HrmpOpenChannelRequestCount::::get(&origin); - let channel_num_limit = if >::is_parathread(origin) { - config.hrmp_max_parathread_outbound_channels - } else { - config.hrmp_max_parachain_outbound_channels - }; + let channel_num_limit = config.hrmp_max_parachain_outbound_channels; ensure!( egress_cnt + open_req_cnt < channel_num_limit, Error::::OpenHrmpChannelLimitExceeded, @@ -1254,11 +1250,7 @@ impl Pallet { // check if by accepting this open channel request, this parachain would exceed the // number of inbound channels. let config = >::config(); - let channel_num_limit = if >::is_parathread(origin) { - config.hrmp_max_parathread_inbound_channels - } else { - config.hrmp_max_parachain_inbound_channels - }; + let channel_num_limit = config.hrmp_max_parachain_inbound_channels; let ingress_cnt = HrmpIngressChannelsIndex::::decode_len(&origin).unwrap_or(0) as u32; let accepted_cnt = HrmpAcceptedChannelRequestCount::::get(&origin); ensure!( diff --git a/runtime/parachains/src/hrmp/tests.rs b/runtime/parachains/src/hrmp/tests.rs index 8b9fd7136a13..8cfaf48d10ef 100644 --- a/runtime/parachains/src/hrmp/tests.rs +++ b/runtime/parachains/src/hrmp/tests.rs @@ -69,10 +69,8 @@ pub(crate) fn run_to_block(to: BlockNumber, new_session: Option 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_paras_outbound_channels: u32, + hrmp_max_paras_inbound_channels: u32, hrmp_max_message_num_per_candidate: u32, hrmp_channel_max_total_size: u32, hrmp_sender_deposit: Balance, @@ -84,10 +82,8 @@ impl Default for GenesisConfigBuilder { 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_paras_outbound_channels: 2, + hrmp_max_paras_inbound_channels: 2, hrmp_max_message_num_per_candidate: 2, hrmp_channel_max_total_size: 16, hrmp_sender_deposit: 100, @@ -102,10 +98,8 @@ impl GenesisConfigBuilder { 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_parachain_outbound_channels = self.hrmp_max_paras_outbound_channels; + config.hrmp_max_parachain_inbound_channels = self.hrmp_max_paras_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; diff --git a/runtime/parachains/src/inclusion/mod.rs b/runtime/parachains/src/inclusion/mod.rs index f4ef3b95065e..9786b87f1162 100644 --- a/runtime/parachains/src/inclusion/mod.rs +++ b/runtime/parachains/src/inclusion/mod.rs @@ -23,7 +23,7 @@ use crate::{ configuration::{self, HostConfiguration}, disputes, dmp, hrmp, paras, - scheduler::CoreAssignment, + scheduler::common::CoreAssignment, shared, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; @@ -178,7 +178,7 @@ pub trait RewardValidators { #[derive(Encode, Decode, PartialEq, TypeInfo)] #[cfg_attr(test, derive(Debug))] pub(crate) struct ProcessedCandidates { - pub(crate) core_indices: Vec, + pub(crate) core_indices: Vec<(CoreIndex, ParaId)>, pub(crate) candidate_receipt_with_backing_validator_indices: Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, } @@ -322,8 +322,6 @@ pub mod pallet { UnscheduledCandidate, /// Candidate scheduled despite pending candidate already existing for the para. CandidateScheduledBeforeParaFree, - /// Candidate included with the wrong collator. - WrongCollator, /// Scheduled cores out of order. ScheduledOutOfOrder, /// Head data exceeds the configured maximum. @@ -599,7 +597,7 @@ impl Pallet { pub(crate) fn process_candidates( parent_storage_root: T::Hash, candidates: Vec>, - scheduled: Vec, + scheduled: Vec>>, group_validators: GV, ) -> Result, DispatchError> where @@ -630,15 +628,16 @@ impl Pallet { let mut core_indices_and_backers = Vec::with_capacity(candidates.len()); let mut last_core = None; - let mut check_assignment_in_order = |assignment: &CoreAssignment| -> DispatchResult { - ensure!( - last_core.map_or(true, |core| assignment.core > core), - Error::::ScheduledOutOfOrder, - ); + let mut check_assignment_in_order = + |assignment: &CoreAssignment>| -> DispatchResult { + ensure!( + last_core.map_or(true, |core| assignment.core > core), + Error::::ScheduledOutOfOrder, + ); - last_core = Some(assignment.core); - Ok(()) - }; + last_core = Some(assignment.core); + Ok(()) + }; let signing_context = SigningContext { parent_hash, session_index: shared::Pallet::::session_index() }; @@ -680,17 +679,10 @@ impl Pallet { let para_id = backed_candidate.descriptor().para_id; let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; - for (i, assignment) in scheduled[skip..].iter().enumerate() { - check_assignment_in_order(assignment)?; - - if para_id == assignment.para_id { - if let Some(required_collator) = assignment.required_collator() { - ensure!( - required_collator == &backed_candidate.descriptor().collator, - Error::::WrongCollator, - ); - } + for (i, core_assignment) in scheduled[skip..].iter().enumerate() { + check_assignment_in_order(core_assignment)?; + if para_id == core_assignment.paras_entry.para_id() { ensure!( >::get(¶_id).is_none() && >::get(¶_id).is_none(), @@ -700,7 +692,7 @@ impl Pallet { // account for already skipped, and then skip this one. skip = i + skip + 1; - let group_vals = group_validators(assignment.group_idx) + let group_vals = group_validators(core_assignment.group_idx) .ok_or_else(|| Error::::InvalidGroupIndex)?; // check the signatures in the backing and that it is a majority. @@ -752,9 +744,9 @@ impl Pallet { } core_indices_and_backers.push(( - assignment.core, + (core_assignment.core, core_assignment.paras_entry.para_id()), backers, - assignment.group_idx, + core_assignment.group_idx, )); continue 'next_backed_candidate } @@ -788,7 +780,7 @@ impl Pallet { Self::deposit_event(Event::::CandidateBacked( candidate.candidate.to_plain(), candidate.candidate.commitments.head_data.clone(), - core, + core.0, group, )); @@ -800,7 +792,7 @@ impl Pallet { >::insert( ¶_id, CandidatePendingAvailability { - core, + core: core.0, hash: candidate_hash, descriptor, availability_votes, diff --git a/runtime/parachains/src/inclusion/tests.rs b/runtime/parachains/src/inclusion/tests.rs index 3b4d7a7df357..70179782a53a 100644 --- a/runtime/parachains/src/inclusion/tests.rs +++ b/runtime/parachains/src/inclusion/tests.rs @@ -24,7 +24,6 @@ use crate::{ }, paras::{ParaGenesisArgs, ParaKind}, paras_inherent::DisputedBitfield, - scheduler::AssignmentKind, }; use primitives::{SignedAvailabilityBitfields, UncheckedSignedAvailabilityBitfields}; @@ -33,6 +32,7 @@ use frame_support::assert_noop; use keyring::Sr25519Keyring; use parity_scale_codec::DecodeAll; use primitives::{ + v5::{Assignment, ParasEntry}, BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId, CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement, ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID, @@ -44,7 +44,7 @@ use test_helpers::{dummy_collator, dummy_collator_signature, dummy_validation_co fn default_config() -> HostConfiguration { let mut config = HostConfiguration::default(); - config.parathread_cores = 1; + config.on_demand_cores = 1; config.max_code_size = 0b100000; config.max_head_data_size = 0b100000; config @@ -201,7 +201,7 @@ pub(crate) fn run_to_block( } pub(crate) fn expected_bits() -> usize { - Paras::parachains().len() + Configuration::config().parathread_cores as usize + Paras::parachains().len() + Configuration::config().on_demand_cores as usize } fn default_bitfield() -> AvailabilityBitfield { @@ -877,26 +877,23 @@ fn candidate_checks() { .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; + let entry_ttl = 10_000; let thread_collator: CollatorId = Sr25519Keyring::Two.public().into(); - let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), group_idx: GroupIndex::from(0), }; let chain_b_assignment = CoreAssignment { core: CoreIndex::from(1), - para_id: chain_b, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl), group_idx: GroupIndex::from(1), }; let thread_a_assignment = CoreAssignment { core: CoreIndex::from(2), - para_id: thread_a, - kind: AssignmentKind::Parathread(thread_collator.clone(), 0), + paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl), group_idx: GroupIndex::from(2), }; @@ -1056,45 +1053,6 @@ fn candidate_checks() { ); } - // candidate has wrong collator. - { - let mut candidate = TestCandidateBuilder { - para_id: thread_a, - relay_parent: System::parent_hash(), - pov_hash: Hash::repeat_byte(1), - persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(), - hrmp_watermark: RELAY_PARENT_NUM, - ..Default::default() - } - .build(); - - assert!(CollatorId::from(Sr25519Keyring::One.public()) != thread_collator); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(2)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - ); - - assert_noop!( - ParaInclusion::process_candidates( - Default::default(), - vec![backed], - vec![ - chain_a_assignment.clone(), - chain_b_assignment.clone(), - thread_a_assignment.clone(), - ], - &group_validators, - ), - Error::::WrongCollator, - ); - } - // candidate not well-signed by collator. { let mut candidate = TestCandidateBuilder { @@ -1424,26 +1382,23 @@ fn backing_works() { .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) }; - let thread_collator: CollatorId = Sr25519Keyring::Two.public().into(); + let entry_ttl = 10_000; let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), group_idx: GroupIndex::from(0), }; let chain_b_assignment = CoreAssignment { core: CoreIndex::from(1), - para_id: chain_b, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl), group_idx: GroupIndex::from(1), }; let thread_a_assignment = CoreAssignment { core: CoreIndex::from(2), - para_id: thread_a, - kind: AssignmentKind::Parathread(thread_collator.clone(), 0), + paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl), group_idx: GroupIndex::from(2), }; @@ -1507,7 +1462,7 @@ fn backing_works() { BackingKind::Threshold, ); - let backed_candidates = vec![backed_a, backed_b, backed_c]; + let backed_candidates = vec![backed_a.clone(), backed_b.clone(), backed_c]; let get_backing_group_idx = { // the order defines the group implicitly for this test case let backed_candidates_with_groups = backed_candidates @@ -1544,7 +1499,11 @@ fn backing_works() { assert_eq!( occupied_cores, - vec![CoreIndex::from(0), CoreIndex::from(1), CoreIndex::from(2)] + vec![ + (CoreIndex::from(0), chain_a), + (CoreIndex::from(1), chain_b), + (CoreIndex::from(2), thread_a) + ] ); // Transform the votes into the setup we expect @@ -1702,10 +1661,11 @@ fn can_include_candidate_with_ok_code_upgrade() { .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) }; + let entry_ttl = 10_000; + let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), group_idx: GroupIndex::from(0), }; @@ -1739,7 +1699,7 @@ fn can_include_candidate_with_ok_code_upgrade() { ) .expect("candidates scheduled, in order, and backed"); - assert_eq!(occupied_cores, vec![CoreIndex::from(0)]); + assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); let backers = { let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len()); @@ -1958,8 +1918,11 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 5, + }, group_idx: GroupIndex::from(0), }; @@ -1993,7 +1956,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { ) .expect("candidates scheduled, in order, and backed"); - assert_eq!(occupied_cores, vec![CoreIndex::from(0)]); + assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); // Run a couple of blocks before the inclusion. run_to_block(7, |_| None); diff --git a/runtime/parachains/src/initializer.rs b/runtime/parachains/src/initializer.rs index e006c38e6dec..b4f8721be518 100644 --- a/runtime/parachains/src/initializer.rs +++ b/runtime/parachains/src/initializer.rs @@ -240,6 +240,9 @@ impl Pallet { buf }; + // inform about upcoming new session + scheduler::Pallet::::pre_new_session(); + let configuration::SessionChangeOutcome { prev_config, new_config } = configuration::Pallet::::initializer_on_new_session(&session_index); let new_config = new_config.unwrap_or_else(|| prev_config.clone()); diff --git a/runtime/parachains/src/lib.rs b/runtime/parachains/src/lib.rs index 43c5c6441ad9..a9348ebd2f41 100644 --- a/runtime/parachains/src/lib.rs +++ b/runtime/parachains/src/lib.rs @@ -23,6 +23,9 @@ #![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "256")] #![cfg_attr(not(feature = "std"), no_std)] +pub mod assigner; +pub mod assigner_on_demand; +pub mod assigner_parachains; pub mod configuration; pub mod disputes; pub mod dmp; diff --git a/runtime/parachains/src/mock.rs b/runtime/parachains/src/mock.rs index bab896c419f6..f978b6c3360e 100644 --- a/runtime/parachains/src/mock.rs +++ b/runtime/parachains/src/mock.rs @@ -17,7 +17,7 @@ //! Mocks for all the traits. use crate::{ - configuration, disputes, dmp, hrmp, + assigner, assigner_on_demand, assigner_parachains, configuration, disputes, dmp, hrmp, inclusion::{self, AggregateMessageOrigin, UmpQueueId}, initializer, origin, paras, paras::ParaKind, @@ -43,7 +43,7 @@ use sp_io::TestExternalities; use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, transaction_validity::TransactionPriority, - BuildStorage, Perbill, Permill, + BuildStorage, FixedU128, Perbill, Permill, }; use std::{cell::RefCell, collections::HashMap}; @@ -62,6 +62,9 @@ frame_support::construct_runtime!( ParaInclusion: inclusion, ParaInherent: paras_inherent, Scheduler: scheduler, + Assigner: assigner, + OnDemandAssigner: assigner_on_demand, + ParachainsAssigner: assigner_parachains, Initializer: initializer, Dmp: dmp, Hrmp: hrmp, @@ -281,7 +284,9 @@ impl crate::disputes::SlashingHandler for Test { fn initializer_on_new_session(_: SessionIndex) {} } -impl crate::scheduler::Config for Test {} +impl crate::scheduler::Config for Test { + type AssignmentProvider = Assigner; +} pub struct TestMessageQueueWeight; impl pallet_message_queue::WeightInfo for TestMessageQueueWeight { @@ -334,6 +339,24 @@ impl pallet_message_queue::Config for Test { type ServiceWeight = MessageQueueServiceWeight; } +impl assigner::Config for Test { + type ParachainsAssignmentProvider = ParachainsAssigner; + type OnDemandAssignmentProvider = OnDemandAssigner; +} + +impl assigner_parachains::Config for Test {} + +parameter_types! { + pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); +} + +impl assigner_on_demand::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type TrafficDefaultValue = OnDemandTrafficDefaultValue; + type WeightInfo = crate::assigner_on_demand::TestWeightInfo; +} + impl crate::inclusion::Config for Test { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; diff --git a/runtime/parachains/src/paras/tests.rs b/runtime/parachains/src/paras/tests.rs index a9b51fe2b45e..e2067448b288 100644 --- a/runtime/parachains/src/paras/tests.rs +++ b/runtime/parachains/src/paras/tests.rs @@ -746,8 +746,7 @@ fn full_parachain_cleanup_storage() { minimum_validation_upgrade_delay: 2, // Those are not relevant to this test. However, HostConfiguration is still a // subject for the consistency check. - chain_availability_period: 1, - thread_availability_period: 1, + paras_availability_period: 1, ..Default::default() }, }, diff --git a/runtime/parachains/src/paras_inherent/mod.rs b/runtime/parachains/src/paras_inherent/mod.rs index da0b972bc92c..0ace3c312269 100644 --- a/runtime/parachains/src/paras_inherent/mod.rs +++ b/runtime/parachains/src/paras_inherent/mod.rs @@ -28,7 +28,8 @@ use crate::{ inclusion::CandidateCheckContext, initializer, metrics::METRICS, - scheduler::{self, CoreAssignment, FreedReason}, + scheduler, + scheduler::common::{CoreAssignment, FreedReason}, shared, ParaId, }; use bitvec::prelude::BitVec; @@ -518,7 +519,7 @@ impl Pallet { .map(|(_session, candidate)| candidate) .collect::>(); - let mut freed_disputed: Vec<_> = + let freed_disputed: BTreeMap = >::collect_disputed(¤t_concluded_invalid_disputes) .into_iter() .map(|core| (core, FreedReason::Concluded)) @@ -528,16 +529,10 @@ impl Pallet { // a core index that was freed due to a dispute. // // I.e. 010100 would indicate, the candidates on Core 1 and 3 would be disputed. - let disputed_bitfield = create_disputed_bitfield( - expected_bits, - freed_disputed.iter().map(|(core_index, _)| core_index), - ); + let disputed_bitfield = create_disputed_bitfield(expected_bits, freed_disputed.keys()); if !freed_disputed.is_empty() { - // unstable sort is fine, because core indices are unique - // i.e. the same candidate can't occupy 2 cores at once. - freed_disputed.sort_unstable_by_key(|pair| pair.0); // sort by core index - >::free_cores(freed_disputed.clone()); + >::update_claimqueue(freed_disputed.clone(), now); } let bitfields = sanitize_bitfields::( @@ -569,10 +564,7 @@ impl Pallet { let freed = collect_all_freed_cores::(freed_concluded.iter().cloned()); - >::clear(); - >::schedule(freed, now); - - let scheduled = >::scheduled(); + let scheduled = >::update_claimqueue(freed, now); let relay_parent_number = now - One::one(); let parent_storage_root = *parent_header.state_root(); @@ -614,7 +606,7 @@ impl Pallet { >::group_validators, )?; // Note which of the scheduled cores were actually occupied by a backed candidate. - >::occupied(&occupied); + >::occupied(occupied.into_iter().map(|e| (e.0, e.1)).collect()); set_scrapable_on_chain_backings::( current_session, @@ -908,7 +900,7 @@ fn sanitize_backed_candidates< relay_parent: T::Hash, mut backed_candidates: Vec>, mut candidate_has_concluded_invalid_dispute_or_is_invalid: F, - scheduled: &[CoreAssignment], + scheduled: &[CoreAssignment>], ) -> Vec> { // Remove any candidates that were concluded invalid. // This does not assume sorting. @@ -918,7 +910,7 @@ fn sanitize_backed_candidates< let scheduled_paras_to_core_idx = scheduled .into_iter() - .map(|core_assignment| (core_assignment.para_id, core_assignment.core)) + .map(|core_assignment| (core_assignment.paras_entry.para_id(), core_assignment.core)) .collect::>(); // Assure the backed candidate's `ParaId`'s core is free. diff --git a/runtime/parachains/src/paras_inherent/tests.rs b/runtime/parachains/src/paras_inherent/tests.rs index 4de12bcc91b7..4636200b762b 100644 --- a/runtime/parachains/src/paras_inherent/tests.rs +++ b/runtime/parachains/src/paras_inherent/tests.rs @@ -72,7 +72,10 @@ mod enter { // freed via becoming fully available, the backed candidates will not be filtered out in // `create_inherent` and will not cause `enter` to early. fn include_backed_candidates() { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let config = MockGenesisConfig::default(); + assert!(config.configuration.config.scheduling_lookahead > 0); + + new_test_ext(config).execute_with(|| { let dispute_statements = BTreeMap::new(); let mut backed_and_concluding = BTreeMap::new(); @@ -106,7 +109,7 @@ mod enter { .unwrap(); // The current schedule is empty prior to calling `create_inherent_enter`. - assert_eq!(>::scheduled(), vec![]); + assert!(>::claimqueue_is_empty()); // Nothing is filtered out (including the backed candidates.) assert_eq!( @@ -253,7 +256,7 @@ mod enter { .unwrap(); // The current schedule is empty prior to calling `create_inherent_enter`. - assert_eq!(>::scheduled(), vec![]); + assert!(>::claimqueue_is_empty()); let multi_dispute_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); @@ -322,7 +325,7 @@ mod enter { .unwrap(); // The current schedule is empty prior to calling `create_inherent_enter`. - assert_eq!(>::scheduled(), vec![]); + assert!(>::claimqueue_is_empty()); let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); @@ -391,7 +394,7 @@ mod enter { .unwrap(); // The current schedule is empty prior to calling `create_inherent_enter`. - assert_eq!(>::scheduled(), vec![]); + assert!(>::claimqueue_is_empty()); // Nothing is filtered out (including the backed candidates.) let limit_inherent_data = @@ -475,7 +478,7 @@ mod enter { .unwrap(); // The current schedule is empty prior to calling `create_inherent_enter`. - assert_eq!(>::scheduled(), vec![]); + assert!(>::claimqueue_is_empty()); // Nothing is filtered out (including the backed candidates.) let limit_inherent_data = @@ -601,7 +604,10 @@ mod enter { #[test] // Ensure that when a block is over weight due to disputes and bitfields, we filter. fn limit_candidates_over_weight_1() { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let config = MockGenesisConfig::default(); + assert!(config.configuration.config.scheduling_lookahead > 0); + + new_test_ext(config).execute_with(|| { // Create the inherent data for this block let mut dispute_statements = BTreeMap::new(); // Control the number of statements per dispute to ensure we have enough space @@ -953,7 +959,10 @@ mod sanitizers { use crate::mock::Test; use keyring::Sr25519Keyring; - use primitives::PARACHAIN_KEY_TYPE_ID; + use primitives::{ + v5::{Assignment, ParasEntry}, + PARACHAIN_KEY_TYPE_ID, + }; use sc_keystore::LocalKeystore; use sp_keystore::{Keystore, KeystorePtr}; use std::sync::Arc; @@ -1225,19 +1234,22 @@ mod sanitizers { let has_concluded_invalid = |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; + let entry_ttl = 10_000; let scheduled = (0_usize..2) .into_iter() .map(|idx| { + let core_idx = CoreIndex::from(idx as u32); let ca = CoreAssignment { - kind: scheduler::AssignmentKind::Parachain, + paras_entry: ParasEntry::new( + Assignment::new(ParaId::from(1_u32 + idx as u32)), + entry_ttl, + ), group_idx: GroupIndex::from(idx as u32), - para_id: ParaId::from(1_u32 + idx as u32), - core: CoreIndex::from(idx as u32), + core: core_idx, }; ca }) .collect::>(); - let scheduled = &scheduled[..]; let group_validators = |group_index: GroupIndex| { match group_index { @@ -1282,14 +1294,14 @@ mod sanitizers { relay_parent, backed_candidates.clone(), has_concluded_invalid, - scheduled + &scheduled ), backed_candidates ); // nothing is scheduled, so no paraids match, thus all backed candidates are skipped { - let scheduled = &[][..]; + let scheduled = &Vec::new(); assert!(sanitize_backed_candidates::( relay_parent, backed_candidates.clone(), @@ -1306,7 +1318,7 @@ mod sanitizers { relay_parent, backed_candidates.clone(), has_concluded_invalid, - scheduled + &scheduled ) .is_empty()); } @@ -1330,7 +1342,7 @@ mod sanitizers { relay_parent, backed_candidates.clone(), has_concluded_invalid, - scheduled + &scheduled ) .len(), backed_candidates.len() / 2 diff --git a/runtime/parachains/src/runtime_api_impl/v5.rs b/runtime/parachains/src/runtime_api_impl/v5.rs index 4c9c8c911f62..36b93a70a9f2 100644 --- a/runtime/parachains/src/runtime_api_impl/v5.rs +++ b/runtime/parachains/src/runtime_api_impl/v5.rs @@ -27,8 +27,8 @@ use primitives::{ CoreIndex, CoreOccupied, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScheduledCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_runtime::traits::One; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -52,13 +52,8 @@ pub fn validator_groups( /// Implementation for the `availability_cores` function of the runtime API. pub fn availability_cores() -> Vec>> { let cores = >::availability_cores(); - let parachains = >::parachains(); let config = >::config(); - let now = >::block_number() + One::one(); - >::clear(); - >::schedule(Vec::new(), now); - let rotation_info = >::group_rotation_info(now); let time_out_at = |backed_in_number, availability_period| { @@ -102,73 +97,39 @@ pub fn availability_cores() -> Vec CoreState::Occupied(match occupied { - CoreOccupied::Parachain => { - let para_id = parachains[i]; - let pending_availability = - >::pending_availability(para_id) - .expect("Occupied core always has pending availability; qed"); - - let backed_in_number = *pending_availability.backed_in_number(); - OccupiedCore { - next_up_on_available: >::next_up_on_available( - CoreIndex(i as u32), - ), - occupied_since: backed_in_number, - time_out_at: time_out_at( - backed_in_number, - config.chain_availability_period, - ), - next_up_on_time_out: >::next_up_on_time_out( - CoreIndex(i as u32), - ), - availability: pending_availability.availability_votes().clone(), - group_responsible: group_responsible_for( - backed_in_number, - pending_availability.core_occupied(), - ), - candidate_hash: pending_availability.candidate_hash(), - candidate_descriptor: pending_availability.candidate_descriptor().clone(), - } - }, - CoreOccupied::Parathread(p) => { - let para_id = p.claim.0; - let pending_availability = - >::pending_availability(para_id) - .expect("Occupied core always has pending availability; qed"); - - let backed_in_number = *pending_availability.backed_in_number(); - OccupiedCore { - next_up_on_available: >::next_up_on_available( - CoreIndex(i as u32), - ), - occupied_since: backed_in_number, - time_out_at: time_out_at( - backed_in_number, - config.thread_availability_period, - ), - next_up_on_time_out: >::next_up_on_time_out( - CoreIndex(i as u32), - ), - availability: pending_availability.availability_votes().clone(), - group_responsible: group_responsible_for( - backed_in_number, - pending_availability.core_occupied(), - ), - candidate_hash: pending_availability.candidate_hash(), - candidate_descriptor: pending_availability.candidate_descriptor().clone(), - } - }, - }), - None => CoreState::Free, + CoreOccupied::Paras(entry) => { + let pending_availability = + >::pending_availability(entry.para_id()) + .expect("Occupied core always has pending availability; qed"); + + let backed_in_number = *pending_availability.backed_in_number(); + CoreState::Occupied(OccupiedCore { + next_up_on_available: >::next_up_on_available(CoreIndex( + i as u32, + )), + occupied_since: backed_in_number, + time_out_at: time_out_at(backed_in_number, config.paras_availability_period), + next_up_on_time_out: >::next_up_on_time_out(CoreIndex( + i as u32, + )), + availability: pending_availability.availability_votes().clone(), + group_responsible: group_responsible_for( + backed_in_number, + pending_availability.core_occupied(), + ), + candidate_hash: pending_availability.candidate_hash(), + candidate_descriptor: pending_availability.candidate_descriptor().clone(), + }) + }, + CoreOccupied::Free => CoreState::Free, }) .collect(); // This will overwrite only `Free` cores if the scheduler module is working as intended. - for scheduled in >::scheduled() { - core_states[scheduled.core.0 as usize] = CoreState::Scheduled(ScheduledCore { - para_id: scheduled.para_id, - collator: scheduled.required_collator().map(|c| c.clone()), + for scheduled in >::scheduled_claimqueue(now) { + core_states[scheduled.core.0 as usize] = CoreState::Scheduled(primitives::ScheduledCore { + para_id: scheduled.paras_entry.para_id(), + collator: None, }); } diff --git a/runtime/parachains/src/scheduler.rs b/runtime/parachains/src/scheduler.rs index 6882834187dc..81a8bfc535e0 100644 --- a/runtime/parachains/src/scheduler.rs +++ b/runtime/parachains/src/scheduler.rs @@ -36,135 +36,46 @@ //! number of groups as availability cores. Validator groups will be assigned to different //! availability cores over time. +use crate::{configuration, initializer::SessionChangeNotification, paras}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - CollatorId, CoreIndex, CoreOccupied, GroupIndex, GroupRotationInfo, Id as ParaId, - ParathreadClaim, ParathreadEntry, ScheduledCore, ValidatorIndex, + v5::ParasEntry, CoreIndex, CoreOccupied, GroupIndex, GroupRotationInfo, Id as ParaId, + ScheduledCore, ValidatorIndex, }; -use scale_info::TypeInfo; use sp_runtime::traits::{One, Saturating}; -use sp_std::prelude::*; +use sp_std::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + prelude::*, +}; -use crate::{configuration, initializer::SessionChangeNotification, paras}; +pub mod common; + +use common::{AssignmentProvider, AssignmentProviderConfig, CoreAssignment, FreedReason}; 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))] -pub struct QueuedParathread { - claim: ParathreadEntry, - core_offset: u32, -} - -/// The queue of all parathread claims. -#[derive(Encode, Decode, TypeInfo)] -#[cfg_attr(test, derive(PartialEq, Debug))] -pub struct ParathreadClaimQueue { - queue: Vec, - // this value is between 0 and config.parathread_cores - next_core_offset: u32, -} - -impl ParathreadClaimQueue { - /// Queue a parathread entry to be processed. - /// - /// Provide the entry and the number of parathread cores, which must be greater than 0. - fn enqueue_entry(&mut self, entry: ParathreadEntry, n_parathread_cores: u32) { - let core_offset = self.next_core_offset; - self.next_core_offset = (self.next_core_offset + 1) % n_parathread_cores; - - self.queue.push(QueuedParathread { claim: entry, core_offset }) - } - - /// Take next queued entry with given core offset, if any. - fn take_next_on_core(&mut self, core_offset: u32) -> Option { - let pos = self.queue.iter().position(|queued| queued.core_offset == core_offset); - pos.map(|i| self.queue.remove(i).claim) - } - - /// Get the next queued entry with given core offset, if any. - fn get_next_on_core(&self, core_offset: u32) -> Option<&ParathreadEntry> { - let pos = self.queue.iter().position(|queued| queued.core_offset == core_offset); - pos.map(|i| &self.queue[i].claim) - } -} - -impl Default for ParathreadClaimQueue { - fn default() -> Self { - Self { queue: vec![], next_core_offset: 0 } - } -} - -/// Reasons a core might be freed -#[derive(Clone, Copy)] -pub enum FreedReason { - /// The core's work concluded and the parablock assigned to it is considered available. - Concluded, - /// The core's work timed out. - TimedOut, -} - -/// The assignment type. -#[derive(Clone, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(PartialEq, Debug))] -pub enum AssignmentKind { - /// A parachain. - Parachain, - /// A parathread. - Parathread(CollatorId, u32), -} - -/// How a free core is scheduled to be assigned. -#[derive(Clone, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(PartialEq, Debug))] -pub struct CoreAssignment { - /// The core that is assigned. - pub core: CoreIndex, - /// The unique ID of the para that is assigned to the core. - pub para_id: ParaId, - /// The kind of the assignment. - pub kind: AssignmentKind, - /// The index of the validator group assigned to the core. - pub group_idx: GroupIndex, -} - -impl CoreAssignment { - /// Get the ID of a collator who is required to collate this block. - pub fn required_collator(&self) -> Option<&CollatorId> { - match self.kind { - AssignmentKind::Parachain => None, - AssignmentKind::Parathread(ref id, _) => Some(id), - } - } - - /// Get the `CoreOccupied` from this. - pub fn to_core_occupied(&self) -> CoreOccupied { - match self.kind { - AssignmentKind::Parachain => CoreOccupied::Parachain, - AssignmentKind::Parathread(ref collator, retries) => - CoreOccupied::Parathread(ParathreadEntry { - claim: ParathreadClaim(self.para_id, collator.clone()), - retries, - }), - } - } -} +const LOG_TARGET: &str = "runtime::parachains::scheduler"; +pub mod migration; #[frame_support::pallet] pub mod pallet { use super::*; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + configuration::Config + paras::Config {} + pub trait Config: frame_system::Config + configuration::Config + paras::Config { + type AssignmentProvider: AssignmentProvider>; + } /// All the validator groups. One for each core. Indices are into `ActiveValidators` - not the /// broader set of Polkadot validators, but instead just the subset used for parachains during @@ -177,13 +88,6 @@ pub mod pallet { #[pallet::getter(fn validator_groups)] pub(crate) type ValidatorGroups = StorageValue<_, Vec>, ValueQuery>; - /// A queue of upcoming claims and which core they should be mapped onto. - /// - /// The number of queued claims is bounded at the `scheduling_lookahead` - /// multiplied by the number of parathread multiplexer cores. Reasonably, 10 * 50 = 500. - #[pallet::storage] - pub(crate) type ParathreadQueue = StorageValue<_, ParathreadClaimQueue, ValueQuery>; - /// One entry for each availability core. Entries are `None` if the core is not currently /// occupied. Can be temporarily `Some` if scheduled but not occupied. /// The i'th parachain belongs to the i'th core, with the remaining cores all being @@ -194,15 +98,8 @@ pub mod pallet { /// * The number of validators divided by `configuration.max_validators_per_core`. #[pallet::storage] #[pallet::getter(fn availability_cores)] - pub(crate) type AvailabilityCores = StorageValue<_, Vec>, ValueQuery>; - - /// An index used to ensure that only one claim on a parathread exists in the queue or is - /// currently being handled by an occupied core. - /// - /// Bounded by the number of parathread cores and scheduling lookahead. Reasonably, 10 * 50 = - /// 500. - #[pallet::storage] - pub(crate) type ParathreadClaimIndex = StorageValue<_, Vec, ValueQuery>; + pub(crate) type AvailabilityCores = + StorageValue<_, Vec>>, ValueQuery>; /// The block number where the session start occurred. Used to track how many group rotations /// have occurred. @@ -215,18 +112,24 @@ pub mod pallet { #[pallet::getter(fn session_start_block)] pub(crate) type SessionStartBlock = StorageValue<_, BlockNumberFor, ValueQuery>; - /// Currently scheduled cores - free but up to be occupied. - /// - /// Bounded by the number of cores: one for each parachain and parathread multiplexer. - /// - /// The value contained here will not be valid after the end of a block. Runtime APIs should be - /// used to determine scheduled cores/ for the upcoming block. + /// One entry for each availability core. The `VecDeque` represents the assignments to be + /// scheduled on that core. `None` is used to signal to not schedule the next para of the core + /// as there is one currently being scheduled. Not using `None` here would overwrite the + /// `CoreState` in the runtime API. The value contained here will not be valid after the end of + /// a block. Runtime APIs should be used to determine scheduled cores/ for the upcoming block. #[pallet::storage] - #[pallet::getter(fn scheduled)] - pub(crate) type Scheduled = StorageValue<_, Vec, ValueQuery>; - // sorted ascending by CoreIndex. + #[pallet::getter(fn claimqueue)] + pub(crate) type ClaimQueue = StorageValue< + _, + BTreeMap>>>>, + ValueQuery, + >; } +type PositionInClaimqueue = u32; +type TimedoutParas = BTreeMap>>; +type ConcludedParas = BTreeMap; + impl Pallet { /// Called by the initializer to initialize the scheduler pallet. pub(crate) fn initializer_initialize(_now: BlockNumberFor) -> Weight { @@ -236,6 +139,12 @@ impl Pallet { /// Called by the initializer to finalize the scheduler pallet. pub(crate) fn initializer_finalize() {} + /// Called before the initializer notifies of a new session. + pub(crate) fn pre_new_session() { + Self::push_claimqueue_items_to_assignment_provider(); + Self::push_occupied_cores_to_assignment_provider(); + } + /// Called by the initializer to note that a new session has started. pub(crate) fn initializer_on_new_session( notification: &SessionChangeNotification>, @@ -243,10 +152,8 @@ impl Pallet { let SessionChangeNotification { validators, new_config, .. } = notification; let config = new_config; - let mut thread_queue = ParathreadQueue::::get(); - let n_parachains = >::parachains().len() as u32; let n_cores = core::cmp::max( - n_parachains + config.parathread_cores, + T::AssignmentProvider::session_core_count(), match config.max_validators_per_core { Some(x) if x != 0 => validators.len() as u32 / x, _ => 0, @@ -254,19 +161,7 @@ impl Pallet { ); AvailabilityCores::::mutate(|cores| { - // clear all occupied cores. - for maybe_occupied in cores.iter_mut() { - if let Some(CoreOccupied::Parathread(claim)) = maybe_occupied.take() { - let queued = QueuedParathread { - claim, - core_offset: 0, // this gets set later in the re-balancing. - }; - - thread_queue.queue.push(queued); - } - } - - cores.resize(n_cores as _, None); + cores.resize(n_cores as _, CoreOccupied::Free); }); // shuffle validators into groups. @@ -303,288 +198,134 @@ impl Pallet { ValidatorGroups::::set(groups); } - // prune out all parathread claims with too many retries. - // assign all non-pruned claims to new cores, if they've changed. - ParathreadClaimIndex::::mutate(|claim_index| { - // wipe all parathread metadata if no parathread cores are configured. - if config.parathread_cores == 0 { - thread_queue = ParathreadClaimQueue { queue: Vec::new(), next_core_offset: 0 }; - claim_index.clear(); - return - } - - // prune out all entries beyond retry or that no longer correspond to live parathread. - thread_queue.queue.retain(|queued| { - let will_keep = queued.claim.retries <= config.parathread_retries && - >::is_parathread(queued.claim.claim.0); - - if !will_keep { - let claim_para = queued.claim.claim.0; - - // clean up the pruned entry from the index. - if let Ok(i) = claim_index.binary_search(&claim_para) { - claim_index.remove(i); - } - } - - will_keep - }); - - // do re-balancing of claims. - { - for (i, queued) in thread_queue.queue.iter_mut().enumerate() { - queued.core_offset = (i as u32) % config.parathread_cores; - } - - thread_queue.next_core_offset = - ((thread_queue.queue.len()) as u32) % config.parathread_cores; - } - }); - ParathreadQueue::::set(thread_queue); - let now = >::block_number() + One::one(); >::set(now); } - /// Add a parathread claim to the queue. If there is a competing claim in the queue or currently - /// assigned to a core, this call will fail. This call will also fail if the queue is full. - /// - /// Fails if the claim does not correspond to any live parathread. - #[allow(unused)] - pub fn add_parathread_claim(claim: ParathreadClaim) { - if !>::is_parathread(claim.0) { - return - } - - let config = >::config(); - let queue_max_size = config.parathread_cores * config.scheduling_lookahead; - - ParathreadQueue::::mutate(|queue| { - if queue.queue.len() >= queue_max_size as usize { - return - } - - let para_id = claim.0; - - let competes_with_another = - ParathreadClaimIndex::::mutate(|index| match index.binary_search(¶_id) { - Ok(_) => true, - Err(i) => { - index.insert(i, para_id); - false - }, - }); - - if competes_with_another { - return - } - - let entry = ParathreadEntry { claim, retries: 0 }; - queue.enqueue_entry(entry, config.parathread_cores); - }) - } - /// Free unassigned cores. Provide a list of cores that should be considered newly-freed along - /// with the reason for them being freed. The list is assumed to be sorted in ascending order by - /// core index. - pub(crate) fn free_cores(just_freed_cores: impl IntoIterator) { - let config = >::config(); + /// with the reason for them being freed. Returns a tuple of concluded and timedout paras. + fn free_cores( + just_freed_cores: impl IntoIterator, + ) -> (ConcludedParas, TimedoutParas) { + let mut timedout_paras: BTreeMap>> = + BTreeMap::new(); + let mut concluded_paras = BTreeMap::new(); AvailabilityCores::::mutate(|cores| { - for (freed_index, freed_reason) in just_freed_cores { - if (freed_index.0 as usize) < cores.len() { - match cores[freed_index.0 as usize].take() { - None => continue, - Some(CoreOccupied::Parachain) => {}, - Some(CoreOccupied::Parathread(entry)) => { + let c_len = cores.len(); + + just_freed_cores + .into_iter() + .filter(|(freed_index, _)| (freed_index.0 as usize) < c_len) + .for_each(|(freed_index, freed_reason)| { + match &cores[freed_index.0 as usize] { + CoreOccupied::Free => {}, + CoreOccupied::Paras(entry) => { match freed_reason { FreedReason::Concluded => { - // After a parathread candidate has successfully been included, - // open it up for further claims! - ParathreadClaimIndex::::mutate(|index| { - if let Ok(i) = index.binary_search(&entry.claim.0) { - index.remove(i); - } - }) + concluded_paras.insert(freed_index, entry.para_id()); }, FreedReason::TimedOut => { - // If a parathread candidate times out, it's not the collator's - // fault, so we don't increment retries. - ParathreadQueue::::mutate(|queue| { - queue.enqueue_entry(entry, config.parathread_cores); - }) + timedout_paras.insert(freed_index, entry.clone()); }, - } + }; }, - } - } - } - }) - } - - /// Schedule all unassigned cores, where possible. Provide a list of cores that should be - /// considered newly-freed along with the reason for them being freed. The list is assumed to be - /// sorted in ascending order by core index. - pub(crate) fn schedule( - just_freed_cores: impl IntoIterator, - now: BlockNumberFor, - ) { - Self::free_cores(just_freed_cores); - - let cores = AvailabilityCores::::get(); - let parachains = >::parachains(); - let mut scheduled = Scheduled::::get(); - let mut parathread_queue = ParathreadQueue::::get(); + }; - if ValidatorGroups::::get().is_empty() { - return - } + cores[freed_index.0 as usize] = CoreOccupied::Free; + }) + }); - { - let mut prev_scheduled_in_order = scheduled.iter().enumerate().peekable(); + (concluded_paras, timedout_paras) + } - // Updates to the previous list of scheduled updates and the position of where to insert - // them, without accounting for prior updates. - let mut scheduled_updates: Vec<(usize, CoreAssignment)> = Vec::new(); + /// Note that the given cores have become occupied. Update the claimqueue accordingly. + pub(crate) fn occupied( + now_occupied: BTreeMap, + ) -> BTreeMap { + let mut availability_cores = AvailabilityCores::::get(); - // single-sweep O(n) in the number of cores. - for (core_index, _core) in cores.iter().enumerate().filter(|(_, ref c)| c.is_none()) { - let schedule_and_insert_at = { - // advance the iterator until just before the core index we are looking at now. - while prev_scheduled_in_order - .peek() - .map_or(false, |(_, assign)| (assign.core.0 as usize) < core_index) - { - let _ = prev_scheduled_in_order.next(); - } + log::debug!(target: LOG_TARGET, "[occupied] now_occupied {:?}", now_occupied); + + let pos_mapping: BTreeMap = now_occupied + .iter() + .flat_map(|(core_idx, para_id)| { + match Self::remove_from_claimqueue(*core_idx, *para_id) { + Err(e) => { + log::debug!( + target: LOG_TARGET, + "[occupied] error on remove_from_claimqueue {}", + e + ); + None + }, + Ok((pos_in_claimqueue, pe)) => { + // is this correct? + availability_cores[core_idx.0 as usize] = CoreOccupied::Paras(pe); - // check the first entry already scheduled with core index >= than the one we - // are looking at. 3 cases: - // 1. No such entry, clearly this core is not scheduled, so we need to schedule - // and put at the end. 2. Entry exists and has same index as the core we are - // inspecting. do not schedule again. 3. Entry exists and has higher index than - // the core we are inspecting. schedule and note insertion position. - prev_scheduled_in_order.peek().map_or( - Some(scheduled.len()), - |(idx_in_scheduled, assign)| { - if (assign.core.0 as usize) == core_index { - None - } else { - Some(*idx_in_scheduled) - } - }, - ) - }; - - let schedule_and_insert_at = match schedule_and_insert_at { - None => continue, - Some(at) => at, - }; - - let core = CoreIndex(core_index as u32); - - let core_assignment = if core_index < parachains.len() { - // parachain core. - Some(CoreAssignment { - kind: AssignmentKind::Parachain, - para_id: parachains[core_index], - core, - group_idx: Self::group_assigned_to_core(core, now).expect( - "core is not out of bounds and we are guaranteed \ - to be after the most recent session start; qed", - ), - }) - } else { - // parathread core offset, rel. to beginning. - let core_offset = (core_index - parachains.len()) as u32; - - parathread_queue.take_next_on_core(core_offset).map(|entry| CoreAssignment { - kind: AssignmentKind::Parathread(entry.claim.1, entry.retries), - para_id: entry.claim.0, - core, - group_idx: Self::group_assigned_to_core(core, now).expect( - "core is not out of bounds and we are guaranteed \ - to be after the most recent session start; qed", - ), - }) - }; - - if let Some(assignment) = core_assignment { - scheduled_updates.push((schedule_and_insert_at, assignment)) + Some((*core_idx, pos_in_claimqueue)) + }, } - } + }) + .collect(); - // at this point, because `Scheduled` is guaranteed to be sorted and we navigated - // unassigned core indices in ascending order, we can enact the updates prepared by the - // previous actions. - // - // while inserting, we have to account for the amount of insertions already done. - // - // This is O(n) as well, capped at n operations, where n is the number of cores. - for (num_insertions_before, (insert_at, to_insert)) in - scheduled_updates.into_iter().enumerate() - { - let insert_at = num_insertions_before + insert_at; - scheduled.insert(insert_at, to_insert); - } + // Drop expired claims after processing now_occupied. + Self::drop_expired_claims_from_claimqueue(); - // scheduled is guaranteed to be sorted after this point because it was sorted before, - // and we applied sorted updates at their correct positions, accounting for the offsets - // of previous insertions. - } + AvailabilityCores::::set(availability_cores); - Scheduled::::set(scheduled); - ParathreadQueue::::set(parathread_queue); + pos_mapping } - /// Note that the given cores have become occupied. Behavior undefined if any of the given cores - /// were not scheduled or the slice is not sorted ascending by core index. - /// - /// Complexity: O(n) in the number of scheduled cores, which is capped at the number of total - /// cores. This is efficient in the case that most scheduled cores are occupied. - pub(crate) fn occupied(now_occupied: &[CoreIndex]) { - if now_occupied.is_empty() { - return - } + /// Iterates through every element in all claim queues and tries to add new assignments from the + /// `AssignmentProvider`. A claim is considered expired if it's `ttl` field is lower than the + /// current block height. + fn drop_expired_claims_from_claimqueue() { + let now = >::block_number(); + let availability_cores = AvailabilityCores::::get(); - let mut availability_cores = AvailabilityCores::::get(); - Scheduled::::mutate(|scheduled| { - // The constraints on the function require that `now_occupied` is a sorted subset of the - // `scheduled` cores, which are also sorted. - - let mut occupied_iter = now_occupied.iter().cloned().peekable(); - scheduled.retain(|assignment| { - let retain = occupied_iter - .peek() - .map_or(true, |occupied_idx| occupied_idx != &assignment.core); - - if !retain { - // remove this entry - it's now occupied. and begin inspecting the next extry - // of the occupied iterator. - let _ = occupied_iter.next(); - - availability_cores[assignment.core.0 as usize] = - Some(assignment.to_core_occupied()); + ClaimQueue::::mutate(|cq| { + for (idx, _) in (0u32..).zip(availability_cores) { + let core_idx = CoreIndex(idx); + if let Some(core_claimqueue) = cq.get_mut(&core_idx) { + let mut dropped_claims: Vec> = vec![]; + core_claimqueue.retain(|maybe_entry| { + if let Some(entry) = maybe_entry { + if entry.ttl < now { + dropped_claims.push(Some(entry.para_id())); + return false + } + } + true + }); + + // For all claims dropped due to TTL, attempt to pop a new entry to + // the back of the claimqueue. + for drop in dropped_claims { + match T::AssignmentProvider::pop_assignment_for_core(core_idx, drop) { + Some(assignment) => { + let AssignmentProviderConfig { ttl, .. } = + T::AssignmentProvider::get_provider_config(core_idx); + core_claimqueue.push_back(Some(ParasEntry::new( + assignment.clone(), + now + ttl, + ))); + }, + None => (), + } + } } - - retain - }) + } }); - - AvailabilityCores::::set(availability_cores); } /// Get the para (chain or thread) ID assigned to a particular core or index, if any. Core /// indices out of bounds will return `None`, as will indices of unassigned cores. pub(crate) fn core_para(core_index: CoreIndex) -> Option { let cores = AvailabilityCores::::get(); - match cores.get(core_index.0 as usize).and_then(|c| c.as_ref()) { - None => None, - Some(CoreOccupied::Parachain) => { - let parachains = >::parachains(); - Some(parachains[core_index.0 as usize]) - }, - Some(CoreOccupied::Parathread(ref entry)) => Some(entry.claim.0), + match cores.get(core_index.0 as usize) { + None | Some(CoreOccupied::Free) => None, + Some(CoreOccupied::Paras(entry)) => Some(entry.para_id()), } } @@ -630,52 +371,44 @@ impl Pallet { /// Returns an optional predicate that should be used for timing out occupied cores. /// /// If `None`, no timing-out should be done. The predicate accepts the index of the core, and - /// the block number since which it has been occupied, and the respective parachain and - /// parathread timeouts, i.e. only within `max(config.chain_availability_period, - /// config.thread_availability_period)` of the last rotation would this return `Some`, unless - /// there are no rotations. + /// the block number since which it has been occupied, and the respective parachain timeouts, + /// i.e. only within `config.paras_availability_period` of the last rotation would this return + /// `Some`, unless there are no rotations. /// - /// This really should not be a box, but is working around a compiler limitation filed here: - /// https://github.com/rust-lang/rust/issues/73226 - /// which prevents us from testing the code if using `impl Trait`. + /// The timeout used to depend, but does not depend any more on group rotations. First of all + /// it only matters if a para got another chance (a retry). If there is a retry and it happens + /// still within the same group rotation a censoring backing group would need to censor again + /// and lose out again on backing rewards. This is bad for the censoring backing group, it does + /// not matter for the parachain as long as it is retried often enough (so it eventually gets a + /// try on another backing group) - the effect is similar to having a prolonged timeout. It + /// should also be noted that for both malicious and offline backing groups it is actually more + /// realistic that the candidate will not be backed to begin with, instead of getting backed + /// and then not made available. pub(crate) fn availability_timeout_predicate( - ) -> Option) -> bool>> { + ) -> Option) -> bool> { let now = >::block_number(); let config = >::config(); - let session_start = >::get(); + let blocks_since_session_start = now.saturating_sub(session_start); let blocks_since_last_rotation = blocks_since_session_start % config.group_rotation_frequency.max(1u8.into()); - let absolute_cutoff = - sp_std::cmp::max(config.chain_availability_period, config.thread_availability_period); - - let availability_cores = AvailabilityCores::::get(); - - if blocks_since_last_rotation >= absolute_cutoff { + if blocks_since_last_rotation >= config.paras_availability_period { None } else { - Some(Box::new(move |core_index: CoreIndex, pending_since| { + Some(|core_index: CoreIndex, pending_since| { + let availability_cores = AvailabilityCores::::get(); + let AssignmentProviderConfig { availability_period, .. } = + T::AssignmentProvider::get_provider_config(core_index); + let now = >::block_number(); match availability_cores.get(core_index.0 as usize) { - None => true, // out-of-bounds, doesn't really matter what is returned. - Some(None) => true, // core not occupied, still doesn't really matter. - Some(Some(CoreOccupied::Parachain)) => { - if blocks_since_last_rotation >= config.chain_availability_period { - false // no pruning except recently after rotation. - } else { - now.saturating_sub(pending_since) >= config.chain_availability_period - } - }, - Some(Some(CoreOccupied::Parathread(_))) => { - if blocks_since_last_rotation >= config.thread_availability_period { - false // no pruning except recently after rotation. - } else { - now.saturating_sub(pending_since) >= config.thread_availability_period - } - }, + None => true, // out-of-bounds, doesn't really matter what is returned. + Some(CoreOccupied::Free) => true, // core free, still doesn't matter. + Some(CoreOccupied::Paras(_)) => + now.saturating_sub(pending_since) >= availability_period, } - })) + }) } } @@ -692,83 +425,254 @@ impl Pallet { /// Return the next thing that will be scheduled on this core assuming it is currently /// occupied and the candidate occupying it became available. - /// - /// For parachains, this is always the ID of the parachain and no specified collator. - /// For parathreads, this is based on the next item in the `ParathreadQueue` assigned to that - /// core, and is None if there isn't one. pub(crate) fn next_up_on_available(core: CoreIndex) -> Option { - let parachains = >::parachains(); - if (core.0 as usize) < parachains.len() { - Some(ScheduledCore { para_id: parachains[core.0 as usize], collator: None }) - } else { - let queue = ParathreadQueue::::get(); - let core_offset = (core.0 as usize - parachains.len()) as u32; - queue.get_next_on_core(core_offset).map(|entry| ScheduledCore { - para_id: entry.claim.0, - collator: Some(entry.claim.1.clone()), - }) - } + ClaimQueue::::get().get(&core).and_then(|a| { + a.iter() + .find_map(|e| e.as_ref()) + .map(|pe| Self::paras_entry_to_scheduled_core(pe)) + }) + } + + fn paras_entry_to_scheduled_core(pe: &ParasEntry>) -> ScheduledCore { + ScheduledCore { para_id: pe.para_id(), collator: None } } /// Return the next thing that will be scheduled on this core assuming it is currently - /// occupied and the candidate occupying it became available. - /// - /// For parachains, this is always the ID of the parachain and no specified collator. - /// For parathreads, this is based on the next item in the `ParathreadQueue` assigned to that - /// core, or if there isn't one, the claim that is currently occupying the core, as long - /// as the claim's retries would not exceed the limit. Otherwise None. + /// occupied and the candidate occupying it times out. pub(crate) fn next_up_on_time_out(core: CoreIndex) -> Option { - let parachains = >::parachains(); - if (core.0 as usize) < parachains.len() { - Some(ScheduledCore { para_id: parachains[core.0 as usize], collator: None }) - } else { - let queue = ParathreadQueue::::get(); - - // This is the next scheduled para on this core. - let core_offset = (core.0 as usize - parachains.len()) as u32; - queue - .get_next_on_core(core_offset) - .map(|entry| ScheduledCore { - para_id: entry.claim.0, - collator: Some(entry.claim.1.clone()), - }) - .or_else(|| { - // Or, if none, the claim currently occupying the core, - // as it would be put back on the queue after timing out. - let cores = AvailabilityCores::::get(); - cores.get(core.0 as usize).and_then(|c| c.as_ref()).and_then(|o| { - match o { - CoreOccupied::Parathread(entry) => Some(ScheduledCore { - para_id: entry.claim.0, - collator: Some(entry.claim.1.clone()), - }), - CoreOccupied::Parachain => None, // defensive; not possible. - } - }) - }) + Self::next_up_on_available(core).or_else(|| { + // Or, if none, the claim currently occupying the core, + // as it would be put back on the queue after timing out if number of retries is not at + // the maximum. + let cores = AvailabilityCores::::get(); + cores.get(core.0 as usize).and_then(|c| match c { + CoreOccupied::Free => None, + CoreOccupied::Paras(pe) => { + let AssignmentProviderConfig { max_availability_timeouts, .. } = + T::AssignmentProvider::get_provider_config(core); + + if pe.availability_timeouts < max_availability_timeouts { + Some(Self::paras_entry_to_scheduled_core(pe)) + } else { + None + } + }, + }) + }) + } + + /// Pushes occupied cores to the assignment provider. + fn push_occupied_cores_to_assignment_provider() { + AvailabilityCores::::mutate(|cores| { + for (core_idx, core) in cores.iter_mut().enumerate() { + match core { + CoreOccupied::Free => continue, + CoreOccupied::Paras(entry) => { + let core_idx = CoreIndex::from(core_idx as u32); + Self::maybe_push_assignment(core_idx, entry.clone()); + }, + } + *core = CoreOccupied::Free; + } + }); + } + + // on new session + fn push_claimqueue_items_to_assignment_provider() { + for (core_idx, core_claimqueue) in ClaimQueue::::take() { + // Push back in reverse order so that when we pop from the provider again, + // the entries in the claimqueue are in the same order as they are right now. + for para_entry in core_claimqueue.into_iter().flatten().rev() { + Self::maybe_push_assignment(core_idx, para_entry); + } } } - // Free all scheduled cores and return parathread claims to queue, with retries incremented. - pub(crate) fn clear() { - let config = >::config(); - ParathreadQueue::::mutate(|queue| { - for core_assignment in Scheduled::::take() { - if let AssignmentKind::Parathread(collator, retries) = core_assignment.kind { - if !>::is_parathread(core_assignment.para_id) { + /// Push assignments back to the provider on session change unless the paras + /// timed out on availability before. + fn maybe_push_assignment(core_idx: CoreIndex, pe: ParasEntry>) { + if pe.availability_timeouts == 0 { + T::AssignmentProvider::push_assignment_for_core(core_idx, pe.assignment); + } + } + + // + // ClaimQueue related functions + // + fn claimqueue_lookahead() -> u32 { + >::config().scheduling_lookahead + } + + /// Updates the claimqueue by moving it to the next paras and filling empty spots with new + /// paras. + pub(crate) fn update_claimqueue( + just_freed_cores: impl IntoIterator, + now: BlockNumberFor, + ) -> Vec>> { + Self::move_claimqueue_forward(); + Self::free_cores_and_fill_claimqueue(just_freed_cores, now) + } + + /// Moves all elements in the claimqueue forward. + fn move_claimqueue_forward() { + let mut cq = ClaimQueue::::get(); + for (_, core_queue) in cq.iter_mut() { + // First pop the finished claims from the front. + match core_queue.front() { + None => {}, + Some(None) => { + core_queue.pop_front(); + }, + Some(_) => {}, + } + } + + ClaimQueue::::set(cq); + } + + /// Frees cores and fills the free claimqueue spots by popping from the `AssignmentProvider`. + fn free_cores_and_fill_claimqueue( + just_freed_cores: impl IntoIterator, + now: BlockNumberFor, + ) -> Vec>> { + let (mut concluded_paras, mut timedout_paras) = Self::free_cores(just_freed_cores); + + // This can only happen on new sessions at which we move all assignments back to the + // provider. Hence, there's nothing we need to do here. + if ValidatorGroups::::get().is_empty() { + vec![] + } else { + let n_lookahead = Self::claimqueue_lookahead(); + let n_session_cores = T::AssignmentProvider::session_core_count(); + let cq = ClaimQueue::::get(); + let ttl = >::config().on_demand_ttl; + + for core_idx in 0..n_session_cores { + let core_idx = CoreIndex::from(core_idx); + + // add previously timedout paras back into the queue + if let Some(mut entry) = timedout_paras.remove(&core_idx) { + let AssignmentProviderConfig { max_availability_timeouts, .. } = + T::AssignmentProvider::get_provider_config(core_idx); + if entry.availability_timeouts < max_availability_timeouts { + // Increment the timeout counter. + entry.availability_timeouts += 1; + // Reset the ttl so that a timed out assignment. + entry.ttl = now + ttl; + Self::add_to_claimqueue(core_idx, entry); + // The claim has been added back into the claimqueue. + // Do not pop another assignment for the core. continue + } else { + // Consider timed out assignments for on demand parachains as concluded for + // the assignment provider + let ret = concluded_paras.insert(core_idx, entry.para_id()); + debug_assert!(ret.is_none()); } + } - let entry = ParathreadEntry { - claim: ParathreadClaim(core_assignment.para_id, collator), - retries: retries + 1, - }; - - if entry.retries <= config.parathread_retries { - queue.enqueue_entry(entry, config.parathread_cores); + // We consider occupied cores to be part of the claimqueue + let n_lookahead_used = cq.get(&core_idx).map_or(0, |v| v.len() as u32) + + if Self::is_core_occupied(core_idx) { 1 } else { 0 }; + for _ in n_lookahead_used..n_lookahead { + let concluded_para = concluded_paras.remove(&core_idx); + if let Some(assignment) = + T::AssignmentProvider::pop_assignment_for_core(core_idx, concluded_para) + { + Self::add_to_claimqueue(core_idx, ParasEntry::new(assignment, now + ttl)); } } } + + debug_assert!(timedout_paras.is_empty()); + debug_assert!(concluded_paras.is_empty()); + + Self::scheduled_claimqueue(now) + } + } + + fn is_core_occupied(core_idx: CoreIndex) -> bool { + match AvailabilityCores::::get().get(core_idx.0 as usize) { + None | Some(CoreOccupied::Free) => false, + Some(CoreOccupied::Paras(_)) => true, + } + } + + fn add_to_claimqueue(core_idx: CoreIndex, pe: ParasEntry>) { + ClaimQueue::::mutate(|la| { + let la_deque = la.entry(core_idx).or_insert_with(|| VecDeque::new()); + la_deque.push_back(Some(pe)); }); } + + /// Returns `ParasEntry` with `para_id` at `core_idx` if found. + fn remove_from_claimqueue( + core_idx: CoreIndex, + para_id: ParaId, + ) -> Result<(PositionInClaimqueue, ParasEntry>), &'static str> { + ClaimQueue::::mutate(|cq| { + let core_claims = cq.get_mut(&core_idx).ok_or("core_idx not found in lookahead")?; + + let pos = core_claims + .iter() + .position(|a| a.as_ref().map_or(false, |pe| pe.para_id() == para_id)) + .ok_or("para id not found at core_idx lookahead")?; + + let pe = core_claims + .remove(pos) + .ok_or("remove returned None")? + .ok_or("Element in Claimqueue was None.")?; + + // Since the core is now occupied, the next entry in the claimqueue in order to achieve + // 12 second block times needs to be None + if core_claims.front() != Some(&None) { + core_claims.push_front(None); + } + Ok((pos as u32, pe)) + }) + } + + // TODO: Temporary to imitate the old schedule() call. Will be adjusted when we make the + // scheduler AB ready + pub(crate) fn scheduled_claimqueue( + now: BlockNumberFor, + ) -> Vec>> { + let claimqueue = ClaimQueue::::get(); + + claimqueue + .into_iter() + .flat_map(|(core_idx, v)| { + v.front() + .cloned() + .flatten() + .and_then(|pe| Self::paras_entry_to_core_assignment(now, core_idx, pe)) + }) + .collect() + } + + fn paras_entry_to_core_assignment( + now: BlockNumberFor, + core_idx: CoreIndex, + pe: ParasEntry>, + ) -> Option>> { + let group_idx = Self::group_assigned_to_core(core_idx, now)?; + Some(CoreAssignment { core: core_idx, group_idx, paras_entry: pe }) + } + + #[cfg(any(feature = "runtime-benchmarks", test))] + pub(crate) fn assignment_provider_config( + core_idx: CoreIndex, + ) -> AssignmentProviderConfig> { + T::AssignmentProvider::get_provider_config(core_idx) + } + + #[cfg(any(feature = "try-runtime", test))] + fn claimqueue_len() -> usize { + ClaimQueue::::get().iter().map(|la_vec| la_vec.1.len()).sum() + } + + #[cfg(all(not(feature = "runtime-benchmarks"), test))] + pub(crate) fn claimqueue_is_empty() -> bool { + Self::claimqueue_len() == 0 + } } diff --git a/runtime/parachains/src/scheduler/common.rs b/runtime/parachains/src/scheduler/common.rs new file mode 100644 index 000000000000..c0404a875f33 --- /dev/null +++ b/runtime/parachains/src/scheduler/common.rs @@ -0,0 +1,98 @@ +// Copyright (C) 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 . + +//! Common traits and types used by the scheduler and assignment providers. + +use frame_support::pallet_prelude::*; +use primitives::{ + v5::{Assignment, ParasEntry}, + CoreIndex, GroupIndex, Id as ParaId, +}; +use scale_info::TypeInfo; +use sp_std::prelude::*; + +// Only used to link to configuration documentation. +#[allow(unused)] +use crate::configuration::HostConfiguration; + +/// Reasons a core might be freed +#[derive(Clone, Copy)] +pub enum FreedReason { + /// The core's work concluded and the parablock assigned to it is considered available. + Concluded, + /// The core's work timed out. + TimedOut, +} + +/// A set of variables required by the scheduler in order to operate. +pub struct AssignmentProviderConfig { + /// The availability period specified by the implementation. + /// See [`HostConfiguration::paras_availability_period`] for more information. + pub availability_period: BlockNumber, + + /// How many times a collation can time out on availability. + /// Zero timeouts still means that a collation can be provided as per the slot auction + /// assignment provider. + pub max_availability_timeouts: u32, + + /// How long the collator has to provide a collation to the backing group before being dropped. + pub ttl: BlockNumber, +} + +pub trait AssignmentProvider { + /// How many cores are allocated to this provider. + fn session_core_count() -> u32; + + /// Pops an [`Assignment`] from the provider for a specified [`CoreIndex`]. + /// The `concluded_para` field makes the caller report back to the provider + /// which [`ParaId`] it processed last on the supplied [`CoreIndex`]. + fn pop_assignment_for_core( + core_idx: CoreIndex, + concluded_para: Option, + ) -> Option; + + /// Push back an already popped assignment. Intended for provider implementations + /// that need to be able to keep track of assignments over session boundaries, + /// such as the on demand assignment provider. + fn push_assignment_for_core(core_idx: CoreIndex, assignment: Assignment); + + /// Returns a set of variables needed by the scheduler + fn get_provider_config(core_idx: CoreIndex) -> AssignmentProviderConfig; +} + +/// How a core is mapped to a backing group and a `ParaId` +#[derive(Clone, Encode, Decode, PartialEq, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct CoreAssignment { + /// The core that is assigned. + pub core: CoreIndex, + /// The para id and accompanying information needed to collate and back a parablock. + pub paras_entry: ParasEntry, + /// The index of the validator group assigned to the core. + pub group_idx: GroupIndex, +} + +impl CoreAssignment { + /// Returns the [`ParaId`] of the assignment. + pub fn para_id(&self) -> ParaId { + self.paras_entry.para_id() + } + + /// Returns the inner [`ParasEntry`] of the assignment. + pub fn to_paras_entry(self) -> ParasEntry { + self.paras_entry + } +} diff --git a/runtime/parachains/src/scheduler/migration.rs b/runtime/parachains/src/scheduler/migration.rs new file mode 100644 index 000000000000..4284b979264b --- /dev/null +++ b/runtime/parachains/src/scheduler/migration.rs @@ -0,0 +1,170 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A module that is responsible for migration of storage. + +use super::*; +use frame_support::{ + pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight, +}; +use primitives::vstaging::Assignment; + +mod v0 { + use super::*; + + use primitives::CollatorId; + #[storage_alias] + pub(super) type Scheduled = StorageValue, Vec, ValueQuery>; + + #[derive(Encode, Decode)] + pub struct QueuedParathread { + claim: primitives::ParathreadEntry, + core_offset: u32, + } + + #[derive(Encode, Decode, Default)] + pub struct ParathreadClaimQueue { + queue: Vec, + next_core_offset: u32, + } + + // Only here to facilitate the migration. + impl ParathreadClaimQueue { + pub fn len(self) -> usize { + self.queue.len() + } + } + + #[storage_alias] + pub(super) type ParathreadQueue = + StorageValue, ParathreadClaimQueue, ValueQuery>; + + #[storage_alias] + pub(super) type ParathreadClaimIndex = + StorageValue, Vec, ValueQuery>; + + /// The assignment type. + #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] + #[cfg_attr(feature = "std", derive(PartialEq))] + pub enum AssignmentKind { + /// A parachain. + Parachain, + /// A parathread. + Parathread(CollatorId, u32), + } + + /// How a free core is scheduled to be assigned. + #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] + #[cfg_attr(feature = "std", derive(PartialEq))] + pub struct CoreAssignment { + /// The core that is assigned. + pub core: CoreIndex, + /// The unique ID of the para that is assigned to the core. + pub para_id: ParaId, + /// The kind of the assignment. + pub kind: AssignmentKind, + /// The index of the validator group assigned to the core. + pub group_idx: GroupIndex, + } +} + +pub mod v1 { + use super::*; + use crate::scheduler; + use frame_support::traits::StorageVersion; + + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + fn on_runtime_upgrade() -> Weight { + if StorageVersion::get::>() == 0 { + let weight_consumed = migrate_to_v1::(); + + log::info!(target: scheduler::LOG_TARGET, "Migrating para scheduler storage to v1"); + StorageVersion::new(1).put::>(); + + weight_consumed + } else { + log::warn!(target: scheduler::LOG_TARGET, "Para scheduler v1 migration should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + log::trace!( + target: crate::scheduler::LOG_TARGET, + "Scheduled before migration: {}", + v0::Scheduled::::get().len() + ); + ensure!( + StorageVersion::get::>() == 0, + "Storage version should be less than `1` before the migration", + ); + + let bytes = u32::to_be_bytes(v0::Scheduled::::get().len() as u32); + + Ok(bytes.to_vec()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::DispatchError> { + log::trace!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); + ensure!( + StorageVersion::get::>() == 1, + "Storage version should be `1` after the migration" + ); + ensure!( + v0::Scheduled::::get().len() == 0, + "Scheduled should be empty after the migration" + ); + + let sched_len = u32::from_be_bytes(state.try_into().unwrap()); + ensure!( + Pallet::::claimqueue_len() as u32 == sched_len, + "Scheduled completely moved to ClaimQueue after migration" + ); + + Ok(()) + } + } +} + +pub fn migrate_to_v1() -> Weight { + let mut weight: Weight = Weight::zero(); + + let pq = v0::ParathreadQueue::::take(); + let pq_len = pq.len() as u64; + + let pci = v0::ParathreadClaimIndex::::take(); + let pci_len = pci.len() as u64; + + let now = >::block_number(); + let scheduled = v0::Scheduled::::take(); + let sched_len = scheduled.len() as u64; + for core_assignment in scheduled { + let core_idx = core_assignment.core; + let assignment = Assignment::new(core_assignment.para_id); + let pe = ParasEntry::new(assignment, now); + Pallet::::add_to_claimqueue(core_idx, pe); + } + + // 2x as once for Scheduled and once for Claimqueue + weight = weight.saturating_add(T::DbWeight::get().reads_writes(2 * sched_len, 2 * sched_len)); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(pq_len, pq_len)); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(pci_len, pci_len)); + + weight +} diff --git a/runtime/parachains/src/scheduler/tests.rs b/runtime/parachains/src/scheduler/tests.rs index cc2aee357231..0f64432c5f3a 100644 --- a/runtime/parachains/src/scheduler/tests.rs +++ b/runtime/parachains/src/scheduler/tests.rs @@ -18,13 +18,15 @@ use super::*; use frame_support::assert_ok; use keyring::Sr25519Keyring; -use primitives::{BlockNumber, CollatorId, SessionIndex, ValidationCode, ValidatorId}; +use primitives::{v5::Assignment, BlockNumber, SessionIndex, ValidationCode, ValidatorId}; +use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use crate::{ + assigner_on_demand::QueuePushDirection, configuration::HostConfiguration, initializer::SessionChangeNotification, mock::{ - new_test_ext, Configuration, MockGenesisConfig, Paras, ParasShared, RuntimeOrigin, + new_test_ext, MockGenesisConfig, OnDemandAssigner, Paras, ParasShared, RuntimeOrigin, Scheduler, System, Test, }, paras::{ParaGenesisArgs, ParaKind}, @@ -61,6 +63,8 @@ fn run_to_block( if notification_with_session_index.session_index == SessionIndex::default() { notification_with_session_index.session_index = ParasShared::scheduled_session(); } + Scheduler::pre_new_session(); + Paras::initializer_on_new_session(¬ification_with_session_index); Scheduler::initializer_on_new_session(¬ification_with_session_index); } @@ -74,8 +78,7 @@ fn run_to_block( 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); + Scheduler::update_claimqueue(BTreeMap::new(), b + 1); } } @@ -89,6 +92,8 @@ fn run_to_end_of_block( Paras::initializer_finalize(to); if let Some(notification) = new_session(to + 1) { + Scheduler::pre_new_session(); + Paras::initializer_on_new_session(¬ification); Scheduler::initializer_on_new_session(¬ification); } @@ -98,12 +103,11 @@ fn run_to_end_of_block( fn default_config() -> HostConfiguration { HostConfiguration { - parathread_cores: 3, + on_demand_cores: 3, group_rotation_frequency: 10, - chain_availability_period: 3, - thread_availability_period: 5, + paras_availability_period: 3, scheduling_lookahead: 2, - parathread_retries: 1, + on_demand_retries: 1, // 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 @@ -113,218 +117,181 @@ fn default_config() -> HostConfiguration { } } -#[test] -fn add_parathread_claim_works() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, +fn genesis_config(config: &HostConfiguration) -> MockGenesisConfig { + MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { config: config.clone() }, ..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, ParaKind::Parathread); - - assert!(!Paras::is_parathread(thread_id)); + } +} - run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); +pub(crate) fn claimqueue_contains_only_none() -> bool { + let mut cq = Scheduler::claimqueue(); + for (_, v) in cq.iter_mut() { + v.retain(|e| e.is_some()); + } - assert!(Paras::is_parathread(thread_id)); + cq.values().map(|v| v.len()).sum::() == 0 +} - { - 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, - } - ); - } +pub(crate) fn claimqueue_contains_para_ids(pids: Vec) -> bool { + let set: BTreeSet = ClaimQueue::::get() + .into_iter() + .flat_map(|(_, assignments)| { + assignments + .into_iter() + .filter_map(|assignment| assignment.and_then(|pe| Some(pe.para_id()))) + }) + .collect(); + + pids.into_iter().all(|pid| set.contains(&pid)) +} - // 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, - } - ); - } +pub(crate) fn availability_cores_contains_para_ids(pids: Vec) -> bool { + let set: BTreeSet = AvailabilityCores::::get() + .into_iter() + .filter_map(|core| match core { + CoreOccupied::Free => None, + CoreOccupied::Paras(entry) => Some(entry.para_id()), + }) + .collect(); - // 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, - } - ); - } - }) + pids.into_iter().all(|pid| set.contains(&pid)) } #[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() - }; +fn claimqueue_ttl_drop_fn_works() { + let mut config = default_config(); + config.scheduling_lookahead = 3; + let genesis_config = genesis_config(&config); - let thread_id = ParaId::from(10); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let para_id = ParaId::from(100); + let core_idx = CoreIndex::from(0); + let mut now = 10; new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(thread_id, ParaKind::Parathread); - - assert!(!Paras::is_parathread(thread_id)); - + assert!(default_config().on_demand_ttl == 5); + // Register and run to a blockheight where the para is in a valid state. + schedule_blank_para(para_id, ParaKind::Parathread); 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()); + // Add a claim on core 0 with a ttl in the past. + let paras_entry = ParasEntry::new(Assignment::new(para_id), now - 5); + Scheduler::add_to_claimqueue(core_idx, paras_entry.clone()); + + // Claim is in queue prior to call. + assert!(claimqueue_contains_para_ids::(vec![para_id])); + + // Claim is dropped post call. + Scheduler::drop_expired_claims_from_claimqueue(); + assert!(!claimqueue_contains_para_ids::(vec![para_id])); + + // Add a claim on core 0 with a ttl in the future (15). + let paras_entry = ParasEntry::new(Assignment::new(para_id), now + 5); + Scheduler::add_to_claimqueue(core_idx, paras_entry.clone()); + + // Claim is in queue post call. + Scheduler::drop_expired_claims_from_claimqueue(); + assert!(claimqueue_contains_para_ids::(vec![para_id])); + + now = now + 6; + run_to_block(now, |_| None); + + // Claim is dropped + Scheduler::drop_expired_claims_from_claimqueue(); + assert!(!claimqueue_contains_para_ids::(vec![para_id])); + + // Add a claim on core 0 with a ttl == now (16) + let paras_entry = ParasEntry::new(Assignment::new(para_id), now); + Scheduler::add_to_claimqueue(core_idx, paras_entry.clone()); + + // Claim is in queue post call. + Scheduler::drop_expired_claims_from_claimqueue(); + assert!(claimqueue_contains_para_ids::(vec![para_id])); + + now = now + 1; + run_to_block(now, |_| None); + + // Drop expired claim. + Scheduler::drop_expired_claims_from_claimqueue(); + + // Add a claim on core 0 with a ttl == now (17) + let paras_entry_non_expired = ParasEntry::new(Assignment::new(para_id), now); + let paras_entry_expired = ParasEntry::new(Assignment::new(para_id), now - 2); + // ttls = [17, 15, 17] + Scheduler::add_to_claimqueue(core_idx, paras_entry_non_expired.clone()); + Scheduler::add_to_claimqueue(core_idx, paras_entry_expired.clone()); + Scheduler::add_to_claimqueue(core_idx, paras_entry_non_expired.clone()); + let cq = Scheduler::claimqueue(); + assert!(cq.get(&core_idx).unwrap().len() == 3); + + // Add claims to on demand assignment provider. + let assignment = Assignment::new(para_id); + + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment.clone(), + QueuePushDirection::Back + )); + + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment, + QueuePushDirection::Back + )); + + // Drop expired claim. + Scheduler::drop_expired_claims_from_claimqueue(); + + let cq = Scheduler::claimqueue(); + let cqc = cq.get(&core_idx).unwrap(); + // Same number of claims + assert!(cqc.len() == 3); + + // The first 2 claims in the queue should have a ttl of 17, + // being the ones set up prior in this test as claims 1 and 3. + // The third claim is popped from the assignment provider and + // has a new ttl set by the scheduler of now + config.on_demand_ttl. + // ttls = [17, 17, 22] + assert!(cqc.iter().enumerate().all(|(index, entry)| { + match index { + 0 | 1 => return entry.clone().unwrap().ttl == 17, + 2 => return entry.clone().unwrap().ttl == 22, + _ => return false, + } + })) }); } +// Pretty useless here. Should be on parathread assigner... if at all #[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() - }; - let max_parathread_retries = default_config().parathread_retries; - - let thread_a = ParaId::from(1_u32); - let thread_b = ParaId::from(2_u32); - let thread_c = ParaId::from(3_u32); - let thread_d = ParaId::from(4_u32); +fn add_parathread_claim_works() { + let genesis_config = genesis_config(&default_config()); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let thread_id = ParaId::from(10); + let core_index = CoreIndex::from(0); + let entry_ttl = 10_000; 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, ParaKind::Parathread); - schedule_blank_para(thread_b, ParaKind::Parathread); - schedule_blank_para(thread_c, ParaKind::Parathread); - } - - // 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, - ); + schedule_blank_para(thread_id, ParaKind::Parathread); - // Will not be pruned. - queue.enqueue_entry( - ParathreadEntry { claim: ParathreadClaim(thread_c, collator.clone()), retries: 0 }, - 4, - ); + assert!(!Paras::is_parathread(thread_id)); - // Will be pruned: not a live parathread. - queue.enqueue_entry( - ParathreadEntry { claim: ParathreadClaim(thread_d, collator.clone()), retries: 0 }, - 4, - ); + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); - queue - }); + assert!(Paras::is_parathread(thread_id)); - ParathreadClaimIndex::::put(vec![thread_a, thread_b, thread_c, thread_d]); + let pe = ParasEntry::new(Assignment::new(thread_id), entry_ttl); + Scheduler::add_to_claimqueue(core_index, pe.clone()); - 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]); + let cq = Scheduler::claimqueue(); + assert_eq!(Scheduler::claimqueue_len(), 1); + assert_eq!(*(cq.get(&core_index).unwrap().front().unwrap()), Some(pe)); }) } #[test] fn session_change_shuffles_validators() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; + let genesis_config = genesis_config(&default_config()); - assert_eq!(default_config().parathread_cores, 3); + assert_eq!(default_config().on_demand_cores, 3); new_test_ext(genesis_config).execute_with(|| { let chain_a = ParaId::from(1_u32); let chain_b = ParaId::from(2_u32); @@ -369,15 +336,12 @@ fn session_change_shuffles_validators() { fn session_change_takes_only_max_per_core() { let config = { let mut config = default_config(); - config.parathread_cores = 0; + config.on_demand_cores = 0; config.max_validators_per_core = Some(1); config }; - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: config.clone() }, - ..Default::default() - }; + let genesis_config = genesis_config(&config); new_test_ext(genesis_config).execute_with(|| { let chain_a = ParaId::from(1_u32); @@ -418,12 +382,10 @@ fn session_change_takes_only_max_per_core() { } #[test] -fn schedule_schedules() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; +fn fill_claimqueue_fills() { + let genesis_config = genesis_config(&default_config()); + let lookahead = genesis_config.configuration.config.scheduling_lookahead as usize; let chain_a = ParaId::from(1_u32); let chain_b = ParaId::from(2_u32); @@ -431,10 +393,12 @@ fn schedule_schedules() { let thread_b = ParaId::from(4_u32); let thread_c = ParaId::from(5_u32); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let assignment_a = Assignment { para_id: thread_a }; + let assignment_b = Assignment { para_id: thread_b }; + let assignment_c = Assignment { para_id: thread_c }; new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); + assert_eq!(default_config().on_demand_cores, 3); // register 2 parachains schedule_blank_para(chain_a, ParaKind::Parachain); @@ -462,15 +426,21 @@ fn schedule_schedules() { }); { - let scheduled = Scheduler::scheduled(); - assert_eq!(scheduled.len(), 2); + assert_eq!(Scheduler::claimqueue_len(), 2 * lookahead); + let scheduled = Scheduler::scheduled_claimqueue(1); + + // Cannot assert on indices anymore as they depend on the assignment providers + assert!(claimqueue_contains_para_ids::(vec![chain_a, chain_b])); assert_eq!( scheduled[0], CoreAssignment { core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 6 + }, group_idx: GroupIndex(0), } ); @@ -479,59 +449,98 @@ fn schedule_schedules() { scheduled[1], CoreAssignment { core: CoreIndex(1), - para_id: chain_b, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_b }, + availability_timeouts: 0, + ttl: 6 + }, 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())); + // add a couple of parathread assignments. + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a, + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_b, + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_c, + QueuePushDirection::Back + )); run_to_block(2, |_| None); + // cores 0 and 1 should be occupied. mark them as such. + Scheduler::occupied( + vec![(CoreIndex(0), chain_a), (CoreIndex(1), chain_b)].into_iter().collect(), + ); + + run_to_block(3, |_| None); { - let scheduled = Scheduler::scheduled(); - assert_eq!(scheduled.len(), 4); + assert_eq!(Scheduler::claimqueue_len(), 5); + let scheduled = Scheduler::scheduled_claimqueue(3); assert_eq!( scheduled[0], CoreAssignment { core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 6 + }, group_idx: GroupIndex(0), } ); - assert_eq!( scheduled[1], CoreAssignment { core: CoreIndex(1), - para_id: chain_b, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_b }, + availability_timeouts: 0, + ttl: 6 + }, group_idx: GroupIndex(1), } ); + // Was added a block later, note the TTL. assert_eq!( scheduled[2], CoreAssignment { core: CoreIndex(2), - para_id: thread_a, - kind: AssignmentKind::Parathread(collator.clone(), 0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: thread_a }, + availability_timeouts: 0, + ttl: 7 + }, group_idx: GroupIndex(2), } ); - + // Sits on the same core as `thread_a` + assert_eq!( + Scheduler::claimqueue().get(&CoreIndex(2)).unwrap()[1], + Some(ParasEntry { + assignment: Assignment { para_id: thread_b }, + availability_timeouts: 0, + ttl: 7 + }) + ); assert_eq!( scheduled[3], CoreAssignment { core: CoreIndex(3), - para_id: thread_c, - kind: AssignmentKind::Parathread(collator.clone(), 0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: thread_c }, + availability_timeouts: 0, + ttl: 7 + }, group_idx: GroupIndex(3), } ); @@ -541,10 +550,11 @@ fn schedule_schedules() { #[test] fn schedule_schedules_including_just_freed() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; + let mut config = default_config(); + // NOTE: This test expects on demand cores to each get slotted on to a different core + // and not fill up the claimqueue of each core first. + config.scheduling_lookahead = 1; + let genesis_config = genesis_config(&config); let chain_a = ParaId::from(1_u32); let chain_b = ParaId::from(2_u32); @@ -555,10 +565,14 @@ fn schedule_schedules_including_just_freed() { let thread_d = ParaId::from(6_u32); let thread_e = ParaId::from(7_u32); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let assignment_a = Assignment { para_id: thread_a }; + let assignment_b = Assignment { para_id: thread_b }; + let assignment_c = Assignment { para_id: thread_c }; + let assignment_d = Assignment { para_id: thread_d }; + let assignment_e = Assignment { para_id: thread_e }; new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); + assert_eq!(default_config().on_demand_cores, 3); // register 2 parachains schedule_blank_para(chain_a, ParaKind::Parachain); @@ -588,39 +602,68 @@ fn schedule_schedules_including_just_freed() { }); // 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())); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a, + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_c, + QueuePushDirection::Back + )); - run_to_block(2, |_| None); + let mut now = 2; + run_to_block(now, |_| None); - assert_eq!(Scheduler::scheduled().len(), 4); + assert_eq!(Scheduler::scheduled_claimqueue(now).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 mut occupied_map: BTreeMap = BTreeMap::new(); + occupied_map.insert(CoreIndex(0), chain_a); + occupied_map.insert(CoreIndex(1), chain_b); + occupied_map.insert(CoreIndex(2), thread_a); + occupied_map.insert(CoreIndex(3), thread_c); + Scheduler::occupied(occupied_map); { 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()); + // cores 0, 1, 2, and 3 are all `CoreOccupied::Paras(ParasEntry...)` + assert!(cores[0] != CoreOccupied::Free); + assert!(cores[1] != CoreOccupied::Free); + assert!(cores[2] != CoreOccupied::Free); + assert!(cores[3] != CoreOccupied::Free); + + // core 4 is free + assert!(cores[4] == CoreOccupied::Free); - assert!(Scheduler::scheduled().is_empty()); + assert!(Scheduler::scheduled_claimqueue(now).is_empty()); + + // All core index entries in the claimqueue should have `None` in them. + Scheduler::claimqueue().iter().for_each(|(_core_idx, core_queue)| { + assert!(core_queue.iter().all(|claim| claim.is_none())) + }) } // 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); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_b, + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_d, + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_e.clone(), + QueuePushDirection::Back + )); + now = 3; + run_to_block(now, |_| None); { - let scheduled = Scheduler::scheduled(); + let scheduled = Scheduler::scheduled_claimqueue(now); // cores 0 and 1 are occupied by parachains. cores 2 and 3 are occupied by parathread // claims. core 4 was free. @@ -629,25 +672,28 @@ fn schedule_schedules_including_just_freed() { scheduled[0], CoreAssignment { core: CoreIndex(4), - para_id: thread_b, - kind: AssignmentKind::Parathread(collator.clone(), 0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: thread_b }, + availability_timeouts: 0, + ttl: 8 + }, 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 just_updated: BTreeMap = vec![ + (CoreIndex(0), FreedReason::Concluded), + (CoreIndex(2), FreedReason::Concluded), + (CoreIndex(3), FreedReason::TimedOut), // should go back on queue. + ] + .into_iter() + .collect(); + Scheduler::update_claimqueue(just_updated, now); { - let scheduled = Scheduler::scheduled(); + let scheduled = Scheduler::scheduled_claimqueue(now); // 1 thing scheduled before, + 3 cores freed. assert_eq!(scheduled.len(), 4); @@ -655,8 +701,11 @@ fn schedule_schedules_including_just_freed() { scheduled[0], CoreAssignment { core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 8 + }, group_idx: GroupIndex(0), } ); @@ -664,17 +713,24 @@ fn schedule_schedules_including_just_freed() { scheduled[1], CoreAssignment { core: CoreIndex(2), - para_id: thread_d, - kind: AssignmentKind::Parathread(collator.clone(), 0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: thread_d }, + availability_timeouts: 0, + ttl: 8 + }, group_idx: GroupIndex(2), } ); + // Although C was descheduled, the core `4` was occupied so C goes back to the queue. assert_eq!( scheduled[2], CoreAssignment { core: CoreIndex(3), - para_id: thread_e, - kind: AssignmentKind::Parathread(collator.clone(), 0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: thread_c }, + availability_timeouts: 1, + ttl: 8 + }, group_idx: GroupIndex(3), } ); @@ -682,49 +738,44 @@ fn schedule_schedules_including_just_freed() { scheduled[3], CoreAssignment { core: CoreIndex(4), - para_id: thread_b, - kind: AssignmentKind::Parathread(collator.clone(), 0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: thread_b }, + availability_timeouts: 0, + ttl: 8 + }, 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. - } - ); + // The only assignment yet to be popped on to the claim queue is `thread_e`. + // This is due to `thread_c` timing out. + let order_queue = OnDemandAssigner::get_queue(); + assert!(order_queue.len() == 1); + assert!(order_queue[0] == assignment_e); + + // Chain B's core was not marked concluded or timed out, it should be on an + // availability core + assert!(availability_cores_contains_para_ids::(vec![chain_b])); + // Thread A claim should have been wiped, but thread C claim should remain. + assert!(!claimqueue_contains_para_ids::(vec![thread_a])); + assert!(claimqueue_contains_para_ids::(vec![thread_c])); + assert!(!availability_cores_contains_para_ids::(vec![thread_a, thread_c])); } }); } #[test] fn schedule_clears_availability_cores() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; + let mut config = default_config(); + config.scheduling_lookahead = 1; + let genesis_config = genesis_config(&config); let chain_a = ParaId::from(1_u32); let chain_b = ParaId::from(2_u32); let chain_c = ParaId::from(3_u32); new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); + assert_eq!(default_config().on_demand_cores, 3); // register 3 parachains schedule_blank_para(chain_a, ParaKind::Parachain); @@ -749,56 +800,55 @@ fn schedule_clears_availability_cores() { run_to_block(2, |_| None); - assert_eq!(Scheduler::scheduled().len(), 3); + assert_eq!(Scheduler::claimqueue().len(), 3); // cores 0, 1, and 2 should be occupied. mark them as such. - Scheduler::occupied(&[CoreIndex(0), CoreIndex(1), CoreIndex(2)]); + Scheduler::occupied( + vec![(CoreIndex(0), chain_a), (CoreIndex(1), chain_b), (CoreIndex(2), chain_c)] + .into_iter() + .collect(), + ); { let cores = AvailabilityCores::::get(); - assert!(cores[0].is_some()); - assert!(cores[1].is_some()); - assert!(cores[2].is_some()); + assert_eq!(cores[0].is_free(), false); + assert_eq!(cores[1].is_free(), false); + assert_eq!(cores[2].is_free(), false); - assert!(Scheduler::scheduled().is_empty()); + assert!(claimqueue_contains_only_none()); } 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)], + Scheduler::free_cores_and_fill_claimqueue( + vec![(CoreIndex(0), FreedReason::Concluded), (CoreIndex(2), FreedReason::Concluded)] + .into_iter() + .collect::>(), 3, ); { - let scheduled = Scheduler::scheduled(); - - assert_eq!(scheduled.len(), 2); + let claimqueue = Scheduler::claimqueue(); + let claimqueue_0 = claimqueue.get(&CoreIndex(0)).unwrap().clone(); + let claimqueue_2 = claimqueue.get(&CoreIndex(2)).unwrap().clone(); + let entry_ttl = 8; + assert_eq!(claimqueue_0.len(), 1); + assert_eq!(claimqueue_2.len(), 1); assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - } + claimqueue_0, + vec![Some(ParasEntry::new(Assignment::new(chain_a), entry_ttl))], ); assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(2), - para_id: chain_c, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(2), - } + claimqueue_2, + vec![Some(ParasEntry::new(Assignment::new(chain_c), entry_ttl))], ); - // The freed cores should be `None` in `AvailabilityCores`. + // The freed cores should be `Free` in `AvailabilityCores`. let cores = AvailabilityCores::::get(); - assert!(cores[0].is_none()); - assert!(cores[2].is_none()); + assert!(cores[0].is_free()); + assert!(cores[2].is_free()); } }); } @@ -808,27 +858,26 @@ 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; + // make sure on demand requests don't retry-out + config.on_demand_retries = config.group_rotation_frequency * 3; + config.on_demand_cores = 2; + config.scheduling_lookahead = 1; config }; let rotation_frequency = config.group_rotation_frequency; - let parathread_cores = config.parathread_cores; + let on_demand_cores = config.on_demand_cores; - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: config.clone() }, - ..Default::default() - }; + let genesis_config = genesis_config(&config); let thread_a = ParaId::from(1_u32); let thread_b = ParaId::from(2_u32); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let assignment_a = Assignment { para_id: thread_a }; + let assignment_b = Assignment { para_id: thread_b }; new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); + assert_eq!(default_config().on_demand_cores, 3); schedule_blank_para(thread_a, ParaKind::Parathread); schedule_blank_para(thread_b, ParaKind::Parathread); @@ -846,64 +895,72 @@ fn schedule_rotates_groups() { _ => None, }); - let session_start_block = SessionStartBlock::::get(); + let session_start_block = Scheduler::session_start_block(); assert_eq!(session_start_block, 1); - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a, + QueuePushDirection::Back + )); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_b, + QueuePushDirection::Back + )); - run_to_block(2, |_| None); + let mut now = 2; + run_to_block(now, |_| None); - let assert_groups_rotated = |rotations: u32| { - let scheduled = Scheduler::scheduled(); + let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor| { + let scheduled = Scheduler::scheduled_claimqueue(*now); 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_eq!(scheduled[0].group_idx, GroupIndex((0u32 + rotations) % on_demand_cores)); + assert_eq!(scheduled[1].group_idx, GroupIndex((1u32 + rotations) % on_demand_cores)); }; - assert_groups_rotated(0); + assert_groups_rotated(0, &now); // one block before first rotation. + now = rotation_frequency; run_to_block(rotation_frequency, |_| None); - assert_groups_rotated(0); + assert_groups_rotated(0, &now); // first rotation. - run_to_block(rotation_frequency + 1, |_| None); - assert_groups_rotated(1); + now = now + 1; + run_to_block(now, |_| None); + assert_groups_rotated(1, &now); // one block before second rotation. - run_to_block(rotation_frequency * 2, |_| None); - assert_groups_rotated(1); + now = rotation_frequency * 2; + run_to_block(now, |_| None); + assert_groups_rotated(1, &now); // second rotation. - run_to_block(rotation_frequency * 2 + 1, |_| None); - assert_groups_rotated(2); + now = now + 1; + run_to_block(now, |_| None); + assert_groups_rotated(2, &now); }); } #[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() - }; +fn on_demand_claims_are_pruned_after_timing_out() { + let max_retries = 20; + let mut config = default_config(); + config.scheduling_lookahead = 1; + config.on_demand_cores = 2; + config.on_demand_retries = max_retries; + let genesis_config = genesis_config(&config); let thread_a = ParaId::from(1_u32); - let thread_b = ParaId::from(2_u32); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let assignment_a = Assignment { para_id: thread_a }; new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - schedule_blank_para(thread_a, ParaKind::Parathread); - schedule_blank_para(thread_b, ParaKind::Parathread); - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { + // #1 + let mut now = 1; + run_to_block(now, |number| match number { 1 => Some(SessionChangeNotification { new_config: default_config(), validators: vec![ @@ -915,39 +972,126 @@ fn parathread_claims_are_pruned_after_retries() { _ => None, }); - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a.clone(), + QueuePushDirection::Back + )); + + // #2 + now += 1; + run_to_block(now, |_| None); + assert_eq!(Scheduler::claimqueue().len(), 1); + // ParaId a is in the claimqueue. + assert!(claimqueue_contains_para_ids::(vec![thread_a])); + + Scheduler::occupied(vec![(CoreIndex(0), thread_a)].into_iter().collect()); + // ParaId a is no longer in the claimqueue. + assert!(!claimqueue_contains_para_ids::(vec![thread_a])); + // It is in availability cores. + assert!(availability_cores_contains_para_ids::(vec![thread_a])); + + // #3 + now += 1; + // Run to block #n over the max_retries value. + // In this case, both validator groups with time out on availability and + // the assignment will be dropped. + for n in now..=(now + max_retries + 1) { + // #n + run_to_block(n, |_| None); + // Time out on core 0. + let just_updated: BTreeMap = vec![ + (CoreIndex(0), FreedReason::TimedOut), // should go back on queue. + ] + .into_iter() + .collect(); + let core_assignments = Scheduler::update_claimqueue(just_updated, now); + + // ParaId a exists in the claim queue until max_retries is reached. + if n < max_retries + now { + assert!(claimqueue_contains_para_ids::(vec![thread_a])); + } else { + assert!(!claimqueue_contains_para_ids::(vec![thread_a])); + } - run_to_block(2, |_| None); - assert_eq!(Scheduler::scheduled().len(), 2); + // Occupy the cores based on the output of update_claimqueue. + Scheduler::occupied( + core_assignments + .iter() + .map(|core_assignment| (core_assignment.core, core_assignment.para_id())) + .collect(), + ); + } - run_to_block(2 + max_retries, |_| None); - assert_eq!(Scheduler::scheduled().len(), 2); + // ParaId a does not exist in the claimqueue/availability_cores after + // threshold has been reached. + assert!(!claimqueue_contains_para_ids::(vec![thread_a])); + assert!(!availability_cores_contains_para_ids::(vec![thread_a])); + + // #25 + now += max_retries + 2; + + // Add assignment back to the mix. + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a.clone(), + QueuePushDirection::Back + )); + run_to_block(now, |_| None); + + assert!(claimqueue_contains_para_ids::(vec![thread_a])); + + // #26 + now += 1; + // Run to block #n but this time have group 1 conclude the availabilty. + for n in now..=(now + max_retries + 1) { + // #n + run_to_block(n, |_| None); + // Time out core 0 if group 0 is assigned to it, if group 1 is assigned, conclude. + let mut just_updated: BTreeMap = BTreeMap::new(); + if let Some(group) = Scheduler::group_assigned_to_core(CoreIndex(0), n) { + match group { + GroupIndex(0) => { + just_updated.insert(CoreIndex(0), FreedReason::TimedOut); // should go back on queue. + }, + GroupIndex(1) => { + just_updated.insert(CoreIndex(0), FreedReason::Concluded); + }, + _ => panic!("Should only have 2 groups here"), + } + } + + let core_assignments = Scheduler::update_claimqueue(just_updated, now); + + // ParaId a exists in the claim queue until groups are rotated. + if n < 31 { + assert!(claimqueue_contains_para_ids::(vec![thread_a])); + } else { + assert!(!claimqueue_contains_para_ids::(vec![thread_a])); + } + + // Occupy the cores based on the output of update_claimqueue. + Scheduler::occupied( + core_assignments + .iter() + .map(|core_assignment| (core_assignment.core, core_assignment.para_id())) + .collect(), + ); + } - run_to_block(2 + max_retries + 1, |_| None); - assert_eq!(Scheduler::scheduled().len(), 0); + // ParaId a does not exist in the claimqueue/availability_cores after + // being concluded + assert!(!claimqueue_contains_para_ids::(vec![thread_a])); + assert!(!availability_cores_contains_para_ids::(vec![thread_a])); }); } #[test] fn availability_predicate_works() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; + let genesis_config = genesis_config(&default_config()); - let HostConfiguration { - group_rotation_frequency, - chain_availability_period, - thread_availability_period, - .. - } = default_config(); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let HostConfiguration { group_rotation_frequency, paras_availability_period, .. } = + default_config(); - assert!( - chain_availability_period < thread_availability_period && - thread_availability_period < group_rotation_frequency - ); + assert!(paras_availability_period < group_rotation_frequency); let chain_a = ParaId::from(1_u32); let thread_a = ParaId::from(2_u32); @@ -956,7 +1100,7 @@ fn availability_predicate_works() { schedule_blank_para(chain_a, ParaKind::Parachain); schedule_blank_para(thread_a, ParaKind::Parathread); - // start a new session with our chain & thread registered. + // start a new session with our chain registered. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { new_config: default_config(), @@ -974,16 +1118,17 @@ fn availability_predicate_works() { // assign some availability cores. { + let entry_ttl = 10_000; AvailabilityCores::::mutate(|cores| { - cores[0] = Some(CoreOccupied::Parachain); - cores[1] = Some(CoreOccupied::Parathread(ParathreadEntry { - claim: ParathreadClaim(thread_a, collator), - retries: 0, - })) + cores[0] = + CoreOccupied::Paras(ParasEntry::new(Assignment::new(chain_a), entry_ttl)); + cores[1] = + CoreOccupied::Paras(ParasEntry::new(Assignment::new(thread_a), entry_ttl)); }); } - run_to_block(1 + thread_availability_period, |_| None); + run_to_block(1 + paras_availability_period, |_| None); + assert!(Scheduler::availability_timeout_predicate().is_none()); run_to_block(1 + group_rotation_frequency, |_| None); @@ -993,59 +1138,40 @@ fn availability_predicate_works() { .expect("predicate exists recently after rotation"); let now = System::block_number(); - let would_be_timed_out = now - thread_availability_period; + let would_be_timed_out = now - paras_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. + // And can time out paras 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(0), now)); + assert!(!pred(CoreIndex(1), now)); 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 tight bound. + assert!(pred(CoreIndex(0), now - paras_availability_period)); + assert!(pred(CoreIndex(1), now - paras_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)); + assert!(!pred(CoreIndex(0), now - paras_availability_period + 1)); + assert!(!pred(CoreIndex(1), now - paras_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()); + run_to_block(1 + group_rotation_frequency + paras_availability_period, |_| None); }); } #[test] fn next_up_on_available_uses_next_scheduled_or_none_for_thread() { let mut config = default_config(); - config.parathread_cores = 1; + config.on_demand_cores = 1; - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: config.clone() }, - ..Default::default() - }; + let genesis_config = genesis_config(&config); let thread_a = ParaId::from(1_u32); let thread_b = ParaId::from(2_u32); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - new_test_ext(genesis_config).execute_with(|| { schedule_blank_para(thread_a, ParaKind::Parathread); schedule_blank_para(thread_b, ParaKind::Parathread); @@ -1063,38 +1189,42 @@ fn next_up_on_available_uses_next_scheduled_or_none_for_thread() { _ => None, }); - let thread_claim_a = ParathreadClaim(thread_a, collator.clone()); - let thread_claim_b = ParathreadClaim(thread_b, collator.clone()); + let thread_entry_a = ParasEntry { + assignment: Assignment { para_id: thread_a }, + availability_timeouts: 0, + ttl: 5, + }; + let thread_entry_b = ParasEntry { + assignment: Assignment { para_id: thread_b }, + availability_timeouts: 0, + ttl: 5, + }; - Scheduler::add_parathread_claim(thread_claim_a.clone()); + Scheduler::add_to_claimqueue(CoreIndex(0), thread_entry_a.clone()); run_to_block(2, |_| None); { - assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::claimqueue_len(), 1); assert_eq!(Scheduler::availability_cores().len(), 1); - Scheduler::occupied(&[CoreIndex(0)]); + let mut map = BTreeMap::new(); + map.insert(CoreIndex(0), thread_a); + Scheduler::occupied(map); let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parathread(entry) => assert_eq!(entry.claim, thread_claim_a), + match &cores[0] { + CoreOccupied::Paras(entry) => assert_eq!(entry, &thread_entry_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()), - ); + Scheduler::add_to_claimqueue(CoreIndex(0), thread_entry_b); assert_eq!( Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: thread_b, collator: Some(collator.clone()) } + ScheduledCore { para_id: thread_b, collator: None } ); } }); @@ -1103,17 +1233,15 @@ fn next_up_on_available_uses_next_scheduled_or_none_for_thread() { #[test] fn next_up_on_time_out_reuses_claim_if_nothing_queued() { let mut config = default_config(); - config.parathread_cores = 1; + config.on_demand_cores = 1; - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: config.clone() }, - ..Default::default() - }; + let genesis_config = genesis_config(&config); let thread_a = ParaId::from(1_u32); let thread_b = ParaId::from(2_u32); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + let assignment_a = Assignment { para_id: thread_a }; + let assignment_b = Assignment { para_id: thread_b }; new_test_ext(genesis_config).execute_with(|| { schedule_blank_para(thread_a, ParaKind::Parathread); @@ -1132,44 +1260,49 @@ fn next_up_on_time_out_reuses_claim_if_nothing_queued() { _ => 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()); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_a.clone(), + QueuePushDirection::Back + )); run_to_block(2, |_| None); { - assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::claimqueue().len(), 1); assert_eq!(Scheduler::availability_cores().len(), 1); - Scheduler::occupied(&[CoreIndex(0)]); + let mut map = BTreeMap::new(); + map.insert(CoreIndex(0), thread_a); + Scheduler::occupied(map); let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parathread(entry) => assert_eq!(entry.claim, thread_claim_a), + match cores.get(0).unwrap() { + CoreOccupied::Paras(entry) => assert_eq!(entry.assignment, assignment_a.clone()), _ => panic!("with no chains, only core should be a thread core"), } - let queue = ParathreadQueue::::get(); - assert!(queue.get_next_on_core(0).is_none()); + // There's nothing more to pop for core 0 from the assignment provider. + assert!( + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(thread_a)).is_none() + ); + assert_eq!( Scheduler::next_up_on_time_out(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: thread_a, collator: Some(collator.clone()) } + ScheduledCore { para_id: thread_a, collator: None } ); - Scheduler::add_parathread_claim(thread_claim_b); + assert_ok!(OnDemandAssigner::add_on_demand_assignment( + assignment_b.clone(), + QueuePushDirection::Back + )); - let queue = ParathreadQueue::::get(); - assert_eq!( - queue.get_next_on_core(0).unwrap().claim, - ParathreadClaim(thread_b, collator.clone()), - ); + // Pop assignment_b into the claimqueue + Scheduler::update_claimqueue(BTreeMap::new(), 2); - // Now that there is an earlier next-up, we use that. + //// 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()) } + ScheduledCore { para_id: thread_b, collator: None } ); } }); @@ -1178,13 +1311,8 @@ fn next_up_on_time_out_reuses_claim_if_nothing_queued() { #[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() - }; - + config.on_demand_cores = 0; + let genesis_config = genesis_config(&config); let chain_a = ParaId::from(1_u32); new_test_ext(genesis_config).execute_with(|| { @@ -1206,14 +1334,14 @@ fn next_up_on_available_is_parachain_always() { run_to_block(2, |_| None); { - assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::claimqueue().len(), 1); assert_eq!(Scheduler::availability_cores().len(), 1); - Scheduler::occupied(&[CoreIndex(0)]); + Scheduler::occupied(vec![(CoreIndex(0), chain_a)].into_iter().collect()); let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parachain => {}, + match &cores[0] { + CoreOccupied::Paras(pe) if pe.para_id() == chain_a => {}, _ => panic!("with no threads, only core should be a chain core"), } @@ -1229,12 +1357,9 @@ fn next_up_on_available_is_parachain_always() { #[test] fn next_up_on_time_out_is_parachain_always() { let mut config = default_config(); - config.parathread_cores = 0; + config.on_demand_cores = 0; - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: config.clone() }, - ..Default::default() - }; + let genesis_config = genesis_config(&config); let chain_a = ParaId::from(1_u32); @@ -1257,15 +1382,15 @@ fn next_up_on_time_out_is_parachain_always() { run_to_block(2, |_| None); { - assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::claimqueue().len(), 1); assert_eq!(Scheduler::availability_cores().len(), 1); - Scheduler::occupied(&[CoreIndex(0)]); + Scheduler::occupied(vec![(CoreIndex(0), chain_a)].into_iter().collect()); let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parachain => {}, - _ => panic!("with no threads, only core should be a chain core"), + match &cores[0] { + CoreOccupied::Paras(pe) if pe.para_id() == chain_a => {}, + _ => panic!("Core should be occupied by chain_a ParaId"), } // Now that there is an earlier next-up, we use that. @@ -1279,12 +1404,11 @@ fn next_up_on_time_out_is_parachain_always() { #[test] fn session_change_requires_reschedule_dropping_removed_paras() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; + let mut config = default_config(); + config.scheduling_lookahead = 1; + let genesis_config = genesis_config(&config); - assert_eq!(default_config().parathread_cores, 3); + assert_eq!(default_config().on_demand_cores, 3); new_test_ext(genesis_config).execute_with(|| { let chain_a = ParaId::from(1_u32); let chain_b = ParaId::from(2_u32); @@ -1311,13 +1435,12 @@ fn session_change_requires_reschedule_dropping_removed_paras() { _ => None, }); - assert_eq!(Scheduler::scheduled().len(), 2); + assert_eq!(Scheduler::claimqueue().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(), @@ -1336,73 +1459,78 @@ fn session_change_requires_reschedule_dropping_removed_paras() { _ => None, }); - Scheduler::clear(); - Scheduler::schedule(Vec::new(), 3); + Scheduler::update_claimqueue(BTreeMap::new(), 3); assert_eq!( - Scheduler::scheduled(), - vec![CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - }], + Scheduler::claimqueue(), + vec![( + CoreIndex(0), + vec![Some(ParasEntry::new( + Assignment::new(chain_a), + // At end of block 2 + config.on_demand_ttl + 2 + ))] + .into_iter() + .collect() + )] + .into_iter() + .collect() ); - }); -} - -#[test] -fn parathread_claims_are_pruned_after_deregistration() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config: default_config() }, - ..Default::default() - }; - - let thread_a = ParaId::from(1_u32); - let thread_b = ParaId::from(2_u32); - 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, ParaKind::Parathread); - schedule_blank_para(thread_b, ParaKind::Parathread); + // Add parachain back + schedule_blank_para(chain_b, ParaKind::Parachain); - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { + run_to_block(3, |number| match number { + 3 => 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::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + assert_eq!(Scheduler::claimqueue().len(), 2); - run_to_block(2, |_| None); - assert_eq!(Scheduler::scheduled().len(), 2); + let groups = ValidatorGroups::::get(); + assert_eq!(groups.len(), 5); - assert_ok!(Paras::schedule_para_cleanup(thread_a)); + Scheduler::update_claimqueue(BTreeMap::new(), 4); - // 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); + assert_eq!( + Scheduler::claimqueue(), + vec![ + ( + CoreIndex(0), + vec![Some(ParasEntry::new( + Assignment::new(chain_a), + // At block 3 + config.on_demand_ttl + 3 + ))] + .into_iter() + .collect() + ), + ( + CoreIndex(1), + vec![Some(ParasEntry::new( + Assignment::new(chain_b), + // At block 3 + config.on_demand_ttl + 3 + ))] + .into_iter() + .collect() + ), + ] + .into_iter() + .collect() + ); }); } diff --git a/runtime/parachains/src/session_info/tests.rs b/runtime/parachains/src/session_info/tests.rs index c4475526d58f..727b7c79fbae 100644 --- a/runtime/parachains/src/session_info/tests.rs +++ b/runtime/parachains/src/session_info/tests.rs @@ -62,7 +62,7 @@ fn run_to_block( fn default_config() -> HostConfiguration { HostConfiguration { - parathread_cores: 1, + on_demand_cores: 1, dispute_period: 2, needed_approvals: 3, ..Default::default() diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index fbf896cdedc5..da8cf7cb5a61 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -27,6 +27,7 @@ use runtime_common::{ }; use runtime_parachains::{ + assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, @@ -1183,7 +1184,11 @@ impl parachains_paras_inherent::Config for Runtime { type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; } -impl parachains_scheduler::Config for Runtime {} +impl parachains_scheduler::Config for Runtime { + type AssignmentProvider = ParaAssignmentProvider; +} + +impl parachains_assigner_parachains::Config for Runtime {} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; @@ -1434,6 +1439,7 @@ construct_runtime! { ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event} = 62, ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63, + ParaAssignmentProvider: parachains_assigner_parachains::{Pallet} = 64, // Parachain Onboarding Pallets. Start indices at 70 to leave room. Registrar: paras_registrar::{Pallet, Call, Storage, Event} = 70, @@ -1494,6 +1500,8 @@ pub mod migrations { pub type Unreleased = ( pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, + parachains_scheduler::migration::v1::MigrateToV1, + parachains_configuration::migration::v8::MigrateToV8, ); } diff --git a/runtime/polkadot/src/weights/runtime_parachains_configuration.rs b/runtime/polkadot/src/weights/runtime_parachains_configuration.rs index af8e4c111b20..39b0d893edbb 100644 --- a/runtime/polkadot/src/weights/runtime_parachains_configuration.rs +++ b/runtime/polkadot/src/weights/runtime_parachains_configuration.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("polkadot-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=polkadot-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::configuration // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_parachains::configuration +// --chain=polkadot-dev // --header=./file_header.txt -// --output=./runtime/polkadot/src/weights/runtime_parachains_configuration.rs +// --output=./runtime/polkadot/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,62 +48,56 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::configuration`. pub struct WeightInfo(PhantomData); impl runtime_parachains::configuration::WeightInfo for WeightInfo { - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_block_number() -> Weight { // Proof Size summary in bytes: - // Measured: `443` - // Estimated: `1928` - // Minimum execution time: 13_403_000 picoseconds. - Weight::from_parts(13_933_000, 0) - .saturating_add(Weight::from_parts(0, 1928)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_330_000 picoseconds. + Weight::from_parts(9_663_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `443` - // Estimated: `1928` - // Minimum execution time: 13_210_000 picoseconds. - Weight::from_parts(13_674_000, 0) - .saturating_add(Weight::from_parts(0, 1928)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_155_000 picoseconds. + Weight::from_parts(9_554_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_option_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `443` - // Estimated: `1928` - // Minimum execution time: 13_351_000 picoseconds. - Weight::from_parts(13_666_000, 0) - .saturating_add(Weight::from_parts(0, 1928)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_299_000 picoseconds. + Weight::from_parts(9_663_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_hrmp_open_request_ttl() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -114,40 +106,52 @@ impl runtime_parachains::configuration::WeightInfo for Weight::from_parts(2_000_000_000_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `443` - // Estimated: `1928` - // Minimum execution time: 13_299_000 picoseconds. - Weight::from_parts(13_892_000, 0) - .saturating_add(Weight::from_parts(0, 1928)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_130_000 picoseconds. + Weight::from_parts(9_554_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_executor_params() -> Weight { // Proof Size summary in bytes: - // Measured: `443` - // Estimated: `1928` - // Minimum execution time: 14_002_000 picoseconds. - Weight::from_parts(14_673_000, 0) - .saturating_add(Weight::from_parts(0, 1928)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 10_177_000 picoseconds. + Weight::from_parts(10_632_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_perbill() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_136_000 picoseconds. + Weight::from_parts(9_487_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index d923437a67e5..a9811872b6af 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -38,6 +38,8 @@ use scale_info::TypeInfo; use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; use runtime_parachains::{ + assigner as parachains_assigner, assigner_on_demand as parachains_assigner_on_demand, + assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, @@ -77,7 +79,7 @@ use sp_runtime::{ Extrinsic as ExtrinsicT, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, KeyTypeId, Perbill, Percent, Permill, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, }; use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] @@ -879,6 +881,7 @@ pub enum ProxyType { CancelProxy, Auction, Society, + OnDemandOrdering, } impl Default for ProxyType { fn default() -> Self { @@ -965,6 +968,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::Slots { .. } ), ProxyType::Society => matches!(c, RuntimeCall::Society(..)), + ProxyType::OnDemandOrdering => matches!(c, RuntimeCall::OnDemandAssignmentProvider(..)), } } fn is_superset(&self, o: &Self) -> bool { @@ -1095,7 +1099,27 @@ impl parachains_paras_inherent::Config for Runtime { type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; } -impl parachains_scheduler::Config for Runtime {} +impl parachains_scheduler::Config for Runtime { + type AssignmentProvider = ParaAssignmentProvider; +} + +parameter_types! { + pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); +} + +impl parachains_assigner_on_demand::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type TrafficDefaultValue = OnDemandTrafficDefaultValue; + type WeightInfo = weights::runtime_parachains_assigner_on_demand::WeightInfo; +} + +impl parachains_assigner_parachains::Config for Runtime {} + +impl parachains_assigner::Config for Runtime { + type OnDemandAssignmentProvider = OnDemandAssignmentProvider; + type ParachainsAssignmentProvider = ParachainsAssignmentProvider; +} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; @@ -1451,6 +1475,9 @@ construct_runtime! { ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event} = 62, ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 64, + ParaAssignmentProvider: parachains_assigner::{Pallet, Storage} = 65, + OnDemandAssignmentProvider: parachains_assigner_on_demand::{Pallet, Call, Storage, Event} = 66, + ParachainsAssignmentProvider: parachains_assigner_parachains::{Pallet} = 67, // Parachain Onboarding Pallets. Start indices at 70 to leave room. Registrar: paras_registrar::{Pallet, Call, Storage, Event, Config} = 70, @@ -1524,6 +1551,8 @@ pub mod migrations { pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, assigned_slots::migration::v1::VersionCheckedMigrateToV1, + parachains_scheduler::migration::v1::MigrateToV1, + parachains_configuration::migration::v8::MigrateToV8, ); } @@ -1583,6 +1612,7 @@ mod benches { [runtime_parachains::initializer, Initializer] [runtime_parachains::paras_inherent, ParaInherent] [runtime_parachains::paras, Paras] + [runtime_parachains::assigner_on_demand, OnDemandAssignmentProvider] // Substrate [pallet_balances, Balances] [pallet_balances, NisCounterpartBalances] diff --git a/runtime/rococo/src/weights/mod.rs b/runtime/rococo/src/weights/mod.rs index 75acfe9a5d64..21558ca3fb90 100644 --- a/runtime/rococo/src/weights/mod.rs +++ b/runtime/rococo/src/weights/mod.rs @@ -48,6 +48,7 @@ pub mod runtime_common_claims; pub mod runtime_common_crowdloan; pub mod runtime_common_paras_registrar; pub mod runtime_common_slots; +pub mod runtime_parachains_assigner_on_demand; pub mod runtime_parachains_configuration; pub mod runtime_parachains_disputes; pub mod runtime_parachains_hrmp; diff --git a/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs b/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs new file mode 100644 index 000000000000..ac0f05301b48 --- /dev/null +++ b/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs @@ -0,0 +1,91 @@ +// Copyright (C) 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 . + +//! Autogenerated weights for `runtime_parachains::assigner_on_demand` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_parachains::assigner_on_demand +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `runtime_parachains::assigner_on_demand`. +pub struct WeightInfo(PhantomData); +impl runtime_parachains::assigner_on_demand::WeightInfo for WeightInfo { + /// Storage: `OnDemandAssignmentProvider::SpotTraffic` (r:1 w:0) + /// Proof: `OnDemandAssignmentProvider::SpotTraffic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::OnDemandQueue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::OnDemandQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[1, 9999]`. + fn place_order_keep_alive(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `297 + s * (4 ±0)` + // Estimated: `3762 + s * (4 ±0)` + // Minimum execution time: 33_522_000 picoseconds. + Weight::from_parts(35_436_835, 0) + .saturating_add(Weight::from_parts(0, 3762)) + // Standard Error: 129 + .saturating_add(Weight::from_parts(14_041, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) + } + /// Storage: `OnDemandAssignmentProvider::SpotTraffic` (r:1 w:0) + /// Proof: `OnDemandAssignmentProvider::SpotTraffic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::OnDemandQueue` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::OnDemandQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[1, 9999]`. + fn place_order_allow_death(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `297 + s * (4 ±0)` + // Estimated: `3762 + s * (4 ±0)` + // Minimum execution time: 33_488_000 picoseconds. + Weight::from_parts(34_848_934, 0) + .saturating_add(Weight::from_parts(0, 3762)) + // Standard Error: 143 + .saturating_add(Weight::from_parts(14_215, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) + } +} diff --git a/runtime/rococo/src/weights/runtime_parachains_configuration.rs b/runtime/rococo/src/weights/runtime_parachains_configuration.rs index c44046382d5a..29f387657786 100644 --- a/runtime/rococo/src/weights/runtime_parachains_configuration.rs +++ b/runtime/rococo/src/weights/runtime_parachains_configuration.rs @@ -17,24 +17,25 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --pallet=runtime_parachains::configuration // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_parachains::configuration +// --chain=rococo-dev // --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_configuration.rs +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,63 +48,56 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::configuration`. pub struct WeightInfo(PhantomData); impl runtime_parachains::configuration::WeightInfo for WeightInfo { - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_block_number() -> Weight { // Proof Size summary in bytes: - // Measured: `414` - // Estimated: `1899` - // Minimum execution time: 13_097_000 picoseconds. - Weight::from_parts(13_667_000, 0) - .saturating_add(Weight::from_parts(0, 1899)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_051_000 picoseconds. + Weight::from_parts(9_496_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `414` - // Estimated: `1899` - // Minimum execution time: 13_199_000 picoseconds. - Weight::from_parts(13_400_000, 0) - .saturating_add(Weight::from_parts(0, 1899)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_104_000 picoseconds. + Weight::from_parts(9_403_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_option_u32() -> Weight { // Proof Size summary in bytes: - // Measured: `397` - // Estimated: `1882` - // Minimum execution time: 12_831_000 picoseconds. - Weight::from_parts(13_151_000, 0) - .saturating_add(Weight::from_parts(0, 1882)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_112_000 picoseconds. + Weight::from_parts(9_495_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_hrmp_open_request_ttl() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -112,40 +106,52 @@ impl runtime_parachains::configuration::WeightInfo for Weight::from_parts(2_000_000_000_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `414` - // Estimated: `1899` - // Minimum execution time: 13_059_000 picoseconds. - Weight::from_parts(13_481_000, 0) - .saturating_add(Weight::from_parts(0, 1899)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_011_000 picoseconds. + Weight::from_parts(9_460_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_executor_params() -> Weight { // Proof Size summary in bytes: - // Measured: `414` - // Estimated: `1899` - // Minimum execution time: 13_764_000 picoseconds. - Weight::from_parts(14_224_000, 0) - .saturating_add(Weight::from_parts(0, 1899)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_940_000 picoseconds. + Weight::from_parts(10_288_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_perbill() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_192_000 picoseconds. + Weight::from_parts(9_595_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/test-runtime/src/lib.rs b/runtime/test-runtime/src/lib.rs index d7594e67c12a..b2397299430d 100644 --- a/runtime/test-runtime/src/lib.rs +++ b/runtime/test-runtime/src/lib.rs @@ -25,6 +25,7 @@ use parity_scale_codec::Encode; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use polkadot_runtime_parachains::{ + assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, initializer as parachains_initializer, @@ -555,7 +556,11 @@ impl parachains_hrmp::Config for Runtime { type WeightInfo = parachains_hrmp::TestWeightInfo; } -impl parachains_scheduler::Config for Runtime {} +impl parachains_assigner_parachains::Config for Runtime {} + +impl parachains_scheduler::Config for Runtime { + type AssignmentProvider = ParaAssignmentProvider; +} impl paras_sudo_wrapper::Config for Runtime {} @@ -697,6 +702,7 @@ construct_runtime! { Xcm: pallet_xcm::{Pallet, Call, Event, Origin}, ParasDisputes: parachains_disputes::{Pallet, Storage, Event}, ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned}, + ParaAssignmentProvider: parachains_assigner_parachains::{Pallet}, Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 9c322d6b8436..e6fa4afc9388 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -52,6 +52,7 @@ use runtime_common::{ BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance, }; use runtime_parachains::{ + assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, @@ -994,7 +995,11 @@ impl parachains_paras_inherent::Config for Runtime { type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; } -impl parachains_scheduler::Config for Runtime {} +impl parachains_scheduler::Config for Runtime { + type AssignmentProvider = ParaAssignmentProvider; +} + +impl parachains_assigner_parachains::Config for Runtime {} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; @@ -1221,6 +1226,7 @@ construct_runtime! { ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 52, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event} = 53, ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 54, + ParaAssignmentProvider: parachains_assigner_parachains::{Pallet, Storage} = 55, // Parachain Onboarding Pallets. Start indices at 60 to leave room. Registrar: paras_registrar::{Pallet, Call, Storage, Event, Config} = 60, @@ -1283,6 +1289,8 @@ pub mod migrations { pallet_im_online::migration::v1::Migration, parachains_configuration::migration::v7::MigrateToV7, assigned_slots::migration::v1::VersionCheckedMigrateToV1, + parachains_scheduler::migration::v1::MigrateToV1, + parachains_configuration::migration::v8::MigrateToV8, ); } diff --git a/runtime/westend/src/weights/runtime_parachains_configuration.rs b/runtime/westend/src/weights/runtime_parachains_configuration.rs index 60f6f8e214c3..585dc9058f21 100644 --- a/runtime/westend/src/weights/runtime_parachains_configuration.rs +++ b/runtime/westend/src/weights/runtime_parachains_configuration.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner--ss9ysm1-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=westend-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::configuration // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_parachains::configuration +// --chain=westend-dev // --header=./file_header.txt -// --output=./runtime/westend/src/weights/runtime_parachains_configuration.rs +// --output=./runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,56 +48,56 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::configuration`. pub struct WeightInfo(PhantomData); impl runtime_parachains::configuration::WeightInfo for WeightInfo { - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_998_000 picoseconds. - Weight::from_parts(10_268_000, 0) + // Minimum execution time: 9_616_000 picoseconds. + Weight::from_parts(9_961_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_851_000 picoseconds. - Weight::from_parts(10_102_000, 0) + // Minimum execution time: 9_587_000 picoseconds. + Weight::from_parts(9_964_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_option_u32() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_932_000 picoseconds. - Weight::from_parts(10_248_000, 0) + // Minimum execution time: 9_650_000 picoseconds. + Weight::from_parts(9_960_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_hrmp_open_request_ttl() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -108,34 +106,50 @@ impl runtime_parachains::configuration::WeightInfo for Weight::from_parts(2_000_000_000_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_balance() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 9_804_000 picoseconds. - Weight::from_parts(10_173_000, 0) + // Minimum execution time: 9_545_000 picoseconds. + Weight::from_parts(9_845_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration PendingConfigs (r:1 w:1) - /// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration BypassConsistencyCheck (r:1 w:0) - /// Proof Skipped: Configuration BypassConsistencyCheck (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn set_config_with_executor_params() -> Weight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1612` - // Minimum execution time: 10_531_000 picoseconds. - Weight::from_parts(10_984_000, 0) + // Minimum execution time: 10_258_000 picoseconds. + Weight::from_parts(10_607_000, 0) + .saturating_add(Weight::from_parts(0, 1612)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_perbill() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `1612` + // Minimum execution time: 9_502_000 picoseconds. + Weight::from_parts(9_902_000, 0) .saturating_add(Weight::from_parts(0, 1612)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml index d7a12ad0723f..6d023489c073 100644 --- a/scripts/ci/gitlab/pipeline/zombienet.yml +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -23,7 +23,7 @@ zombienet-tests-parachains-smoke-test: - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} - export MALUS_IMAGE=${MALUS_IMAGE_NAME}:${MALUS_IMAGE_TAG} - - export COL_IMAGE="docker.io/paritypr/colander:4519" # The collator image is fixed + - export COL_IMAGE="docker.io/paritypr/colander:7292" # The collator image is fixed script: - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh --github-remote-dir="${GH_DIR}" diff --git a/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl b/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl index ccc1ea258f52..50fff9e3d597 100644 --- a/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl +++ b/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl @@ -9,7 +9,7 @@ honest-validator-2: reports node_roles is 4 malus-validator-0: reports node_roles is 4 # Parachains should be making progress even if we have up to 1/3 malicious validators. -honest-validator-0: parachain 2000 block height is at least 2 within 180 seconds +honest-validator-0: parachain 2000 block height is at least 2 within 240 seconds honest-validator-1: parachain 2001 block height is at least 2 within 180 seconds honest-validator-2: parachain 2002 block height is at least 2 within 180 seconds diff --git a/zombienet_tests/misc/0003-parathreads.toml b/zombienet_tests/misc/0003-parathreads.toml new file mode 100644 index 000000000000..83b6d39bffb0 --- /dev/null +++ b/zombienet_tests/misc/0003-parathreads.toml @@ -0,0 +1,32 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +command = "polkadot" + + [[relaychain.nodes]] + name = "alice" + args = [ "--alice", "-lruntime=debug,parachain=trace" ] + + [[relaychain.nodes]] + name = "bob" + args = [ "--bob", "-lruntime=debug,parachain=trace" ] + +[[parachains]] +id = 100 +add_to_genesis = false +register_para = true +onboard_as_parachain = false + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "adder-collator" + args = [ "-lruntime=debug,parachain=trace" ] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/zombienet_tests/smoke/0001-parachains-smoke-test.zndsl b/zombienet_tests/smoke/0001-parachains-smoke-test.zndsl index 13d0624158f2..b280a198e085 100644 --- a/zombienet_tests/smoke/0001-parachains-smoke-test.zndsl +++ b/zombienet_tests/smoke/0001-parachains-smoke-test.zndsl @@ -3,4 +3,4 @@ Network: ./0001-parachains-smoke-test.toml Creds: config alice: parachain 100 is registered within 225 seconds -alice: parachain 100 block height is at least 10 within 200 seconds +alice: parachain 100 block height is at least 10 within 400 seconds diff --git a/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.zndsl b/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.zndsl index fec28455f5f2..bcea5aa1646e 100644 --- a/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.zndsl +++ b/zombienet_tests/smoke/0002-parachains-upgrade-smoke-test.zndsl @@ -3,6 +3,6 @@ Network: ./0002-parachains-upgrade-smoke-test.toml Creds: config alice: parachain 100 is registered within 225 seconds -alice: parachain 100 block height is at least 10 within 400 seconds +alice: parachain 100 block height is at least 10 within 460 seconds alice: parachain 100 perform dummy upgrade within 200 seconds alice: parachain 100 block height is at least 14 within 200 seconds From 1ef2f8a27b0b6253981a52c2fede3bb33f18ded0 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 17 Aug 2023 22:15:35 -0700 Subject: [PATCH 32/45] XCM: Replace council XCM origin with general admin (#7633) * XCM: Replace council XCM origin with general admin * Fixes * Fixes * Update runtime/polkadot/src/xcm_config.rs Co-authored-by: ordian * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: ordian Co-authored-by: command-bot <> --- runtime/kusama/src/xcm_config.rs | 2 +- runtime/polkadot/src/lib.rs | 4 ++-- runtime/polkadot/src/xcm_config.rs | 37 ++++++++++++++---------------- runtime/rococo/src/xcm_config.rs | 28 ++++------------------ 4 files changed, 25 insertions(+), 46 deletions(-) diff --git a/runtime/kusama/src/xcm_config.rs b/runtime/kusama/src/xcm_config.rs index 5725f54eddd5..c90e6c55a94b 100644 --- a/runtime/kusama/src/xcm_config.rs +++ b/runtime/kusama/src/xcm_config.rs @@ -385,7 +385,7 @@ pub type LocalPalletOriginToLocation = ( impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // We only allow the root, the council, fellows and the staking admin to send messages. + // We only allow the root, fellows and the staking admin to send messages. // This is basically safe to enable for everyone (safe the possibility of someone spamming the // parachain if they're willing to pay the KSM to send from the Relay-chain), but it's useless // until we bring in XCM v3 which will make `DescendOrigin` a bit more useful. diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index da8cf7cb5a61..96ac8bad6c67 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -110,8 +110,8 @@ mod bag_thresholds; // Governance configurations. pub mod governance; use governance::{ - old::CouncilCollective, pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, - LeaseAdmin, StakingAdmin, Treasurer, TreasurySpender, + pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, StakingAdmin, + Treasurer, TreasurySpender, }; pub mod xcm_config; diff --git a/runtime/polkadot/src/xcm_config.rs b/runtime/polkadot/src/xcm_config.rs index b2e09b1453af..6c45f1cec402 100644 --- a/runtime/polkadot/src/xcm_config.rs +++ b/runtime/polkadot/src/xcm_config.rs @@ -17,8 +17,8 @@ //! XCM configuration for Polkadot. use super::{ - parachains_origin, AccountId, AllPalletsWithSystem, Balances, CouncilCollective, Dmp, - FellowshipAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, + parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin, + GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, TransactionByteFee, WeightToFee, XcmPallet, }; use frame_support::{ @@ -40,11 +40,11 @@ use sp_core::ConstU32; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, BackingToPlurality, - ChildParachainAsNative, ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, - IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, MintLocation, + OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::traits::WithOriginFilter; @@ -350,7 +350,8 @@ impl xcm_executor::Config for XcmConfig { } parameter_types! { - pub const CouncilBodyId: BodyId = BodyId::Executive; + // `GeneralAdmin` pluralistic body. + pub const GeneralAdminBodyId: BodyId = BodyId::Administration; // StakingAdmin pluralistic body. pub const StakingAdminBodyId: BodyId = BodyId::Defense; // FellowshipAdmin pluralistic body. @@ -362,17 +363,14 @@ parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); } -/// Type to convert a council origin to a Plurality `MultiLocation` value. -pub type CouncilToPlurality = BackingToPlurality< - RuntimeOrigin, - pallet_collective::Origin, - CouncilBodyId, ->; +/// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. +pub type GeneralAdminToPlurality = + OriginToPluralityVoice; /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// location of this chain. pub type LocalOriginToLocation = ( - CouncilToPlurality, + GeneralAdminToPlurality, // And a usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, ); @@ -381,16 +379,15 @@ pub type LocalOriginToLocation = ( pub type StakingAdminToPlurality = OriginToPluralityVoice; -/// Type to convert the FellowshipAdmin origin to a Plurality `MultiLocation` value. +/// Type to convert the `FellowshipAdmin` origin to a Plurality `MultiLocation` value. pub type FellowshipAdminToPlurality = OriginToPluralityVoice; /// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an /// interior location of this chain for a destination chain. pub type LocalPalletOriginToLocation = ( - // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality - // of the `Unit` body. - CouncilToPlurality, + // GeneralAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + GeneralAdminToPlurality, // StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. StakingAdminToPlurality, // FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. @@ -399,7 +396,7 @@ pub type LocalPalletOriginToLocation = ( impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // We only allow the root, the council, the fellowship admin and the staking admin to send + // We only allow the root, the general admin, the fellowship admin and the staking admin to send // messages. type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; diff --git a/runtime/rococo/src/xcm_config.rs b/runtime/rococo/src/xcm_config.rs index 75e06391c56b..356cffaa0ba2 100644 --- a/runtime/rococo/src/xcm_config.rs +++ b/runtime/rococo/src/xcm_config.rs @@ -17,8 +17,8 @@ //! XCM configuration for Rococo. use super::{ - parachains_origin, AccountId, AllPalletsWithSystem, Balances, CouncilCollective, Dmp, ParaId, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmPallet, + parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, ParaId, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmPallet, }; use frame_support::{ match_types, parameter_types, @@ -36,8 +36,8 @@ use sp_core::ConstU32; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, BackingToPlurality, - ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, + ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete, MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, @@ -322,33 +322,15 @@ impl xcm_executor::Config for XcmConfig { type Aliasers = Nothing; } -parameter_types! { - pub const CollectiveBodyId: BodyId = BodyId::Unit; -} - -parameter_types! { - pub const CouncilBodyId: BodyId = BodyId::Executive; -} - #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parachain(1000).into()); } -/// Type to convert the council origin to a Plurality `MultiLocation` value. -pub type CouncilToPlurality = BackingToPlurality< - RuntimeOrigin, - pallet_collective::Origin, - CouncilBodyId, ->; - /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// location of this chain. pub type LocalOriginToLocation = ( - // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality - // of the `Unit` body. - CouncilToPlurality, - // And a usual Signed origin to be used in XCM as a corresponding AccountId32 + // A usual Signed origin to be used in XCM as a corresponding AccountId32 SignedToAccountId32, ); impl pallet_xcm::Config for Runtime { From a877cc5dbb013ea8a65950563c06c53763bca450 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 18 Aug 2023 19:03:09 +1000 Subject: [PATCH 33/45] migration: unlock/unreserve Gov v1 balances and remove kvs (#7314) * restore old gov configs * migrate old gov v1 storage * exclude the Call enum for gov v1 pallets * update substrate * update tips pallet * update chain_spec * fix migrations tuple * oliver comments * format comment * ".git/.scripts/commands/fmt/fmt.sh" * comments * polkadot migrations * fix cargo.lock * fix compilation * use democracy standalone migration * re-remove gov v1 pallets from kusama * remove unnecessary feature * fix unlock configs * use substrate master * reset cargo.lock * cargo update -p sp-io * remove from chainspec * remove polkadot gov v1 pallets * clean up chain spec * cargo fmt * remove old gov import --------- Co-authored-by: command-bot <> --- node/service/src/chain_spec.rs | 8 -- runtime/kusama/src/lib.rs | 60 ++++++++ runtime/polkadot/src/governance/mod.rs | 3 - runtime/polkadot/src/governance/old.rs | 191 ------------------------- runtime/polkadot/src/lib.rs | 163 ++++++++++----------- 5 files changed, 132 insertions(+), 293 deletions(-) delete mode 100644 runtime/polkadot/src/governance/old.rs diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index 7e2d9c470450..4d0d11ba436e 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -1284,14 +1284,6 @@ pub fn polkadot_testnet_genesis( slash_reward_fraction: Perbill::from_percent(10), ..Default::default() }, - phragmen_election: Default::default(), - democracy: polkadot::DemocracyConfig::default(), - council: polkadot::CouncilConfig { members: vec![], phantom: Default::default() }, - technical_committee: polkadot::TechnicalCommitteeConfig { - members: vec![], - phantom: Default::default(), - }, - technical_membership: Default::default(), babe: polkadot::BabeConfig { authorities: Default::default(), epoch_config: Some(polkadot::BABE_GENESIS_EPOCH_CONFIG), diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index ae1925e898a2..c7077e38a653 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1533,6 +1533,51 @@ pub type Migrations = (migrations::Unreleased,); #[allow(deprecated, missing_docs)] pub mod migrations { use super::*; + use frame_support::traits::LockIdentifier; + use frame_system::pallet_prelude::BlockNumberFor; + + parameter_types! { + pub const DemocracyPalletName: &'static str = "Democracy"; + pub const CouncilPalletName: &'static str = "Council"; + pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; + pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; + pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; + pub const TipsPalletName: &'static str = "Tips"; + pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; + } + + // Special Config for Gov V1 pallets, allowing us to run migrations for them without + // implementing their configs on [`Runtime`]. + pub struct UnlockConfig; + impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { + type Currency = Balances; + type MaxVotes = ConstU32<100>; + type MaxDeposits = ConstU32<100>; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = DemocracyPalletName; + } + impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig + for UnlockConfig + { + type Currency = Balances; + type MaxVotesPerVoter = ConstU32<16>; + type PalletId = PhragmenElectionPalletId; + type AccountId = AccountId; + type DbWeight = ::DbWeight; + type PalletName = PhragmenElectionPalletName; + } + impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { + type Currency = Balances; + type Hash = Hash; + type DataDepositPerByte = DataDepositPerByte; + type TipReportDepositBase = TipReportDepositBase; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = TipsPalletName; + } /// Unreleased migrations. Add new ones here: pub type Unreleased = ( @@ -1546,6 +1591,21 @@ pub mod migrations { parachains_configuration::migration::v7::MigrateToV7, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, + + // Unlock/unreserve balances from Gov v1 pallets that hold them + // https://github.com/paritytech/polkadot/issues/6749 + pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + + // Delete storage key/values from all Gov v1 pallets + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + ); } diff --git a/runtime/polkadot/src/governance/mod.rs b/runtime/polkadot/src/governance/mod.rs index 870d143dbaf0..79c904622ddd 100644 --- a/runtime/polkadot/src/governance/mod.rs +++ b/runtime/polkadot/src/governance/mod.rs @@ -23,9 +23,6 @@ use frame_system::EnsureRootWithSuccess; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use xcm::latest::BodyId; -// Old governance configurations. -pub mod old; - mod origins; pub use origins::{ pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, diff --git a/runtime/polkadot/src/governance/old.rs b/runtime/polkadot/src/governance/old.rs deleted file mode 100644 index 4c7b503472f2..000000000000 --- a/runtime/polkadot/src/governance/old.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (C) 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 . - -//! Old governance configurations for the Polkadot runtime. - -use crate::*; -use frame_support::{parameter_types, traits::EitherOfDiverse}; - -parameter_types! { - pub LaunchPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1, "DOT_LAUNCH_PERIOD"); - pub VotingPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1 * MINUTES, "DOT_VOTING_PERIOD"); - pub FastTrackVotingPeriod: BlockNumber = prod_or_fast!(3 * HOURS, 1 * MINUTES, "DOT_FAST_TRACK_VOTING_PERIOD"); - pub const MinimumDeposit: Balance = 100 * DOLLARS; - pub EnactmentPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1, "DOT_ENACTMENT_PERIOD"); - pub CooloffPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1, "DOT_COOLOFF_PERIOD"); - pub const InstantAllowed: bool = true; - pub const MaxVotes: u32 = 100; - pub const MaxProposals: u32 = 100; -} - -impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EnactmentPeriod = EnactmentPeriod; - type VoteLockingPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type MinimumDeposit = MinimumDeposit; - type SubmitOrigin = frame_system::EnsureSigned; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - frame_system::EnsureRoot, - >; - /// A 60% super-majority can have the next scheduled referendum be a straight majority-carries - /// vote. - type ExternalMajorityOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - frame_system::EnsureRoot, - >; - /// A unanimous council can have the next scheduled referendum be a straight default-carries - /// (NTB) vote. - type ExternalDefaultOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - frame_system::EnsureRoot, - >; - /// Two thirds of the technical committee can have an `ExternalMajority/ExternalDefault` vote - /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - frame_system::EnsureRoot, - >; - type InstantOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - frame_system::EnsureRoot, - >; - type InstantAllowed = InstantAllowed; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - pallet_collective::EnsureProportionAtLeast, - EnsureRoot, - >; - type BlacklistOrigin = EnsureRoot; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cooloff period. - type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = Treasury; - type Scheduler = Scheduler; - type PalletsOrigin = OriginCaller; - type MaxVotes = MaxVotes; - type WeightInfo = weights::pallet_democracy::WeightInfo; - type MaxProposals = MaxProposals; - type Preimages = Preimage; - type MaxDeposits = ConstU32<100>; - type MaxBlacklisted = ConstU32<100>; -} - -parameter_types! { - pub CouncilMotionDuration: BlockNumber = prod_or_fast!(7 * DAYS, 2 * MINUTES, "DOT_MOTION_DURATION"); - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 100; - pub MaxProposalWeight: Weight = Perbill::from_percent(50) * BlockWeights::get().max_block; -} - -pub type CouncilCollective = pallet_collective::Instance1; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type SetMembersOrigin = EnsureRoot; - type WeightInfo = weights::pallet_collective_council::WeightInfo; - type MaxProposalWeight = MaxProposalWeight; -} - -parameter_types! { - pub const CandidacyBond: Balance = 100 * DOLLARS; - // 1 storage item created, key size is 32 bytes, value size is 16+16. - pub const VotingBondBase: Balance = deposit(1, 64); - // additional data per vote is 32 bytes (account id). - pub const VotingBondFactor: Balance = deposit(0, 32); - /// Weekly council elections; scaling up to monthly eventually. - pub TermDuration: BlockNumber = prod_or_fast!(7 * DAYS, 2 * MINUTES, "DOT_TERM_DURATION"); - /// 13 members initially, to be increased to 23 eventually. - pub const DesiredMembers: u32 = 13; - pub const DesiredRunnersUp: u32 = 20; - pub const MaxVoters: u32 = 10 * 1000; - pub const MaxVotesPerVoter: u32 = 16; - pub const MaxCandidates: u32 = 1000; - pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; -} -// Make sure that there are no more than `MaxMembers` members elected via phragmen. -const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); - -impl pallet_elections_phragmen::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type PalletId = PhragmenElectionPalletId; - type Currency = Balances; - type ChangeMembers = Council; - type InitializeMembers = Council; - type CurrencyToVote = runtime_common::CurrencyToVote; - type CandidacyBond = CandidacyBond; - type VotingBondBase = VotingBondBase; - type VotingBondFactor = VotingBondFactor; - type LoserCandidate = Treasury; - type KickedMember = Treasury; - type DesiredMembers = DesiredMembers; - type DesiredRunnersUp = DesiredRunnersUp; - type TermDuration = TermDuration; - type MaxVoters = MaxVoters; - type MaxVotesPerVoter = MaxVotesPerVoter; - type MaxCandidates = MaxCandidates; - type WeightInfo = weights::pallet_elections_phragmen::WeightInfo; -} - -parameter_types! { - pub const TechnicalMotionDuration: BlockNumber = 7 * DAYS; - pub const TechnicalMaxProposals: u32 = 100; - pub const TechnicalMaxMembers: u32 = 100; -} - -pub type TechnicalCollective = pallet_collective::Instance2; -impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = TechnicalMotionDuration; - type MaxProposals = TechnicalMaxProposals; - type MaxMembers = TechnicalMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type SetMembersOrigin = EnsureRoot; - type WeightInfo = weights::pallet_collective_technical_committee::WeightInfo; - type MaxProposalWeight = MaxProposalWeight; -} - -impl pallet_membership::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = TechnicalCommittee; - type MembershipChanged = TechnicalCommittee; - type MaxMembers = TechnicalMaxMembers; - type WeightInfo = weights::pallet_membership::WeightInfo; -} diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index 96ac8bad6c67..e03b2b673706 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -47,8 +47,8 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, - PrivilegeCmp, ProcessMessage, ProcessMessageError, WithdrawReasons, + ConstU32, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, PrivilegeCmp, + ProcessMessage, ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter}, PalletId, RuntimeDebug, @@ -85,7 +85,6 @@ use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use static_assertions::const_assert; use xcm::latest::Junction; pub use frame_system::Call as SystemCall; @@ -202,11 +201,6 @@ impl PrivilegeCmp for OriginPrivilegeCmp { match (left, right) { // Root is greater than anything. (OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater), - // Check which one has more yes votes. - ( - OriginCaller::Council(pallet_collective::RawOrigin::Members(l_yes_votes, l_count)), - OriginCaller::Council(pallet_collective::RawOrigin::Members(r_yes_votes, r_count)), - ) => Some((l_yes_votes * r_count).cmp(&(r_yes_votes * l_count))), // For every other origin we don't care, as they are not used for `ScheduleOrigin`. _ => None, } @@ -718,17 +712,6 @@ impl pallet_child_bounties::Config for Runtime { type WeightInfo = weights::pallet_child_bounties::WeightInfo; } -impl pallet_tips::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type DataDepositPerByte = DataDepositPerByte; - type MaximumReasonLength = MaximumReasonLength; - type Tippers = PhragmenElection; - type TipCountdown = TipCountdown; - type TipFindersFee = TipFindersFee; - type TipReportDepositBase = TipReportDepositBase; - type WeightInfo = weights::pallet_tips::WeightInfo; -} - impl pallet_offences::Config for Runtime { type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; @@ -988,15 +971,9 @@ impl InstanceFilter for ProxyType { RuntimeCall::Session(..) | RuntimeCall::Grandpa(..) | RuntimeCall::ImOnline(..) | - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | - RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::PhragmenElection(..) | - RuntimeCall::TechnicalMembership(..) | RuntimeCall::Treasury(..) | RuntimeCall::Bounties(..) | RuntimeCall::ChildBounties(..) | - RuntimeCall::Tips(..) | RuntimeCall::ConvictionVoting(..) | RuntimeCall::Referenda(..) | RuntimeCall::Whitelist(..) | @@ -1019,20 +996,16 @@ impl InstanceFilter for ProxyType { RuntimeCall::NominationPools(..) | RuntimeCall::FastUnstake(..) ), - ProxyType::Governance => - matches!( - c, - RuntimeCall::Democracy(..) | - RuntimeCall::Council(..) | RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::PhragmenElection(..) | - RuntimeCall::Treasury(..) | - RuntimeCall::Bounties(..) | - RuntimeCall::Tips(..) | RuntimeCall::Utility(..) | - RuntimeCall::ChildBounties(..) | - RuntimeCall::ConvictionVoting(..) | - RuntimeCall::Referenda(..) | - RuntimeCall::Whitelist(..) - ), + ProxyType::Governance => matches!( + c, + RuntimeCall::Treasury(..) | + RuntimeCall::Bounties(..) | + RuntimeCall::Utility(..) | + RuntimeCall::ChildBounties(..) | + RuntimeCall::ConvictionVoting(..) | + RuntimeCall::Referenda(..) | + RuntimeCall::Whitelist(..) + ), ProxyType::Staking => { matches!( c, @@ -1375,15 +1348,8 @@ construct_runtime! { ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config} = 12, AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 13, - // Old governance stuff. - Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event} = 14, - Council: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config} = 15, - TechnicalCommittee: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config} = 16, - PhragmenElection: pallet_elections_phragmen::{Pallet, Call, Storage, Event, Config} = 17, - TechnicalMembership: pallet_membership::::{Pallet, Call, Storage, Event, Config} = 18, - Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 19, - // OpenGov stuff. + Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 19, ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 20, Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 21, Origins: pallet_custom_origins::{Origin} = 22, @@ -1409,9 +1375,6 @@ construct_runtime! { Bounties: pallet_bounties::{Pallet, Call, Storage, Event} = 34, ChildBounties: pallet_child_bounties = 38, - // Tips module. - Tips: pallet_tips::{Pallet, Call, Storage, Event} = 35, - // Election pallet. Only works with staking, but placed here to maintain indices. ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned} = 36, @@ -1495,6 +1458,51 @@ pub type Migrations = migrations::Unreleased; #[allow(deprecated, missing_docs)] pub mod migrations { use super::*; + use frame_support::traits::LockIdentifier; + use frame_system::pallet_prelude::BlockNumberFor; + + parameter_types! { + pub const DemocracyPalletName: &'static str = "Democracy"; + pub const CouncilPalletName: &'static str = "Council"; + pub const TechnicalCommitteePalletName: &'static str = "TechnicalCommittee"; + pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; + pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; + pub const TipsPalletName: &'static str = "Tips"; + pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; + } + + // Special Config for Gov V1 pallets, allowing us to run migrations for them without + // implementing their configs on [`Runtime`]. + pub struct UnlockConfig; + impl pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockConfig for UnlockConfig { + type Currency = Balances; + type MaxVotes = ConstU32<100>; + type MaxDeposits = ConstU32<100>; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = DemocracyPalletName; + } + impl pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockConfig + for UnlockConfig + { + type Currency = Balances; + type MaxVotesPerVoter = ConstU32<16>; + type PalletId = PhragmenElectionPalletId; + type AccountId = AccountId; + type DbWeight = ::DbWeight; + type PalletName = PhragmenElectionPalletName; + } + impl pallet_tips::migrations::unreserve_deposits::UnlockConfig<()> for UnlockConfig { + type Currency = Balances; + type Hash = Hash; + type DataDepositPerByte = DataDepositPerByte; + type TipReportDepositBase = TipReportDepositBase; + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type DbWeight = ::DbWeight; + type PalletName = TipsPalletName; + } /// Unreleased migrations. Add new ones here: pub type Unreleased = ( @@ -1502,6 +1510,20 @@ pub mod migrations { parachains_configuration::migration::v7::MigrateToV7, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, + + // Gov v1 storage migrations + // https://github.com/paritytech/polkadot/issues/6749 + pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, + pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + + // Delete all Gov v1 pallet storage key/values. + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, + frame_support::migrations::RemovePallet::DbWeight>, ); } @@ -1546,17 +1568,12 @@ mod benches { [frame_benchmarking::baseline, Baseline::] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] - [pallet_collective, Council] - [pallet_collective, TechnicalCommittee] - [pallet_democracy, Democracy] - [pallet_elections_phragmen, PhragmenElection] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [frame_election_provider_support, ElectionProviderBench::] [pallet_fast_unstake, FastUnstake] [pallet_identity, Identity] [pallet_im_online, ImOnline] [pallet_indices, Indices] - [pallet_membership, TechnicalMembership] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] @@ -1568,7 +1585,6 @@ mod benches { [pallet_staking, Staking] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] - [pallet_tips, Tips] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -2181,7 +2197,6 @@ sp_api::impl_runtime_apis! { #[cfg(test)] mod test_fees { use super::*; - use crate::governance::old::*; use frame_support::{dispatch::GetDispatchInfo, weights::WeightToFee as WeightToFeeT}; use keyring::Sr25519Keyring::{Alice, Charlie}; use pallet_transaction_payment::Multiplier; @@ -2282,40 +2297,6 @@ mod test_fees { test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000_000u128)); } - #[test] - fn full_block_council_election_cost() { - // the number of voters needed to consume almost a full block in council election, and how - // much it is going to cost. - use pallet_elections_phragmen::WeightInfo; - - // Loser candidate lose a lot of money; sybil attack by candidates is even more expensive, - // and we don't care about it here. For now, we assume no extra candidates, and only - // superfluous voters. - let candidates = DesiredMembers::get() + DesiredRunnersUp::get(); - let mut voters = 1u32; - let weight_with = |v| { - ::WeightInfo::election_phragmen( - candidates, - v, - v * 16, - ) - }; - - while weight_with(voters).all_lte(BlockWeights::get().max_block) { - voters += 1; - } - - let cost = voters as Balance * (VotingBondBase::get() + 16 * VotingBondFactor::get()); - let cost_dollars = cost / DOLLARS; - println!( - "can support {} voters in a single block for council elections; total bond {}", - voters, cost_dollars, - ); - // The minimal number of voters we expect per block. - assert!(voters >= 1_000); - assert!(cost_dollars >= 10_000); - } - #[test] fn nominator_limit() { use pallet_election_provider_multi_phase::WeightInfo; From 6b06242190dc68385ab36d8d8f4b6c6a269f1857 Mon Sep 17 00:00:00 2001 From: mrq1911 Date: Fri, 18 Aug 2023 11:11:16 +0200 Subject: [PATCH 34/45] protobuf is required dep bor build (#7636) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6e969760362..dcebcf727754 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ rustup update Once done, finish installing the support software: ```bash -sudo apt install build-essential git clang libclang-dev pkg-config libssl-dev +sudo apt install build-essential git clang libclang-dev pkg-config libssl-dev protobuf-compiler ``` Build the client by cloning this repository and running the following commands from the root From 4b7822adeb666ad33539c7ecf1e4518d04b3a90c Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Fri, 18 Aug 2023 11:11:56 -0500 Subject: [PATCH 35/45] Asynchronous Backing MegaPR (#5022) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * inclusion emulator logic for asynchronous backing (#4790) * initial stab at candidate_context * fmt * docs & more TODOs * some cleanups * reframe as inclusion_emulator * documentations yes * update types * add constraint modifications * watermark * produce modifications * v2 primitives: re-export all v1 for consistency * vstaging primitives * emulator constraints: handle code upgrades * produce outbound HRMP modifications * stack. * method for applying modifications * method just for sanity-checking modifications * fragments produce modifications, not prospectives * make linear * add some TODOs * remove stacking; handle code upgrades * take `fragment` private * reintroduce stacking. * fragment constructor * add TODO * allow validating fragments against future constraints * docs * relay-parent number and min code size checks * check code upgrade restriction * check max hrmp per candidate * fmt * remove GoAhead logic because it wasn't helpful * docs on code upgrade failure * test stacking * test modifications against constraints * fmt * test fragments * descending or duplicate test * fmt * remove unused imports in vstaging * wrong primitives * spellcheck * Runtime changes for Asynchronous Backing (#4786) * inclusion: utility for allowed relay-parents * inclusion: use prev number instead of prev hash * track most recent context of paras * inclusion: accept previous relay-parents * update dmp advancement rule for async backing * fmt * add a comment about validation outputs * clean up a couple of TODOs * weights * fix weights * fmt * Resolve dmp todo * Restore inclusion tests * Restore paras_inherent tests * MostRecentContext test * Benchmark for new paras dispatchable * Prepare check_validation_outputs for upgrade * cargo run --quiet --profile=production --features=runtime-benchmarks -- benchmark --chain=kusama-dev --steps=50 --repeat=20 --pallet=runtime_parachains::paras --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=./runtime/kusama/src/weights/runtime_parachains_paras.rs * cargo run --quiet --profile=production --features=runtime-benchmarks -- benchmark --chain=westend-dev --steps=50 --repeat=20 --pallet=runtime_parachains::paras --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=./runtime/westend/src/weights/runtime_parachains_paras.rs * cargo run --quiet --profile=production --features=runtime-benchmarks -- benchmark --chain=polkadot-dev --steps=50 --repeat=20 --pallet=runtime_parachains::paras --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=./runtime/polkadot/src/weights/runtime_parachains_paras.rs * cargo run --quiet --profile=production --features=runtime-benchmarks -- benchmark --chain=rococo-dev --steps=50 --repeat=20 --pallet=runtime_parachains::paras --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=./runtime/rococo/src/weights/runtime_parachains_paras.rs * Implementers guide changes * More tests for allowed relay parents * Add a github issue link * Compute group index based on relay parent * Storage migration * Move allowed parents tracker to shared * Compile error * Get group assigned to core at the next block * Test group assignment * fmt * Error instead of panic * Update guide * Extend doc-comment * Update runtime/parachains/src/shared.rs Co-authored-by: Robert Habermeier Co-authored-by: Chris Sosnin Co-authored-by: Parity Bot Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * Prospective Parachains Subsystem (#4913) * docs and skeleton * subsystem skeleton * main loop * fragment tree basics & fmt * begin fragment trees & view * flesh out more of view update logic * further flesh out update logic * some refcount functions for fragment trees * add fatal/non-fatal errors * use non-fatal results * clear up some TODOs * ideal format for scheduling info * add a bunch of TODOs * some more fluff * extract fragment graph to submodule * begin fragment graph API * trees, not graphs * improve docs * scope and constructor for trees * add some test TODOs * limit max ancestors and store constraints * constructor * constraints: fix bug in HRMP watermarks * fragment tree population logic * set::retain * extract population logic * implement add_and_populate * fmt * add some TODOs in tests * implement child-selection * strip out old stuff based on wrong assumptions * use fatality * implement pruning * remove unused ancestor constraints * fragment tree instantiation * remove outdated comment * add message/request types and skeleton for handling * fmt * implement handle_candidate_seconded * candidate storage: handle backed * implement handle_candidate_backed * implement answer_get_backable_candidate * remove async where not needed * implement fetch_ancestry * add logic for run_iteration * add some docs * remove global allow(unused), fix warnings * make spellcheck happy (despite English) * fmt * bump Cargo.lock * replace tracing with gum * introduce PopulateFrom trait * implement GetHypotheticalDepths * revise docs slightly * first fragment tree scope test * more scope tests * test add_candidate * fmt * test retain * refactor test code * test populate is recursive * test contiguity of depth 0 is maintained * add_and_populate tests * cycle tests * remove PopulateFrom trait * fmt * test hypothetical depths (non-recursive) * have CandidateSeconded return membership * tree membership requests * Add a ProspectiveParachainsSubsystem struct * add a staging API for base constraints * add a `From` impl * add runtime API for staging_validity_constraints * implement fetch_base_constraints * implement `fetch_upcoming_paras` * remove reconstruction of candidate receipt; no obvious usecase * fmt * export message to broader module * remove last TODO * correctly export * fix compilation and add GetMinimumRelayParent request * make provisioner into a real subsystem with proper mesage bounds * fmt * fix ChannelsOut in overseer test * fix overseer tests * fix again * fmt * Integrate prospective parachains subsystem into backing: Part 1 (#5557) * BEGIN ASYNC candidate-backing CHANGES * rename & document modes * answer prospective validation data requests * GetMinimumRelayParents request is now plural * implement an implicit view utility for backing subsystems * implicit-view: get allowed relay parents * refactorings and improvements to implicit view * add some TODOs for tests * split implicit view updates into 2 functions * backing: define State to prepare for functional refactor * add some docs * backing: implement bones of new leaf activation logic * backing: create per-relay-parent-states * use new handle_active_leaves_update * begin extracting logic from CandidateBackingJob * mostly extract statement import from job logic * handle statement imports outside of job logic * do some TODO planning for prospective parachains integration * finish rewriting backing subsystem in functional style * add prospective parachains mode to relay parent entries * fmt * add a RejectedByProspectiveParachains error * notify prospective parachains of seconded and backed candidates * always validate candidates exhaustively in backing. * return persisted_validation_data from validation * handle rejections by prospective parachains * implement seconding sanity check * invoke validate_and_second * Alter statement table to allow multiple seconded messages per validator * refactor backing to have statements carry PVD * clean up all warnings * Add tests for implicit view * Improve doc comments * Prospective parachains mode based on Runtime API version * Add a TODO * Rework seconding_sanity_check * Iterate over responses * Update backing tests * collator-protocol: load PVD from runtime * Fix validator side tests * Update statement-distribution to fetch PVD * Fix statement-distribution tests * Backing tests with prospective paras #1 * fix per_relay_parent pruning in backing * Test multiple leaves * Test seconding sanity check * Import statement order Before creating an entry in `PerCandidateState` map wait for the approval from the prospective parachains * Add a test for correct state updates * Second multiple candidates per relay parent test * Add backing tests with prospective paras * Second more than one test without prospective paras * Add a test for prospective para blocks * Update malus * typos Co-authored-by: Chris Sosnin * Track occupied depth in backing per parachain (#5778) * provisioner: async backing changes (#5711) * Provisioner changes for async backing * Select candidates based on prospective paras mode * Revert naming * Update tests * Update TODO comment * review * provisioner: async backing changes (#5711) * Provisioner changes for async backing * Select candidates based on prospective paras mode * Revert naming * Update tests * Update TODO comment * review * fmt * Network bridge changes for asynchronous backing + update subsystems to handle versioned packets (#5991) * BEGIN STATEMENT DISTRIBUTION WORK create a vstaging network protocol which is the same as v1 * mostly make network bridge amenable to vstaging * network-bridge: fully adapt to vstaging * add some TODOs for tests * fix fallout in bitfield-distribution * bitfield distribution tests + TODOs * fix fallout in gossip-support * collator-protocol: fix message fallout * collator-protocol: load PVD from runtime * add TODO for vstaging tests * make things compile * set used network protocol version using a feature * fmt * get approval-distribution building * fix approval-distribution tests * spellcheck * nits * approval distribution net protocol test * bitfield distribution net protocol test * Revert "collator-protocol: fix message fallout" This reverts commit 07cc887303e16c6b3843ecb25cdc7cc2080e2ed1. * Network bridge tests Co-authored-by: Chris Sosnin * remove max_pov_size requirement from prospective pvd request (#6014) * remove max_pov_size requirement from prospective pvd request * fmt * Extract legacy statement distribution to its own module (#6026) * add compatibility type to v2 statement distribution message * warning cleanup * handle compatibility layer for v2 * clean up an unimplemented!() block * circulate statements based on version * extract legacy v1 code into separate module * remove unimplemented * clean up naming of from_requester/responder * remove TODOs * have backing share seconded statements with PVD * fmt * fix warning * Quick fix unused warning for not yet implemented/used staging messages. * Fix network bridge test * Fix wrong merge. We now have 23 subsystems (network bridge split + prospective parachains) Co-authored-by: Robert Klotzner * Version 3 is already live. * Fix tests (#6055) * Fix backing tests * Fix warnings. * fmt * collator-protocol: asynchronous backing changes (#5740) * Draft collator side changes * Start working on collations management * Handle peer's view change * Versioning on advertising * Versioned collation fetching request * Handle versioned messages * Improve docs for collation requests * Add spans * Add request receiver to overseer * Fix collator side tests * Extract relay parent mode to lib * Validator side draft * Add more checks for advertisement * Request pvd based on async backing mode * review * Validator side improvements * Make old tests green * More fixes * Collator side tests draft * Send collation test * fmt * Collator side network protocol versioning * cleanup * merge artifacts * Validator side net protocol versioning * Remove fragment tree membership request * Resolve todo * Collator side core state test * Improve net protocol compatibility * Validator side tests * more improvements * style fixes * downgrade log * Track implicit assignments * Limit the number of seconded candidates per para * Add a sanity check * Handle fetched candidate * fix tests * Retry fetch * Guard against dequeueing while already fetching * Reintegrate connection management * Timeout on advertisements * fmt * spellcheck * update tests after merge * validator assignment fixes for backing and collator protocol (#6158) * Rename depth->ancestry len in tests * Refactor group assignments * Remove implicit assignments * backing: consider occupied core assignments * Track a single para on validator side * Refactor prospective parachains mode request (#6179) * Extract prospective parachains mode into util * Skip activations depending on the mode * backing: don't send backed candidate to provisioner (#6185) * backing: introduce `CanSecond` request for advertisements filtering (#6225) * Drop BoundToRelayParent * draft changes * fix backing tests * Fix genesis ancestry * Fix validator side tests * more tests * cargo generate-lockfile * Implement `StagingValidityConstraints` Runtime API method (#6258) * Implement StagingValidityConstraints * spellcheck * fix ump params * Update hrmp comment * Introduce ump per candidate limit * hypothetical earliest block * refactor primitives usage * hypothetical earliest block number test * fix build * Prepare the Runtime for asynchronous backing upgrade (#6287) * Introduce async backing params to runtime config * fix cumulus config * use config * finish runtimes * Introduce new staging API * Update collator protocol * Update provisioner * Update prospective parachains * Update backing * Move async backing params lower in the config * make naming consistent * misc * Use real prospective parachains subsystem (#6407) * Backport `HypotheticalFrontier` into the feature branch (#6605) * implement more general HypotheticalFrontier * fmt * drop unneeded request Co-authored-by: Robert Habermeier * Resolve todo about legacy leaf activation (#6447) * fix bug/warning in handling membership answers * Remove `HypotheticalDepthRequest` in favor of `HypotheticalFrontierRequest` (#6521) * Remove `HypotheticalDepthRequest` for `HypotheticalFrontierRequest` * Update tests * Fix (removed wrong docstring) * Fix can_second request * Patch some dead_code errors --------- Co-authored-by: Chris Sosnin * Async Backing: Send Statement Distribution "Backed" messages (#6634) * Backing: Send Statement Distribution "Backed" messages Closes #6590. **TODO:** - [ ] Adjust tests * Fix compile errors * (Mostly) fix tests * Fix comment * Fix test and compile error * Test that `StatementDistributionMessage::Backed` is sent * Fix compile error * Fix some clippy errors * Add prospective parachains subsystem tests (#6454) * Add prospective parachains subsystem test * Add `should_do_no_work_if_async_backing_disabled_for_leaf` test * Implement `activate_leaf` helper, up to getting ancestry * Finish implementing `activate_leaf` * Small refactor in `activate_leaf` * Get `CandidateSeconded` working * Finish `send_candidate_and_check_if_found` test * Refactor; send more leaves & candidates * Refactor test * Implement `check_candidate_parent_leaving_view` test * Start work on `check_candidate_on_multiple_forks` test * Don’t associate specific parachains with leaf * Finish `correctly_updates_leaves` test * Fix cycle due to reused head data * Fix `check_backable_query` test * Fix `check_candidate_on_multiple_forks` test * Add `check_depth_and_pvd_queries` test * Address review comments * Remove TODO * add a new index for output head data to candidate storage * Resolve test TODOs * Fix compile errors * test candidate storage pruning, make sure new index is cleaned up --------- Co-authored-by: Robert Habermeier * Node-side metrics for asynchronous backing (#6549) * Add metrics for `prune_view_candidate_storage` * Add metrics for `request_unblocked_collations` * Fix docstring * Couple fixes from review comments * Fix `check_depth_query` test * inclusion-emulator: mirror advancement rule check (#6361) * inclusion-emulator: mirror advancement rule check * fix build * prospective-parachains: introduce `backed_in_path_only` flag for advertisements (#6649) * Introduce `backed_in_path_only` flag for depth request * fmt * update doc comment * fmt * Add async-backing zombienet tests (#6314) * Async backing: impl guide for statement distribution (#6738) Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Co-authored-by: alexgparity <115470171+alexgparity@users.noreply.github.com> * Asynchronous backing statement distribution: Take III (#5999) * add notification types for v2 statement-distribution * improve protocol docs * add empty vstaging module * fmt * add backed candidate packet request types * start putting down structure of new logic * handle activated leaf * some sanity-checking on outbound statements * fmt * update vstaging share to use statements with PVD * tiny refactor, candidate_hash location * import local statements * refactor statement import * first stab at broadcast logic * fmt * fill out some TODOs * start on handling incoming * split off session info into separate map * start in on a knowledge tracker * address some grumbles * format * missed comment * some docs for direct * add note on slashing * amend * simplify 'direct' code * finish up the 'direct' logic * add a bunch of tests for the direct-in-group logic * rename 'direct' to 'cluster', begin a candidate_entry module * distill candidate_entry * start in on a statement-store module * some utilities for the statement store * rewrite 'send_statement_direct' using new tools * filter sending logic on peers which have the relay-parent in their view. * some more logic for handling incoming statements * req/res: BackedCandidatePacket -> AttestedCandidate + tweaks * add a `validated_in_group` bitfield to BackedCandidateInventory * BackedCandidateInventory -> Manifest * start in on requester module * add outgoing request for attested candidate * add a priority mechanism for requester * some request dispatch logic * add seconded mask to tagged-request * amend manifest to hold group index * handle errors and set up scaffold for response validation * validate attested candidate responses * requester -> requests * add some utilities for manipulating requests * begin integrating requester * start grid module * tiny * refactor grid topology to expose more info to subsystems * fix grid_topology test * fix overseer test * implement topology group-based view construction logic * fmt * flesh out grid slightly more * add indexed groups utility * integrate Groups into per-session info * refactor statement store to borrow Groups * implement manifest knowledge utility * add a test for topology setup * don't send to group members * test for conflicting manifests * manifest knowledge tests * fmt * rename field * garbage collection for grid tracker * routines for finding correct/incorrect advertisers * add manifest import logic * tweak naming * more tests for manifest import * add comment * rework candidates into a view-wide tracker * fmt * start writing boilerplate for grid sending * fmt * some more group boilerplate * refactor handling of topology and authority IDs * fmt * send statements directly to grid peers where possible * send to cluster only if statement belongs to cluster * improve handling of cluster statements * handle incoming statements along the grid * API for introduction of candidates into the tree * backing: use new prospective parachains API * fmt prospective parachains changes * fmt statement-dist * fix condition * get ready for tracking importable candidates * prospective parachains: add Cow logic * incomplete and complete hypothetical candidates * remove keep_if_unneeded * fmt * implement more general HypotheticalFrontier * fmt, cleanup * add a by_parent_hash index to candidate tracker * more framework for future code * utilities for getting all hypothetical candidates for frontier * track origin in statement store * fmt * requests should return peer * apply post-confirmation reckoning * flesh out import/announce/circulate logic on new statements * adjust * adjust TODO comment * fix backing tests * update statement-distribution to use new indexedvec * fmt * query hypothetical candidates * implement `note_importable_under` * extract common utility of fragment tree updates * add a helper function for getting statements unknown by backing * import fresh statements to backing * send announcements and acknowledgements over grid * provide freshly importable statements also avoid tracking backed candidates in statement distribution * do not issue requests on newly importable candidates * add TODO for later when confirming candidate * write a routine for handling backed candidate notifications * simplify grid substantially * add some test TODOs * handle confirmed candidates & grid announcements * finish implementing manifest handling, including follow up statements * send follow-up statements when acknowledging freshly backed * fmt * handle incoming acknowledgements * a little DRYing * wire up network messages to handlers * fmt * some skeleton code for peer view update handling * more peer view skeleton stuff * Fix async backing statement distribution tests (#6621) * Fix compile errors in tests * Cargo fmt * Resolve some todos in async backing statement-distribution branch (#6482) * Implement `remove_by_relay_parent` * Extract `minimum_votes` to shared primitives. * Add `can_send_statements_received_with_prejudice` test * Fix test * Update docstrings * Cargo fmt * Fix compile error * Fix compile errors in tests * Cargo fmt * Add module docs; write `test_priority_ordering` (first draft) * Fix `test_priority_ordering` * Move `insert_or_update_priority`: `Drop` -> `set_cluster_priority` * Address review comments * Remove `Entry::get_mut` * fix test compilation * add a TODO for a test * clean up a couple of TODOs * implement sending pending cluster statements * refactor utility function for sending acknowledgement and statements * mostly implement catching peers up via grid * Fix clippy error * alter grid to track all pending statements * fix more TODOs and format * tweak a TODO in requests * some logic for dispatching requests * fmt * skeleton for response receiving * Async backing statement distribution: cluster tests (#6678) * Add `pending_statements_set_when_receiving_fresh_statements` * Add `pending_statements_updated_when_sending_statements` test * fix up * fmt * update TODO * rework seconded mask in requests * change doc * change unhandledresponse not to borrow request manager * only accept responses sufficient to back * finish implementing response handling * extract statement filter to protocol crate * rework requests: use statement filter in network protocol * dispatch cluster requests correctly * rework cluster statement sending * implement request answering * fmt * only send confirmed candidate statement messages on unified relay-parent * Fix Tests In Statement Distribution Branch * Async Backing: Integrate `vstaging` of statement distribution into `lib.rs` (#6715) * Integrate `handle_active_leaves_update` * Integrate `share_local_statement`/`handle_backed_candidate_message` * Start hooking up request/response flow * Finish hooking up request/response flow * Limit number of parallel requests in responder * Fix test compilation errors * Fix missing check for prospective parachains mode * Fix some more compile errors * clean up some review comments * clean up warnings * Async backing statement distribution: grid tests (#6673) * Add `manifest_import_returns_ok_true` test * cargo fmt * Add pending_communication_receiving_manifest_on_confirmed_candidate * Add `senders_can_provide_manifests_in_acknowledgement` test * Add a couple of tests for pending statements * Add `pending_statements_cleared_when_sending` test * Add `pending_statements_respect_remote_knowledge` test * Refactor group creation in tests * Clarify docs * Address some review comments * Make some clarifications * Fix post-merge errors * Clarify test `senders_can_provide_manifests_in_acknowledgement` * Try writing `pending_statements_are_updated_after_manifest_exchange` * Document "seconding limit" and `reject_overflowing_manifests` test * Test that seconding counts are not updated for validators on error * Fix tests * Fix manifest exchange test * Add more tests in `requests.rs` (#6707) This resolves remaining TODOs in this file. * remove outdated inventory terminology * Async backing statement distribution: `Candidates` tests (#6658) * Async Backing: Fix clippy errors in statement distribution branch (#6720) * Integrate `handle_active_leaves_update` * Integrate `share_local_statement`/`handle_backed_candidate_message` * Start hooking up request/response flow * Finish hooking up request/response flow * Limit number of parallel requests in responder * Fix test compilation errors * Fix missing check for prospective parachains mode * Fix some more compile errors * Async Backing: Fix clippy errors in statement distribution branch * Fix some more clippy lints * add tests module * fix warnings in existing tests * create basic test harness * create a test state struct * fmt * create empty cluster & grid modules for tests * some TODOs for cluster test suite * describe test-suite for grid logic * describe request test suite * fix seconding-limit bug * Remove extraneous `pub` This somehow made it into my clippy PR. * Fix some test compile warnings * Remove some unneeded `allow`s * adapt some new test helpers from Marcin * add helper for activating a gossip topology * add utility for signing statements * helpers for connecting/disconnecting peers * round out network utilities * fmt * fix bug in initializing validator-meta * fix compilation * implement first cluster test * TODOs for incoming request tests * Remove unneeded `make_committed_candidate` helper * fmt * some more tests for cluster * add a TODO about grid senders * integrate inbound req/res into test harness * polish off initial cluster test suite * keep introduce candidate request * fix tests after introduce candidate request * fmt * Add grid protocol to module docs * Fix comments * Test `backed_in_path_only: true` * Update node/network/protocol/src/lib.rs Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * Update node/network/protocol/src/request_response/mod.rs Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * Mark receiver with `vstaging` * validate grid senders based on manifest kind * fix mask_seconded/valid * fix unwanted-mask check * fix build * resolve todo on leaf mode * Unify protocol naming to vstaging * fmt, fix grid test after topology change * typo Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * address review * adjust comment, make easier to understand * Fix typo --------- Co-authored-by: Marcin S Co-authored-by: Marcin S Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> Co-authored-by: Chris Sosnin * miscellaneous fixes to make asynchronous backing work (#6791) * propagate network-protocol-staging feature * add feature to adder-collator as well * allow collation-generation of occupied cores * prospective parachains: special treatment for pending availability candidates * runtime: fetch candidates pending availability * lazily construct PVD for pending candidates * fix fallout in prospective parachains hypothetical/select_child * runtime: enact candidates when creating paras-inherent * make tests compile * test pending availability in the scope * add prospective parachains test * fix validity constraints leftovers * drop prints * Fix typos --------- Co-authored-by: Chris Sosnin Co-authored-by: Marcin S * Remove restart from test (#6840) * Async Backing: Statement Distribution Tests (#6755) * start on handling incoming * split off session info into separate map * start in on a knowledge tracker * address some grumbles * format * missed comment * some docs for direct * add note on slashing * amend * simplify 'direct' code * finish up the 'direct' logic * add a bunch of tests for the direct-in-group logic * rename 'direct' to 'cluster', begin a candidate_entry module * distill candidate_entry * start in on a statement-store module * some utilities for the statement store * rewrite 'send_statement_direct' using new tools * filter sending logic on peers which have the relay-parent in their view. * some more logic for handling incoming statements * req/res: BackedCandidatePacket -> AttestedCandidate + tweaks * add a `validated_in_group` bitfield to BackedCandidateInventory * BackedCandidateInventory -> Manifest * start in on requester module * add outgoing request for attested candidate * add a priority mechanism for requester * some request dispatch logic * add seconded mask to tagged-request * amend manifest to hold group index * handle errors and set up scaffold for response validation * validate attested candidate responses * requester -> requests * add some utilities for manipulating requests * begin integrating requester * start grid module * tiny * refactor grid topology to expose more info to subsystems * fix grid_topology test * fix overseer test * implement topology group-based view construction logic * fmt * flesh out grid slightly more * add indexed groups utility * integrate Groups into per-session info * refactor statement store to borrow Groups * implement manifest knowledge utility * add a test for topology setup * don't send to group members * test for conflicting manifests * manifest knowledge tests * fmt * rename field * garbage collection for grid tracker * routines for finding correct/incorrect advertisers * add manifest import logic * tweak naming * more tests for manifest import * add comment * rework candidates into a view-wide tracker * fmt * start writing boilerplate for grid sending * fmt * some more group boilerplate * refactor handling of topology and authority IDs * fmt * send statements directly to grid peers where possible * send to cluster only if statement belongs to cluster * improve handling of cluster statements * handle incoming statements along the grid * API for introduction of candidates into the tree * backing: use new prospective parachains API * fmt prospective parachains changes * fmt statement-dist * fix condition * get ready for tracking importable candidates * prospective parachains: add Cow logic * incomplete and complete hypothetical candidates * remove keep_if_unneeded * fmt * implement more general HypotheticalFrontier * fmt, cleanup * add a by_parent_hash index to candidate tracker * more framework for future code * utilities for getting all hypothetical candidates for frontier * track origin in statement store * fmt * requests should return peer * apply post-confirmation reckoning * flesh out import/announce/circulate logic on new statements * adjust * adjust TODO comment * fix backing tests * update statement-distribution to use new indexedvec * fmt * query hypothetical candidates * implement `note_importable_under` * extract common utility of fragment tree updates * add a helper function for getting statements unknown by backing * import fresh statements to backing * send announcements and acknowledgements over grid * provide freshly importable statements also avoid tracking backed candidates in statement distribution * do not issue requests on newly importable candidates * add TODO for later when confirming candidate * write a routine for handling backed candidate notifications * simplify grid substantially * add some test TODOs * handle confirmed candidates & grid announcements * finish implementing manifest handling, including follow up statements * send follow-up statements when acknowledging freshly backed * fmt * handle incoming acknowledgements * a little DRYing * wire up network messages to handlers * fmt * some skeleton code for peer view update handling * more peer view skeleton stuff * Fix async backing statement distribution tests (#6621) * Fix compile errors in tests * Cargo fmt * Resolve some todos in async backing statement-distribution branch (#6482) * Implement `remove_by_relay_parent` * Extract `minimum_votes` to shared primitives. * Add `can_send_statements_received_with_prejudice` test * Fix test * Update docstrings * Cargo fmt * Fix compile error * Fix compile errors in tests * Cargo fmt * Add module docs; write `test_priority_ordering` (first draft) * Fix `test_priority_ordering` * Move `insert_or_update_priority`: `Drop` -> `set_cluster_priority` * Address review comments * Remove `Entry::get_mut` * fix test compilation * add a TODO for a test * clean up a couple of TODOs * implement sending pending cluster statements * refactor utility function for sending acknowledgement and statements * mostly implement catching peers up via grid * Fix clippy error * alter grid to track all pending statements * fix more TODOs and format * tweak a TODO in requests * some logic for dispatching requests * fmt * skeleton for response receiving * Async backing statement distribution: cluster tests (#6678) * Add `pending_statements_set_when_receiving_fresh_statements` * Add `pending_statements_updated_when_sending_statements` test * fix up * fmt * update TODO * rework seconded mask in requests * change doc * change unhandledresponse not to borrow request manager * only accept responses sufficient to back * finish implementing response handling * extract statement filter to protocol crate * rework requests: use statement filter in network protocol * dispatch cluster requests correctly * rework cluster statement sending * implement request answering * fmt * only send confirmed candidate statement messages on unified relay-parent * Fix Tests In Statement Distribution Branch * Async Backing: Integrate `vstaging` of statement distribution into `lib.rs` (#6715) * Integrate `handle_active_leaves_update` * Integrate `share_local_statement`/`handle_backed_candidate_message` * Start hooking up request/response flow * Finish hooking up request/response flow * Limit number of parallel requests in responder * Fix test compilation errors * Fix missing check for prospective parachains mode * Fix some more compile errors * clean up some review comments * clean up warnings * Async backing statement distribution: grid tests (#6673) * Add `manifest_import_returns_ok_true` test * cargo fmt * Add pending_communication_receiving_manifest_on_confirmed_candidate * Add `senders_can_provide_manifests_in_acknowledgement` test * Add a couple of tests for pending statements * Add `pending_statements_cleared_when_sending` test * Add `pending_statements_respect_remote_knowledge` test * Refactor group creation in tests * Clarify docs * Address some review comments * Make some clarifications * Fix post-merge errors * Clarify test `senders_can_provide_manifests_in_acknowledgement` * Try writing `pending_statements_are_updated_after_manifest_exchange` * Document "seconding limit" and `reject_overflowing_manifests` test * Test that seconding counts are not updated for validators on error * Fix tests * Fix manifest exchange test * Add more tests in `requests.rs` (#6707) This resolves remaining TODOs in this file. * remove outdated inventory terminology * Async backing statement distribution: `Candidates` tests (#6658) * Async Backing: Fix clippy errors in statement distribution branch (#6720) * Integrate `handle_active_leaves_update` * Integrate `share_local_statement`/`handle_backed_candidate_message` * Start hooking up request/response flow * Finish hooking up request/response flow * Limit number of parallel requests in responder * Fix test compilation errors * Fix missing check for prospective parachains mode * Fix some more compile errors * Async Backing: Fix clippy errors in statement distribution branch * Fix some more clippy lints * add tests module * fix warnings in existing tests * create basic test harness * create a test state struct * fmt * create empty cluster & grid modules for tests * some TODOs for cluster test suite * describe test-suite for grid logic * describe request test suite * fix seconding-limit bug * Remove extraneous `pub` This somehow made it into my clippy PR. * Fix some test compile warnings * Remove some unneeded `allow`s * adapt some new test helpers from Marcin * add helper for activating a gossip topology * add utility for signing statements * helpers for connecting/disconnecting peers * round out network utilities * fmt * fix bug in initializing validator-meta * fix compilation * implement first cluster test * TODOs for incoming request tests * Remove unneeded `make_committed_candidate` helper * fmt * Hook up request sender * Add `valid_statement_without_prior_seconded_is_ignored` test * Fix `valid_statement_without_prior_seconded_is_ignored` test * some more tests for cluster * add a TODO about grid senders * integrate inbound req/res into test harness * polish off initial cluster test suite * keep introduce candidate request * fix tests after introduce candidate request * fmt * Add grid protocol to module docs * Remove obsolete test * Fix comments * Test `backed_in_path_only: true` * Update node/network/protocol/src/lib.rs Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * Update node/network/protocol/src/request_response/mod.rs Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * Mark receiver with `vstaging` * First draft of `ensure_seconding_limit_is_respected` test * validate grid senders based on manifest kind * fix mask_seconded/valid * fix unwanted-mask check * fix build * resolve todo on leaf mode * Unify protocol naming to vstaging * Fix `ensure_seconding_limit_is_respected` test * Start `backed_candidate_leads_to_advertisement` test * fmt, fix grid test after topology change * Send Backed notification * Finish `backed_candidate_leads_to_advertisement` test * Finish `peer_reported_for_duplicate_statements` test * Finish `received_advertisement_before_confirmation_leads_to_request` * Add `advertisements_rejected_from_incorrect_peers` test * Add `manifest_rejected_*` tests * Add `manifest_rejected_when_group_does_not_match_para` test * Add `local_node_sanity_checks_incoming_requests` test * Add `local_node_respects_statement_mask` test * Add tests where peer is reported for providing invalid signatures * Add `cluster_peer_allowed_to_send_incomplete_statements` test * Add `received_advertisement_after_backing_leads_to_acknowledgement` * Add `received_advertisement_after_confirmation_before_backing` test * peer_reported_for_advertisement_conflicting_with_confirmed_candidate * Add `peer_reported_for_not_enough_statements` test * Add `peer_reported_for_providing_statements_meant_to_be_masked_out` * Add `additional_statements_are_shared_after_manifest_exchange` * Add `grid_statements_imported_to_backing` test * Add `relay_parent_entering_peer_view_leads_to_advertisement` test * Add `advertisement_not_re_sent_when_peer_re_enters_view` test * Update node/network/statement-distribution/src/vstaging/tests/grid.rs Co-authored-by: asynchronous rob * Resolve TODOs, update test * Address unused code * Add check after every test for unhandled requests * Refactor (`make_dummy_leaf` and `handle_sent_request`) * Refactor (`make_dummy_topology`) * Minor refactor --------- Co-authored-by: Robert Habermeier Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> Co-authored-by: Chris Sosnin * Fix some clippy lints in tests * Async backing: minor fixes (#6920) * bitfield-distribution test * implicit view tests * Refactor parameters -> params * scheduler: update storage migration (#6963) * update scheduler migration * Adjust weight to account for storage read * Statement Distribution Guide Edits (#7025) * Statement distribution guide edits * Addressed Marcin's comments * Add attested candidate request retry timeouts (#6833) Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> Co-authored-by: asynchronous rob Co-authored-by: Robert Habermeier Co-authored-by: Chris Sosnin Fix async backing statement distribution tests (#6621) Resolve some todos in async backing statement-distribution branch (#6482) Fix clippy errors in statement distribution branch (#6720) * Async backing: add Prospective Parachains impl guide (#6933) Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> * Updates to Provisioner Guide for Async Backing (#7106) * Initial corrections and clarifications * Partial first draft * Finished first draft * Adding back wrongly removed test bit * fmt * Update roadmap/implementers-guide/src/node/utility/provisioner.md Co-authored-by: Marcin S. * Addressing comments * Reorganization * fmt --------- Co-authored-by: Marcin S. * fmt * Renaming Parathread Mentions (#7287) * Renaming parathreads * Renaming module to pallet * More updates * PVF: Refactor workers into separate crates, remove host dependency (#7253) * PVF: Refactor workers into separate crates, remove host dependency * Fix compile error * Remove some leftover code * Fix compile errors * Update Cargo.lock * Remove worker main.rs files I accidentally copied these from the other PR. This PR isn't intended to introduce standalone workers yet. * Address review comments * cargo fmt * Update a couple of comments * Update log targets * Update quote to 1.0.27 (#7280) Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> * pallets: implement `Default` for `GenesisConfig` in `no_std` (#7271) * pallets: implement Default for GenesisConfig in no_std This change is follow-up of: https://github.com/paritytech/substrate/pull/14108 It is a step towards: https://github.com/paritytech/substrate/issues/13334 * Cargo.lock updated * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> * cli: enable BEEFY by default on test networks (#7293) We consider BEEFY mature enough to run by default on all nodes for test networks (Rococo/Wococo/Versi). Right now, most nodes are not running it since it's opt-in using --beefy flag. Switch to an opt-out model for test networks. Replace --beefy flag from CLI with --no-beefy and have BEEFY client start by default on test networks. Signed-off-by: acatangiu * runtime: past session slashing runtime API (#6667) * runtime/vstaging: unapplied_slashes runtime API * runtime/vstaging: key_ownership_proof runtime API * runtime/ParachainHost: submit_report_dispute_lost * fix key_ownership_proof API * runtime: submit_report_dispute_lost runtime API * nits * Update node/subsystem-types/src/messages.rs Co-authored-by: Marcin S. * revert unrelated fmt changes * post merge fixes * fix compilation --------- Co-authored-by: Marcin S. * Correcting git mishap * Document usage of `gum` crate (#7294) * Document usage of gum crate * Small fix * Add some more basic info * Update node/gum/src/lib.rs Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * Update target docs --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * XCM: Fix issue with RequestUnlock (#7278) * XCM: Fix issue with RequestUnlock * Leave API changes for v4 * Fix clippy errors * Fix tests --------- Co-authored-by: parity-processbot <> * Companion for Substrate#14228 (#7295) * Companion for Substrate#14228 https://github.com/paritytech/substrate/pull/14228 * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> * Companion for #14237: Use latest sp-crates (#7300) * To revert: Update substrate branch to "lexnv/bump_sp_crates" Signed-off-by: Alexandru Vasile * Revert "To revert: Update substrate branch to "lexnv/bump_sp_crates"" This reverts commit 5f1db84eac4a226c37b7f6ce6ee19b49dc7e2008. * Update cargo lock Signed-off-by: Alexandru Vasile * Update cargo.lock Signed-off-by: Alexandru Vasile * Update cargo.lock Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile * bounded-collections bump to 0.1.7 (#7305) * bounded-collections bump to 0.1.7 Companion for: paritytech/substrate#14225 * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> * bump to quote 1.0.28 (#7306) * `RollingSessionWindow` cleanup (#7204) * Replace `RollingSessionWindow` with `RuntimeInfo` - initial commit * Fix tests in import * Fix the rest of the tests * Remove dead code * Fix todos * Simplify session caching * Comments for `SessionInfoProvider` * Separate `SessionInfoProvider` from `State` * `cache_session_info_for_head` becomes freestanding function * Remove unneeded `mut` usage * fn session_info -> fn get_session_info() to avoid name clashes. The function also tries to initialize `SessionInfoProvider` * Fix SessionInfo retrieval * Code cleanup * Don't wrap `SessionInfoProvider` in an `Option` * Remove `earliest_session()` * Remove pre-caching -> wip * Fix some tests and code cleanup * Fix all tests * Fixes in tests * Fix comments, variable names and small style changes * Fix a warning * impl From for NonZeroUsize * Fix logging for `get_session_info` - remove redundant logs and decrease log level to DEBUG * Code review feedback * Storage migration removing `COL_SESSION_WINDOW_DATA` from parachains db * Remove `col_session_data` usages * Storage migration clearing columns w/o removing them * Remove session data column usages from `approval-voting` and `dispute-coordinator` tests * Add some test cases from `RollingSessionWindow` to `dispute-coordinator` tests * Fix formatting in initialized.rs * Fix a corner case in `SessionInfo` caching for `dispute-coordinator` * Remove `RollingSessionWindow` ;( * Revert "Fix formatting in initialized.rs" This reverts commit 0f94664ec9f3a7e3737a30291195990e1e7065fc. * v2 to v3 migration drops `COL_DISPUTE_COORDINATOR_DATA` instead of clearing it * Fix `NUM_COLUMNS` in `approval-voting` * Use `columns::v3::NUM_COLUMNS` when opening db * Update node/service/src/parachains_db/upgrade.rs Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * Don't write in `COL_DISPUTE_COORDINATOR_DATA` for `test_rocksdb_migrate_2_to_3` * Fix `NUM+COLUMNS` in approval_voting * Fix formatting * Fix columns usage * Clarification comments about the different db versions --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * pallet-para-config: Remove remnant WeightInfo functions (#7308) * pallet-para-config: Remove remnant WeightInfo functions Signed-off-by: Oliver Tale-Yazdi * set_config_with_weight begone Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" runtime kusama-dev runtime_parachains::configuration --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> * XCM: PayOverXcm config (#6900) * Move XCM query functionality to trait * Fix tests * Add PayOverXcm implementation * fix the PayOverXcm trait to compile * moved doc comment out of trait implmeentation and to the trait * PayOverXCM documentation * Change documentation a bit * Added empty benchmark methods implementation and changed docs * update PayOverXCM to convert AccountIds to MultiLocations * Implement benchmarking method * Change v3 to latest * Descend origin to an asset sender (#6970) * descend origin to an asset sender * sender as tuple of dest and sender * Add more variants to the QueryResponseStatus enum * Change Beneficiary to Into<[u8; 32]> * update PayOverXcm to return concrete errors and use AccountId as sender * use polkadot-primitives for AccountId * fix dependency to use polkadot-core-primitives * force Unpaid instruction to the top of the instructions list * modify report_outcome to accept interior argument * use new_query directly for building final xcm query, instead of report_outcome * fix usage of new_query to use the XcmQueryHandler * fix usage of new_query to use the XcmQueryHandler * tiny method calling fix * xcm query handler (#7198) * drop redundant query status * rename ReportQueryStatus to OuterQueryStatus * revert rename of QueryResponseStatus * update mapping * Update xcm/xcm-builder/src/pay.rs Co-authored-by: Gavin Wood * Updates * Docs * Fix benchmarking stuff * Destination can be determined based on asset_kind * Tweaking API to minimise clones * Some repotting and docs --------- Co-authored-by: Anthony Alaribe Co-authored-by: Muharem Ismailov Co-authored-by: Anthony Alaribe Co-authored-by: Gavin Wood * Companion for #14265 (#7307) * Update Cargo.lock Signed-off-by: Alexandru Vasile * Update Cargo.lock Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: parity-processbot <> * bump serde to 1.0.163 (#7315) * bump serde to 1.0.163 * bump ci * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> * fmt * Updated fmt * Removing changes accidentally pulled from master * fix another master pull issue * Another master pull fix * fmt * Fixing implementers guide build * Revert "Merge branch 'rh-async-backing-feature-while-frozen' of https://github.com/paritytech/polkadot into brad-rename-parathread" This reverts commit bebc24af52ab61155e3fe02cb3ce66a592bce49c, reversing changes made to 1b2de662dfb11173679d6da5bd0da9d149c85547. --------- Signed-off-by: Oliver Tale-Yazdi Signed-off-by: acatangiu Signed-off-by: Alexandru Vasile Co-authored-by: Marcin S Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Adrian Catangiu Co-authored-by: ordian Co-authored-by: Marcin S. Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Co-authored-by: Francisco Aguirre Co-authored-by: Bastian Köcher Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Sam Johnson Co-authored-by: Tsvetomir Dimitrov Co-authored-by: Anthony Alaribe Co-authored-by: Muharem Ismailov Co-authored-by: Anthony Alaribe Co-authored-by: Gavin Wood * fix bitfield distribution test * approval distribution tests * fix bridge tests * update Cargo.lock * [async-backing-branch] Optimize collator-protocol validator-side request fetching (#7457) * Optimize collator-protocol validator-side request fetching * address feedback: replace tuples with structs * feedback: add doc comments * move collation types to subfolder --------- Signed-off-by: alindima * Update collation generation for asynchronous backing (#7405) * break candidate receipt construction and distribution into own function * update implementers' guide to include SubmitCollation * implement SubmitCollation for collation-generation * fmt * fix test compilation & remove unnecessary submodule * add some TODOs for a test suite. * Update roadmap/implementers-guide/src/types/overseer-protocol.md Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * add new test harness and first test * refactor to avoid requiring background sender * ensure collation gets packaged and distributed * tests for the fallback case with no hint * add parent rp-number hint tests * fmt * update uses of CollationGenerationConfig * fix remaining test * address review comments * use subsystemsender for background tasks * fmt * remove ValidationCodeHashHint and related tests --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * fix some more fallout from merge * fmt * remove staging APIs from Rococo & Westend (#7513) * send network messages on main protocol name (#7515) * misc async backing improvements for allowed ancestry blocks (#7532) * shared: fix acquire_info * backwards-compat test for prospective parachains * same relay parent is allowed * provisioner: request candidate receipt by relay parent (#7527) * return candidates hash from prospective parachains * update provisioner * update tests * guide changes * send a single message to backing * fix test * revert to old `handle_new_activations` logic in some cases (#7514) * revert to old `handle_new_activations` logic * gate sending messages on scheduled cores to max_depth >= 2 * fmt * 2->1 * Omnibus asynchronous backing bugfix PR (#7529) * fix a bug in backing * add some more logs * prospective parachains: take ancestry only up to session bounds * add test * fix zombienet tests (#7614) Signed-off-by: Andrei Sandu * fix runtime compilation * make bitfield distribution tests compile * attempt to fix zombienet disputes (#7618) * update metric name * update some metric names * avoid cycles when creating fake candidates * make undying collator more friendly to malformed parents * fix a bug in malus * fmt * clippy * add RUN_IN_CONTAINER to new ZombieNet tests (#7631) * remove duplicated migration happened because of master-merge --------- Signed-off-by: Oliver Tale-Yazdi Signed-off-by: acatangiu Signed-off-by: Alexandru Vasile Signed-off-by: alindima Signed-off-by: Andrei Sandu Co-authored-by: Chris Sosnin Co-authored-by: Parity Bot Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> Co-authored-by: Robert Klotzner Co-authored-by: Robert Klotzner Co-authored-by: Marcin S Co-authored-by: Marcin S Co-authored-by: Mattia L.V. Bradascio <28816406+bredamatt@users.noreply.github.com> Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Co-authored-by: alexgparity <115470171+alexgparity@users.noreply.github.com> Co-authored-by: BradleyOlson64 Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Adrian Catangiu Co-authored-by: ordian Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Co-authored-by: Francisco Aguirre Co-authored-by: Bastian Köcher Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Sam Johnson Co-authored-by: Tsvetomir Dimitrov Co-authored-by: Anthony Alaribe Co-authored-by: Muharem Ismailov Co-authored-by: Anthony Alaribe Co-authored-by: Gavin Wood Co-authored-by: Alin Dima --- Cargo.lock | 498 +-- Cargo.toml | 3 + cli/Cargo.toml | 1 + node/collation-generation/Cargo.toml | 2 + node/collation-generation/src/lib.rs | 399 ++- node/collation-generation/src/metrics.rs | 15 + node/collation-generation/src/tests.rs | 1019 +++--- node/core/backing/src/error.rs | 43 +- node/core/backing/src/lib.rs | 2182 ++++++++----- .../backing/src/{tests.rs => tests/mod.rs} | 757 ++++- .../src/tests/prospective_parachains.rs | 1690 ++++++++++ .../dispute-coordinator/src/scraping/tests.rs | 3 +- node/core/prospective-parachains/Cargo.toml | 29 + node/core/prospective-parachains/src/error.rs | 87 + .../src/fragment_tree.rs | 1991 ++++++++++++ node/core/prospective-parachains/src/lib.rs | 939 ++++++ .../prospective-parachains/src/metrics.rs | 52 + node/core/prospective-parachains/src/tests.rs | 1652 ++++++++++ node/core/provisioner/src/error.rs | 9 +- node/core/provisioner/src/lib.rs | 176 +- node/core/provisioner/src/tests.rs | 244 +- node/core/runtime-api/src/cache.rs | 39 + node/core/runtime-api/src/lib.rs | 30 + node/core/runtime-api/src/tests.rs | 15 + .../0001-dispute-valid-block.zndsl | 22 +- node/malus/src/variants/common.rs | 73 +- .../src/variants/suggest_garbage_candidate.rs | 15 +- node/network/approval-distribution/src/lib.rs | 303 +- .../approval-distribution/src/tests.rs | 230 +- node/network/bitfield-distribution/Cargo.toml | 1 + node/network/bitfield-distribution/src/lib.rs | 188 +- .../bitfield-distribution/src/tests.rs | 230 +- node/network/bridge/src/network.rs | 10 +- node/network/bridge/src/rx/mod.rs | 261 +- node/network/bridge/src/rx/tests.rs | 233 +- node/network/bridge/src/tx/mod.rs | 66 +- node/network/bridge/src/tx/tests.rs | 125 +- node/network/collator-protocol/Cargo.toml | 3 +- .../src/collator_side/collation.rs | 162 + .../src/collator_side/metrics.rs | 2 +- .../src/collator_side/mod.rs | 1064 ++++--- .../collator_side/{tests.rs => tests/mod.rs} | 479 ++- .../tests/prospective_parachains.rs | 575 ++++ .../src/collator_side/validators_buffer.rs | 78 +- node/network/collator-protocol/src/error.rs | 74 +- node/network/collator-protocol/src/lib.rs | 41 +- .../src/validator_side/collation.rs | 366 +++ .../src/validator_side/metrics.rs | 142 + .../src/validator_side/mod.rs | 2160 +++++++------ .../validator_side/{tests.rs => tests/mod.rs} | 453 ++- .../tests/prospective_parachains.rs | 988 ++++++ node/network/gossip-support/src/lib.rs | 8 +- node/network/protocol/Cargo.toml | 4 + node/network/protocol/src/lib.rs | 318 +- node/network/protocol/src/peer_set.rs | 47 + .../protocol/src/request_response/mod.rs | 108 +- .../protocol/src/request_response/outgoing.rs | 12 +- .../protocol/src/request_response/vstaging.rs | 80 + .../network/statement-distribution/Cargo.toml | 6 +- .../statement-distribution/src/error.rs | 35 +- .../src/legacy_v1/mod.rs | 2177 +++++++++++++ .../src/{ => legacy_v1}/requester.rs | 5 +- .../src/{ => legacy_v1}/responder.rs | 4 +- .../src/{ => legacy_v1}/tests.rs | 241 +- .../network/statement-distribution/src/lib.rs | 2284 ++------------ .../statement-distribution/src/metrics.rs | 17 +- .../src/vstaging/candidates.rs | 1298 ++++++++ .../src/vstaging/cluster.rs | 1203 +++++++ .../src/vstaging/grid.rs | 2252 +++++++++++++ .../src/vstaging/groups.rs | 70 + .../src/vstaging/mod.rs | 2810 +++++++++++++++++ .../src/vstaging/requests.rs | 1248 ++++++++ .../src/vstaging/statement_store.rs | 283 ++ .../src/vstaging/tests/cluster.rs | 1257 ++++++++ .../src/vstaging/tests/grid.rs | 2455 ++++++++++++++ .../src/vstaging/tests/mod.rs | 606 ++++ .../src/vstaging/tests/requests.rs | 1871 +++++++++++ node/overseer/src/dummy.rs | 8 +- node/overseer/src/lib.rs | 16 +- node/overseer/src/tests.rs | 24 +- node/primitives/src/disputes/mod.rs | 26 +- node/primitives/src/lib.rs | 142 +- node/service/Cargo.toml | 4 + node/service/src/lib.rs | 13 +- node/service/src/overseer.rs | 38 +- node/subsystem-types/src/messages.rs | 274 +- node/subsystem-types/src/runtime_client.rs | 46 +- .../src/backing_implicit_view.rs | 739 +++++ .../src/inclusion_emulator/mod.rs | 14 + .../src/inclusion_emulator/staging.rs | 1450 +++++++++ node/subsystem-util/src/lib.rs | 36 +- node/subsystem-util/src/runtime/mod.rs | 69 +- node/test/service/src/lib.rs | 3 +- parachain/src/primitives.rs | 3 +- .../test-parachains/adder/collator/Cargo.toml | 1 + .../adder/collator/src/main.rs | 5 +- .../undying/collator/src/lib.rs | 59 +- .../undying/collator/src/main.rs | 5 +- primitives/src/runtime_api.rs | 11 + primitives/src/v5/mod.rs | 28 +- primitives/src/v5/signed.rs | 29 +- primitives/src/vstaging/mod.rs | 85 + primitives/test-helpers/src/lib.rs | 46 +- roadmap/implementers-guide/src/SUMMARY.md | 25 +- roadmap/implementers-guide/src/glossary.md | 5 +- .../src/node/backing/candidate-backing.md | 2 +- .../node/backing/prospective-parachains.md | 158 + .../backing/statement-distribution-legacy.md | 119 + .../node/backing/statement-distribution.md | 560 +++- .../node/collators/collation-generation.md | 10 +- .../src/node/utility/provisioner.md | 144 +- .../implementers-guide/src/pvf-prechecking.md | 8 +- .../src/runtime-api/availability-cores.md | 4 +- .../implementers-guide/src/runtime/README.md | 8 +- .../src/runtime/configuration.md | 2 +- .../src/runtime/disputes.md | 2 +- roadmap/implementers-guide/src/runtime/dmp.md | 6 +- .../implementers-guide/src/runtime/hrmp.md | 2 +- .../src/runtime/inclusion.md | 24 +- .../src/runtime/initializer.md | 2 +- .../implementers-guide/src/runtime/paras.md | 57 +- .../src/runtime/scheduler.md | 76 +- .../implementers-guide/src/runtime/shared.md | 27 +- .../implementers-guide/src/types/candidate.md | 6 +- .../src/types/overseer-protocol.md | 60 +- .../implementers-guide/src/types/runtime.md | 12 +- roadmap/parachains.md | 14 +- runtime/common/src/assigned_slots/mod.rs | 24 +- runtime/common/src/integration_tests.rs | 28 +- runtime/common/src/mock.rs | 11 +- runtime/common/src/paras_registrar.rs | 66 +- runtime/common/src/paras_sudo_wrapper.rs | 18 +- runtime/common/src/slots/mod.rs | 13 +- runtime/common/src/traits.rs | 14 +- .../src/weights/runtime_parachains_paras.rs | 6 + runtime/parachains/src/configuration/tests.rs | 2 +- runtime/parachains/src/dmp.rs | 16 +- runtime/parachains/src/dmp/tests.rs | 34 +- runtime/parachains/src/hrmp.rs | 37 +- runtime/parachains/src/inclusion/mod.rs | 194 +- runtime/parachains/src/inclusion/tests.rs | 348 +- runtime/parachains/src/lib.rs | 4 +- runtime/parachains/src/paras/benchmarking.rs | 4 + runtime/parachains/src/paras/mod.rs | 92 +- runtime/parachains/src/paras/tests.rs | 44 + runtime/parachains/src/paras_inherent/mod.rs | 58 +- .../parachains/src/paras_inherent/tests.rs | 19 +- runtime/parachains/src/runtime_api_impl/v5.rs | 9 +- .../src/runtime_api_impl/vstaging.rs | 103 + runtime/parachains/src/scheduler.rs | 22 +- runtime/parachains/src/scheduler/common.rs | 4 +- runtime/parachains/src/scheduler/tests.rs | 47 +- runtime/parachains/src/shared.rs | 100 +- runtime/parachains/src/shared/tests.rs | 69 + runtime/polkadot/src/lib.rs | 1 + .../src/weights/runtime_parachains_paras.rs | 6 + runtime/rococo/src/lib.rs | 1 - .../src/weights/runtime_parachains_paras.rs | 6 + runtime/westend/src/lib.rs | 1 - .../src/weights/runtime_parachains_paras.rs | 6 + scripts/ci/gitlab/lingua.dic | 4 +- scripts/ci/gitlab/pipeline/zombienet.yml | 100 + statement-table/src/generic.rs | 95 +- statement-table/src/lib.rs | 2 +- .../001-async-backing-compatibility.toml | 34 + .../001-async-backing-compatibility.zndsl | 23 + .../002-async-backing-runtime-upgrade.toml | 54 + .../002-async-backing-runtime-upgrade.zndsl | 34 + .../003-async-backing-collator-mix.toml | 40 + .../003-async-backing-collator-mix.zndsl | 19 + zombienet_tests/async_backing/README.md | 9 + .../functional/0002-parachains-disputes.zndsl | 6 +- .../0003-parachains-garbage-candidate.zndsl | 10 +- ...004-parachains-disputes-past-session.zndsl | 6 +- zombienet_tests/misc/0001-paritydb.zndsl | 20 +- 175 files changed, 40854 insertions(+), 6434 deletions(-) rename node/core/backing/src/{tests.rs => tests/mod.rs} (65%) create mode 100644 node/core/backing/src/tests/prospective_parachains.rs create mode 100644 node/core/prospective-parachains/Cargo.toml create mode 100644 node/core/prospective-parachains/src/error.rs create mode 100644 node/core/prospective-parachains/src/fragment_tree.rs create mode 100644 node/core/prospective-parachains/src/lib.rs create mode 100644 node/core/prospective-parachains/src/metrics.rs create mode 100644 node/core/prospective-parachains/src/tests.rs create mode 100644 node/network/collator-protocol/src/collator_side/collation.rs rename node/network/collator-protocol/src/collator_side/{tests.rs => tests/mod.rs} (75%) create mode 100644 node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs create mode 100644 node/network/collator-protocol/src/validator_side/collation.rs create mode 100644 node/network/collator-protocol/src/validator_side/metrics.rs rename node/network/collator-protocol/src/validator_side/{tests.rs => tests/mod.rs} (70%) create mode 100644 node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs create mode 100644 node/network/protocol/src/request_response/vstaging.rs create mode 100644 node/network/statement-distribution/src/legacy_v1/mod.rs rename node/network/statement-distribution/src/{ => legacy_v1}/requester.rs (98%) rename node/network/statement-distribution/src/{ => legacy_v1}/responder.rs (97%) rename node/network/statement-distribution/src/{ => legacy_v1}/tests.rs (91%) create mode 100644 node/network/statement-distribution/src/vstaging/candidates.rs create mode 100644 node/network/statement-distribution/src/vstaging/cluster.rs create mode 100644 node/network/statement-distribution/src/vstaging/grid.rs create mode 100644 node/network/statement-distribution/src/vstaging/groups.rs create mode 100644 node/network/statement-distribution/src/vstaging/mod.rs create mode 100644 node/network/statement-distribution/src/vstaging/requests.rs create mode 100644 node/network/statement-distribution/src/vstaging/statement_store.rs create mode 100644 node/network/statement-distribution/src/vstaging/tests/cluster.rs create mode 100644 node/network/statement-distribution/src/vstaging/tests/grid.rs create mode 100644 node/network/statement-distribution/src/vstaging/tests/mod.rs create mode 100644 node/network/statement-distribution/src/vstaging/tests/requests.rs create mode 100644 node/subsystem-util/src/backing_implicit_view.rs create mode 100644 node/subsystem-util/src/inclusion_emulator/mod.rs create mode 100644 node/subsystem-util/src/inclusion_emulator/staging.rs create mode 100644 roadmap/implementers-guide/src/node/backing/prospective-parachains.md create mode 100644 roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md create mode 100644 zombienet_tests/async_backing/001-async-backing-compatibility.toml create mode 100644 zombienet_tests/async_backing/001-async-backing-compatibility.zndsl create mode 100644 zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml create mode 100644 zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl create mode 100644 zombienet_tests/async_backing/003-async-backing-collator-mix.toml create mode 100644 zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl create mode 100644 zombienet_tests/async_backing/README.md diff --git a/Cargo.lock b/Cargo.lock index 0cf0541fa5f7..c2f31fe36efd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -826,16 +826,28 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +[[package]] +name = "bitvec" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" +dependencies = [ + "funty 1.1.0", + "radium 0.6.2", + "tap", + "wyz 0.2.0", +] + [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty", - "radium", + "funty 2.0.0", + "radium 0.7.0", "tap", - "wyz", + "wyz 0.5.1", ] [[package]] @@ -945,7 +957,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6" dependencies = [ "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", ] @@ -2767,7 +2779,7 @@ dependencies = [ "futures-timer", "log", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "scale-info", ] @@ -2833,7 +2845,7 @@ name = "fork-tree" version = "3.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", ] [[package]] @@ -2861,7 +2873,7 @@ dependencies = [ "frame-system", "linregress", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "paste", "scale-info", "serde", @@ -2895,7 +2907,7 @@ dependencies = [ "lazy_static", "linked-hash-map", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rand 0.8.5", "rand_pcg", "sc-block-builder", @@ -2943,7 +2955,7 @@ dependencies = [ "frame-election-provider-solution-type", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-arithmetic", "sp-core", @@ -2960,7 +2972,7 @@ dependencies = [ "frame-support", "frame-system", "frame-try-runtime", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -2976,7 +2988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692" dependencies = [ "cfg-if", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", ] @@ -2991,7 +3003,7 @@ dependencies = [ "indicatif", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "serde", "sp-core", "sp-io", @@ -3018,7 +3030,7 @@ dependencies = [ "k256", "log", "macro_magic", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "paste", "scale-info", "serde", @@ -3091,7 +3103,7 @@ dependencies = [ "frame-support", "frame-support-test-pallet", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "pretty_assertions", "rustversion", "scale-info", @@ -3115,7 +3127,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-runtime", @@ -3129,7 +3141,7 @@ dependencies = [ "cfg-if", "frame-support", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-core", @@ -3148,7 +3160,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-runtime", @@ -3160,7 +3172,7 @@ name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-api", ] @@ -3170,7 +3182,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-api", "sp-runtime", "sp-std", @@ -3202,6 +3214,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "funty" version = "2.0.0" @@ -3857,7 +3875,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", ] [[package]] @@ -4255,7 +4273,7 @@ dependencies = [ name = "kusama-runtime" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -4317,7 +4335,7 @@ dependencies = [ "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -5350,7 +5368,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "futures", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sc-offchain", "sp-api", @@ -5369,7 +5387,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "anyhow", "jsonrpsee", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "serde", "sp-api", "sp-blockchain", @@ -5907,7 +5925,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-runtime", @@ -5922,7 +5940,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-application-crypto", "sp-authority-discovery", @@ -5938,7 +5956,7 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-std", @@ -5956,7 +5974,7 @@ dependencies = [ "pallet-authorship", "pallet-session", "pallet-timestamp", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-application-crypto", "sp-consensus-babe", @@ -5981,7 +5999,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6018,7 +6036,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-std", @@ -6033,7 +6051,7 @@ dependencies = [ "frame-system", "pallet-authorship", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-consensus-beefy", @@ -6056,7 +6074,7 @@ dependencies = [ "pallet-beefy", "pallet-mmr", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-api", @@ -6077,7 +6095,7 @@ dependencies = [ "frame-system", "log", "pallet-treasury", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6096,7 +6114,7 @@ dependencies = [ "log", "pallet-bounties", "pallet-treasury", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6113,7 +6131,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6130,7 +6148,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-io", @@ -6147,7 +6165,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-core", @@ -6167,7 +6185,7 @@ dependencies = [ "frame-system", "log", "pallet-election-provider-support-benchmarking", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rand 0.8.5", "scale-info", "sp-arithmetic", @@ -6187,7 +6205,7 @@ dependencies = [ "frame-benchmarking", "frame-election-provider-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-npos-elections", "sp-runtime", ] @@ -6201,7 +6219,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6222,7 +6240,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6241,7 +6259,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-application-crypto", "sp-consensus-grandpa", @@ -6262,7 +6280,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6279,7 +6297,7 @@ dependencies = [ "frame-system", "log", "pallet-authorship", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-application-crypto", "sp-core", @@ -6297,7 +6315,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6315,7 +6333,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6332,7 +6350,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-arithmetic", "sp-core", @@ -6350,7 +6368,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6368,7 +6386,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6383,7 +6401,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-arithmetic", "sp-core", @@ -6400,7 +6418,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6422,7 +6440,7 @@ dependencies = [ "pallet-bags-list", "pallet-nomination-pools", "pallet-staking", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-runtime-interface", @@ -6436,7 +6454,7 @@ version = "1.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "pallet-nomination-pools", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-api", "sp-std", ] @@ -6450,7 +6468,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-runtime", @@ -6475,7 +6493,7 @@ dependencies = [ "pallet-offences", "pallet-session", "pallet-staking", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-staking", @@ -6491,7 +6509,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6507,7 +6525,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6523,7 +6541,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-arithmetic", "sp-core", @@ -6540,7 +6558,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6557,7 +6575,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-arithmetic", @@ -6576,7 +6594,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6594,7 +6612,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-timestamp", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6630,7 +6648,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rand_chacha 0.2.2", "scale-info", "sp-arithmetic", @@ -6651,7 +6669,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rand_chacha 0.2.2", "scale-info", "serde", @@ -6687,7 +6705,7 @@ name = "pallet-staking-runtime-api" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-api", ] @@ -6700,7 +6718,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6716,7 +6734,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-io", "sp-runtime", @@ -6732,7 +6750,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-inherents", "sp-io", @@ -6751,7 +6769,7 @@ dependencies = [ "frame-system", "log", "pallet-treasury", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-core", @@ -6767,7 +6785,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-core", @@ -6783,7 +6801,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-api", "sp-blockchain", "sp-core", @@ -6798,7 +6816,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "pallet-transaction-payment", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-api", "sp-runtime", "sp-weights", @@ -6814,7 +6832,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-runtime", @@ -6830,7 +6848,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-std", @@ -6844,7 +6862,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-io", @@ -6861,7 +6879,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-std", @@ -6875,7 +6893,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-api", "sp-runtime", @@ -6892,7 +6910,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-runtime-parachains", "scale-info", @@ -6917,7 +6935,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "polkadot-runtime-common", "scale-info", @@ -6951,6 +6969,19 @@ dependencies = [ "snap", ] +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec 0.7.4", + "bitvec 0.20.4", + "byte-slice-cast", + "impl-trait-for-tuples", + "serde", +] + [[package]] name = "parity-scale-codec" version = "3.6.4" @@ -6958,7 +6989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" dependencies = [ "arrayvec 0.7.4", - "bitvec", + "bitvec 1.0.1", "byte-slice-cast", "bytes", "impl-trait-for-tuples", @@ -7280,8 +7311,9 @@ dependencies = [ name = "polkadot-availability-bitfield-distribution" version = "0.9.43" dependencies = [ + "always-assert", "assert_matches", - "bitvec", + "bitvec 1.0.1", "env_logger 0.9.3", "futures", "futures-timer", @@ -7312,7 +7344,7 @@ dependencies = [ "futures", "futures-timer", "lru 0.11.0", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7342,7 +7374,7 @@ dependencies = [ "futures-timer", "log", "lru 0.11.0", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7392,15 +7424,14 @@ dependencies = [ name = "polkadot-collator-protocol" version = "0.9.43" dependencies = [ - "always-assert", "assert_matches", - "bitvec", + "bitvec 1.0.1", "env_logger 0.9.3", "fatality", "futures", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7408,12 +7439,14 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "sc-keystore", "sc-network", "sp-core", "sp-keyring", "sp-keystore", "sp-runtime", "thiserror", + "tokio-util", "tracing-gum", ] @@ -7421,7 +7454,7 @@ dependencies = [ name = "polkadot-core-primitives" version = "0.9.43" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-runtime", @@ -7442,7 +7475,7 @@ dependencies = [ "indexmap 1.9.3", "lazy_static", "lru 0.11.0", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7466,7 +7499,7 @@ name = "polkadot-erasure-coding" version = "0.9.43" dependencies = [ "criterion", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-primitives", "polkadot-primitives", "reed-solomon-novelpoly", @@ -7514,7 +7547,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "polkadot-node-metrics", "polkadot-node-network-protocol", @@ -7536,8 +7569,9 @@ dependencies = [ name = "polkadot-node-collation-generation" version = "0.9.43" dependencies = [ + "assert_matches", "futures", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7546,6 +7580,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "sp-core", + "sp-keyring", "sp-maybe-compressed-blob", "thiserror", "tracing-gum", @@ -7557,7 +7592,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "async-trait", - "bitvec", + "bitvec 1.0.1", "derive_more", "futures", "futures-timer", @@ -7565,7 +7600,7 @@ dependencies = [ "kvdb-memorydb", "lru 0.11.0", "merlin 2.0.1", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -7595,14 +7630,14 @@ name = "polkadot-node-core-av-store" version = "0.9.43" dependencies = [ "assert_matches", - "bitvec", + "bitvec 1.0.1", "env_logger 0.9.3", "futures", "futures-timer", "kvdb", "kvdb-memorydb", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "polkadot-erasure-coding", "polkadot-node-jaeger", @@ -7625,7 +7660,7 @@ name = "polkadot-node-core-backing" version = "0.9.43" dependencies = [ "assert_matches", - "bitvec", + "bitvec 1.0.1", "fatality", "futures", "polkadot-erasure-coding", @@ -7670,7 +7705,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-core-pvf", "polkadot-node-metrics", "polkadot-node-primitives", @@ -7693,7 +7728,7 @@ version = "0.9.43" dependencies = [ "futures", "maplit", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-metrics", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7715,7 +7750,7 @@ dependencies = [ "futures-timer", "kvdb", "kvdb-memorydb", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7738,7 +7773,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "lru 0.11.0", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -7771,11 +7806,36 @@ dependencies = [ "tracing-gum", ] +[[package]] +name = "polkadot-node-core-prospective-parachains" +version = "0.9.16" +dependencies = [ + "assert_matches", + "bitvec 1.0.1", + "fatality", + "futures", + "parity-scale-codec 2.3.1", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-types", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "polkadot-primitives-test-helpers", + "sc-keystore", + "sp-application-crypto", + "sp-core", + "sp-keyring", + "sp-keystore", + "thiserror", + "tracing-gum", +] + [[package]] name = "polkadot-node-core-provisioner" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "fatality", "futures", "futures-timer", @@ -7801,7 +7861,7 @@ dependencies = [ "futures-timer", "hex-literal 0.3.4", "libc", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "pin-project", "polkadot-core-primitives", "polkadot-node-core-pvf", @@ -7858,7 +7918,7 @@ dependencies = [ "futures", "landlock", "libc", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-primitives", "sc-executor", @@ -7879,7 +7939,7 @@ version = "0.9.43" dependencies = [ "cpu-time", "futures", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-core-pvf-common", "polkadot-parachain", "polkadot-primitives", @@ -7898,7 +7958,7 @@ version = "0.9.43" dependencies = [ "futures", "libc", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-core-pvf-common", "polkadot-parachain", "polkadot-primitives", @@ -7942,7 +8002,7 @@ dependencies = [ "lazy_static", "log", "mick-jaeger", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-primitives", @@ -7962,7 +8022,7 @@ dependencies = [ "futures-timer", "hyper", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "polkadot-test-service", "prioritized-metered-channel", @@ -7984,11 +8044,12 @@ version = "0.9.43" dependencies = [ "async-channel", "async-trait", + "bitvec 1.0.1", "derive_more", "fatality", "futures", "hex", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", @@ -8007,7 +8068,7 @@ version = "0.9.43" dependencies = [ "bounded-vec", "futures", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-erasure-coding", "polkadot-parachain", "polkadot-primitives", @@ -8092,7 +8153,7 @@ dependencies = [ "log", "lru 0.11.0", "parity-db", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.11.2", "pin-project", "polkadot-node-jaeger", @@ -8147,7 +8208,7 @@ dependencies = [ "bounded-collections", "derive_more", "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-core-primitives", "scale-info", "serde", @@ -8177,9 +8238,9 @@ dependencies = [ name = "polkadot-primitives" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "hex-literal 0.4.1", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-core-primitives", "polkadot-parachain", "scale-info", @@ -8245,7 +8306,7 @@ dependencies = [ name = "polkadot-runtime" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -8302,7 +8363,7 @@ dependencies = [ "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", @@ -8348,7 +8409,7 @@ dependencies = [ name = "polkadot-runtime-common" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -8370,7 +8431,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-parachains", @@ -8414,7 +8475,7 @@ version = "0.9.43" dependencies = [ "bs58", "frame-benchmarking", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "sp-std", "sp-tracing", @@ -8426,7 +8487,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "bitflags 1.3.2", - "bitvec", + "bitvec 1.0.1", "derive_more", "frame-benchmarking", "frame-support", @@ -8444,7 +8505,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "pallet-vesting", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-primitives", "polkadot-primitives-test-helpers", @@ -8502,7 +8563,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-db", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -8522,6 +8583,7 @@ dependencies = [ "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", + "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", @@ -8607,18 +8669,22 @@ version = "0.9.43" dependencies = [ "arrayvec 0.5.2", "assert_matches", + "async-channel", + "bitvec 1.0.1", "fatality", "futures", "futures-timer", "indexmap 1.9.3", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rand_chacha 0.3.1", "sc-keystore", "sc-network", "sp-application-crypto", @@ -8636,7 +8702,7 @@ dependencies = [ name = "polkadot-statement-table" version = "0.9.43" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-primitives", "sp-core", ] @@ -8647,7 +8713,7 @@ version = "0.9.43" dependencies = [ "frame-benchmarking", "futures", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-node-subsystem", "polkadot-primitives", "polkadot-test-runtime", @@ -8705,7 +8771,7 @@ dependencies = [ name = "polkadot-test-runtime" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "frame-election-provider-support", "frame-executive", "frame-support", @@ -8729,7 +8795,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-vesting", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -9282,6 +9348,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + [[package]] name = "radium" version = "0.7.0" @@ -9728,7 +9800,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -10051,7 +10123,7 @@ dependencies = [ "libp2p", "log", "multihash", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "prost", "prost-build", "rand 0.8.5", @@ -10075,7 +10147,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -10095,7 +10167,7 @@ name = "sc-block-builder" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sp-api", "sp-block-builder", @@ -10148,7 +10220,7 @@ dependencies = [ "libp2p-identity", "log", "names 0.13.0", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rand 0.8.5", "regex", "rpassword", @@ -10182,7 +10254,7 @@ dependencies = [ "fnv", "futures", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-executor", "sc-transaction-pool-api", @@ -10212,7 +10284,7 @@ dependencies = [ "linked-hash-map", "log", "parity-db", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-client-api", "sc-state-db", @@ -10263,7 +10335,7 @@ dependencies = [ "num-bigint", "num-rational", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-client-api", "sc-consensus", @@ -10320,7 +10392,7 @@ dependencies = [ "fnv", "futures", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-client-api", "sc-consensus", @@ -10351,7 +10423,7 @@ dependencies = [ "futures", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-consensus-beefy", "sc-rpc", @@ -10368,7 +10440,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "fork-tree", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sc-consensus", "sp-blockchain", @@ -10389,7 +10461,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "rand 0.8.5", "sc-block-builder", @@ -10425,7 +10497,7 @@ dependencies = [ "futures", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sc-consensus-grandpa", "sc-rpc", @@ -10445,7 +10517,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sc-consensus", "sc-telemetry", @@ -10464,7 +10536,7 @@ name = "sc-executor" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-executor-common", "sc-executor-wasmtime", @@ -10559,7 +10631,7 @@ dependencies = [ "linked_hash_set", "log", "mockall", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "partial_sort", "pin-project", @@ -10610,7 +10682,7 @@ dependencies = [ "bitflags 1.3.2", "futures", "libp2p-identity", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "prost-build", "sc-consensus", "sp-consensus", @@ -10646,7 +10718,7 @@ dependencies = [ "futures", "libp2p-identity", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "prost", "prost-build", "sc-client-api", @@ -10671,7 +10743,7 @@ dependencies = [ "libp2p", "log", "mockall", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "prost", "prost-build", "sc-client-api", @@ -10700,7 +10772,7 @@ dependencies = [ "futures", "libp2p", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-network", "sc-network-common", "sc-utils", @@ -10725,7 +10797,7 @@ dependencies = [ "log", "num_cpus", "once_cell", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "rand 0.8.5", "sc-client-api", @@ -10760,7 +10832,7 @@ dependencies = [ "futures", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-block-builder", "sc-chain-spec", @@ -10789,7 +10861,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-chain-spec", "sc-transaction-pool-api", "scale-info", @@ -10828,7 +10900,7 @@ dependencies = [ "hex", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-chain-spec", "sc-client-api", @@ -10857,7 +10929,7 @@ dependencies = [ "futures-timer", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "pin-project", "rand 0.8.5", @@ -10915,7 +10987,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sp-core", ] @@ -10940,7 +11012,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-chain-spec", "sc-client-api", "sc-consensus-babe", @@ -11041,7 +11113,7 @@ dependencies = [ "futures-timer", "linked-hash-map", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sc-client-api", "sc-transaction-pool-api", @@ -11065,7 +11137,7 @@ dependencies = [ "async-trait", "futures", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "serde", "sp-blockchain", "sp-core", @@ -11094,10 +11166,10 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ - "bitvec", + "bitvec 1.0.1", "cfg-if", "derive_more", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info-derive", "serde", ] @@ -11576,7 +11648,7 @@ name = "slot-range-helper" version = "0.9.43" dependencies = [ "enumn", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "paste", "sp-runtime", "sp-std", @@ -11664,7 +11736,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "hash-db", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-api-proc-macro", "sp-core", @@ -11697,7 +11769,7 @@ name = "sp-application-crypto" version = "23.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-core", @@ -11712,7 +11784,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "integer-sqrt", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-std", @@ -11724,7 +11796,7 @@ name = "sp-authority-discovery" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-api", "sp-application-crypto", @@ -11750,7 +11822,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "futures", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "schnellru", "sp-api", @@ -11782,7 +11854,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-api", "sp-application-crypto", @@ -11799,7 +11871,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-api", @@ -11818,7 +11890,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "lazy_static", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-api", @@ -11838,7 +11910,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "finality-grandpa", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-api", @@ -11854,7 +11926,7 @@ name = "sp-consensus-slots" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-std", @@ -11883,7 +11955,7 @@ dependencies = [ "libsecp256k1", "log", "merlin 2.0.1", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "paste", "primitive-types", @@ -11956,7 +12028,7 @@ version = "0.19.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "environmental", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-std", "sp-storage", ] @@ -11979,7 +12051,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "async-trait", "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-runtime", "sp-std", @@ -11996,7 +12068,7 @@ dependencies = [ "ed25519-dalek", "libsecp256k1", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rustversion", "secp256k1", "sp-core", @@ -12027,7 +12099,7 @@ name = "sp-keystore" version = "0.27.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "sp-core", "sp-externalities", @@ -12049,7 +12121,7 @@ version = "0.1.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "frame-metadata", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-std", ] @@ -12061,7 +12133,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "ckb-merkle-mountain-range", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-api", @@ -12077,7 +12149,7 @@ name = "sp-npos-elections" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-arithmetic", @@ -12125,7 +12197,7 @@ dependencies = [ "hash256-std-hasher", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "paste", "rand 0.8.5", "scale-info", @@ -12145,7 +12217,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "bytes", "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "primitive-types", "sp-externalities", "sp-runtime-interface-proc-macro", @@ -12173,7 +12245,7 @@ name = "sp-session" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-api", "sp-core", @@ -12189,7 +12261,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-core", @@ -12204,7 +12276,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029 dependencies = [ "hash-db", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "rand 0.8.5", "smallvec", @@ -12227,7 +12299,7 @@ dependencies = [ "curve25519-dalek 3.2.0", "ed25519-dalek", "hkdf", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "rand 0.8.5", "scale-info", "sha2 0.10.7", @@ -12253,7 +12325,7 @@ version = "13.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "impl-serde", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "ref-cast", "serde", "sp-debug-derive", @@ -12266,7 +12338,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-inherents", "sp-runtime", "sp-std", @@ -12278,7 +12350,7 @@ name = "sp-tracing" version = "10.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-std", "tracing", "tracing-core", @@ -12300,7 +12372,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "async-trait", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "sp-core", "sp-inherents", @@ -12320,7 +12392,7 @@ dependencies = [ "lazy_static", "memory-db", "nohash-hasher", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parking_lot 0.12.1", "scale-info", "schnellru", @@ -12338,7 +12410,7 @@ version = "22.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "impl-serde", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "parity-wasm", "scale-info", "serde", @@ -12354,7 +12426,7 @@ name = "sp-version-proc-macro" version = "8.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "proc-macro2", "quote", "syn 2.0.28", @@ -12368,7 +12440,7 @@ dependencies = [ "anyhow", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-std", "wasmtime", ] @@ -12378,7 +12450,7 @@ name = "sp-weights" version = "20.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "smallvec", @@ -12465,7 +12537,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-staking", "pallet-transaction-payment", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "paste", "polkadot-core-primitives", "polkadot-runtime", @@ -12628,7 +12700,7 @@ dependencies = [ "futures", "jsonrpsee", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-rpc-api", "sc-transaction-pool-api", "sp-api", @@ -12669,7 +12741,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" dependencies = [ "jsonrpsee", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sc-rpc-api", "serde", @@ -12688,7 +12760,7 @@ dependencies = [ "array-bytes", "async-trait", "futures", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-client-api", "sc-client-db", "sc-consensus", @@ -12951,7 +13023,7 @@ name = "test-parachain-adder" version = "0.9.43" dependencies = [ "dlmalloc", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "sp-io", "sp-std", @@ -12967,7 +13039,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -13000,7 +13072,7 @@ version = "0.9.43" dependencies = [ "dlmalloc", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "sp-io", "sp-std", @@ -13016,7 +13088,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -13039,7 +13111,7 @@ dependencies = [ name = "test-parachains" version = "0.9.43" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-core", "test-parachain-adder", "test-parachain-halt", @@ -13646,7 +13718,7 @@ dependencies = [ "frame-try-runtime", "hex", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sc-cli", "sc-executor", "serde", @@ -14580,7 +14652,7 @@ dependencies = [ name = "westend-runtime" version = "0.9.43" dependencies = [ - "bitvec", + "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -14635,7 +14707,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -14957,6 +15029,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "wyz" version = "0.5.1" @@ -15035,7 +15113,7 @@ dependencies = [ "hex-literal 0.4.1", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "scale-info", "serde", "sp-io", @@ -15055,7 +15133,7 @@ dependencies = [ "pallet-balances", "pallet-transaction-payment", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-parachain", "polkadot-runtime-parachains", "polkadot-test-runtime", @@ -15079,7 +15157,7 @@ dependencies = [ "frame-support", "impl-trait-for-tuples", "log", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "sp-arithmetic", "sp-core", "sp-io", @@ -15124,7 +15202,7 @@ name = "xcm-simulator" version = "0.9.43" dependencies = [ "frame-support", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "paste", "polkadot-core-primitives", "polkadot-parachain", @@ -15147,7 +15225,7 @@ dependencies = [ "pallet-message-queue", "pallet-uniques", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -15174,7 +15252,7 @@ dependencies = [ "pallet-balances", "pallet-message-queue", "pallet-xcm", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -15244,7 +15322,7 @@ version = "0.9.43" dependencies = [ "futures-util", "lazy_static", - "parity-scale-codec", + "parity-scale-codec 3.6.4", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index dc42123a9f20..c1b94357c3cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ members = [ "node/core/chain-selection", "node/core/dispute-coordinator", "node/core/parachains-inherent", + "node/core/prospective-parachains", "node/core/provisioner", "node/core/pvf", "node/core/pvf/common", @@ -226,6 +227,8 @@ fast-runtime = [ "polkadot-cli/fast-runtime" ] runtime-metrics = [ "polkadot-cli/runtime-metrics" ] pyroscope = ["polkadot-cli/pyroscope"] jemalloc-allocator = ["polkadot-node-core-pvf-prepare-worker/jemalloc-allocator", "polkadot-overseer/jemalloc-allocator"] +network-protocol-staging = ["polkadot-cli/network-protocol-staging"] + # Enables timeout-based tests supposed to be run only in CI environment as they may be flaky # when run locally depending on system load ci-only-tests = ["polkadot-node-core-pvf/ci-only-tests"] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index df1a22d8c18d..9846bc4cf66e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -75,3 +75,4 @@ rococo-native = ["service/rococo-native"] malus = ["full-node", "service/malus"] runtime-metrics = ["service/runtime-metrics", "polkadot-node-metrics/runtime-metrics"] +network-protocol-staging = ["service/network-protocol-staging"] diff --git a/node/collation-generation/Cargo.toml b/node/collation-generation/Cargo.toml index d48167af3902..60c165784673 100644 --- a/node/collation-generation/Cargo.toml +++ b/node/collation-generation/Cargo.toml @@ -21,3 +21,5 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } +assert_matches = "1.4.0" +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/node/collation-generation/src/lib.rs b/node/collation-generation/src/lib.rs index 8726ebf44c71..27779f3d1acb 100644 --- a/node/collation-generation/src/lib.rs +++ b/node/collation-generation/src/lib.rs @@ -31,21 +31,25 @@ #![deny(missing_docs)] -use futures::{channel::mpsc, future::FutureExt, join, select, sink::SinkExt, stream::StreamExt}; +use futures::{channel::oneshot, future::FutureExt, join, select}; use parity_scale_codec::Encode; -use polkadot_node_primitives::{AvailableData, CollationGenerationConfig, PoV}; +use polkadot_node_primitives::{ + AvailableData, Collation, CollationGenerationConfig, CollationSecondedSignal, PoV, + SubmitCollationParams, +}; use polkadot_node_subsystem::{ messages::{CollationGenerationMessage, CollatorProtocolMessage}, - overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, SpawnedSubsystem, SubsystemContext, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{ - request_availability_cores, request_persisted_validation_data, request_validation_code, - request_validation_code_hash, request_validators, + request_availability_cores, request_persisted_validation_data, + request_staging_async_backing_params, request_validation_code, request_validation_code_hash, + request_validators, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, - CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, + CollatorPair, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, ValidationCodeHash, }; use sp_core::crypto::Pair; @@ -86,26 +90,13 @@ impl CollationGenerationSubsystem { /// If `err_tx` is not `None`, errors are forwarded onto that channel as they occur. /// Otherwise, most are logged and then discarded. async fn run(mut self, mut ctx: Context) { - // when we activate new leaves, we spawn a bunch of sub-tasks, each of which is - // expected to generate precisely one message. We don't want to block the main loop - // at any point waiting for them all, so instead, we create a channel on which they can - // send those messages. We can then just monitor the channel and forward messages on it - // to the overseer here, via the context. - let (sender, receiver) = mpsc::channel(0); - - let mut receiver = receiver.fuse(); loop { select! { incoming = ctx.recv().fuse() => { - if self.handle_incoming::(incoming, &mut ctx, &sender).await { + if self.handle_incoming::(incoming, &mut ctx).await { break; } }, - msg = receiver.next() => { - if let Some(msg) = msg { - ctx.send_message(msg).await; - } - }, } } } @@ -119,7 +110,6 @@ impl CollationGenerationSubsystem { &mut self, incoming: SubsystemResult::Message>>, ctx: &mut Context, - sender: &mpsc::Sender, ) -> bool { match incoming { Ok(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { @@ -134,7 +124,6 @@ impl CollationGenerationSubsystem { activated.into_iter().map(|v| v.hash), ctx, metrics, - sender, ) .await { @@ -155,6 +144,21 @@ impl CollationGenerationSubsystem { } false }, + Ok(FromOrchestra::Communication { + msg: CollationGenerationMessage::SubmitCollation(params), + }) => { + if let Some(config) = &self.config { + if let Err(err) = + handle_submit_collation(params, config, ctx, &self.metrics).await + { + gum::error!(target: LOG_TARGET, ?err, "Failed to submit collation"); + } + } else { + gum::error!(target: LOG_TARGET, "Collation submitted before initialization"); + } + + false + }, Ok(FromOrchestra::Signal(OverseerSignal::BlockFinalized(..))) => false, Err(err) => { gum::error!( @@ -188,23 +192,28 @@ async fn handle_new_activations( activated: impl IntoIterator, ctx: &mut Context, metrics: Metrics, - sender: &mpsc::Sender, ) -> crate::error::Result<()> { // follow the procedure from the guide: // https://paritytech.github.io/polkadot/book/node/collators/collation-generation.html + if config.collator.is_none() { + return Ok(()) + } + let _overall_timer = metrics.time_new_activations(); for relay_parent in activated { let _relay_parent_timer = metrics.time_new_activations_relay_parent(); - let (availability_cores, validators) = join!( + let (availability_cores, validators, async_backing_params) = join!( request_availability_cores(relay_parent, ctx.sender()).await, request_validators(relay_parent, ctx.sender()).await, + request_staging_async_backing_params(relay_parent, ctx.sender()).await, ); let availability_cores = availability_cores??; let n_validators = validators??.len(); + let async_backing_params = async_backing_params?.ok(); for (core_idx, core) in availability_cores.into_iter().enumerate() { let _availability_core_timer = metrics.time_new_activations_availability_core(); @@ -212,15 +221,30 @@ async fn handle_new_activations( let (scheduled_core, assumption) = match core { CoreState::Scheduled(scheduled_core) => (scheduled_core, OccupiedCoreAssumption::Free), - CoreState::Occupied(_occupied_core) => { - // TODO: https://github.com/paritytech/polkadot/issues/1573 - gum::trace!( - target: LOG_TARGET, - core_idx = %core_idx, - relay_parent = ?relay_parent, - "core is occupied. Keep going.", - ); - continue + CoreState::Occupied(occupied_core) => match async_backing_params { + Some(params) if params.max_candidate_depth >= 1 => { + // maximum candidate depth when building on top of a block + // pending availability is necessarily 1 - the depth of the + // pending block is 0 so the child has depth 1. + + // TODO [now]: this assumes that next up == current. + // in practice we should only set `OccupiedCoreAssumption::Included` + // when the candidate occupying the core is also of the same para. + if let Some(scheduled) = occupied_core.next_up_on_available { + (scheduled, OccupiedCoreAssumption::Included) + } else { + continue + } + }, + _ => { + gum::trace!( + target: LOG_TARGET, + core_idx = %core_idx, + relay_parent = ?relay_parent, + "core is occupied. Keep going.", + ); + continue + }, }, CoreState::Free => { gum::trace!( @@ -271,7 +295,7 @@ async fn handle_new_activations( }, }; - let validation_code_hash = match obtain_current_validation_code_hash( + let validation_code_hash = match obtain_validation_code_hash_with_assumption( relay_parent, scheduled_core.para_id, assumption, @@ -294,15 +318,18 @@ async fn handle_new_activations( }; let task_config = config.clone(); - let mut task_sender = sender.clone(); let metrics = metrics.clone(); + let mut task_sender = ctx.sender().clone(); ctx.spawn( "collation-builder", Box::pin(async move { - let persisted_validation_data_hash = validation_data.hash(); + let collator_fn = match task_config.collator.as_ref() { + Some(x) => x, + None => return, + }; let (collation, result_sender) = - match (task_config.collator)(relay_parent, &validation_data).await { + match collator_fn(relay_parent, &validation_data).await { Some(collation) => collation.into_inner(), None => { gum::debug!( @@ -314,104 +341,21 @@ async fn handle_new_activations( }, }; - // Apply compression to the block data. - let pov = { - let pov = collation.proof_of_validity.into_compressed(); - let encoded_size = pov.encoded_size(); - - // As long as `POV_BOMB_LIMIT` is at least `max_pov_size`, this ensures - // that honest collators never produce a PoV which is uncompressed. - // - // As such, honest collators never produce an uncompressed PoV which starts - // with a compression magic number, which would lead validators to reject - // the collation. - if encoded_size > validation_data.max_pov_size as usize { - gum::debug!( - target: LOG_TARGET, - para_id = %scheduled_core.para_id, - size = encoded_size, - max_size = validation_data.max_pov_size, - "PoV exceeded maximum size" - ); - - return - } - - pov - }; - - let pov_hash = pov.hash(); - - let signature_payload = collator_signature_payload( - &relay_parent, - &scheduled_core.para_id, - &persisted_validation_data_hash, - &pov_hash, - &validation_code_hash, - ); - - let erasure_root = - match erasure_root(n_validators, validation_data, pov.clone()) { - Ok(erasure_root) => erasure_root, - Err(err) => { - gum::error!( - target: LOG_TARGET, - para_id = %scheduled_core.para_id, - err = ?err, - "failed to calculate erasure root", - ); - return - }, - }; - - let commitments = CandidateCommitments { - upward_messages: collation.upward_messages, - horizontal_messages: collation.horizontal_messages, - new_validation_code: collation.new_validation_code, - head_data: collation.head_data, - processed_downward_messages: collation.processed_downward_messages, - hrmp_watermark: collation.hrmp_watermark, - }; - - let ccr = CandidateReceipt { - commitments_hash: commitments.hash(), - descriptor: CandidateDescriptor { - signature: task_config.key.sign(&signature_payload), + construct_and_distribute_receipt( + PreparedCollation { + collation, para_id: scheduled_core.para_id, relay_parent, - collator: task_config.key.public(), - persisted_validation_data_hash, - pov_hash, - erasure_root, - para_head: commitments.head_data.hash(), + validation_data, validation_code_hash, + n_validators, }, - }; - - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?ccr.hash(), - ?pov_hash, - ?relay_parent, - para_id = %scheduled_core.para_id, - "candidate is generated", - ); - metrics.on_collation_generated(); - - if let Err(err) = task_sender - .send( - CollatorProtocolMessage::DistributeCollation(ccr, pov, result_sender) - .into(), - ) - .await - { - gum::warn!( - target: LOG_TARGET, - para_id = %scheduled_core.para_id, - err = ?err, - "failed to send collation result", - ); - } + task_config.key.clone(), + &mut task_sender, + result_sender, + &metrics, + ) + .await; }), )?; } @@ -420,14 +364,199 @@ async fn handle_new_activations( Ok(()) } -async fn obtain_current_validation_code_hash( +#[overseer::contextbounds(CollationGeneration, prefix = self::overseer)] +async fn handle_submit_collation( + params: SubmitCollationParams, + config: &CollationGenerationConfig, + ctx: &mut Context, + metrics: &Metrics, +) -> crate::error::Result<()> { + let _timer = metrics.time_submit_collation(); + + let SubmitCollationParams { + relay_parent, + collation, + parent_head, + validation_code_hash, + result_sender, + } = params; + + let validators = request_validators(relay_parent, ctx.sender()).await.await??; + let n_validators = validators.len(); + + // We need to swap the parent-head data, but all other fields here will be correct. + let mut validation_data = match request_persisted_validation_data( + relay_parent, + config.para_id, + OccupiedCoreAssumption::TimedOut, + ctx.sender(), + ) + .await + .await?? + { + Some(v) => v, + None => { + gum::debug!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + our_para = %config.para_id, + "No validation data for para - does it exist at this relay-parent?", + ); + return Ok(()) + }, + }; + + validation_data.parent_head = parent_head; + + let collation = PreparedCollation { + collation, + relay_parent, + para_id: config.para_id, + validation_data, + validation_code_hash, + n_validators, + }; + + construct_and_distribute_receipt( + collation, + config.key.clone(), + ctx.sender(), + result_sender, + metrics, + ) + .await; + + Ok(()) +} + +struct PreparedCollation { + collation: Collation, + para_id: ParaId, + relay_parent: Hash, + validation_data: PersistedValidationData, + validation_code_hash: ValidationCodeHash, + n_validators: usize, +} + +/// Takes a prepared collation, along with its context, and produces a candidate receipt +/// which is distributed to validators. +async fn construct_and_distribute_receipt( + collation: PreparedCollation, + key: CollatorPair, + sender: &mut impl overseer::CollationGenerationSenderTrait, + result_sender: Option>, + metrics: &Metrics, +) { + let PreparedCollation { + collation, + para_id, + relay_parent, + validation_data, + validation_code_hash, + n_validators, + } = collation; + + let persisted_validation_data_hash = validation_data.hash(); + let parent_head_data_hash = validation_data.parent_head.hash(); + + // Apply compression to the block data. + let pov = { + let pov = collation.proof_of_validity.into_compressed(); + let encoded_size = pov.encoded_size(); + + // As long as `POV_BOMB_LIMIT` is at least `max_pov_size`, this ensures + // that honest collators never produce a PoV which is uncompressed. + // + // As such, honest collators never produce an uncompressed PoV which starts with + // a compression magic number, which would lead validators to reject the collation. + if encoded_size > validation_data.max_pov_size as usize { + gum::debug!( + target: LOG_TARGET, + para_id = %para_id, + size = encoded_size, + max_size = validation_data.max_pov_size, + "PoV exceeded maximum size" + ); + + return + } + + pov + }; + + let pov_hash = pov.hash(); + + let signature_payload = collator_signature_payload( + &relay_parent, + ¶_id, + &persisted_validation_data_hash, + &pov_hash, + &validation_code_hash, + ); + + let erasure_root = match erasure_root(n_validators, validation_data, pov.clone()) { + Ok(erasure_root) => erasure_root, + Err(err) => { + gum::error!( + target: LOG_TARGET, + para_id = %para_id, + err = ?err, + "failed to calculate erasure root", + ); + return + }, + }; + + let commitments = CandidateCommitments { + upward_messages: collation.upward_messages, + horizontal_messages: collation.horizontal_messages, + new_validation_code: collation.new_validation_code, + head_data: collation.head_data, + processed_downward_messages: collation.processed_downward_messages, + hrmp_watermark: collation.hrmp_watermark, + }; + + let ccr = CandidateReceipt { + commitments_hash: commitments.hash(), + descriptor: CandidateDescriptor { + signature: key.sign(&signature_payload), + para_id, + relay_parent, + collator: key.public(), + persisted_validation_data_hash, + pov_hash, + erasure_root, + para_head: commitments.head_data.hash(), + validation_code_hash, + }, + }; + + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?ccr.hash(), + ?pov_hash, + ?relay_parent, + para_id = %para_id, + "candidate is generated", + ); + metrics.on_collation_generated(); + + sender + .send_message(CollatorProtocolMessage::DistributeCollation( + ccr, + parent_head_data_hash, + pov, + result_sender, + )) + .await; +} + +async fn obtain_validation_code_hash_with_assumption( relay_parent: Hash, para_id: ParaId, assumption: OccupiedCoreAssumption, sender: &mut impl overseer::CollationGenerationSenderTrait, -) -> Result, crate::error::Error> { - use polkadot_node_subsystem::RuntimeApiError; - +) -> crate::error::Result> { match request_validation_code_hash(relay_parent, para_id, assumption, sender) .await .await? diff --git a/node/collation-generation/src/metrics.rs b/node/collation-generation/src/metrics.rs index cb9e4a0c8e85..c7690ec82c4f 100644 --- a/node/collation-generation/src/metrics.rs +++ b/node/collation-generation/src/metrics.rs @@ -22,6 +22,7 @@ pub(crate) struct MetricsInner { pub(crate) new_activations_overall: prometheus::Histogram, pub(crate) new_activations_per_relay_parent: prometheus::Histogram, pub(crate) new_activations_per_availability_core: prometheus::Histogram, + pub(crate) submit_collation: prometheus::Histogram, } /// `CollationGenerationSubsystem` metrics. @@ -57,6 +58,11 @@ impl Metrics { .as_ref() .map(|metrics| metrics.new_activations_per_availability_core.start_timer()) } + + /// Provide a timer for submitting a collation which updates on drop. + pub fn time_submit_collation(&self) -> Option { + self.0.as_ref().map(|metrics| metrics.submit_collation.start_timer()) + } } impl metrics::Metrics for Metrics { @@ -96,6 +102,15 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + submit_collation: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_collation_generation_submit_collation", + "Time spent preparing and submitting a collation to the network protocol", + ) + )?, + registry, + )?, }; Ok(Metrics(Some(metrics))) } diff --git a/node/collation-generation/src/tests.rs b/node/collation-generation/src/tests.rs index 09e5e88c221c..da6b343e6aee 100644 --- a/node/collation-generation/src/tests.rs +++ b/node/collation-generation/src/tests.rs @@ -14,472 +14,623 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -mod handle_new_activations { - use super::super::*; - use ::test_helpers::{dummy_hash, dummy_head_data, dummy_validator}; - use futures::{ - lock::Mutex, - task::{Context as FuturesContext, Poll}, - Future, +use super::*; +use assert_matches::assert_matches; +use futures::{ + lock::Mutex, + task::{Context as FuturesContext, Poll}, + Future, +}; +use polkadot_node_primitives::{BlockData, Collation, CollationResult, MaybeCompressedPoV, PoV}; +use polkadot_node_subsystem::{ + errors::RuntimeApiError, + messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, +}; +use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; +use polkadot_node_subsystem_util::TimeoutExt; +use polkadot_primitives::{ + CollatorPair, HeadData, Id as ParaId, PersistedValidationData, ScheduledCore, ValidationCode, +}; +use sp_keyring::sr25519::Keyring as Sr25519Keyring; +use std::pin::Pin; +use test_helpers::{dummy_hash, dummy_head_data, dummy_validator}; + +type VirtualOverseer = TestSubsystemContextHandle; + +fn test_harness>(test: impl FnOnce(VirtualOverseer) -> T) { + let pool = sp_core::testing::TaskExecutor::new(); + let (context, virtual_overseer) = + polkadot_node_subsystem_test_helpers::make_subsystem_context(pool); + let subsystem = async move { + let subsystem = crate::CollationGenerationSubsystem::new(Metrics::default()); + + subsystem.run(context).await; }; - use polkadot_node_primitives::{ - BlockData, Collation, CollationResult, MaybeCompressedPoV, PoV, - }; - use polkadot_node_subsystem::{ - errors::RuntimeApiError, - messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, - }; - use polkadot_node_subsystem_test_helpers::{ - subsystem_test_harness, TestSubsystemContextHandle, - }; - use polkadot_primitives::{ - CollatorPair, Id as ParaId, PersistedValidationData, ScheduledCore, ValidationCode, - }; - use std::pin::Pin; - - fn test_collation() -> Collation { - Collation { - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: None, - head_data: dummy_head_data(), - proof_of_validity: MaybeCompressedPoV::Raw(PoV { block_data: BlockData(Vec::new()) }), - processed_downward_messages: 0_u32, - hrmp_watermark: 0_u32.into(), - } - } - fn test_collation_compressed() -> Collation { - let mut collation = test_collation(); - let compressed = collation.proof_of_validity.clone().into_compressed(); - collation.proof_of_validity = MaybeCompressedPoV::Compressed(compressed); - collation - } + let test_fut = test(virtual_overseer); + + futures::pin_mut!(test_fut); + futures::executor::block_on(futures::future::join( + async move { + let mut virtual_overseer = test_fut.await; + // Ensure we have handled all responses. + if let Ok(Some(msg)) = virtual_overseer.rx.try_next() { + panic!("Did not handle all responses: {:?}", msg); + } + // Conclude. + virtual_overseer.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; + }, + subsystem, + )); +} - fn test_validation_data() -> PersistedValidationData { - let mut persisted_validation_data = PersistedValidationData::default(); - persisted_validation_data.max_pov_size = 1024; - persisted_validation_data +fn test_collation() -> Collation { + Collation { + upward_messages: Default::default(), + horizontal_messages: Default::default(), + new_validation_code: None, + head_data: dummy_head_data(), + proof_of_validity: MaybeCompressedPoV::Raw(PoV { block_data: BlockData(Vec::new()) }), + processed_downward_messages: 0_u32, + hrmp_watermark: 0_u32.into(), } +} - // Box + Unpin + Send - struct TestCollator; +fn test_collation_compressed() -> Collation { + let mut collation = test_collation(); + let compressed = collation.proof_of_validity.clone().into_compressed(); + collation.proof_of_validity = MaybeCompressedPoV::Compressed(compressed); + collation +} - impl Future for TestCollator { - type Output = Option; +fn test_validation_data() -> PersistedValidationData { + let mut persisted_validation_data = PersistedValidationData::default(); + persisted_validation_data.max_pov_size = 1024; + persisted_validation_data +} - fn poll(self: Pin<&mut Self>, _cx: &mut FuturesContext) -> Poll { - Poll::Ready(Some(CollationResult { collation: test_collation(), result_sender: None })) - } +// Box + Unpin + Send +struct TestCollator; + +impl Future for TestCollator { + type Output = Option; + + fn poll(self: Pin<&mut Self>, _cx: &mut FuturesContext) -> Poll { + Poll::Ready(Some(CollationResult { collation: test_collation(), result_sender: None })) } +} + +impl Unpin for TestCollator {} - impl Unpin for TestCollator {} +async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages { + const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2000); - fn test_config>(para_id: Id) -> Arc { - Arc::new(CollationGenerationConfig { - key: CollatorPair::generate().0, - collator: Box::new(|_: Hash, _vd: &PersistedValidationData| TestCollator.boxed()), - para_id: para_id.into(), - }) + overseer + .recv() + .timeout(TIMEOUT) + .await + .expect(&format!("{:?} is long enough to receive messages", TIMEOUT)) +} + +fn test_config>(para_id: Id) -> CollationGenerationConfig { + CollationGenerationConfig { + key: CollatorPair::generate().0, + collator: Some(Box::new(|_: Hash, _vd: &PersistedValidationData| TestCollator.boxed())), + para_id: para_id.into(), } +} - fn scheduled_core_for>(para_id: Id) -> ScheduledCore { - ScheduledCore { para_id: para_id.into(), collator: None } +fn test_config_no_collator>(para_id: Id) -> CollationGenerationConfig { + CollationGenerationConfig { + key: CollatorPair::generate().0, + collator: None, + para_id: para_id.into(), } +} - #[test] - fn requests_availability_per_relay_parent() { - let activated_hashes: Vec = - vec![[1; 32].into(), [4; 32].into(), [9; 32].into(), [16; 32].into()]; - - let requested_availability_cores = Arc::new(Mutex::new(Vec::new())); - - let overseer_requested_availability_cores = requested_availability_cores.clone(); - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::AvailabilityCores(tx)))) => { - overseer_requested_availability_cores.lock().await.push(hash); - tx.send(Ok(vec![])).unwrap(); - } - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(_hash, RuntimeApiRequest::Validators(tx)))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - } - Some(msg) => panic!("didn't expect any other overseer requests given no availability cores; got {:?}", msg), +fn scheduled_core_for>(para_id: Id) -> ScheduledCore { + ScheduledCore { para_id: para_id.into(), collator: None } +} + +#[test] +fn requests_availability_per_relay_parent() { + let activated_hashes: Vec = + vec![[1; 32].into(), [4; 32].into(), [9; 32].into(), [16; 32].into()]; + + let requested_availability_cores = Arc::new(Mutex::new(Vec::new())); + + let overseer_requested_availability_cores = requested_availability_cores.clone(); + let overseer = |mut handle: TestSubsystemContextHandle| async move { + loop { + match handle.try_recv().await { + None => break, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::AvailabilityCores(tx)))) => { + overseer_requested_availability_cores.lock().await.push(hash); + tx.send(Ok(vec![])).unwrap(); + } + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(_hash, RuntimeApiRequest::Validators(tx)))) => { + tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); } + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::StagingAsyncBackingParams( + tx, + ), + ))) => { + tx.send(Err(RuntimeApiError::NotSupported { runtime_api_name: "doesnt_matter" })).unwrap(); + }, + Some(msg) => panic!("didn't expect any other overseer requests given no availability cores; got {:?}", msg), } - }; - - let (tx, _rx) = mpsc::channel(0); - - let subsystem_activated_hashes = activated_hashes.clone(); - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations( - test_config(123u32), - subsystem_activated_hashes, - &mut ctx, - Metrics(None), - &tx, - ) - .await - .unwrap(); - }); - - let mut requested_availability_cores = Arc::try_unwrap(requested_availability_cores) - .expect("overseer should have shut down by now") - .into_inner(); - requested_availability_cores.sort(); + } + }; - assert_eq!(requested_availability_cores, activated_hashes); - } + let subsystem_activated_hashes = activated_hashes.clone(); + subsystem_test_harness(overseer, |mut ctx| async move { + handle_new_activations( + Arc::new(test_config(123u32)), + subsystem_activated_hashes, + &mut ctx, + Metrics(None), + ) + .await + .unwrap(); + }); + + let mut requested_availability_cores = Arc::try_unwrap(requested_availability_cores) + .expect("overseer should have shut down by now") + .into_inner(); + requested_availability_cores.sort(); + + assert_eq!(requested_availability_cores, activated_hashes); +} - #[test] - fn requests_validation_data_for_scheduled_matches() { - let activated_hashes: Vec = vec![ - Hash::repeat_byte(1), - Hash::repeat_byte(4), - Hash::repeat_byte(9), - Hash::repeat_byte(16), - ]; - - let requested_validation_data = Arc::new(Mutex::new(Vec::new())); - - let overseer_requested_validation_data = requested_validation_data.clone(); - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AvailabilityCores(tx), - ))) => { - tx.send(Ok(vec![ - CoreState::Free, - // this is weird, see explanation below - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 4) as u32, - )), - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 5) as u32, - )), - ])) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::PersistedValidationData( - _para_id, - _occupied_core_assumption, - tx, - ), - ))) => { - overseer_requested_validation_data.lock().await.push(hash); - tx.send(Ok(None)).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Validators(tx), - ))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - }, - Some(msg) => { - panic!("didn't expect any other overseer requests; got {:?}", msg) - }, - } +#[test] +fn requests_validation_data_for_scheduled_matches() { + let activated_hashes: Vec = vec![ + Hash::repeat_byte(1), + Hash::repeat_byte(4), + Hash::repeat_byte(9), + Hash::repeat_byte(16), + ]; + + let requested_validation_data = Arc::new(Mutex::new(Vec::new())); + + let overseer_requested_validation_data = requested_validation_data.clone(); + let overseer = |mut handle: TestSubsystemContextHandle| async move { + loop { + match handle.try_recv().await { + None => break, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::AvailabilityCores(tx), + ))) => { + tx.send(Ok(vec![ + CoreState::Free, + // this is weird, see explanation below + CoreState::Scheduled(scheduled_core_for( + (hash.as_fixed_bytes()[0] * 4) as u32, + )), + CoreState::Scheduled(scheduled_core_for( + (hash.as_fixed_bytes()[0] * 5) as u32, + )), + ])) + .unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::PersistedValidationData( + _para_id, + _occupied_core_assumption, + tx, + ), + ))) => { + overseer_requested_validation_data.lock().await.push(hash); + tx.send(Ok(None)).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Validators(tx), + ))) => { + tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::StagingAsyncBackingParams(tx), + ))) => { + tx.send(Err(RuntimeApiError::NotSupported { + runtime_api_name: "doesnt_matter", + })) + .unwrap(); + }, + Some(msg) => { + panic!("didn't expect any other overseer requests; got {:?}", msg) + }, } - }; + } + }; - let (tx, _rx) = mpsc::channel(0); + subsystem_test_harness(overseer, |mut ctx| async move { + handle_new_activations( + Arc::new(test_config(16)), + activated_hashes, + &mut ctx, + Metrics(None), + ) + .await + .unwrap(); + }); + + let requested_validation_data = Arc::try_unwrap(requested_validation_data) + .expect("overseer should have shut down by now") + .into_inner(); + + // the only activated hash should be from the 4 hash: + // each activated hash generates two scheduled cores: one with its value * 4, one with its value + // * 5 given that the test configuration has a `para_id` of 16, there's only one way to get that + // value: with the 4 hash. + assert_eq!(requested_validation_data, vec![[4; 32].into()]); +} - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations(test_config(16), activated_hashes, &mut ctx, Metrics(None), &tx) - .await - .unwrap(); - }); +#[test] +fn sends_distribute_collation_message() { + let activated_hashes: Vec = vec![ + Hash::repeat_byte(1), + Hash::repeat_byte(4), + Hash::repeat_byte(9), + Hash::repeat_byte(16), + ]; + + // empty vec doesn't allocate on the heap, so it's ok we throw it away + let to_collator_protocol = Arc::new(Mutex::new(Vec::new())); + let inner_to_collator_protocol = to_collator_protocol.clone(); + + let overseer = |mut handle: TestSubsystemContextHandle| async move { + loop { + match handle.try_recv().await { + None => break, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::AvailabilityCores(tx), + ))) => { + tx.send(Ok(vec![ + CoreState::Free, + // this is weird, see explanation below + CoreState::Scheduled(scheduled_core_for( + (hash.as_fixed_bytes()[0] * 4) as u32, + )), + CoreState::Scheduled(scheduled_core_for( + (hash.as_fixed_bytes()[0] * 5) as u32, + )), + ])) + .unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::PersistedValidationData( + _para_id, + _occupied_core_assumption, + tx, + ), + ))) => { + tx.send(Ok(Some(test_validation_data()))).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Validators(tx), + ))) => { + tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ValidationCodeHash( + _para_id, + OccupiedCoreAssumption::Free, + tx, + ), + ))) => { + tx.send(Ok(Some(ValidationCode(vec![1, 2, 3]).hash()))).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::StagingAsyncBackingParams(tx), + ))) => { + tx.send(Err(RuntimeApiError::NotSupported { + runtime_api_name: "doesnt_matter", + })) + .unwrap(); + }, + Some(msg @ AllMessages::CollatorProtocol(_)) => { + inner_to_collator_protocol.lock().await.push(msg); + }, + Some(msg) => { + panic!("didn't expect any other overseer requests; got {:?}", msg) + }, + } + } + }; - let requested_validation_data = Arc::try_unwrap(requested_validation_data) - .expect("overseer should have shut down by now") - .into_inner(); + let config = Arc::new(test_config(16)); + let subsystem_config = config.clone(); - // the only activated hash should be from the 4 hash: - // each activated hash generates two scheduled cores: one with its value * 4, one with its - // value * 5 given that the test configuration has a `para_id` of 16, there's only one way - // to get that value: with the 4 hash. - assert_eq!(requested_validation_data, vec![[4; 32].into()]); + subsystem_test_harness(overseer, |mut ctx| async move { + handle_new_activations(subsystem_config, activated_hashes, &mut ctx, Metrics(None)) + .await + .unwrap(); + }); + + let mut to_collator_protocol = Arc::try_unwrap(to_collator_protocol) + .expect("subsystem should have shut down by now") + .into_inner(); + + // we expect a single message to be sent, containing a candidate receipt. + // we don't care too much about the `commitments_hash` right now, but let's ensure that we've + // calculated the correct descriptor + let expect_pov_hash = test_collation_compressed().proof_of_validity.into_compressed().hash(); + let expect_validation_data_hash = test_validation_data().hash(); + let expect_relay_parent = Hash::repeat_byte(4); + let expect_validation_code_hash = ValidationCode(vec![1, 2, 3]).hash(); + let expect_payload = collator_signature_payload( + &expect_relay_parent, + &config.para_id, + &expect_validation_data_hash, + &expect_pov_hash, + &expect_validation_code_hash, + ); + let expect_descriptor = CandidateDescriptor { + signature: config.key.sign(&expect_payload), + para_id: config.para_id, + relay_parent: expect_relay_parent, + collator: config.key.public(), + persisted_validation_data_hash: expect_validation_data_hash, + pov_hash: expect_pov_hash, + erasure_root: dummy_hash(), // this isn't something we're checking right now + para_head: test_collation().head_data.hash(), + validation_code_hash: expect_validation_code_hash, + }; + + assert_eq!(to_collator_protocol.len(), 1); + match AllMessages::from(to_collator_protocol.pop().unwrap()) { + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( + CandidateReceipt { descriptor, .. }, + _pov, + .., + )) => { + // signature generation is non-deterministic, so we can't just assert that the + // expected descriptor is correct. What we can do is validate that the produced + // descriptor has a valid signature, then just copy in the generated signature + // and check the rest of the fields for equality. + assert!(CollatorPair::verify( + &descriptor.signature, + &collator_signature_payload( + &descriptor.relay_parent, + &descriptor.para_id, + &descriptor.persisted_validation_data_hash, + &descriptor.pov_hash, + &descriptor.validation_code_hash, + ) + .as_ref(), + &descriptor.collator, + )); + let expect_descriptor = { + let mut expect_descriptor = expect_descriptor; + expect_descriptor.signature = descriptor.signature.clone(); + expect_descriptor.erasure_root = descriptor.erasure_root; + expect_descriptor + }; + assert_eq!(descriptor, expect_descriptor); + }, + _ => panic!("received wrong message type"), } +} - #[test] - fn sends_distribute_collation_message() { - let activated_hashes: Vec = vec![ - Hash::repeat_byte(1), - Hash::repeat_byte(4), - Hash::repeat_byte(9), - Hash::repeat_byte(16), - ]; - - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AvailabilityCores(tx), - ))) => { - tx.send(Ok(vec![ - CoreState::Free, - // this is weird, see explanation below - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 4) as u32, - )), - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 5) as u32, - )), - ])) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::PersistedValidationData( - _para_id, - _occupied_core_assumption, - tx, - ), - ))) => { - tx.send(Ok(Some(test_validation_data()))).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Validators(tx), - ))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ValidationCodeHash( - _para_id, - OccupiedCoreAssumption::Free, - tx, - ), - ))) => { - tx.send(Ok(Some(ValidationCode(vec![1, 2, 3]).hash()))).unwrap(); - }, - Some(msg) => { - panic!("didn't expect any other overseer requests; got {:?}", msg) - }, - } +#[test] +fn fallback_when_no_validation_code_hash_api() { + // This is a variant of the above test, but with the validation code hash API disabled. + + let activated_hashes: Vec = vec![ + Hash::repeat_byte(1), + Hash::repeat_byte(4), + Hash::repeat_byte(9), + Hash::repeat_byte(16), + ]; + + // empty vec doesn't allocate on the heap, so it's ok we throw it away + let to_collator_protocol = Arc::new(Mutex::new(Vec::new())); + let inner_to_collator_protocol = to_collator_protocol.clone(); + + let overseer = |mut handle: TestSubsystemContextHandle| async move { + loop { + match handle.try_recv().await { + None => break, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::AvailabilityCores(tx), + ))) => { + tx.send(Ok(vec![ + CoreState::Free, + CoreState::Scheduled(scheduled_core_for( + (hash.as_fixed_bytes()[0] * 4) as u32, + )), + CoreState::Scheduled(scheduled_core_for( + (hash.as_fixed_bytes()[0] * 5) as u32, + )), + ])) + .unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::PersistedValidationData( + _para_id, + _occupied_core_assumption, + tx, + ), + ))) => { + tx.send(Ok(Some(test_validation_data()))).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Validators(tx), + ))) => { + tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ValidationCodeHash( + _para_id, + OccupiedCoreAssumption::Free, + tx, + ), + ))) => { + tx.send(Err(RuntimeApiError::NotSupported { + runtime_api_name: "validation_code_hash", + })) + .unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ValidationCode(_para_id, OccupiedCoreAssumption::Free, tx), + ))) => { + tx.send(Ok(Some(ValidationCode(vec![1, 2, 3])))).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::StagingAsyncBackingParams(tx), + ))) => { + tx.send(Err(RuntimeApiError::NotSupported { + runtime_api_name: "doesnt_matter", + })) + .unwrap(); + }, + Some(msg @ AllMessages::CollatorProtocol(_)) => { + inner_to_collator_protocol.lock().await.push(msg); + }, + Some(msg) => { + panic!("didn't expect any other overseer requests; got {:?}", msg) + }, } - }; - - let config = test_config(16); - let subsystem_config = config.clone(); - - let (tx, rx) = mpsc::channel(0); - - // empty vec doesn't allocate on the heap, so it's ok we throw it away - let sent_messages = Arc::new(Mutex::new(Vec::new())); - let subsystem_sent_messages = sent_messages.clone(); - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations( - subsystem_config, - activated_hashes, - &mut ctx, - Metrics(None), - &tx, - ) + } + }; + + let config = Arc::new(test_config(16u32)); + let subsystem_config = config.clone(); + + // empty vec doesn't allocate on the heap, so it's ok we throw it away + subsystem_test_harness(overseer, |mut ctx| async move { + handle_new_activations(subsystem_config, activated_hashes, &mut ctx, Metrics(None)) .await .unwrap(); + }); + + let to_collator_protocol = Arc::try_unwrap(to_collator_protocol) + .expect("subsystem should have shut down by now") + .into_inner(); + + let expect_validation_code_hash = ValidationCode(vec![1, 2, 3]).hash(); + + assert_eq!(to_collator_protocol.len(), 1); + match &to_collator_protocol[0] { + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( + CandidateReceipt { descriptor, .. }, + _pov, + .., + )) => { + assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash); + }, + _ => panic!("received wrong message type"), + } +} + +#[test] +fn submit_collation_is_no_op_before_initialization() { + test_harness(|mut virtual_overseer| async move { + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::SubmitCollation(SubmitCollationParams { + relay_parent: Hash::repeat_byte(0), + collation: test_collation(), + parent_head: vec![1, 2, 3].into(), + validation_code_hash: Hash::repeat_byte(1).into(), + result_sender: None, + }), + }) + .await; + + virtual_overseer + }); +} + +#[test] +fn submit_collation_leads_to_distribution() { + let relay_parent = Hash::repeat_byte(0); + let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); + let parent_head = HeadData::from(vec![1, 2, 3]); + let para_id = ParaId::from(5); + let expected_pvd = PersistedValidationData { + parent_head: parent_head.clone(), + relay_parent_number: 10, + relay_parent_storage_root: Hash::repeat_byte(1), + max_pov_size: 1024, + }; - std::mem::drop(tx); - - // collect all sent messages - *subsystem_sent_messages.lock().await = rx.collect().await; - }); - - let mut sent_messages = Arc::try_unwrap(sent_messages) - .expect("subsystem should have shut down by now") - .into_inner(); - - // we expect a single message to be sent, containing a candidate receipt. - // we don't care too much about the `commitments_hash` right now, but let's ensure that - // we've calculated the correct descriptor - let expect_pov_hash = - test_collation_compressed().proof_of_validity.into_compressed().hash(); - let expect_validation_data_hash = test_validation_data().hash(); - let expect_relay_parent = Hash::repeat_byte(4); - let expect_validation_code_hash = ValidationCode(vec![1, 2, 3]).hash(); - let expect_payload = collator_signature_payload( - &expect_relay_parent, - &config.para_id, - &expect_validation_data_hash, - &expect_pov_hash, - &expect_validation_code_hash, + test_harness(|mut virtual_overseer| async move { + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::Initialize(test_config_no_collator(para_id)), + }) + .await; + + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::SubmitCollation(SubmitCollationParams { + relay_parent, + collation: test_collation(), + parent_head: vec![1, 2, 3].into(), + validation_code_hash, + result_sender: None, + }), + }) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::Validators(tx))) => { + assert_eq!(rp, relay_parent); + let _ = tx.send(Ok(vec![ + Sr25519Keyring::Alice.public().into(), + Sr25519Keyring::Bob.public().into(), + Sr25519Keyring::Charlie.public().into(), + ])); + } ); - let expect_descriptor = CandidateDescriptor { - signature: config.key.sign(&expect_payload), - para_id: config.para_id, - relay_parent: expect_relay_parent, - collator: config.key.public(), - persisted_validation_data_hash: expect_validation_data_hash, - pov_hash: expect_pov_hash, - erasure_root: dummy_hash(), // this isn't something we're checking right now - para_head: test_collation().head_data.hash(), - validation_code_hash: expect_validation_code_hash, - }; - - assert_eq!(sent_messages.len(), 1); - match AllMessages::from(sent_messages.pop().unwrap()) { + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { + assert_eq!(rp, relay_parent); + assert_eq!(id, para_id); + assert_eq!(a, OccupiedCoreAssumption::TimedOut); + + // Candidate receipt should be constructed with the real parent head. + let mut pvd = expected_pvd.clone(); + pvd.parent_head = vec![4, 5, 6].into(); + let _ = tx.send(Ok(Some(pvd))); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( - CandidateReceipt { descriptor, .. }, - _pov, - .., + ccr, + parent_head_data_hash, + .. )) => { - // signature generation is non-deterministic, so we can't just assert that the - // expected descriptor is correct. What we can do is validate that the produced - // descriptor has a valid signature, then just copy in the generated signature - // and check the rest of the fields for equality. - assert!(CollatorPair::verify( - &descriptor.signature, - &collator_signature_payload( - &descriptor.relay_parent, - &descriptor.para_id, - &descriptor.persisted_validation_data_hash, - &descriptor.pov_hash, - &descriptor.validation_code_hash, - ) - .as_ref(), - &descriptor.collator, - )); - let expect_descriptor = { - let mut expect_descriptor = expect_descriptor; - expect_descriptor.signature = descriptor.signature.clone(); - expect_descriptor.erasure_root = descriptor.erasure_root; - expect_descriptor - }; - assert_eq!(descriptor, expect_descriptor); - }, - _ => panic!("received wrong message type"), - } - } - - #[test] - fn fallback_when_no_validation_code_hash_api() { - // This is a variant of the above test, but with the validation code hash API disabled. - - let activated_hashes: Vec = vec![ - Hash::repeat_byte(1), - Hash::repeat_byte(4), - Hash::repeat_byte(9), - Hash::repeat_byte(16), - ]; - - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AvailabilityCores(tx), - ))) => { - tx.send(Ok(vec![ - CoreState::Free, - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 4) as u32, - )), - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 5) as u32, - )), - ])) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::PersistedValidationData( - _para_id, - _occupied_core_assumption, - tx, - ), - ))) => { - tx.send(Ok(Some(test_validation_data()))).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Validators(tx), - ))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ValidationCodeHash( - _para_id, - OccupiedCoreAssumption::Free, - tx, - ), - ))) => { - tx.send(Err(RuntimeApiError::NotSupported { - runtime_api_name: "validation_code_hash", - })) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ValidationCode( - _para_id, - OccupiedCoreAssumption::Free, - tx, - ), - ))) => { - tx.send(Ok(Some(ValidationCode(vec![1, 2, 3])))).unwrap(); - }, - Some(msg) => { - panic!("didn't expect any other overseer requests; got {:?}", msg) - }, - } + assert_eq!(parent_head_data_hash, parent_head.hash()); + assert_eq!(ccr.descriptor().persisted_validation_data_hash, expected_pvd.hash()); + assert_eq!(ccr.descriptor().para_head, dummy_head_data().hash()); + assert_eq!(ccr.descriptor().validation_code_hash, validation_code_hash); } - }; - - let config = test_config(16u32); - let subsystem_config = config.clone(); - - let (tx, rx) = mpsc::channel(0); - - // empty vec doesn't allocate on the heap, so it's ok we throw it away - let sent_messages = Arc::new(Mutex::new(Vec::new())); - let subsystem_sent_messages = sent_messages.clone(); - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations( - subsystem_config, - activated_hashes, - &mut ctx, - Metrics(None), - &tx, - ) - .await - .unwrap(); + ); - std::mem::drop(tx); - - *subsystem_sent_messages.lock().await = rx.collect().await; - }); - - let sent_messages = Arc::try_unwrap(sent_messages) - .expect("subsystem should have shut down by now") - .into_inner(); - - let expect_validation_code_hash = ValidationCode(vec![1, 2, 3]).hash(); - - assert_eq!(sent_messages.len(), 1); - match &sent_messages[0] { - overseer::CollationGenerationOutgoingMessages::CollatorProtocolMessage( - CollatorProtocolMessage::DistributeCollation( - CandidateReceipt { descriptor, .. }, - _pov, - .., - ), - ) => { - assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash); - }, - _ => panic!("received wrong message type"), - } - } + virtual_overseer + }); } diff --git a/node/core/backing/src/error.rs b/node/core/backing/src/error.rs index ae138e8510ea..d8f9e82d8f48 100644 --- a/node/core/backing/src/error.rs +++ b/node/core/backing/src/error.rs @@ -19,10 +19,10 @@ use futures::channel::{mpsc, oneshot}; use polkadot_node_subsystem::{ messages::{StoreAvailableDataError, ValidationFailed}, - SubsystemError, + RuntimeApiError, SubsystemError, }; -use polkadot_node_subsystem_util::Error as UtilError; -use polkadot_primitives::BackedCandidate; +use polkadot_node_subsystem_util::{runtime, Error as UtilError}; +use polkadot_primitives::{BackedCandidate, ValidationCodeHash}; use crate::LOG_TARGET; @@ -33,6 +33,18 @@ pub type FatalResult = std::result::Result; #[allow(missing_docs)] #[fatality::fatality(splitable)] pub enum Error { + #[fatal] + #[error("Failed to spawn background task")] + FailedToSpawnBackgroundTask, + + #[fatal(forward)] + #[error("Error while accessing runtime information")] + Runtime(#[from] runtime::Error), + + #[fatal] + #[error(transparent)] + BackgroundValidationMpsc(#[from] mpsc::SendError), + #[error("Candidate is not found")] CandidateNotFound, @@ -45,16 +57,27 @@ pub enum Error { #[error("FetchPoV failed")] FetchPoV, - #[fatal] - #[error("Failed to spawn background task")] - FailedToSpawnBackgroundTask, + #[error("Fetching validation code by hash failed {0:?}, {1:?}")] + FetchValidationCode(ValidationCodeHash, RuntimeApiError), + + #[error("Fetching Runtime API version failed {0:?}")] + FetchRuntimeApiVersion(RuntimeApiError), + + #[error("No validation code {0:?}")] + NoValidationCode(ValidationCodeHash), + + #[error("Candidate rejected by prospective parachains subsystem")] + RejectedByProspectiveParachains, - #[error("ValidateFromChainState channel closed before receipt")] - ValidateFromChainState(#[source] oneshot::Canceled), + #[error("ValidateFromExhaustive channel closed before receipt")] + ValidateFromExhaustive(#[source] oneshot::Canceled), #[error("StoreAvailableData channel closed before receipt")] StoreAvailableDataChannel(#[source] oneshot::Canceled), + #[error("RuntimeAPISubsystem channel closed before receipt")] + RuntimeApiUnavailable(#[source] oneshot::Canceled), + #[error("a channel was closed before receipt in try_join!")] JoinMultiple(#[source] oneshot::Canceled), @@ -64,10 +87,6 @@ pub enum Error { #[error(transparent)] ValidationFailed(#[from] ValidationFailed), - #[fatal] - #[error(transparent)] - BackgroundValidationMpsc(#[from] mpsc::SendError), - #[error(transparent)] UtilError(#[from] UtilError), diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index ccfbb4e5145f..58763e6d80cc 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -14,43 +14,98 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Implements a `CandidateBackingSubsystem`. +//! Implements the `CandidateBackingSubsystem`. +//! +//! This subsystem maintains the entire responsibility of tracking parachain +//! candidates which can be backed, as well as the issuance of statements +//! about candidates when run on a validator node. +//! +//! There are two types of statements: `Seconded` and `Valid`. +//! `Seconded` implies `Valid`, and nothing should be stated as +//! `Valid` unless its already been `Seconded`. +//! +//! Validators may only second candidates which fall under their own group +//! assignment, and they may only second one candidate per depth per active leaf. +//! Candidates which are stated as either `Second` or `Valid` by a majority of the +//! assigned group of validators may be backed on-chain and proceed to the availability +//! stage. +//! +//! Depth is a concept relating to asynchronous backing, by which validators +//! short sub-chains of candidates are backed and extended off-chain, and then placed +//! asynchronously into blocks of the relay chain as those are authored and as the +//! relay-chain state becomes ready for them. Asynchronous backing allows parachains to +//! grow mostly independently from the state of the relay chain, which gives more time for +//! parachains to be validated and thereby increases performance. +//! +//! Most of the work of asynchronous backing is handled by the Prospective Parachains +//! subsystem. The 'depth' of a parachain block with respect to a relay chain block is +//! a measure of how many parachain blocks are between the most recent included parachain block +//! in the post-state of the relay-chain block and the candidate. For instance, +//! a candidate that descends directly from the most recent parachain block in the relay-chain +//! state has depth 0. The child of that candidate would have depth 1. And so on. +//! +//! The candidate backing subsystem keeps track of a set of 'active leaves' which are the +//! most recent blocks in the relay-chain (which is in fact a tree) which could be built +//! upon. Depth is always measured against active leaves, and the valid relay-parent that +//! each candidate can have is determined by the active leaves. The Prospective Parachains +//! subsystem enforces that the relay-parent increases monotonically, so that logic +//! is not handled here. By communicating with the Prospective Parachains subsystem, +//! this subsystem extrapolates an "implicit view" from the set of currently active leaves, +//! which determines the set of all recent relay-chain block hashes which could be relay-parents +//! for candidates backed in children of the active leaves. +//! +//! In fact, this subsystem relies on the Statement Distribution subsystem to prevent spam +//! by enforcing the rule that each validator may second at most one candidate per depth per +//! active leaf. This bounds the number of candidates that the system needs to consider and +//! is not handled within this subsystem, except for candidates seconded locally. +//! +//! This subsystem also handles relay-chain heads which don't support asynchronous backing. +//! For such active leaves, the only valid relay-parent is the leaf hash itself and the only +//! allowed depth is 0. #![deny(unused_crate_dependencies)] use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, sync::Arc, }; use bitvec::vec::BitVec; use futures::{ channel::{mpsc, oneshot}, - FutureExt, SinkExt, StreamExt, + future::BoxFuture, + stream::FuturesOrdered, + FutureExt, SinkExt, StreamExt, TryFutureExt, }; use error::{Error, FatalResult}; use polkadot_node_primitives::{ - AvailableData, InvalidCandidate, PoV, SignedFullStatement, Statement, ValidationResult, + minimum_votes, AvailableData, InvalidCandidate, PoV, SignedFullStatementWithPVD, + StatementWithPVD, ValidationResult, }; use polkadot_node_subsystem::{ - jaeger, messages::{ - AvailabilityDistributionMessage, AvailabilityStoreMessage, CandidateBackingMessage, - CandidateValidationMessage, CollatorProtocolMessage, ProvisionableData, ProvisionerMessage, + AvailabilityDistributionMessage, AvailabilityStoreMessage, CanSecondRequest, + CandidateBackingMessage, CandidateValidationMessage, CollatorProtocolMessage, + HypotheticalCandidate, HypotheticalFrontierRequest, IntroduceCandidateRequest, + ProspectiveParachainsMessage, ProvisionableData, ProvisionerMessage, RuntimeApiMessage, RuntimeApiRequest, StatementDistributionMessage, StoreAvailableDataError, }, - overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, SpawnedSubsystem, - Stage, SubsystemError, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_util::{ - self as util, request_from_runtime, request_session_index_for_child, request_validator_groups, - request_validators, Validator, + self as util, + backing_implicit_view::{FetchError as ImplicitViewFetchError, View as ImplicitView}, + request_from_runtime, request_session_index_for_child, request_validator_groups, + request_validators, + runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, + Validator, }; use polkadot_primitives::{ BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, PvfExecTimeoutKind, - SigningContext, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, + CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, PersistedValidationData, + PvfExecTimeoutKind, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, + ValidatorSignature, ValidityAttestation, }; use sp_keystore::KeystorePtr; use statement_table::{ @@ -59,7 +114,7 @@ use statement_table::{ SignedStatement as TableSignedStatement, Statement as TableStatement, Summary as TableSummary, }, - Context as TableContextTrait, Table, + Config as TableConfig, Context as TableContextTrait, Table, }; mod error; @@ -107,9 +162,9 @@ impl std::fmt::Debug for ValidatedCandidateCommand { impl ValidatedCandidateCommand { fn candidate_hash(&self) -> CandidateHash { match *self { - ValidatedCandidateCommand::Second(Ok((ref candidate, _, _))) => candidate.hash(), + ValidatedCandidateCommand::Second(Ok(ref outputs)) => outputs.candidate.hash(), ValidatedCandidateCommand::Second(Err(ref candidate)) => candidate.hash(), - ValidatedCandidateCommand::Attest(Ok((ref candidate, _, _))) => candidate.hash(), + ValidatedCandidateCommand::Attest(Ok(ref outputs)) => outputs.candidate.hash(), ValidatedCandidateCommand::Attest(Err(ref candidate)) => candidate.hash(), ValidatedCandidateCommand::AttestNoPoV(candidate_hash) => candidate_hash, } @@ -146,6 +201,98 @@ where } } +struct PerRelayParentState { + prospective_parachains_mode: ProspectiveParachainsMode, + /// The hash of the relay parent on top of which this job is doing it's work. + parent: Hash, + /// The `ParaId` assigned to the local validator at this relay parent. + assignment: Option, + /// The candidates that are backed by enough validators in their group, by hash. + backed: HashSet, + /// The table of candidates and statements under this relay-parent. + table: Table, + /// The table context, including groups. + table_context: TableContext, + /// We issued `Seconded` or `Valid` statements on about these candidates. + issued_statements: HashSet, + /// These candidates are undergoing validation in the background. + awaiting_validation: HashSet, + /// Data needed for retrying in case of `ValidatedCandidateCommand::AttestNoPoV`. + fallbacks: HashMap, +} + +struct PerCandidateState { + persisted_validation_data: PersistedValidationData, + seconded_locally: bool, + para_id: ParaId, + relay_parent: Hash, +} + +struct ActiveLeafState { + prospective_parachains_mode: ProspectiveParachainsMode, + /// The candidates seconded at various depths under this active + /// leaf with respect to parachain id. A candidate can only be + /// seconded when its hypothetical frontier under every active leaf + /// has an empty entry in this map. + /// + /// When prospective parachains are disabled, the only depth + /// which is allowed is 0. + seconded_at_depth: HashMap>, +} + +/// The state of the subsystem. +struct State { + /// The utility for managing the implicit and explicit views in a consistent way. + /// + /// We only feed leaves which have prospective parachains enabled to this view. + implicit_view: ImplicitView, + /// State tracked for all active leaves, whether or not they have prospective parachains + /// enabled. + per_leaf: HashMap, + /// State tracked for all relay-parents backing work is ongoing for. This includes + /// all active leaves. + /// + /// relay-parents fall into one of 3 categories. + /// 1. active leaves which do support prospective parachains + /// 2. active leaves which do not support prospective parachains + /// 3. relay-chain blocks which are ancestors of an active leaf and do support prospective + /// parachains. + /// + /// Relay-chain blocks which don't support prospective parachains are + /// never included in the fragment trees of active leaves which do. + /// + /// While it would be technically possible to support such leaves in + /// fragment trees, it only benefits the transition period when asynchronous + /// backing is being enabled and complicates code complexity. + per_relay_parent: HashMap, + /// State tracked for all candidates relevant to the implicit view. + /// + /// This is guaranteed to have an entry for each candidate with a relay parent in the implicit + /// or explicit view for which a `Seconded` statement has been successfully imported. + per_candidate: HashMap, + /// A cloneable sender which is dispatched to background candidate validation tasks to inform + /// the main task of the result. + background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, + /// The handle to the keystore used for signing. + keystore: KeystorePtr, +} + +impl State { + fn new( + background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, + keystore: KeystorePtr, + ) -> Self { + State { + implicit_view: ImplicitView::default(), + per_leaf: HashMap::default(), + per_relay_parent: HashMap::default(), + per_candidate: HashMap::new(), + background_validation_tx, + keystore, + } + } +} + #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] async fn run( mut ctx: Context, @@ -153,18 +300,11 @@ async fn run( metrics: Metrics, ) -> FatalResult<()> { let (background_validation_tx, mut background_validation_rx) = mpsc::channel(16); - let mut jobs = HashMap::new(); + let mut state = State::new(background_validation_tx, keystore); loop { - let res = run_iteration( - &mut ctx, - keystore.clone(), - &metrics, - &mut jobs, - background_validation_tx.clone(), - &mut background_validation_rx, - ) - .await; + let res = + run_iteration(&mut ctx, &mut state, &metrics, &mut background_validation_rx).await; match res { Ok(()) => break, @@ -178,10 +318,8 @@ async fn run( #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] async fn run_iteration( ctx: &mut Context, - keystore: KeystorePtr, + state: &mut State, metrics: &Metrics, - jobs: &mut HashMap>, - background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, background_validation_rx: &mut mpsc::Receiver<(Hash, ValidatedCandidateCommand)>, ) -> Result<(), Error> { loop { @@ -190,249 +328,35 @@ async fn run_iteration( if let Some((relay_parent, command)) = validated_command { handle_validated_candidate_command( &mut *ctx, - jobs, + state, relay_parent, command, + metrics, ).await?; } else { panic!("background_validation_tx always alive at this point; qed"); } } from_overseer = ctx.recv().fuse() => { - // Map the error to ensure that the subsystem exits when the overseer is gone. match from_overseer.map_err(Error::OverseerExited)? { - FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => handle_active_leaves_update( - &mut *ctx, - update, - jobs, - &keystore, - &background_validation_tx, - &metrics, - ).await?, + FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { + handle_active_leaves_update( + &mut *ctx, + update, + state, + ).await?; + } FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {} FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), - FromOrchestra::Communication { msg } => handle_communication(&mut *ctx, jobs, msg).await?, + FromOrchestra::Communication { msg } => { + handle_communication(&mut *ctx, state, msg, metrics).await?; + } } } ) } } -#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] -async fn handle_validated_candidate_command( - ctx: &mut Context, - jobs: &mut HashMap>, - relay_parent: Hash, - command: ValidatedCandidateCommand, -) -> Result<(), Error> { - if let Some(job) = jobs.get_mut(&relay_parent) { - job.job.handle_validated_candidate_command(&job.span, ctx, command).await?; - } else { - // simple race condition; can be ignored - this relay-parent - // is no longer relevant. - } - - Ok(()) -} - -#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] -async fn handle_communication( - ctx: &mut Context, - jobs: &mut HashMap>, - message: CandidateBackingMessage, -) -> Result<(), Error> { - match message { - CandidateBackingMessage::Second(relay_parent, candidate, pov) => { - if let Some(job) = jobs.get_mut(&relay_parent) { - job.job.handle_second_msg(&job.span, ctx, candidate, pov).await?; - } - }, - CandidateBackingMessage::Statement(relay_parent, statement) => { - if let Some(job) = jobs.get_mut(&relay_parent) { - job.job.handle_statement_message(&job.span, ctx, statement).await?; - } - }, - CandidateBackingMessage::GetBackedCandidates(relay_parent, requested_candidates, tx) => - if let Some(job) = jobs.get_mut(&relay_parent) { - job.job.handle_get_backed_candidates_message(requested_candidates, tx)?; - }, - } - - Ok(()) -} - -#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] -async fn handle_active_leaves_update( - ctx: &mut Context, - update: ActiveLeavesUpdate, - jobs: &mut HashMap>, - keystore: &KeystorePtr, - background_validation_tx: &mpsc::Sender<(Hash, ValidatedCandidateCommand)>, - metrics: &Metrics, -) -> Result<(), Error> { - for deactivated in update.deactivated { - jobs.remove(&deactivated); - } - - let leaf = match update.activated { - None => return Ok(()), - Some(a) => a, - }; - - macro_rules! try_runtime_api { - ($x: expr) => { - match $x { - Ok(x) => x, - Err(e) => { - gum::warn!( - target: LOG_TARGET, - err = ?e, - "Failed to fetch runtime API data for job", - ); - - // We can't do candidate validation work if we don't have the - // requisite runtime API data. But these errors should not take - // down the node. - return Ok(()); - } - } - } - } - - let parent = leaf.hash; - let span = PerLeafSpan::new(leaf.span, "backing"); - let _span = span.child("runtime-apis"); - - let (validators, groups, session_index, cores) = futures::try_join!( - request_validators(parent, ctx.sender()).await, - request_validator_groups(parent, ctx.sender()).await, - request_session_index_for_child(parent, ctx.sender()).await, - request_from_runtime(parent, ctx.sender(), |tx| { - RuntimeApiRequest::AvailabilityCores(tx) - },) - .await, - ) - .map_err(Error::JoinMultiple)?; - - let validators: Vec<_> = try_runtime_api!(validators); - let (validator_groups, group_rotation_info) = try_runtime_api!(groups); - let session_index = try_runtime_api!(session_index); - let cores = try_runtime_api!(cores); - - drop(_span); - let _span = span.child("validator-construction"); - - let signing_context = SigningContext { parent_hash: parent, session_index }; - let validator = - match Validator::construct(&validators, signing_context.clone(), keystore.clone()) { - Ok(v) => Some(v), - Err(util::Error::NotAValidator) => None, - Err(e) => { - gum::warn!( - target: LOG_TARGET, - err = ?e, - "Cannot participate in candidate backing", - ); - - return Ok(()) - }, - }; - - drop(_span); - let mut assignments_span = span.child("compute-assignments"); - - let mut groups = HashMap::new(); - - let n_cores = cores.len(); - - let mut assignment = None; - - for (idx, core) in cores.into_iter().enumerate() { - // Ignore prospective assignments on occupied cores for the time being. - if let CoreState::Scheduled(scheduled) = core { - let core_index = CoreIndex(idx as _); - let group_index = group_rotation_info.group_for_core(core_index, n_cores); - if let Some(g) = validator_groups.get(group_index.0 as usize) { - if validator.as_ref().map_or(false, |v| g.contains(&v.index())) { - assignment = Some(scheduled.para_id); - } - groups.insert(scheduled.para_id, g.clone()); - } - } - } - - let table_context = TableContext { groups, validators, validator }; - - let assignment = match assignment { - None => { - assignments_span.add_string_tag("assigned", "false"); - None - }, - Some(assignment) => { - assignments_span.add_string_tag("assigned", "true"); - assignments_span.add_para_id(assignment); - Some(assignment) - }, - }; - - drop(assignments_span); - let _span = span.child("wait-for-job"); - - let job = CandidateBackingJob { - parent, - assignment, - issued_statements: HashSet::new(), - awaiting_validation: HashSet::new(), - fallbacks: HashMap::new(), - seconded: None, - unbacked_candidates: HashMap::new(), - backed: HashSet::new(), - keystore: keystore.clone(), - table: Table::default(), - table_context, - background_validation_tx: background_validation_tx.clone(), - metrics: metrics.clone(), - _marker: std::marker::PhantomData, - }; - - jobs.insert(parent, JobAndSpan { job, span }); - - Ok(()) -} - -struct JobAndSpan { - job: CandidateBackingJob, - span: PerLeafSpan, -} - -/// Holds all data needed for candidate backing job operation. -struct CandidateBackingJob { - /// The hash of the relay parent on top of which this job is doing it's work. - parent: Hash, - /// The `ParaId` assigned to this validator - assignment: Option, - /// Spans for all candidates that are not yet backable. - unbacked_candidates: HashMap, - /// We issued `Seconded`, `Valid` or `Invalid` statements on about these candidates. - issued_statements: HashSet, - /// These candidates are undergoing validation in the background. - awaiting_validation: HashSet, - /// Data needed for retrying in case of `ValidatedCandidateCommand::AttestNoPoV`. - fallbacks: HashMap)>, - /// `Some(h)` if this job has already issued `Seconded` statement for some candidate with `h` - /// hash. - seconded: Option, - /// The candidates that are includable, by hash. Each entry here indicates - /// that we've sent the provisioner the backed candidate. - backed: HashSet, - keystore: KeystorePtr, - table: Table, - table_context: TableContext, - background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, - metrics: Metrics, - _marker: std::marker::PhantomData, -} - /// In case a backing validator does not provide a PoV, we need to retry with other backing /// validators. /// @@ -450,13 +374,6 @@ struct AttestingData { backing: Vec, } -/// How many votes we need to consider a candidate backed. -/// -/// WARNING: This has to be kept in sync with the runtime check in the inclusion module. -fn minimum_votes(n_validators: usize) -> usize { - std::cmp::min(2, n_validators) -} - #[derive(Default)] struct TableContext { validator: Option, @@ -490,10 +407,10 @@ impl TableContextTrait for TableContext { // It looks like it's not possible to do an `impl From` given the current state of // the code. So this does the necessary conversion. -fn primitive_statement_to_table(s: &SignedFullStatement) -> TableSignedStatement { +fn primitive_statement_to_table(s: &SignedFullStatementWithPVD) -> TableSignedStatement { let statement = match s.payload() { - Statement::Seconded(c) => TableStatement::Seconded(c.clone()), - Statement::Valid(h) => TableStatement::Valid(*h), + StatementWithPVD::Seconded(c, _) => TableStatement::Seconded(c.clone()), + StatementWithPVD::Valid(h) => TableStatement::Valid(*h), }; TableSignedStatement { @@ -585,19 +502,15 @@ async fn store_available_data( // erasure root matches the `expected_erasure_root`. // This returns `Err()` on erasure root mismatch or due to any AV store subsystem error. // -// Otherwise, it returns either `Ok(())` - +// Otherwise, it returns `Ok(())`. async fn make_pov_available( sender: &mut impl overseer::CandidateBackingSenderTrait, n_validators: usize, pov: Arc, candidate_hash: CandidateHash, - validation_data: polkadot_primitives::PersistedValidationData, + validation_data: PersistedValidationData, expected_erasure_root: Hash, - span: Option<&jaeger::Span>, ) -> Result<(), Error> { - let _span = span.as_ref().map(|s| s.child("store-data").with_candidate(candidate_hash)); - store_available_data( sender, n_validators as u32, @@ -634,13 +547,17 @@ async fn request_pov( async fn request_candidate_validation( sender: &mut impl overseer::CandidateBackingSenderTrait, + pvd: PersistedValidationData, + code: ValidationCode, candidate_receipt: CandidateReceipt, pov: Arc, ) -> Result { let (tx, rx) = oneshot::channel(); sender - .send_message(CandidateValidationMessage::ValidateFromChainState( + .send_message(CandidateValidationMessage::ValidateFromExhaustive( + pvd, + code, candidate_receipt, pov, PvfExecTimeoutKind::Backing, @@ -651,21 +568,26 @@ async fn request_candidate_validation( match rx.await { Ok(Ok(validation_result)) => Ok(validation_result), Ok(Err(err)) => Err(Error::ValidationFailed(err)), - Err(err) => Err(Error::ValidateFromChainState(err)), + Err(err) => Err(Error::ValidateFromExhaustive(err)), } } -type BackgroundValidationResult = - Result<(CandidateReceipt, CandidateCommitments, Arc), CandidateReceipt>; +struct BackgroundValidationOutputs { + candidate: CandidateReceipt, + commitments: CandidateCommitments, + persisted_validation_data: PersistedValidationData, +} + +type BackgroundValidationResult = Result; struct BackgroundValidationParams { sender: S, tx_command: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, candidate: CandidateReceipt, relay_parent: Hash, + persisted_validation_data: PersistedValidationData, pov: PoVData, n_validators: usize, - span: Option, make_command: F, } @@ -680,16 +602,33 @@ async fn validate_and_make_available( mut tx_command, candidate, relay_parent, + persisted_validation_data, pov, n_validators, - span, make_command, } = params; + let validation_code = { + let validation_code_hash = candidate.descriptor().validation_code_hash; + let (tx, rx) = oneshot::channel(); + sender + .send_message(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::ValidationCodeByHash(validation_code_hash, tx), + )) + .await; + + let code = rx.await.map_err(Error::RuntimeApiUnavailable)?; + match code { + Err(e) => return Err(Error::FetchValidationCode(validation_code_hash, e)), + Ok(None) => return Err(Error::NoValidationCode(validation_code_hash)), + Ok(Some(c)) => c, + } + }; + let pov = match pov { PoVData::Ready(pov) => pov, - PoVData::FetchFromValidator { from_validator, candidate_hash, pov_hash } => { - let _span = span.as_ref().map(|s| s.child("request-pov")); + PoVData::FetchFromValidator { from_validator, candidate_hash, pov_hash } => match request_pov( &mut sender, relay_parent, @@ -712,17 +651,18 @@ async fn validate_and_make_available( }, Err(err) => return Err(err), Ok(pov) => pov, - } - }, + }, }; let v = { - let _span = span.as_ref().map(|s| { - s.child("request-validation") - .with_pov(&pov) - .with_para_id(candidate.descriptor().para_id) - }); - request_candidate_validation(&mut sender, candidate.clone(), pov.clone()).await? + request_candidate_validation( + &mut sender, + persisted_validation_data, + validation_code, + candidate.clone(), + pov.clone(), + ) + .await? }; let res = match v { @@ -738,14 +678,17 @@ async fn validate_and_make_available( n_validators, pov.clone(), candidate.hash(), - validation_data, + validation_data.clone(), candidate.descriptor.erasure_root, - span.as_ref(), ) .await; match erasure_valid { - Ok(()) => Ok((candidate, commitments, pov.clone())), + Ok(()) => Ok(BackgroundValidationOutputs { + candidate, + commitments, + persisted_validation_data: validation_data, + }), Err(Error::StoreAvailableData(StoreAvailableDataError::InvalidErasureRoot)) => { gum::debug!( target: LOG_TARGET, @@ -783,529 +726,1294 @@ async fn validate_and_make_available( } #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] -impl CandidateBackingJob { - async fn handle_validated_candidate_command( - &mut self, - root_span: &jaeger::Span, - ctx: &mut Context, - command: ValidatedCandidateCommand, - ) -> Result<(), Error> { - let candidate_hash = command.candidate_hash(); - self.awaiting_validation.remove(&candidate_hash); - - match command { - ValidatedCandidateCommand::Second(res) => { - match res { - Ok((candidate, commitments, _)) => { - // sanity check. - if self.seconded.is_none() && - !self.issued_statements.contains(&candidate_hash) - { - self.seconded = Some(candidate_hash); - self.issued_statements.insert(candidate_hash); - self.metrics.on_candidate_seconded(); - - let statement = Statement::Seconded(CommittedCandidateReceipt { - descriptor: candidate.descriptor.clone(), - commitments, - }); - if let Some(stmt) = self - .sign_import_and_distribute_statement(ctx, statement, root_span)? - { - // Break cycle - bounded as there is only one candidate to - // second per block. - ctx.send_unbounded_message(CollatorProtocolMessage::Seconded( - self.parent, - stmt, - )); - } - } - }, - Err(candidate) => { - // Break cycle - bounded as there is only one candidate to - // second per block. - ctx.send_unbounded_message(CollatorProtocolMessage::Invalid( - self.parent, - candidate, - )); - }, - } - }, - ValidatedCandidateCommand::Attest(res) => { - // We are done - avoid new validation spawns: - self.fallbacks.remove(&candidate_hash); - // sanity check. - if !self.issued_statements.contains(&candidate_hash) { - if res.is_ok() { - let statement = Statement::Valid(candidate_hash); - self.sign_import_and_distribute_statement(ctx, statement, &root_span)?; - } - self.issued_statements.insert(candidate_hash); - } - }, - ValidatedCandidateCommand::AttestNoPoV(candidate_hash) => { - if let Some((attesting, span)) = self.fallbacks.get_mut(&candidate_hash) { - if let Some(index) = attesting.backing.pop() { - attesting.from_validator = index; - // Ok, another try: - let c_span = span.as_ref().map(|s| s.child("try")); - let attesting = attesting.clone(); - self.kick_off_validation_work(ctx, attesting, c_span).await? - } - } else { - gum::warn!( - target: LOG_TARGET, - "AttestNoPoV was triggered without fallback being available." - ); - debug_assert!(false); - } - }, - } - - Ok(()) +async fn handle_communication( + ctx: &mut Context, + state: &mut State, + message: CandidateBackingMessage, + metrics: &Metrics, +) -> Result<(), Error> { + match message { + CandidateBackingMessage::Second(_relay_parent, candidate, pvd, pov) => { + handle_second_message(ctx, state, candidate, pvd, pov, metrics).await?; + }, + CandidateBackingMessage::Statement(relay_parent, statement) => { + handle_statement_message(ctx, state, relay_parent, statement, metrics).await?; + }, + CandidateBackingMessage::GetBackedCandidates(requested_candidates, tx) => + handle_get_backed_candidates_message(state, requested_candidates, tx, metrics)?, + CandidateBackingMessage::CanSecond(request, tx) => + handle_can_second_request(ctx, state, request, tx).await, } - async fn background_validate_and_make_available( - &mut self, - ctx: &mut Context, - params: BackgroundValidationParams< - impl overseer::CandidateBackingSenderTrait, - impl Fn(BackgroundValidationResult) -> ValidatedCandidateCommand + Send + 'static + Sync, - >, - ) -> Result<(), Error> { - let candidate_hash = params.candidate.hash(); - if self.awaiting_validation.insert(candidate_hash) { - // spawn background task. - let bg = async move { - if let Err(e) = validate_and_make_available(params).await { - if let Error::BackgroundValidationMpsc(error) = e { - gum::debug!( - target: LOG_TARGET, - ?error, - "Mpsc background validation mpsc died during validation- leaf no longer active?" - ); - } else { - gum::error!( - target: LOG_TARGET, - "Failed to validate and make available: {:?}", - e - ); - } - } - }; - - ctx.spawn("backing-validation", bg.boxed()) - .map_err(|_| Error::FailedToSpawnBackgroundTask)?; - } + Ok(()) +} - Ok(()) +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn handle_active_leaves_update( + ctx: &mut Context, + update: ActiveLeavesUpdate, + state: &mut State, +) -> Result<(), Error> { + enum LeafHasProspectiveParachains { + Enabled(Result), + Disabled, } - /// Kick off background validation with intent to second. - async fn validate_and_second( - &mut self, - parent_span: &jaeger::Span, - root_span: &jaeger::Span, - ctx: &mut Context, - candidate: &CandidateReceipt, - pov: Arc, - ) -> Result<(), Error> { - let candidate_hash = candidate.hash(); - let mut span = self.get_unbacked_validation_child( - root_span, - candidate_hash, - candidate.descriptor().para_id, - ); + // Activate in implicit view before deactivate, per the docs + // on ImplicitView, this is more efficient. + let res = if let Some(leaf) = update.activated { + // Only activate in implicit view if prospective + // parachains are enabled. + let mode = prospective_parachains_mode(ctx.sender(), leaf.hash).await?; + + let leaf_hash = leaf.hash; + Some(( + leaf, + match mode { + ProspectiveParachainsMode::Disabled => LeafHasProspectiveParachains::Disabled, + ProspectiveParachainsMode::Enabled { .. } => LeafHasProspectiveParachains::Enabled( + state.implicit_view.activate_leaf(ctx.sender(), leaf_hash).await.map(|_| mode), + ), + }, + )) + } else { + None + }; - span.as_mut().map(|span| span.add_follows_from(parent_span)); + for deactivated in update.deactivated { + state.per_leaf.remove(&deactivated); + state.implicit_view.deactivate_leaf(deactivated); + } - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?candidate_hash, - candidate_receipt = ?candidate, - "Validate and second candidate", - ); + // clean up `per_relay_parent` according to ancestry + // of leaves. we do this so we can clean up candidates right after + // as a result. + // + // when prospective parachains are disabled, the implicit view is empty, + // which means we'll clean up everything that's not a leaf - the expected behavior + // for pre-asynchronous backing. + { + let remaining: HashSet<_> = state + .per_leaf + .keys() + .chain(state.implicit_view.all_allowed_relay_parents()) + .collect(); - let bg_sender = ctx.sender().clone(); - self.background_validate_and_make_available( - ctx, - BackgroundValidationParams { - sender: bg_sender, - tx_command: self.background_validation_tx.clone(), - candidate: candidate.clone(), - relay_parent: self.parent, - pov: PoVData::Ready(pov), - n_validators: self.table_context.validators.len(), - span, - make_command: ValidatedCandidateCommand::Second, + state.per_relay_parent.retain(|r, _| remaining.contains(&r)); + } + + // clean up `per_candidate` according to which relay-parents + // are known. + // + // when prospective parachains are disabled, we clean up all candidates + // because we've cleaned up all relay parents. this is correct. + state + .per_candidate + .retain(|_, pc| state.per_relay_parent.contains_key(&pc.relay_parent)); + + // Get relay parents which might be fresh but might be known already + // that are explicit or implicit from the new active leaf. + let (fresh_relay_parents, leaf_mode) = match res { + None => return Ok(()), + Some((leaf, LeafHasProspectiveParachains::Disabled)) => { + // defensive in this case - for enabled, this manifests as an error. + if state.per_leaf.contains_key(&leaf.hash) { + return Ok(()) + } + + state.per_leaf.insert( + leaf.hash, + ActiveLeafState { + prospective_parachains_mode: ProspectiveParachainsMode::Disabled, + // This is empty because the only allowed relay-parent and depth + // when prospective parachains are disabled is the leaf hash and 0, + // respectively. We've just learned about the leaf hash, so we cannot + // have any candidates seconded with it as a relay-parent yet. + seconded_at_depth: HashMap::new(), + }, + ); + + (vec![leaf.hash], ProspectiveParachainsMode::Disabled) + }, + Some((leaf, LeafHasProspectiveParachains::Enabled(Ok(prospective_parachains_mode)))) => { + let fresh_relay_parents = + state.implicit_view.known_allowed_relay_parents_under(&leaf.hash, None); + + // At this point, all candidates outside of the implicit view + // have been cleaned up. For all which remain, which we've seconded, + // we ask the prospective parachains subsystem where they land in the fragment + // tree for the given active leaf. This comprises our `seconded_at_depth`. + + let remaining_seconded = state + .per_candidate + .iter() + .filter(|(_, cd)| cd.seconded_locally) + .map(|(c_hash, cd)| (*c_hash, cd.para_id)); + + // one-to-one correspondence to remaining_seconded + let mut membership_answers = FuturesOrdered::new(); + + for (candidate_hash, para_id) in remaining_seconded { + let (tx, rx) = oneshot::channel(); + membership_answers + .push_back(rx.map_ok(move |membership| (para_id, candidate_hash, membership))); + + ctx.send_message(ProspectiveParachainsMessage::GetTreeMembership( + para_id, + candidate_hash, + tx, + )) + .await; + } + + let mut seconded_at_depth = HashMap::new(); + if let Some(response) = membership_answers.next().await { + match response { + Err(oneshot::Canceled) => { + gum::warn!( + target: LOG_TARGET, + "Prospective parachains subsystem unreachable for membership request", + ); + }, + Ok((para_id, candidate_hash, membership)) => { + // This request gives membership in all fragment trees. We have some + // wasted data here, and it can be optimized if it proves + // relevant to performance. + if let Some((_, depths)) = + membership.into_iter().find(|(leaf_hash, _)| leaf_hash == &leaf.hash) + { + let para_entry: &mut BTreeMap = + seconded_at_depth.entry(para_id).or_default(); + for depth in depths { + para_entry.insert(depth, candidate_hash); + } + } + }, + } + } + + state.per_leaf.insert( + leaf.hash, + ActiveLeafState { prospective_parachains_mode, seconded_at_depth }, + ); + + let fresh_relay_parent = match fresh_relay_parents { + Some(f) => f.to_vec(), + None => { + gum::warn!( + target: LOG_TARGET, + leaf_hash = ?leaf.hash, + "Implicit view gave no relay-parents" + ); + + vec![leaf.hash] + }, + }; + (fresh_relay_parent, prospective_parachains_mode) + }, + Some((leaf, LeafHasProspectiveParachains::Enabled(Err(e)))) => { + gum::debug!( + target: LOG_TARGET, + leaf_hash = ?leaf.hash, + err = ?e, + "Failed to load implicit view for leaf." + ); + + return Ok(()) + }, + }; + + // add entries in `per_relay_parent`. for all new relay-parents. + for maybe_new in fresh_relay_parents { + if state.per_relay_parent.contains_key(&maybe_new) { + continue + } + + let mode = match state.per_leaf.get(&maybe_new) { + None => { + // If the relay-parent isn't a leaf itself, + // then it is guaranteed by the prospective parachains + // subsystem that it is an ancestor of a leaf which + // has prospective parachains enabled and that the + // block itself did. + leaf_mode }, - ) - .await?; + Some(l) => l.prospective_parachains_mode, + }; + + // construct a `PerRelayParent` from the runtime API + // and insert it. + let per = construct_per_relay_parent_state(ctx, maybe_new, &state.keystore, mode).await?; - Ok(()) + if let Some(per) = per { + state.per_relay_parent.insert(maybe_new, per); + } } - fn sign_import_and_distribute_statement( - &mut self, - ctx: &mut Context, - statement: Statement, - root_span: &jaeger::Span, - ) -> Result, Error> { - if let Some(signed_statement) = self.sign_statement(statement) { - self.import_statement(ctx, &signed_statement, root_span)?; - let smsg = StatementDistributionMessage::Share(self.parent, signed_statement.clone()); - ctx.send_unbounded_message(smsg); - - Ok(Some(signed_statement)) + Ok(()) +} + +/// Load the data necessary to do backing work on top of a relay-parent. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn construct_per_relay_parent_state( + ctx: &mut Context, + relay_parent: Hash, + keystore: &KeystorePtr, + mode: ProspectiveParachainsMode, +) -> Result, Error> { + macro_rules! try_runtime_api { + ($x: expr) => { + match $x { + Ok(x) => x, + Err(e) => { + gum::warn!( + target: LOG_TARGET, + err = ?e, + "Failed to fetch runtime API data for job", + ); + + // We can't do candidate validation work if we don't have the + // requisite runtime API data. But these errors should not take + // down the node. + return Ok(None); + } + } + } + } + + let parent = relay_parent; + + let (validators, groups, session_index, cores) = futures::try_join!( + request_validators(parent, ctx.sender()).await, + request_validator_groups(parent, ctx.sender()).await, + request_session_index_for_child(parent, ctx.sender()).await, + request_from_runtime(parent, ctx.sender(), |tx| { + RuntimeApiRequest::AvailabilityCores(tx) + },) + .await, + ) + .map_err(Error::JoinMultiple)?; + + let validators: Vec<_> = try_runtime_api!(validators); + let (validator_groups, group_rotation_info) = try_runtime_api!(groups); + let session_index = try_runtime_api!(session_index); + let cores = try_runtime_api!(cores); + + let signing_context = SigningContext { parent_hash: parent, session_index }; + let validator = + match Validator::construct(&validators, signing_context.clone(), keystore.clone()) { + Ok(v) => Some(v), + Err(util::Error::NotAValidator) => None, + Err(e) => { + gum::warn!( + target: LOG_TARGET, + err = ?e, + "Cannot participate in candidate backing", + ); + + return Ok(None) + }, + }; + + let mut groups = HashMap::new(); + let n_cores = cores.len(); + let mut assignment = None; + + for (idx, core) in cores.into_iter().enumerate() { + let core_para_id = match core { + CoreState::Scheduled(scheduled) => scheduled.para_id, + CoreState::Occupied(occupied) => + if mode.is_enabled() { + // Async backing makes it legal to build on top of + // occupied core. + occupied.candidate_descriptor.para_id + } else { + continue + }, + CoreState::Free => continue, + }; + + let core_index = CoreIndex(idx as _); + let group_index = group_rotation_info.group_for_core(core_index, n_cores); + if let Some(g) = validator_groups.get(group_index.0 as usize) { + if validator.as_ref().map_or(false, |v| g.contains(&v.index())) { + assignment = Some(core_para_id); + } + groups.insert(core_para_id, g.clone()); + } + } + + let table_context = TableContext { groups, validators, validator }; + let table_config = TableConfig { + allow_multiple_seconded: match mode { + ProspectiveParachainsMode::Enabled { .. } => true, + ProspectiveParachainsMode::Disabled => false, + }, + }; + + Ok(Some(PerRelayParentState { + prospective_parachains_mode: mode, + parent, + assignment, + backed: HashSet::new(), + table: Table::new(table_config), + table_context, + issued_statements: HashSet::new(), + awaiting_validation: HashSet::new(), + fallbacks: HashMap::new(), + })) +} + +enum SecondingAllowed { + No, + Yes(Vec<(Hash, Vec)>), +} + +/// Checks whether a candidate can be seconded based on its hypothetical frontiers in the fragment +/// tree and what we've already seconded in all active leaves. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn seconding_sanity_check( + ctx: &mut Context, + active_leaves: &HashMap, + implicit_view: &ImplicitView, + hypothetical_candidate: HypotheticalCandidate, + backed_in_path_only: bool, +) -> SecondingAllowed { + let mut membership = Vec::new(); + let mut responses = FuturesOrdered::>>::new(); + + let candidate_para = hypothetical_candidate.candidate_para(); + let candidate_relay_parent = hypothetical_candidate.relay_parent(); + let candidate_hash = hypothetical_candidate.candidate_hash(); + + for (head, leaf_state) in active_leaves { + if leaf_state.prospective_parachains_mode.is_enabled() { + // Check that the candidate relay parent is allowed for para, skip the + // leaf otherwise. + let allowed_parents_for_para = + implicit_view.known_allowed_relay_parents_under(head, Some(candidate_para)); + if !allowed_parents_for_para.unwrap_or_default().contains(&candidate_relay_parent) { + continue + } + + let (tx, rx) = oneshot::channel(); + ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalFrontier( + HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(*head), + backed_in_path_only, + }, + tx, + )) + .await; + let response = rx.map_ok(move |frontiers| { + let depths: Vec = frontiers + .into_iter() + .flat_map(|(candidate, memberships)| { + debug_assert_eq!(candidate.candidate_hash(), candidate_hash); + memberships.into_iter().flat_map(|(relay_parent, depths)| { + debug_assert_eq!(relay_parent, *head); + depths + }) + }) + .collect(); + (depths, head, leaf_state) + }); + responses.push_back(response.boxed()); } else { - Ok(None) + if *head == candidate_relay_parent { + if leaf_state + .seconded_at_depth + .get(&candidate_para) + .map_or(false, |occupied| occupied.contains_key(&0)) + { + // The leaf is already occupied. + return SecondingAllowed::No + } + responses.push_back(futures::future::ok((vec![0], head, leaf_state)).boxed()); + } } } - /// Check if there have happened any new misbehaviors and issue necessary messages. - fn issue_new_misbehaviors(&mut self, sender: &mut impl overseer::CandidateBackingSenderTrait) { - // collect the misbehaviors to avoid double mutable self borrow issues - let misbehaviors: Vec<_> = self.table.drain_misbehaviors().collect(); - for (validator_id, report) in misbehaviors { - // The provisioner waits on candidate-backing, which means - // that we need to send unbounded messages to avoid cycles. - // - // Misbehaviors are bounded by the number of validators and - // the block production protocol. - sender.send_unbounded_message(ProvisionerMessage::ProvisionableData( - self.parent, - ProvisionableData::MisbehaviorReport(self.parent, validator_id, report), - )); + if responses.is_empty() { + return SecondingAllowed::No + } + + while let Some(response) = responses.next().await { + match response { + Err(oneshot::Canceled) => { + gum::warn!( + target: LOG_TARGET, + "Failed to reach prospective parachains subsystem for hypothetical frontiers", + ); + + return SecondingAllowed::No + }, + Ok((depths, head, leaf_state)) => { + for depth in &depths { + if leaf_state + .seconded_at_depth + .get(&candidate_para) + .map_or(false, |occupied| occupied.contains_key(&depth)) + { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + depth, + leaf_hash = ?head, + "Refusing to second candidate at depth - already occupied." + ); + + return SecondingAllowed::No + } + } + + membership.push((*head, depths)); + }, } } - /// Import a statement into the statement table and return the summary of the import. - fn import_statement( - &mut self, - ctx: &mut Context, - statement: &SignedFullStatement, - root_span: &jaeger::Span, - ) -> Result, Error> { - gum::debug!( - target: LOG_TARGET, - statement = ?statement.payload().to_compact(), - validator_index = statement.validator_index().0, - "Importing statement", - ); + // At this point we've checked the depths of the candidate against all active + // leaves. + SecondingAllowed::Yes(membership) +} - let candidate_hash = statement.payload().candidate_hash(); - let import_statement_span = { - // create a span only for candidates we're already aware of. - self.get_unbacked_statement_child( - root_span, - candidate_hash, - statement.validator_index(), - ) +/// Performs seconding sanity check for an advertisement. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn handle_can_second_request( + ctx: &mut Context, + state: &State, + request: CanSecondRequest, + tx: oneshot::Sender, +) { + let relay_parent = request.candidate_relay_parent; + let response = if state + .per_relay_parent + .get(&relay_parent) + .map_or(false, |pr_state| pr_state.prospective_parachains_mode.is_enabled()) + { + let hypothetical_candidate = HypotheticalCandidate::Incomplete { + candidate_hash: request.candidate_hash, + candidate_para: request.candidate_para_id, + parent_head_data_hash: request.parent_head_data_hash, + candidate_relay_parent: relay_parent, }; - let stmt = primitive_statement_to_table(statement); + let result = seconding_sanity_check( + ctx, + &state.per_leaf, + &state.implicit_view, + hypothetical_candidate, + true, + ) + .await; - let summary = self.table.import_statement(&self.table_context, stmt); + match result { + SecondingAllowed::No => false, + SecondingAllowed::Yes(membership) => { + // Candidate should be recognized by at least some fragment tree. + membership.iter().any(|(_, m)| !m.is_empty()) + }, + } + } else { + // Relay parent is unknown or async backing is disabled. + false + }; - let unbacked_span = if let Some(attested) = summary - .as_ref() - .and_then(|s| self.table.attested_candidate(&s.candidate, &self.table_context)) - { - let candidate_hash = attested.candidate.hash(); - // `HashSet::insert` returns true if the thing wasn't in there already. - if self.backed.insert(candidate_hash) { - let span = self.remove_unbacked_span(&candidate_hash); + let _ = tx.send(response); +} - if let Some(backed) = table_attested_to_backed(attested, &self.table_context) { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?candidate_hash, - relay_parent = ?self.parent, - para_id = %backed.candidate.descriptor.para_id, - "Candidate backed", - ); +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn handle_validated_candidate_command( + ctx: &mut Context, + state: &mut State, + relay_parent: Hash, + command: ValidatedCandidateCommand, + metrics: &Metrics, +) -> Result<(), Error> { + match state.per_relay_parent.get_mut(&relay_parent) { + Some(rp_state) => { + let candidate_hash = command.candidate_hash(); + rp_state.awaiting_validation.remove(&candidate_hash); + + match command { + ValidatedCandidateCommand::Second(res) => match res { + Ok(outputs) => { + let BackgroundValidationOutputs { + candidate, + commitments, + persisted_validation_data, + } = outputs; + + if rp_state.issued_statements.contains(&candidate_hash) { + return Ok(()) + } + + let receipt = CommittedCandidateReceipt { + descriptor: candidate.descriptor.clone(), + commitments, + }; + + let parent_head_data_hash = persisted_validation_data.parent_head.hash(); + // Note that `GetHypotheticalFrontier` doesn't account for recursion, + // i.e. candidates can appear at multiple depths in the tree and in fact + // at all depths, and we don't know what depths a candidate will ultimately + // occupy because that's dependent on other candidates we haven't yet + // received. + // + // The only way to effectively rule this out is to have candidate receipts + // directly commit to the parachain block number or some other incrementing + // counter. That requires a major primitives format upgrade, so for now + // we just rule out trivial cycles. + if parent_head_data_hash == receipt.commitments.head_data.hash() { + return Ok(()) + } + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash, + receipt: Arc::new(receipt.clone()), + persisted_validation_data: persisted_validation_data.clone(), + }; + // sanity check that we're allowed to second the candidate + // and that it doesn't conflict with other candidates we've + // seconded. + let fragment_tree_membership = match seconding_sanity_check( + ctx, + &state.per_leaf, + &state.implicit_view, + hypothetical_candidate, + false, + ) + .await + { + SecondingAllowed::No => return Ok(()), + SecondingAllowed::Yes(membership) => membership, + }; + + let statement = + StatementWithPVD::Seconded(receipt, persisted_validation_data); + + // If we get an Error::RejectedByProspectiveParachains, + // then the statement has not been distributed or imported into + // the table. + let res = sign_import_and_distribute_statement( + ctx, + rp_state, + &mut state.per_candidate, + statement, + state.keystore.clone(), + metrics, + ) + .await; + + if let Err(Error::RejectedByProspectiveParachains) = res { + let candidate_hash = candidate.hash(); + gum::debug!( + target: LOG_TARGET, + relay_parent = ?candidate.descriptor().relay_parent, + ?candidate_hash, + "Attempted to second candidate but was rejected by prospective parachains", + ); + + // Ensure the collator is reported. + ctx.send_message(CollatorProtocolMessage::Invalid( + candidate.descriptor().relay_parent, + candidate, + )) + .await; + + return Ok(()) + } + + if let Some(stmt) = res? { + match state.per_candidate.get_mut(&candidate_hash) { + None => { + gum::warn!( + target: LOG_TARGET, + ?candidate_hash, + "Missing `per_candidate` for seconded candidate.", + ); + }, + Some(p) => p.seconded_locally = true, + } + + // update seconded depths in active leaves. + for (leaf, depths) in fragment_tree_membership { + let leaf_data = match state.per_leaf.get_mut(&leaf) { + None => { + gum::warn!( + target: LOG_TARGET, + leaf_hash = ?leaf, + "Missing `per_leaf` for known active leaf." + ); + + continue + }, + Some(d) => d, + }; + + let seconded_at_depth = leaf_data + .seconded_at_depth + .entry(candidate.descriptor().para_id) + .or_default(); + + for depth in depths { + seconded_at_depth.insert(depth, candidate_hash); + } + } + + rp_state.issued_statements.insert(candidate_hash); + metrics.on_candidate_seconded(); + ctx.send_message(CollatorProtocolMessage::Seconded( + rp_state.parent, + StatementWithPVD::drop_pvd_from_signed(stmt), + )) + .await; + } + }, + Err(candidate) => { + ctx.send_message(CollatorProtocolMessage::Invalid( + rp_state.parent, + candidate, + )) + .await; + }, + }, + ValidatedCandidateCommand::Attest(res) => { + // We are done - avoid new validation spawns: + rp_state.fallbacks.remove(&candidate_hash); + // sanity check. + if !rp_state.issued_statements.contains(&candidate_hash) { + if res.is_ok() { + let statement = StatementWithPVD::Valid(candidate_hash); + + sign_import_and_distribute_statement( + ctx, + rp_state, + &mut state.per_candidate, + statement, + state.keystore.clone(), + metrics, + ) + .await?; + } + rp_state.issued_statements.insert(candidate_hash); + } + }, + ValidatedCandidateCommand::AttestNoPoV(candidate_hash) => { + if let Some(attesting) = rp_state.fallbacks.get_mut(&candidate_hash) { + if let Some(index) = attesting.backing.pop() { + attesting.from_validator = index; + let attesting = attesting.clone(); + + // The candidate state should be available because we've + // validated it before, the relay-parent is still around, + // and candidates are pruned on the basis of relay-parents. + // + // If it's not, then no point in validating it anyway. + if let Some(pvd) = state + .per_candidate + .get(&candidate_hash) + .map(|pc| pc.persisted_validation_data.clone()) + { + kick_off_validation_work( + ctx, + rp_state, + pvd, + &state.background_validation_tx, + attesting, + ) + .await?; + } + } + } else { + gum::warn!( + target: LOG_TARGET, + "AttestNoPoV was triggered without fallback being available." + ); + debug_assert!(false); + } + }, + } + }, + None => { + // simple race condition; can be ignored = this relay-parent + // is no longer relevant. + }, + } + + Ok(()) +} + +fn sign_statement( + rp_state: &PerRelayParentState, + statement: StatementWithPVD, + keystore: KeystorePtr, + metrics: &Metrics, +) -> Option { + let signed = rp_state + .table_context + .validator + .as_ref()? + .sign(keystore, statement) + .ok() + .flatten()?; + metrics.on_statement_signed(); + Some(signed) +} + +/// Import a statement into the statement table and return the summary of the import. +/// +/// This will fail with `Error::RejectedByProspectiveParachains` if the message type +/// is seconded, the candidate is fresh, +/// and any of the following are true: +/// 1. There is no `PersistedValidationData` attached. +/// 2. Prospective parachains are enabled for the relay parent and the prospective parachains +/// subsystem returned an empty `FragmentTreeMembership` i.e. did not recognize the candidate as +/// being applicable to any of the active leaves. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn import_statement( + ctx: &mut Context, + rp_state: &mut PerRelayParentState, + per_candidate: &mut HashMap, + statement: &SignedFullStatementWithPVD, +) -> Result, Error> { + gum::debug!( + target: LOG_TARGET, + statement = ?statement.payload().to_compact(), + validator_index = statement.validator_index().0, + "Importing statement", + ); + + let candidate_hash = statement.payload().candidate_hash(); + + // If this is a new candidate (statement is 'seconded' and candidate is unknown), + // we need to create an entry in the `PerCandidateState` map. + // + // If the relay parent supports prospective parachains, we also need + // to inform the prospective parachains subsystem of the seconded candidate. + // If `ProspectiveParachainsMessage::Second` fails, then we return + // Error::RejectedByProspectiveParachains. + // + // Persisted Validation Data should be available - it may already be available + // if this is a candidate we are seconding. + // + // We should also not accept any candidates which have no valid depths under any of + // our active leaves. + if let StatementWithPVD::Seconded(candidate, pvd) = statement.payload() { + if !per_candidate.contains_key(&candidate_hash) { + if rp_state.prospective_parachains_mode.is_enabled() { + let (tx, rx) = oneshot::channel(); + ctx.send_message(ProspectiveParachainsMessage::IntroduceCandidate( + IntroduceCandidateRequest { + candidate_para: candidate.descriptor().para_id, + candidate_receipt: candidate.clone(), + persisted_validation_data: pvd.clone(), + }, + tx, + )) + .await; + + match rx.await { + Err(oneshot::Canceled) => { + gum::warn!( + target: LOG_TARGET, + "Could not reach the Prospective Parachains subsystem." + ); + + return Err(Error::RejectedByProspectiveParachains) + }, + Ok(membership) => + if membership.is_empty() { + return Err(Error::RejectedByProspectiveParachains) + }, + } + + ctx.send_message(ProspectiveParachainsMessage::CandidateSeconded( + candidate.descriptor().para_id, + candidate_hash, + )) + .await; + } + + // Only save the candidate if it was approved by prospective parachains. + per_candidate.insert( + candidate_hash, + PerCandidateState { + persisted_validation_data: pvd.clone(), + // This is set after importing when seconding locally. + seconded_locally: false, + para_id: candidate.descriptor().para_id, + relay_parent: candidate.descriptor().relay_parent, + }, + ); + } + } + + let stmt = primitive_statement_to_table(statement); + + Ok(rp_state.table.import_statement(&rp_state.table_context, stmt)) +} + +/// Handles a summary received from [`import_statement`] and dispatches `Backed` notifications and +/// misbehaviors as a result of importing a statement. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn post_import_statement_actions( + ctx: &mut Context, + rp_state: &mut PerRelayParentState, + summary: Option<&TableSummary>, +) -> Result<(), Error> { + if let Some(attested) = summary + .as_ref() + .and_then(|s| rp_state.table.attested_candidate(&s.candidate, &rp_state.table_context)) + { + let candidate_hash = attested.candidate.hash(); + + // `HashSet::insert` returns true if the thing wasn't in there already. + if rp_state.backed.insert(candidate_hash) { + if let Some(backed) = table_attested_to_backed(attested, &rp_state.table_context) { + let para_id = backed.candidate.descriptor.para_id; + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?candidate_hash, + relay_parent = ?rp_state.parent, + %para_id, + "Candidate backed", + ); + + if rp_state.prospective_parachains_mode.is_enabled() { + // Inform the prospective parachains subsystem + // that the candidate is now backed. + ctx.send_message(ProspectiveParachainsMessage::CandidateBacked( + para_id, + candidate_hash, + )) + .await; + // Backed candidate potentially unblocks new advertisements, + // notify collator protocol. + ctx.send_message(CollatorProtocolMessage::Backed { + para_id, + para_head: backed.candidate.descriptor.para_head, + }) + .await; + // Notify statement distribution of backed candidate. + ctx.send_message(StatementDistributionMessage::Backed(candidate_hash)).await; + } else { // The provisioner waits on candidate-backing, which means // that we need to send unbounded messages to avoid cycles. // // Backed candidates are bounded by the number of validators, // parachains, and the block production rate of the relay chain. let message = ProvisionerMessage::ProvisionableData( - self.parent, + rp_state.parent, ProvisionableData::BackedCandidate(backed.receipt()), ); ctx.send_unbounded_message(message); - - span.as_ref().map(|s| s.child("backed")); - span - } else { - None } - } else { - None } - } else { - None - }; + } + } - self.issue_new_misbehaviors(ctx.sender()); + issue_new_misbehaviors(ctx, rp_state.parent, &mut rp_state.table); - // It is important that the child span is dropped before its parent span (`unbacked_span`) - drop(import_statement_span); - drop(unbacked_span); + Ok(()) +} - Ok(summary) +/// Check if there have happened any new misbehaviors and issue necessary messages. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +fn issue_new_misbehaviors( + ctx: &mut Context, + relay_parent: Hash, + table: &mut Table, +) { + // collect the misbehaviors to avoid double mutable self borrow issues + let misbehaviors: Vec<_> = table.drain_misbehaviors().collect(); + for (validator_id, report) in misbehaviors { + // The provisioner waits on candidate-backing, which means + // that we need to send unbounded messages to avoid cycles. + // + // Misbehaviors are bounded by the number of validators and + // the block production protocol. + ctx.send_unbounded_message(ProvisionerMessage::ProvisionableData( + relay_parent, + ProvisionableData::MisbehaviorReport(relay_parent, validator_id, report), + )); } +} - async fn handle_second_msg( - &mut self, - root_span: &jaeger::Span, - ctx: &mut Context, - candidate: CandidateReceipt, - pov: PoV, - ) -> Result<(), Error> { - let _timer = self.metrics.time_process_second(); - - let candidate_hash = candidate.hash(); - let span = root_span - .child("second") - .with_stage(jaeger::Stage::CandidateBacking) - .with_pov(&pov) - .with_candidate(candidate_hash) - .with_relay_parent(self.parent); - - // Sanity check that candidate is from our assignment. - if Some(candidate.descriptor().para_id) != self.assignment { - gum::debug!( - target: LOG_TARGET, - our_assignment = ?self.assignment, - collation = ?candidate.descriptor().para_id, - "Subsystem asked to second for para outside of our assignment", - ); +/// Sign, import, and distribute a statement. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn sign_import_and_distribute_statement( + ctx: &mut Context, + rp_state: &mut PerRelayParentState, + per_candidate: &mut HashMap, + statement: StatementWithPVD, + keystore: KeystorePtr, + metrics: &Metrics, +) -> Result, Error> { + if let Some(signed_statement) = sign_statement(&*rp_state, statement, keystore, metrics) { + let summary = import_statement(ctx, rp_state, per_candidate, &signed_statement).await?; - return Ok(()) - } + // `Share` must always be sent before `Backed`. We send the latter in + // `post_import_statement_action` below. + let smsg = StatementDistributionMessage::Share(rp_state.parent, signed_statement.clone()); + ctx.send_unbounded_message(smsg); - // If the message is a `CandidateBackingMessage::Second`, sign and dispatch a - // Seconded statement only if we have not seconded any other candidate and - // have not signed a Valid statement for the requested candidate. - if self.seconded.is_none() { - // This job has not seconded a candidate yet. + post_import_statement_actions(ctx, rp_state, summary.as_ref()).await?; - if !self.issued_statements.contains(&candidate_hash) { - let pov = Arc::new(pov); - self.validate_and_second(&span, &root_span, ctx, &candidate, pov).await?; + Ok(Some(signed_statement)) + } else { + Ok(None) + } +} + +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn background_validate_and_make_available( + ctx: &mut Context, + rp_state: &mut PerRelayParentState, + params: BackgroundValidationParams< + impl overseer::CandidateBackingSenderTrait, + impl Fn(BackgroundValidationResult) -> ValidatedCandidateCommand + Send + 'static + Sync, + >, +) -> Result<(), Error> { + let candidate_hash = params.candidate.hash(); + if rp_state.awaiting_validation.insert(candidate_hash) { + // spawn background task. + let bg = async move { + if let Err(e) = validate_and_make_available(params).await { + if let Error::BackgroundValidationMpsc(error) = e { + gum::debug!( + target: LOG_TARGET, + ?error, + "Mpsc background validation mpsc died during validation- leaf no longer active?" + ); + } else { + gum::error!( + target: LOG_TARGET, + "Failed to validate and make available: {:?}", + e + ); + } } - } + }; - Ok(()) + ctx.spawn("backing-validation", bg.boxed()) + .map_err(|_| Error::FailedToSpawnBackgroundTask)?; } - async fn handle_statement_message( - &mut self, - root_span: &jaeger::Span, - ctx: &mut Context, - statement: SignedFullStatement, - ) -> Result<(), Error> { - let _timer = self.metrics.time_process_statement(); - let _span = root_span - .child("statement") - .with_stage(jaeger::Stage::CandidateBacking) - .with_candidate(statement.payload().candidate_hash()) - .with_relay_parent(self.parent); - - match self.maybe_validate_and_import(&root_span, ctx, statement).await { - Err(Error::ValidationFailed(_)) => Ok(()), - Err(e) => Err(e), - Ok(()) => Ok(()), - } + Ok(()) +} + +/// Kick off validation work and distribute the result as a signed statement. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn kick_off_validation_work( + ctx: &mut Context, + rp_state: &mut PerRelayParentState, + persisted_validation_data: PersistedValidationData, + background_validation_tx: &mpsc::Sender<(Hash, ValidatedCandidateCommand)>, + attesting: AttestingData, +) -> Result<(), Error> { + let candidate_hash = attesting.candidate.hash(); + if rp_state.issued_statements.contains(&candidate_hash) { + return Ok(()) } - fn handle_get_backed_candidates_message( - &mut self, - requested_candidates: Vec, - tx: oneshot::Sender>, - ) -> Result<(), Error> { - let _timer = self.metrics.time_get_backed_candidates(); + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?candidate_hash, + candidate_receipt = ?attesting.candidate, + "Kicking off validation", + ); - let backed = requested_candidates - .into_iter() - .filter_map(|hash| { - self.table - .attested_candidate(&hash, &self.table_context) - .and_then(|attested| table_attested_to_backed(attested, &self.table_context)) - }) - .collect(); + let bg_sender = ctx.sender().clone(); + let pov = PoVData::FetchFromValidator { + from_validator: attesting.from_validator, + candidate_hash, + pov_hash: attesting.pov_hash, + }; - tx.send(backed).map_err(|data| Error::Send(data))?; - Ok(()) - } + background_validate_and_make_available( + ctx, + rp_state, + BackgroundValidationParams { + sender: bg_sender, + tx_command: background_validation_tx.clone(), + candidate: attesting.candidate, + relay_parent: rp_state.parent, + persisted_validation_data, + pov, + n_validators: rp_state.table_context.validators.len(), + make_command: ValidatedCandidateCommand::Attest, + }, + ) + .await +} + +/// Import the statement and kick off validation work if it is a part of our assignment. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn maybe_validate_and_import( + ctx: &mut Context, + state: &mut State, + relay_parent: Hash, + statement: SignedFullStatementWithPVD, +) -> Result<(), Error> { + let rp_state = match state.per_relay_parent.get_mut(&relay_parent) { + Some(r) => r, + None => { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + "Received statement for unknown relay-parent" + ); - /// Kick off validation work and distribute the result as a signed statement. - async fn kick_off_validation_work( - &mut self, - ctx: &mut Context, - attesting: AttestingData, - span: Option, - ) -> Result<(), Error> { - let candidate_hash = attesting.candidate.hash(); - if self.issued_statements.contains(&candidate_hash) { return Ok(()) - } + }, + }; + let res = import_statement(ctx, rp_state, &mut state.per_candidate, &statement).await; + + // if we get an Error::RejectedByProspectiveParachains, + // we will do nothing. + if let Err(Error::RejectedByProspectiveParachains) = res { gum::debug!( target: LOG_TARGET, - candidate_hash = ?candidate_hash, - candidate_receipt = ?attesting.candidate, - "Kicking off validation", + ?relay_parent, + "Statement rejected by prospective parachains." ); - let bg_sender = ctx.sender().clone(); - let pov = PoVData::FetchFromValidator { - from_validator: attesting.from_validator, - candidate_hash, - pov_hash: attesting.pov_hash, - }; - self.background_validate_and_make_available( - ctx, - BackgroundValidationParams { - sender: bg_sender, - tx_command: self.background_validation_tx.clone(), - candidate: attesting.candidate, - relay_parent: self.parent, - pov, - n_validators: self.table_context.validators.len(), - span, - make_command: ValidatedCandidateCommand::Attest, - }, - ) - .await + return Ok(()) } - /// Import the statement and kick off validation work if it is a part of our assignment. - async fn maybe_validate_and_import( - &mut self, - root_span: &jaeger::Span, - ctx: &mut Context, - statement: SignedFullStatement, - ) -> Result<(), Error> { - if let Some(summary) = self.import_statement(ctx, &statement, root_span)? { - if Some(summary.group_id) != self.assignment { - return Ok(()) - } - let (attesting, span) = match statement.payload() { - Statement::Seconded(receipt) => { - let candidate_hash = summary.candidate; - - let span = self.get_unbacked_validation_child( - root_span, - summary.candidate, - summary.group_id, - ); + let summary = res?; + post_import_statement_actions(ctx, rp_state, summary.as_ref()).await?; - let attesting = AttestingData { - candidate: self - .table - .get_candidate(&candidate_hash) - .ok_or(Error::CandidateNotFound)? - .to_plain(), - pov_hash: receipt.descriptor.pov_hash, - from_validator: statement.validator_index(), - backing: Vec::new(), - }; - let child = span.as_ref().map(|s| s.child("try")); - self.fallbacks.insert(summary.candidate, (attesting.clone(), span)); - (attesting, child) - }, - Statement::Valid(candidate_hash) => { - if let Some((attesting, span)) = self.fallbacks.get_mut(candidate_hash) { - let our_index = self.table_context.validator.as_ref().map(|v| v.index()); - if our_index == Some(statement.validator_index()) { - return Ok(()) - } + if let Some(summary) = summary { + // import_statement already takes care of communicating with the + // prospective parachains subsystem. At this point, the candidate + // has already been accepted into the fragment trees. - if self.awaiting_validation.contains(candidate_hash) { - // Job already running: - attesting.backing.push(statement.validator_index()); - return Ok(()) - } else { - // No job, so start another with current validator: - attesting.from_validator = statement.validator_index(); - (attesting.clone(), span.as_ref().map(|s| s.child("try"))) - } - } else { + let candidate_hash = summary.candidate; + + if Some(summary.group_id) != rp_state.assignment { + return Ok(()) + } + let attesting = match statement.payload() { + StatementWithPVD::Seconded(receipt, _) => { + let attesting = AttestingData { + candidate: rp_state + .table + .get_candidate(&candidate_hash) + .ok_or(Error::CandidateNotFound)? + .to_plain(), + pov_hash: receipt.descriptor.pov_hash, + from_validator: statement.validator_index(), + backing: Vec::new(), + }; + rp_state.fallbacks.insert(summary.candidate, attesting.clone()); + attesting + }, + StatementWithPVD::Valid(candidate_hash) => { + if let Some(attesting) = rp_state.fallbacks.get_mut(candidate_hash) { + let our_index = rp_state.table_context.validator.as_ref().map(|v| v.index()); + if our_index == Some(statement.validator_index()) { return Ok(()) } - }, - }; - self.kick_off_validation_work(ctx, attesting, span).await?; + if rp_state.awaiting_validation.contains(candidate_hash) { + // Job already running: + attesting.backing.push(statement.validator_index()); + return Ok(()) + } else { + // No job, so start another with current validator: + attesting.from_validator = statement.validator_index(); + attesting.clone() + } + } else { + return Ok(()) + } + }, + }; + + // After `import_statement` succeeds, the candidate entry is guaranteed + // to exist. + if let Some(pvd) = state + .per_candidate + .get(&candidate_hash) + .map(|pc| pc.persisted_validation_data.clone()) + { + kick_off_validation_work( + ctx, + rp_state, + pvd, + &state.background_validation_tx, + attesting, + ) + .await?; } - Ok(()) } + Ok(()) +} - fn sign_statement(&mut self, statement: Statement) -> Option { - let signed = self - .table_context - .validator - .as_ref()? - .sign(self.keystore.clone(), statement) - .ok() - .flatten()?; - self.metrics.on_statement_signed(); - Some(signed) - } +/// Kick off background validation with intent to second. +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn validate_and_second( + ctx: &mut Context, + rp_state: &mut PerRelayParentState, + persisted_validation_data: PersistedValidationData, + candidate: &CandidateReceipt, + pov: Arc, + background_validation_tx: &mpsc::Sender<(Hash, ValidatedCandidateCommand)>, +) -> Result<(), Error> { + let candidate_hash = candidate.hash(); + + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?candidate_hash, + candidate_receipt = ?candidate, + "Validate and second candidate", + ); + + let bg_sender = ctx.sender().clone(); + background_validate_and_make_available( + ctx, + rp_state, + BackgroundValidationParams { + sender: bg_sender, + tx_command: background_validation_tx.clone(), + candidate: candidate.clone(), + relay_parent: rp_state.parent, + persisted_validation_data, + pov: PoVData::Ready(pov), + n_validators: rp_state.table_context.validators.len(), + make_command: ValidatedCandidateCommand::Second, + }, + ) + .await?; - /// Insert or get the unbacked-span for the given candidate hash. - fn insert_or_get_unbacked_span( - &mut self, - parent_span: &jaeger::Span, - hash: CandidateHash, - para_id: Option, - ) -> Option<&jaeger::Span> { - if !self.backed.contains(&hash) { - // only add if we don't consider this backed. - let span = self.unbacked_candidates.entry(hash).or_insert_with(|| { - let s = parent_span.child("unbacked-candidate").with_candidate(hash); - if let Some(para_id) = para_id { - s.with_para_id(para_id) - } else { - s - } - }); - Some(span) - } else { - None - } + Ok(()) +} + +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn handle_second_message( + ctx: &mut Context, + state: &mut State, + candidate: CandidateReceipt, + persisted_validation_data: PersistedValidationData, + pov: PoV, + metrics: &Metrics, +) -> Result<(), Error> { + let _timer = metrics.time_process_second(); + + let candidate_hash = candidate.hash(); + let relay_parent = candidate.descriptor().relay_parent; + + if candidate.descriptor().persisted_validation_data_hash != persisted_validation_data.hash() { + gum::warn!( + target: LOG_TARGET, + ?candidate_hash, + "Candidate backing was asked to second candidate with wrong PVD", + ); + + return Ok(()) } - fn get_unbacked_validation_child( - &mut self, - parent_span: &jaeger::Span, - hash: CandidateHash, - para_id: ParaId, - ) -> Option { - self.insert_or_get_unbacked_span(parent_span, hash, Some(para_id)).map(|span| { - span.child("validation") - .with_candidate(hash) - .with_stage(Stage::CandidateBacking) - }) + let rp_state = match state.per_relay_parent.get_mut(&relay_parent) { + None => { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?candidate_hash, + "We were asked to second a candidate outside of our view." + ); + + return Ok(()) + }, + Some(r) => r, + }; + + // Sanity check that candidate is from our assignment. + if Some(candidate.descriptor().para_id) != rp_state.assignment { + gum::debug!( + target: LOG_TARGET, + our_assignment = ?rp_state.assignment, + collation = ?candidate.descriptor().para_id, + "Subsystem asked to second for para outside of our assignment", + ); + + return Ok(()) } - fn get_unbacked_statement_child( - &mut self, - parent_span: &jaeger::Span, - hash: CandidateHash, - validator: ValidatorIndex, - ) -> Option { - self.insert_or_get_unbacked_span(parent_span, hash, None).map(|span| { - span.child("import-statement") - .with_candidate(hash) - .with_validator_index(validator) - }) + // If the message is a `CandidateBackingMessage::Second`, sign and dispatch a + // Seconded statement only if we have not signed a Valid statement for the requested candidate. + // + // The actual logic of issuing the signed statement checks that this isn't + // conflicting with other seconded candidates. Not doing that check here + // gives other subsystems the ability to get us to execute arbitrary candidates, + // but no more. + if !rp_state.issued_statements.contains(&candidate_hash) { + let pov = Arc::new(pov); + + validate_and_second( + ctx, + rp_state, + persisted_validation_data, + &candidate, + pov, + &state.background_validation_tx, + ) + .await?; } - fn remove_unbacked_span(&mut self, hash: &CandidateHash) -> Option { - self.unbacked_candidates.remove(hash) + Ok(()) +} + +#[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] +async fn handle_statement_message( + ctx: &mut Context, + state: &mut State, + relay_parent: Hash, + statement: SignedFullStatementWithPVD, + metrics: &Metrics, +) -> Result<(), Error> { + let _timer = metrics.time_process_statement(); + + match maybe_validate_and_import(ctx, state, relay_parent, statement).await { + Err(Error::ValidationFailed(_)) => Ok(()), + Err(e) => Err(e), + Ok(()) => Ok(()), } } + +fn handle_get_backed_candidates_message( + state: &State, + requested_candidates: Vec<(CandidateHash, Hash)>, + tx: oneshot::Sender>, + metrics: &Metrics, +) -> Result<(), Error> { + let _timer = metrics.time_get_backed_candidates(); + + let backed = requested_candidates + .into_iter() + .filter_map(|(candidate_hash, relay_parent)| { + let rp_state = match state.per_relay_parent.get(&relay_parent) { + Some(rp_state) => rp_state, + None => { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?candidate_hash, + "Requested candidate's relay parent is out of view", + ); + return None + }, + }; + rp_state + .table + .attested_candidate(&candidate_hash, &rp_state.table_context) + .and_then(|attested| table_attested_to_backed(attested, &rp_state.table_context)) + }) + .collect(); + + tx.send(backed).map_err(|data| Error::Send(data))?; + Ok(()) +} diff --git a/node/core/backing/src/tests.rs b/node/core/backing/src/tests/mod.rs similarity index 65% rename from node/core/backing/src/tests.rs rename to node/core/backing/src/tests/mod.rs index 1a2c044ccc66..054337669c07 100644 --- a/node/core/backing/src/tests.rs +++ b/node/core/backing/src/tests/mod.rs @@ -17,22 +17,24 @@ use super::*; use ::test_helpers::{ dummy_candidate_receipt_bad_sig, dummy_collator, dummy_collator_signature, - dummy_committed_candidate_receipt, dummy_hash, dummy_validation_code, + dummy_committed_candidate_receipt, dummy_hash, }; use assert_matches::assert_matches; use futures::{future, Future}; -use polkadot_node_primitives::{BlockData, InvalidCandidate}; +use polkadot_node_primitives::{BlockData, InvalidCandidate, SignedFullStatement, Statement}; use polkadot_node_subsystem::{ + errors::RuntimeApiError, + jaeger, messages::{ AllMessages, CollatorProtocolMessage, RuntimeApiMessage, RuntimeApiRequest, ValidationFailed, }, - ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, + ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, TimeoutExt, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, PvfExecTimeoutKind, - ScheduledCore, + ScheduledCore, SessionIndex, }; use sp_application_crypto::AppCrypto; use sp_keyring::Sr25519Keyring; @@ -41,6 +43,11 @@ use sp_tracing as _; use statement_table::v2::Misbehavior; use std::collections::HashMap; +mod prospective_parachains; + +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; + fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { val_ids.iter().map(|v| v.public().into()).collect() } @@ -53,6 +60,15 @@ fn table_statement_to_primitive(statement: TableStatement) -> Statement { } } +fn dummy_pvd() -> PersistedValidationData { + PersistedValidationData { + parent_head: HeadData(vec![7, 8, 9]), + relay_parent_number: 0_u32.into(), + max_pov_size: 1024, + relay_parent_storage_root: dummy_hash(), + } +} + struct TestState { chain_ids: Vec, keystore: KeystorePtr, @@ -66,13 +82,18 @@ struct TestState { relay_parent: Hash, } +impl TestState { + fn session(&self) -> SessionIndex { + self.signing_context.session_index + } +} + impl Default for TestState { fn default() -> Self { let chain_a = ParaId::from(1); let chain_b = ParaId::from(2); - let thread_a = ParaId::from(3); - let chain_ids = vec![chain_a, chain_b, thread_a]; + let chain_ids = vec![chain_a, chain_b]; let validators = vec![ Sr25519Keyring::Alice, @@ -91,7 +112,7 @@ impl Default for TestState { let validator_public = validator_pubkeys(&validators); - let validator_groups = vec![vec![2, 0, 3, 5], vec![1], vec![4]] + let validator_groups = vec![vec![2, 0, 3, 5], vec![1]] .into_iter() .map(|g| g.into_iter().map(ValidatorIndex).collect()) .collect(); @@ -101,11 +122,11 @@ impl Default for TestState { let availability_cores = vec![ CoreState::Scheduled(ScheduledCore { para_id: chain_a, collator: None }), CoreState::Scheduled(ScheduledCore { para_id: chain_b, collator: None }), - CoreState::Scheduled(ScheduledCore { para_id: thread_a, collator: None }), ]; let mut head_data = HashMap::new(); head_data.insert(chain_a, HeadData(vec![4, 5, 6])); + head_data.insert(chain_b, HeadData(vec![5, 6, 7])); let relay_parent = Hash::repeat_byte(5); @@ -162,21 +183,22 @@ fn test_harness>( )); } -fn make_erasure_root(test: &TestState, pov: PoV) -> Hash { - let available_data = - AvailableData { validation_data: test.validation_data.clone(), pov: Arc::new(pov) }; +fn make_erasure_root(test: &TestState, pov: PoV, validation_data: PersistedValidationData) -> Hash { + let available_data = AvailableData { validation_data, pov: Arc::new(pov) }; let chunks = erasure_coding::obtain_chunks_v1(test.validators.len(), &available_data).unwrap(); erasure_coding::branches(&chunks).root() } -#[derive(Default)] +#[derive(Default, Clone)] struct TestCandidateBuilder { para_id: ParaId, head_data: HeadData, pov_hash: Hash, relay_parent: Hash, erasure_root: Hash, + persisted_validation_data_hash: Hash, + validation_code: Vec, } impl TestCandidateBuilder { @@ -189,9 +211,9 @@ impl TestCandidateBuilder { erasure_root: self.erasure_root, collator: dummy_collator(), signature: dummy_collator_signature(), - para_head: dummy_hash(), - validation_code_hash: dummy_validation_code().hash(), - persisted_validation_data_hash: dummy_hash(), + para_head: self.head_data.hash(), + validation_code_hash: ValidationCode(self.validation_code).hash(), + persisted_validation_data_hash: self.persisted_validation_data_hash, }, commitments: CandidateCommitments { head_data: self.head_data, @@ -219,6 +241,15 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS )))) .await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) if parent == test_state.relay_parent => { + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + } + ); + // Check that subsystem job issues a request for a validator set. assert_matches!( virtual_overseer.recv().await, @@ -269,6 +300,8 @@ fn backing_second_works() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); @@ -278,38 +311,59 @@ fn backing_second_works() { relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), } .build(); let second = CandidateBackingMessage::Second( test_state.relay_parent, candidate.to_plain(), + pvd.clone(), pov.clone(), ); virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, candidate_receipt, - pov, + _pov, timeout, tx, - ) - ) if pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && timeout == PvfExecTimeoutKind::Backing && candidate.commitments.hash() == candidate_receipt.commitments_hash => { - tx.send(Ok( - ValidationResult::Valid(CandidateCommitments { + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash => + { + tx.send(Ok(ValidationResult::Valid( + CandidateCommitments { head_data: expected_head_data.clone(), horizontal_messages: Default::default(), upward_messages: Default::default(), new_validation_code: None, processed_downward_messages: 0, hrmp_watermark: 0, - }, test_state.validation_data.clone()), - )).unwrap(); + }, + test_state.validation_data.clone(), + ))) + .unwrap(); } ); @@ -357,6 +411,8 @@ fn backing_works() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let pov_hash = pov.hash(); @@ -367,7 +423,9 @@ fn backing_works() { relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + validation_code: validation_code.0.clone(), + ..Default::default() } .build(); @@ -387,9 +445,9 @@ fn backing_works() { ) .expect("Insert key into keystore"); - let signed_a = SignedFullStatement::sign( + let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate_a.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -398,9 +456,9 @@ fn backing_works() { .flatten() .expect("should be signed"); - let signed_b = SignedFullStatement::sign( + let signed_b = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate_a_hash), + StatementWithPVD::Valid(candidate_a_hash), &test_state.signing_context, ValidatorIndex(5), &public1.into(), @@ -414,6 +472,15 @@ fn backing_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is the PoV. assert_matches!( @@ -434,13 +501,20 @@ fn backing_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == PvfExecTimeoutKind::Backing && c.commitments_hash == candidate_a_commitments_hash=> { + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate_a.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate_a_commitments_hash == candidate_receipt.commitments_hash => + { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -465,22 +539,22 @@ fn backing_works() { assert_matches!( virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(candidate_receipt) - ) + AllMessages::StatementDistribution( + StatementDistributionMessage::Share(hash, _stmt) ) => { - assert_eq!(candidate_receipt, candidate_a.to_plain()); + assert_eq!(test_state.relay_parent, hash); } ); assert_matches!( virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share(hash, _stmt) + AllMessages::Provisioner( + ProvisionerMessage::ProvisionableData( + _, + ProvisionableData::BackedCandidate(candidate_receipt) + ) ) => { - assert_eq!(test_state.relay_parent, hash); + assert_eq!(candidate_receipt, candidate_a.to_plain()); } ); @@ -505,6 +579,8 @@ fn backing_works_while_validation_ongoing() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let pov_hash = pov.hash(); @@ -515,7 +591,9 @@ fn backing_works_while_validation_ongoing() { relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + validation_code: validation_code.0.clone(), + ..Default::default() } .build(); @@ -541,9 +619,9 @@ fn backing_works_while_validation_ongoing() { ) .expect("Insert key into keystore"); - let signed_a = SignedFullStatement::sign( + let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate_a.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -552,9 +630,9 @@ fn backing_works_while_validation_ongoing() { .flatten() .expect("should be signed"); - let signed_b = SignedFullStatement::sign( + let signed_b = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate_a_hash), + StatementWithPVD::Valid(candidate_a_hash), &test_state.signing_context, ValidatorIndex(5), &public1.into(), @@ -563,9 +641,9 @@ fn backing_works_while_validation_ongoing() { .flatten() .expect("should be signed"); - let signed_c = SignedFullStatement::sign( + let signed_c = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate_a_hash), + StatementWithPVD::Valid(candidate_a_hash), &test_state.signing_context, ValidatorIndex(3), &public3.into(), @@ -578,6 +656,15 @@ fn backing_works_while_validation_ongoing() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is PoV from the // `PoVDistribution`. @@ -599,13 +686,20 @@ fn backing_works_while_validation_ongoing() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == PvfExecTimeoutKind::Backing && candidate_a_commitments_hash == c.commitments_hash => { + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate_a.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate_a_commitments_hash == candidate_receipt.commitments_hash => + { // we never validate the candidate. our local node // shouldn't issue any statements. std::mem::forget(tx); @@ -638,8 +732,7 @@ fn backing_works_while_validation_ongoing() { let (tx, rx) = oneshot::channel(); let msg = CandidateBackingMessage::GetBackedCandidates( - test_state.relay_parent, - vec![candidate_a.hash()], + vec![(candidate_a.hash(), test_state.relay_parent)], tx, ); @@ -683,6 +776,8 @@ fn backing_misbehavior_works() { let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; let pov_hash = pov.hash(); + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); @@ -690,8 +785,10 @@ fn backing_misbehavior_works() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), head_data: expected_head_data.clone(), + validation_code: validation_code.0.clone(), + ..Default::default() } .build(); @@ -704,9 +801,9 @@ fn backing_misbehavior_works() { Some(&test_state.validators[2].to_seed()), ) .expect("Insert key into keystore"); - let seconded_2 = SignedFullStatement::sign( + let seconded_2 = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate_a.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -715,9 +812,9 @@ fn backing_misbehavior_works() { .flatten() .expect("should be signed"); - let valid_2 = SignedFullStatement::sign( + let valid_2 = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate_a_hash), + StatementWithPVD::Valid(candidate_a_hash), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -731,6 +828,15 @@ fn backing_misbehavior_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::AvailabilityDistribution( @@ -747,13 +853,20 @@ fn backing_misbehavior_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == PvfExecTimeoutKind::Backing && candidate_a_commitments_hash == c.commitments_hash => { + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate_a.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate_a_commitments_hash == candidate_receipt.commitments_hash => + { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -776,6 +889,18 @@ fn backing_misbehavior_works() { } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + relay_parent, + signed_statement, + ) + ) if relay_parent == test_state.relay_parent => { + assert_eq!(*signed_statement.payload(), StatementWithPVD::Valid(candidate_a_hash)); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::Provisioner( @@ -789,18 +914,6 @@ fn backing_misbehavior_works() { ) if descriptor == candidate_a.descriptor ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - relay_parent, - signed_statement, - ) - ) if relay_parent == test_state.relay_parent => { - assert_eq!(*signed_statement.payload(), Statement::Valid(candidate_a_hash)); - } - ); - // This `Valid` statement is redundant after the `Seconded` statement already sent. let statement = CandidateBackingMessage::Statement(test_state.relay_parent, valid_2.clone()); @@ -853,8 +966,17 @@ fn backing_dont_second_invalid() { test_startup(&mut virtual_overseer, &test_state).await; let pov_block_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd_a = dummy_pvd(); + let validation_code_a = ValidationCode(vec![1, 2, 3]); let pov_block_b = PoV { block_data: BlockData(vec![45, 46, 47]) }; + let pvd_b = { + let mut pvd_b = pvd_a.clone(); + pvd_b.parent_head = HeadData(vec![14, 15, 16]); + pvd_b.max_pov_size = pvd_a.max_pov_size / 2; + pvd_b + }; + let validation_code_b = ValidationCode(vec![4, 5, 6]); let pov_hash_a = pov_block_a.hash(); let pov_hash_b = pov_block_b.hash(); @@ -865,7 +987,9 @@ fn backing_dont_second_invalid() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash: pov_hash_a, - erasure_root: make_erasure_root(&test_state, pov_block_a.clone()), + erasure_root: make_erasure_root(&test_state, pov_block_a.clone(), pvd_a.clone()), + persisted_validation_data_hash: pvd_a.hash(), + validation_code: validation_code_a.0.clone(), ..Default::default() } .build(); @@ -874,29 +998,48 @@ fn backing_dont_second_invalid() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash: pov_hash_b, - erasure_root: make_erasure_root(&test_state, pov_block_b.clone()), + erasure_root: make_erasure_root(&test_state, pov_block_b.clone(), pvd_b.clone()), head_data: expected_head_data.clone(), + persisted_validation_data_hash: pvd_b.hash(), + validation_code: validation_code_b.0.clone(), } .build(); let second = CandidateBackingMessage::Second( test_state.relay_parent, candidate_a.to_plain(), + pvd_a.clone(), pov_block_a.clone(), ); virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code_a.hash() => { + tx.send(Ok(Some(validation_code_a.clone()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate_a.descriptor() && timeout == PvfExecTimeoutKind::Backing => { + ), + ) if _pvd == pvd_a && + _validation_code == validation_code_a && + *_pov == pov_block_a && &candidate_receipt.descriptor == candidate_a.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate_a.commitments.hash() == candidate_receipt.commitments_hash => + { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -911,21 +1054,38 @@ fn backing_dont_second_invalid() { let second = CandidateBackingMessage::Second( test_state.relay_parent, candidate_b.to_plain(), + pvd_b.clone(), pov_block_b.clone(), ); virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code_b.hash() => { + tx.send(Ok(Some(validation_code_b.clone()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate_b.descriptor() && timeout == PvfExecTimeoutKind::Backing => { + ), + ) if pvd == pvd_b && + _validation_code == validation_code_b && + *_pov == pov_block_b && &candidate_receipt.descriptor == candidate_b.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate_b.commitments.hash() == candidate_receipt.commitments_hash => + { tx.send(Ok( ValidationResult::Valid(CandidateCommitments { head_data: expected_head_data.clone(), @@ -934,7 +1094,7 @@ fn backing_dont_second_invalid() { new_validation_code: None, processed_downward_messages: 0, hrmp_watermark: 0, - }, test_state.validation_data.clone()), + }, pvd_b.clone()), )).unwrap(); } ); @@ -956,7 +1116,7 @@ fn backing_dont_second_invalid() { signed_statement, ) ) if parent_hash == test_state.relay_parent => { - assert_eq!(*signed_statement.payload(), Statement::Seconded(candidate_b)); + assert_eq!(*signed_statement.payload(), StatementWithPVD::Seconded(candidate_b, pvd_b.clone())); } ); @@ -978,6 +1138,8 @@ fn backing_second_after_first_fails_works() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let pov_hash = pov.hash(); @@ -985,7 +1147,9 @@ fn backing_second_after_first_fails_works() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), ..Default::default() } .build(); @@ -997,9 +1161,9 @@ fn backing_second_after_first_fails_works() { ) .expect("Insert key into keystore"); - let signed_a = SignedFullStatement::sign( + let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate.clone()), + StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(2), &validator2.into(), @@ -1014,6 +1178,15 @@ fn backing_second_after_first_fails_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + // Subsystem requests PoV and requests validation. assert_matches!( virtual_overseer.recv().await, @@ -1032,13 +1205,20 @@ fn backing_second_after_first_fails_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate.descriptor() && timeout == PvfExecTimeoutKind::Backing && c.commitments_hash == candidate.commitments.hash() => { + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash => + { tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); } ); @@ -1048,12 +1228,15 @@ fn backing_second_after_first_fails_works() { let second = CandidateBackingMessage::Second( test_state.relay_parent, candidate.to_plain(), + pvd.clone(), pov.clone(), ); virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; let pov_to_second = PoV { block_data: BlockData(vec![3, 2, 1]) }; + let pvd_to_second = dummy_pvd(); + let validation_code_to_second = ValidationCode(vec![5, 6, 7]); let pov_hash = pov_to_second.hash(); @@ -1061,7 +1244,13 @@ fn backing_second_after_first_fails_works() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov_to_second.clone()), + erasure_root: make_erasure_root( + &test_state, + pov_to_second.clone(), + pvd_to_second.clone(), + ), + persisted_validation_data_hash: pvd_to_second.hash(), + validation_code: validation_code_to_second.0.clone(), ..Default::default() } .build(); @@ -1069,6 +1258,7 @@ fn backing_second_after_first_fails_works() { let second = CandidateBackingMessage::Second( test_state.relay_parent, candidate_to_second.to_plain(), + pvd_to_second.clone(), pov_to_second.clone(), ); @@ -1077,15 +1267,19 @@ fn backing_second_after_first_fails_works() { // triggered on the prev step. virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code_to_second.hash() => { + tx.send(Ok(Some(validation_code_to_second.clone()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - _, - pov, - _, - _, - ) + CandidateValidationMessage::ValidateFromExhaustive(_, _, _, pov, ..), ) => { assert_eq!(&*pov, &pov_to_second); } @@ -1103,6 +1297,8 @@ fn backing_works_after_failed_validation() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let pov_hash = pov.hash(); @@ -1110,7 +1306,8 @@ fn backing_works_after_failed_validation() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + validation_code: validation_code.0.clone(), ..Default::default() } .build(); @@ -1121,9 +1318,9 @@ fn backing_works_after_failed_validation() { Some(&test_state.validators[2].to_seed()), ) .expect("Insert key into keystore"); - let signed_a = SignedFullStatement::sign( + let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate.clone()), + StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -1138,6 +1335,15 @@ fn backing_works_after_failed_validation() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + // Subsystem requests PoV and requests validation. assert_matches!( virtual_overseer.recv().await, @@ -1156,13 +1362,20 @@ fn backing_works_after_failed_validation() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, tx, - ) - ) if pov == pov && c.descriptor() == candidate.descriptor() && timeout == PvfExecTimeoutKind::Backing && c.commitments_hash == candidate.commitments.hash() => { + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash => + { tx.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); } ); @@ -1171,8 +1384,7 @@ fn backing_works_after_failed_validation() { // and check that it is still alive. let (tx, rx) = oneshot::channel(); let msg = CandidateBackingMessage::GetBackedCandidates( - test_state.relay_parent, - vec![candidate.hash()], + vec![(candidate.hash(), test_state.relay_parent)], tx, ); @@ -1262,6 +1474,8 @@ fn retry_works() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let pov_hash = pov.hash(); @@ -1269,7 +1483,9 @@ fn retry_works() { para_id: test_state.chain_ids[0], relay_parent: test_state.relay_parent, pov_hash, - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), ..Default::default() } .build(); @@ -1292,9 +1508,9 @@ fn retry_works() { Some(&test_state.validators[5].to_seed()), ) .expect("Insert key into keystore"); - let signed_a = SignedFullStatement::sign( + let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate.clone()), + StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -1302,9 +1518,9 @@ fn retry_works() { .ok() .flatten() .expect("should be signed"); - let signed_b = SignedFullStatement::sign( + let signed_b = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate.hash()), + StatementWithPVD::Valid(candidate.hash()), &test_state.signing_context, ValidatorIndex(3), &public3.into(), @@ -1312,9 +1528,9 @@ fn retry_works() { .ok() .flatten() .expect("should be signed"); - let signed_c = SignedFullStatement::sign( + let signed_c = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate.hash()), + StatementWithPVD::Valid(candidate.hash()), &test_state.signing_context, ValidatorIndex(5), &public5.into(), @@ -1328,6 +1544,15 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + // Subsystem requests PoV and requests validation. // We cancel - should mean retry on next backing statement. assert_matches!( @@ -1348,7 +1573,7 @@ fn retry_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; // Not deterministic which message comes first: - for _ in 0u32..2 { + for _ in 0u32..3 { match virtual_overseer.recv().await { AllMessages::Provisioner(ProvisionerMessage::ProvisionableData( _, @@ -1361,6 +1586,12 @@ fn retry_works() { ) if relay_parent == test_state.relay_parent => { std::mem::drop(tx); }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::ValidationCodeByHash(hash, tx), + )) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + }, msg => { assert!(false, "Unexpected message: {:?}", msg); }, @@ -1371,6 +1602,15 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_c.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + assert_matches!( virtual_overseer.recv().await, AllMessages::AvailabilityDistribution( @@ -1389,13 +1629,19 @@ fn retry_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromChainState( - c, - pov, + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, timeout, - _tx, - ) - ) if pov == pov && c.descriptor() == candidate.descriptor() && timeout == PvfExecTimeoutKind::Backing && c.commitments_hash == candidate.commitments.hash() + .. + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash ); virtual_overseer }); @@ -1409,6 +1655,8 @@ fn observes_backing_even_if_not_validator() { test_startup(&mut virtual_overseer, &test_state).await; let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); let pov_hash = pov.hash(); @@ -1419,7 +1667,9 @@ fn observes_backing_even_if_not_validator() { relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone()), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), } .build(); @@ -1445,9 +1695,9 @@ fn observes_backing_even_if_not_validator() { // Produce a 3-of-5 quorum on the candidate. - let signed_a = SignedFullStatement::sign( + let signed_a = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Seconded(candidate_a.clone()), + StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), &test_state.signing_context, ValidatorIndex(0), &public0.into(), @@ -1456,9 +1706,9 @@ fn observes_backing_even_if_not_validator() { .flatten() .expect("should be signed"); - let signed_b = SignedFullStatement::sign( + let signed_b = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate_a_hash), + StatementWithPVD::Valid(candidate_a_hash), &test_state.signing_context, ValidatorIndex(5), &public1.into(), @@ -1467,9 +1717,9 @@ fn observes_backing_even_if_not_validator() { .flatten() .expect("should be signed"); - let signed_c = SignedFullStatement::sign( + let signed_c = SignedFullStatementWithPVD::sign( &test_state.keystore, - Statement::Valid(candidate_a_hash), + StatementWithPVD::Valid(candidate_a_hash), &test_state.signing_context, ValidatorIndex(2), &public2.into(), @@ -1513,3 +1763,232 @@ fn observes_backing_even_if_not_validator() { virtual_overseer }); } + +// Tests that it's impossible to second multiple candidates per relay parent +// without prospective parachains. +#[test] +fn cannot_second_multiple_candidates_per_parent() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + test_startup(&mut virtual_overseer, &test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); + + let pov_hash = pov.hash(); + let candidate_builder = TestCandidateBuilder { + para_id: test_state.chain_ids[0], + relay_parent: test_state.relay_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + }; + let candidate = candidate_builder.clone().build(); + + let second = CandidateBackingMessage::Second( + test_state.relay_parent, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CandidateValidation( + CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, + timeout, + tx, + ), + ) if _pvd == pvd && + _validation_code == validation_code && + *_pov == pov && &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash => + { + tx.send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: expected_head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + test_state.validation_data.clone(), + ))) + .unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::AvailabilityStore( + AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } + ) if candidate_hash == candidate.hash() => { + tx.send(Ok(())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == test_state.relay_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(test_state.relay_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + + // Try to second candidate with the same relay parent again. + + // Make sure the candidate hash is different. + let validation_code = ValidationCode(vec![4, 5, 6]); + let mut candidate_builder = candidate_builder; + candidate_builder.validation_code = validation_code.0.clone(); + let candidate = candidate_builder.build(); + + let second = CandidateBackingMessage::Second( + test_state.relay_parent, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + // The validation is still requested. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CandidateValidation( + CandidateValidationMessage::ValidateFromExhaustive(.., tx), + ) => { + tx.send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: expected_head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + test_state.validation_data.clone(), + ))) + .unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::AvailabilityStore( + AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } + ) if candidate_hash == candidate.hash() => { + tx.send(Ok(())).unwrap(); + } + ); + + // Validation done, but the candidate is rejected cause of 0-depth being already occupied. + + assert!(virtual_overseer + .recv() + .timeout(std::time::Duration::from_millis(50)) + .await + .is_none()); + + virtual_overseer + }); +} + +#[test] +fn new_leaf_view_doesnt_clobber_old() { + let mut test_state = TestState::default(); + let relay_parent_2 = Hash::repeat_byte(1); + assert_ne!(test_state.relay_parent, relay_parent_2); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + test_startup(&mut virtual_overseer, &test_state).await; + + // New leaf that doesn't clobber old. + { + let old_relay_parent = test_state.relay_parent; + test_state.relay_parent = relay_parent_2; + test_startup(&mut virtual_overseer, &test_state).await; + test_state.relay_parent = old_relay_parent; + } + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id: test_state.chain_ids[0], + relay_parent: test_state.relay_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + test_state.relay_parent, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + // If the old leaf was clobbered by the first, the seconded candidate + // would be ignored. + assert!( + virtual_overseer + .recv() + .timeout(std::time::Duration::from_millis(500)) + .await + .is_some(), + "first leaf appears to be inactive" + ); + + virtual_overseer + }); +} diff --git a/node/core/backing/src/tests/prospective_parachains.rs b/node/core/backing/src/tests/prospective_parachains.rs new file mode 100644 index 000000000000..7c2773c8e3b6 --- /dev/null +++ b/node/core/backing/src/tests/prospective_parachains.rs @@ -0,0 +1,1690 @@ +// Copyright 2022 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 . + +//! Tests for the backing subsystem with enabled prospective parachains. + +use polkadot_node_subsystem::{ + messages::{ChainApiMessage, FragmentTreeMembership}, + TimeoutExt, +}; +use polkadot_primitives::{vstaging as vstaging_primitives, BlockNumber, Header, OccupiedCore}; + +use super::*; + +const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParams = + vstaging_primitives::AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; + +struct TestLeaf { + activated: ActivatedLeaf, + min_relay_parents: Vec<(ParaId, u32)>, +} + +fn get_parent_hash(hash: Hash) -> Hash { + Hash::from_low_u64_be(hash.to_low_u64_be() + 1) +} + +async fn activate_leaf( + virtual_overseer: &mut VirtualOverseer, + leaf: TestLeaf, + test_state: &TestState, + seconded_in_view: usize, +) { + let TestLeaf { activated, min_relay_parents } = leaf; + let leaf_hash = activated.hash; + let leaf_number = activated.number; + // Start work on some new parent. + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( + activated, + )))) + .await; + + // Prospective parachains mode is temporarily defined by the Runtime API version. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) if parent == leaf_hash => { + tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); + } + ); + + let min_min = *min_relay_parents + .iter() + .map(|(_, block_num)| block_num) + .min() + .unwrap_or(&leaf_number); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetMinimumRelayParents(parent, tx) + ) if parent == leaf_hash => { + tx.send(min_relay_parents).unwrap(); + } + ); + + let ancestry_len = leaf_number + 1 - min_min; + + let ancestry_hashes = std::iter::successors(Some(leaf_hash), |h| Some(get_parent_hash(*h))) + .take(ancestry_len as usize); + let ancestry_numbers = (min_min..=leaf_number).rev(); + let ancestry_iter = ancestry_hashes.zip(ancestry_numbers).peekable(); + + let mut next_overseer_message = None; + // How many blocks were actually requested. + let mut requested_len = 0; + { + let mut ancestry_iter = ancestry_iter.clone(); + while let Some((hash, number)) = ancestry_iter.next() { + // May be `None` for the last element. + let parent_hash = + ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); + + let msg = virtual_overseer.recv().await; + // It may happen that some blocks were cached by implicit view, + // reuse the message. + if !matches!(&msg, AllMessages::ChainApi(ChainApiMessage::BlockHeader(..))) { + next_overseer_message.replace(msg); + break + } + + assert_matches!( + msg, + AllMessages::ChainApi( + ChainApiMessage::BlockHeader(_hash, tx) + ) if _hash == hash => { + let header = Header { + parent_hash, + number, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + }; + + tx.send(Ok(Some(header))).unwrap(); + } + ); + requested_len += 1; + } + } + + for _ in 0..seconded_in_view { + let msg = match next_overseer_message.take() { + Some(msg) => msg, + None => virtual_overseer.recv().await, + }; + assert_matches!( + msg, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetTreeMembership(.., tx), + ) => { + tx.send(Vec::new()).unwrap(); + } + ); + } + + for (hash, number) in ancestry_iter.take(requested_len) { + // Check that subsystem job issues a request for a validator set. + let msg = match next_overseer_message.take() { + Some(msg) => msg, + None => virtual_overseer.recv().await, + }; + assert_matches!( + msg, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.validator_public.clone())).unwrap(); + } + ); + + // Check that subsystem job issues a request for the validator groups. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx)) + ) if parent == hash => { + let (validator_groups, mut group_rotation_info) = test_state.validator_groups.clone(); + group_rotation_info.now = number; + tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); + } + ); + + // Check that subsystem job issues a request for the session index for child. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + } + ); + + // Check that subsystem job issues a request for the availability cores. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + } + ); + } +} + +async fn assert_validate_seconded_candidate( + virtual_overseer: &mut VirtualOverseer, + relay_parent: Hash, + candidate: &CommittedCandidateReceipt, + pov: &PoV, + pvd: &PersistedValidationData, + validation_code: &ValidationCode, + expected_head_data: &HeadData, + fetch_pov: bool, +) { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if parent == relay_parent && hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + } + ); + + if fetch_pov { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::AvailabilityDistribution( + AvailabilityDistributionMessage::FetchPoV { + relay_parent: hash, + tx, + .. + } + ) if hash == relay_parent => { + tx.send(pov.clone()).unwrap(); + } + ); + } + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive( + _pvd, + _validation_code, + candidate_receipt, + _pov, + timeout, + tx, + )) if &_pvd == pvd && + &_validation_code == validation_code && + &*_pov == pov && + &candidate_receipt.descriptor == candidate.descriptor() && + timeout == PvfExecTimeoutKind::Backing && + candidate.commitments.hash() == candidate_receipt.commitments_hash => + { + tx.send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: expected_head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + pvd.clone(), + ))) + .unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::AvailabilityStore( + AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } + ) if candidate_hash == candidate.hash() => { + tx.send(Ok(())).unwrap(); + } + ); +} + +async fn assert_hypothetical_frontier_requests( + virtual_overseer: &mut VirtualOverseer, + mut expected_requests: Vec<( + HypotheticalFrontierRequest, + Vec<(HypotheticalCandidate, FragmentTreeMembership)>, + )>, +) { + // Requests come with no particular order. + let requests_num = expected_requests.len(); + + for _ in 0..requests_num { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetHypotheticalFrontier(request, tx), + ) => { + let idx = match expected_requests.iter().position(|r| r.0 == request) { + Some(idx) => idx, + None => panic!( + "unexpected hypothetical frontier request, no match found for {:?}", + request + ), + }; + let resp = std::mem::take(&mut expected_requests[idx].1); + tx.send(resp).unwrap(); + + expected_requests.remove(idx); + } + ); + } +} + +fn make_hypothetical_frontier_response( + depths: Vec, + hypothetical_candidate: HypotheticalCandidate, + relay_parent_hash: Hash, +) -> Vec<(HypotheticalCandidate, FragmentTreeMembership)> { + vec![(hypothetical_candidate, vec![(relay_parent_hash, depths)])] +} + +// Test that `seconding_sanity_check` works when a candidate is allowed +// for all leaves. +#[test] +fn seconding_sanity_check_allowed() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + // `a` is grandparent of `b`. + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = ActivatedLeaf { + hash: leaf_a_hash, + number: LEAF_A_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; + + let leaf_b_hash = Hash::from_low_u64_be(128); + let activated = ActivatedLeaf { + hash: leaf_b_hash, + number: LEAF_B_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_a_hash), + backed_in_path_only: false, + }; + let expected_response_a = make_hypothetical_frontier_response( + vec![0, 1, 2, 3], + hypothetical_candidate.clone(), + leaf_a_hash, + ); + let expected_request_b = HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_b_hash), + backed_in_path_only: false, + }; + let expected_response_b = + make_hypothetical_frontier_response(vec![3], hypothetical_candidate, leaf_b_hash); + assert_hypothetical_frontier_requests( + &mut virtual_overseer, + vec![ + (expected_request_a, expected_response_a), + (expected_request_b, expected_response_b), + ], + ) + .await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + // Any non-empty response will do. + tx.send(vec![(leaf_a_hash, vec![0, 1, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( + _, + _ + )) + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == leaf_a_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(leaf_a_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + + virtual_overseer + }); +} + +// Test that `seconding_sanity_check` works when a candidate is disallowed +// for at least one leaf. +#[test] +fn seconding_sanity_check_disallowed() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_b_hash = Hash::from_low_u64_be(128); + // `a` is grandparent of `b`. + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = ActivatedLeaf { + hash: leaf_a_hash, + number: LEAF_A_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; + + let activated = ActivatedLeaf { + hash: leaf_b_hash, + number: LEAF_B_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_a_hash), + backed_in_path_only: false, + }; + let expected_response_a = make_hypothetical_frontier_response( + vec![0, 1, 2, 3], + hypothetical_candidate, + leaf_a_hash, + ); + assert_hypothetical_frontier_requests( + &mut virtual_overseer, + vec![(expected_request_a, expected_response_a)], + ) + .await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + // Any non-empty response will do. + tx.send(vec![(leaf_a_hash, vec![0, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( + _, + _ + )) + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == leaf_a_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(leaf_a_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + + // A seconded candidate occupies a depth, try to second another one. + // It is allowed in a new leaf but not allowed in the old one. + // Expect it to be rejected. + activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state, 1).await; + let leaf_a_grandparent = get_parent_hash(leaf_a_parent); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_grandparent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_grandparent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate), + persisted_validation_data: pvd, + }; + let expected_request_a = HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_a_hash), + backed_in_path_only: false, + }; + let expected_response_a = make_hypothetical_frontier_response( + vec![3], + hypothetical_candidate.clone(), + leaf_a_hash, + ); + let expected_request_b = HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_b_hash), + backed_in_path_only: false, + }; + let expected_response_b = + make_hypothetical_frontier_response(vec![1], hypothetical_candidate, leaf_b_hash); + assert_hypothetical_frontier_requests( + &mut virtual_overseer, + vec![ + (expected_request_a, expected_response_a), // All depths are occupied. + (expected_request_b, expected_response_b), + ], + ) + .await; + + assert!(virtual_overseer + .recv() + .timeout(std::time::Duration::from_millis(50)) + .await + .is_none()); + + virtual_overseer + }); +} + +// Test that a seconded candidate which is not approved by prospective parachains +// subsystem doesn't change the view. +#[test] +fn prospective_parachains_reject_candidate() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = ActivatedLeaf { + hash: leaf_a_hash, + number: LEAF_A_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = vec![( + HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_a_hash), + backed_in_path_only: false, + }, + make_hypothetical_frontier_response( + vec![0, 1, 2, 3], + hypothetical_candidate, + leaf_a_hash, + ), + )]; + assert_hypothetical_frontier_requests(&mut virtual_overseer, expected_request_a.clone()) + .await; + + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + // Reject it. + tx.send(Vec::new()).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Invalid( + relay_parent, + candidate_receipt, + )) if candidate_receipt.descriptor() == candidate.descriptor() && + candidate_receipt.commitments_hash == candidate.commitments.hash() && + relay_parent == leaf_a_parent + ); + + // Try seconding the same candidate. + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + assert_hypothetical_frontier_requests(&mut virtual_overseer, expected_request_a).await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + // Any non-empty response will do. + tx.send(vec![(leaf_a_hash, vec![0, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( + _, + _ + )) + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == leaf_a_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(leaf_a_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + + virtual_overseer + }); +} + +// Test that a validator can second multiple candidates per single relay parent. +#[test] +fn second_multiple_candidates_per_relay_parent() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a parent of the activated `leaf`. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + let leaf_grandparent = get_parent_hash(leaf_parent); + let activated = ActivatedLeaf { + hash: leaf_hash, + number: LEAF_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate_a = TestCandidateBuilder { + para_id, + relay_parent: leaf_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + }; + let mut candidate_b = candidate_a.clone(); + candidate_b.relay_parent = leaf_grandparent; + + // With depths. + let candidate_a = (candidate_a.build(), 1); + let candidate_b = (candidate_b.build(), 2); + + for candidate in &[candidate_a, candidate_b] { + let (candidate, depth) = candidate; + let second = CandidateBackingMessage::Second( + leaf_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + candidate.descriptor().relay_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = vec![( + HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_hash), + backed_in_path_only: false, + }, + make_hypothetical_frontier_response( + vec![*depth], + hypothetical_candidate, + leaf_hash, + ), + )]; + assert_hypothetical_frontier_requests( + &mut virtual_overseer, + expected_request_a.clone(), + ) + .await; + + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + &req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + // Any non-empty response will do. + tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateSeconded(_, _) + ) + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == candidate.descriptor().relay_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(candidate.descriptor().relay_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + } + + virtual_overseer + }); +} + +// Test that the candidate reaches quorum successfully. +#[test] +fn backing_works() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a parent of the activated `leaf`. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + let activated = ActivatedLeaf { + hash: leaf_hash, + number: LEAF_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + + let candidate_a = TestCandidateBuilder { + para_id, + relay_parent: leaf_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + validation_code: validation_code.0.clone(), + persisted_validation_data_hash: pvd.hash(), + } + .build(); + + let candidate_a_hash = candidate_a.hash(); + let candidate_a_para_head = candidate_a.descriptor().para_head; + + let public1 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[5].to_seed()), + ) + .expect("Insert key into keystore"); + let public2 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[2].to_seed()), + ) + .expect("Insert key into keystore"); + + // Signing context should have a parent hash candidate is based on. + let signing_context = + SigningContext { parent_hash: leaf_parent, session_index: test_state.session() }; + let signed_a = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), + &signing_context, + ValidatorIndex(2), + &public2.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let signed_b = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Valid(candidate_a_hash), + &signing_context, + ValidatorIndex(5), + &public1.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let statement = CandidateBackingMessage::Statement(leaf_parent, signed_a.clone()); + + virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + + // Prospective parachains are notified about candidate seconded first. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate_a + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + // Any non-empty response will do. + tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( + _, + _ + )) + ); + + assert_validate_seconded_candidate( + &mut virtual_overseer, + candidate_a.descriptor().relay_parent, + &candidate_a, + &pov, + &pvd, + &validation_code, + expected_head_data, + true, + ) + .await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share(hash, _stmt) + ) => { + assert_eq!(leaf_parent, hash); + } + ); + + // Prospective parachains and collator protocol are notified about candidate backed. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked( + candidate_para_id, candidate_hash + ), + ) if candidate_a_hash == candidate_hash && candidate_para_id == para_id + ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Backed { + para_id: _para_id, + para_head, + }) if para_id == _para_id && candidate_a_para_head == para_head + ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution(StatementDistributionMessage::Backed ( + candidate_hash + )) if candidate_a_hash == candidate_hash + ); + + let statement = CandidateBackingMessage::Statement(leaf_parent, signed_b.clone()); + + virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + + virtual_overseer + }); +} + +// Tests that validators start work on consecutive prospective parachain blocks. +#[test] +fn concurrent_dependent_candidates() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a grandparent of the activated `leaf`, + // candidate `b` -- in parent. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + let leaf_grandparent = get_parent_hash(leaf_parent); + let activated = ActivatedLeaf { + hash: leaf_hash, + number: LEAF_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let head_data = &[ + HeadData(vec![10, 20, 30]), // Before `a`. + HeadData(vec![11, 21, 31]), // After `a`. + HeadData(vec![12, 22]), // After `b`. + ]; + + let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd_a = PersistedValidationData { + parent_head: head_data[0].clone(), + relay_parent_number: LEAF_BLOCK_NUMBER - 2, + relay_parent_storage_root: Hash::zero(), + max_pov_size: 1024, + }; + + let pov_b = PoV { block_data: BlockData(vec![22, 14, 100]) }; + let pvd_b = PersistedValidationData { + parent_head: head_data[1].clone(), + relay_parent_number: LEAF_BLOCK_NUMBER - 1, + relay_parent_storage_root: Hash::zero(), + max_pov_size: 1024, + }; + let validation_code = ValidationCode(vec![1, 2, 3]); + + let candidate_a = TestCandidateBuilder { + para_id, + relay_parent: leaf_grandparent, + pov_hash: pov_a.hash(), + head_data: head_data[1].clone(), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), + persisted_validation_data_hash: pvd_a.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + let candidate_b = TestCandidateBuilder { + para_id, + relay_parent: leaf_parent, + pov_hash: pov_b.hash(), + head_data: head_data[2].clone(), + erasure_root: make_erasure_root(&test_state, pov_b.clone(), pvd_b.clone()), + persisted_validation_data_hash: pvd_b.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + let candidate_a_hash = candidate_a.hash(); + let candidate_b_hash = candidate_b.hash(); + + let public1 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[5].to_seed()), + ) + .expect("Insert key into keystore"); + let public2 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[2].to_seed()), + ) + .expect("Insert key into keystore"); + + // Signing context should have a parent hash candidate is based on. + let signing_context = + SigningContext { parent_hash: leaf_grandparent, session_index: test_state.session() }; + let signed_a = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate_a.clone(), pvd_a.clone()), + &signing_context, + ValidatorIndex(2), + &public2.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let signing_context = + SigningContext { parent_hash: leaf_parent, session_index: test_state.session() }; + let signed_b = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate_b.clone(), pvd_b.clone()), + &signing_context, + ValidatorIndex(5), + &public1.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let statement_a = CandidateBackingMessage::Statement(leaf_grandparent, signed_a.clone()); + let statement_b = CandidateBackingMessage::Statement(leaf_parent, signed_b.clone()); + + virtual_overseer.send(FromOrchestra::Communication { msg: statement_a }).await; + // At this point the subsystem waits for response, the previous message is received, + // send a second one without blocking. + let _ = virtual_overseer + .tx + .start_send_unpin(FromOrchestra::Communication { msg: statement_b }); + + let mut valid_statements = HashSet::new(); + let mut backed_statements = HashSet::new(); + + loop { + let msg = virtual_overseer + .recv() + .timeout(std::time::Duration::from_secs(1)) + .await + .expect("overseer recv timed out"); + + // Order is not guaranteed since we have 2 statements being handled concurrently. + match msg { + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate(_, tx), + ) => { + tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); + }, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateSeconded(_, _), + ) => {}, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::ValidationCodeByHash(_, tx), + )) => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + }, + AllMessages::AvailabilityDistribution( + AvailabilityDistributionMessage::FetchPoV { candidate_hash, tx, .. }, + ) => { + let pov = if candidate_hash == candidate_a_hash { + &pov_a + } else if candidate_hash == candidate_b_hash { + &pov_b + } else { + panic!("unknown candidate hash") + }; + tx.send(pov.clone()).unwrap(); + }, + AllMessages::CandidateValidation( + CandidateValidationMessage::ValidateFromExhaustive(.., candidate, _, _, tx), + ) => { + let candidate_hash = candidate.hash(); + let (head_data, pvd) = if candidate_hash == candidate_a_hash { + (&head_data[1], &pvd_a) + } else if candidate_hash == candidate_b_hash { + (&head_data[2], &pvd_b) + } else { + panic!("unknown candidate hash") + }; + tx.send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + pvd.clone(), + ))) + .unwrap(); + }, + AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { + tx, + .. + }) => { + tx.send(Ok(())).unwrap(); + }, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked(..), + ) => {}, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Backed { .. }) => {}, + AllMessages::StatementDistribution(StatementDistributionMessage::Share( + _, + statement, + )) => { + assert_eq!(statement.validator_index(), ValidatorIndex(0)); + let payload = statement.payload(); + assert_matches!( + payload.clone(), + StatementWithPVD::Valid(hash) + if hash == candidate_a_hash || hash == candidate_b_hash => + { + assert!(valid_statements.insert(hash)); + } + ); + }, + AllMessages::StatementDistribution(StatementDistributionMessage::Backed(hash)) => { + // Ensure that `Share` was received first for the candidate. + assert!(valid_statements.contains(&hash)); + backed_statements.insert(hash); + + if backed_statements.len() == 2 { + break + } + }, + _ => panic!("unexpected message received from overseer: {:?}", msg), + } + } + + assert!(valid_statements.contains(&candidate_a_hash)); + assert!(valid_statements.contains(&candidate_b_hash)); + assert!(backed_statements.contains(&candidate_a_hash)); + assert!(backed_statements.contains(&candidate_b_hash)); + + virtual_overseer + }); +} + +// Test that multiple candidates from different paras can occupy the same depth +// in a given relay parent. +#[test] +fn seconding_sanity_check_occupy_same_depth() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a parent of the activated `leaf`. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + + let para_id_a = test_state.chain_ids[0]; + let para_id_b = test_state.chain_ids[1]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + + let activated = ActivatedLeaf { + hash: leaf_hash, + number: LEAF_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + + let min_block_number = LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN; + let min_relay_parents = vec![(para_id_a, min_block_number), (para_id_b, min_block_number)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data_a = test_state.head_data.get(¶_id_a).unwrap(); + let expected_head_data_b = test_state.head_data.get(¶_id_b).unwrap(); + + let pov_hash = pov.hash(); + let candidate_a = TestCandidateBuilder { + para_id: para_id_a, + relay_parent: leaf_parent, + pov_hash, + head_data: expected_head_data_a.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + }; + + let mut candidate_b = candidate_a.clone(); + candidate_b.para_id = para_id_b; + candidate_b.head_data = expected_head_data_b.clone(); + // A rotation happens, test validator is assigned to second para here. + candidate_b.relay_parent = leaf_hash; + + let candidate_a = (candidate_a.build(), expected_head_data_a, para_id_a); + let candidate_b = (candidate_b.build(), expected_head_data_b, para_id_b); + + for candidate in &[candidate_a, candidate_b] { + let (candidate, expected_head_data, para_id) = candidate; + let second = CandidateBackingMessage::Second( + leaf_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + candidate.descriptor().relay_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = vec![( + HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_hash), + backed_in_path_only: false, + }, + // Send the same membership for both candidates. + make_hypothetical_frontier_response(vec![0, 1], hypothetical_candidate, leaf_hash), + )]; + + assert_hypothetical_frontier_requests( + &mut virtual_overseer, + expected_request_a.clone(), + ) + .await; + + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + &req.candidate_receipt == candidate + && &req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + // Any non-empty response will do. + tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateSeconded(_, _) + ) + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == candidate.descriptor().relay_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(candidate.descriptor().relay_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + } + + virtual_overseer + }); +} + +// Test that the subsystem doesn't skip occupied cores assignments. +#[test] +fn occupied_core_assignment() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + // Set the core state to occupied. + let mut candidate_descriptor = ::test_helpers::dummy_candidate_descriptor(Hash::zero()); + candidate_descriptor.para_id = para_id; + test_state.availability_cores[0] = CoreState::Occupied(OccupiedCore { + group_responsible: Default::default(), + next_up_on_available: None, + occupied_since: 100_u32, + time_out_at: 200_u32, + next_up_on_time_out: None, + availability: Default::default(), + candidate_descriptor, + candidate_hash: Default::default(), + }); + + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = ActivatedLeaf { + hash: leaf_a_hash, + number: LEAF_A_BLOCK_NUMBER, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request = vec![( + HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(leaf_a_hash), + backed_in_path_only: false, + }, + make_hypothetical_frontier_response( + vec![0, 1, 2, 3], + hypothetical_candidate, + leaf_a_hash, + ), + )]; + assert_hypothetical_frontier_requests(&mut virtual_overseer, expected_request).await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + // Any non-empty response will do. + tx.send(vec![(leaf_a_hash, vec![0, 1, 2, 3])]).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( + _, + _ + )) + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == leaf_a_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(leaf_a_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + + virtual_overseer + }); +} diff --git a/node/core/dispute-coordinator/src/scraping/tests.rs b/node/core/dispute-coordinator/src/scraping/tests.rs index d938304a9e97..3dd58a060d70 100644 --- a/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/node/core/dispute-coordinator/src/scraping/tests.rs @@ -136,8 +136,7 @@ fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { para_head: zeros, validation_code_hash: zeros.into(), }; - let candidate = CandidateReceipt { descriptor, commitments_hash: zeros }; - candidate + CandidateReceipt { descriptor, commitments_hash: zeros } } /// Get a dummy `ActivatedLeaf` for a given block number. diff --git a/node/core/prospective-parachains/Cargo.toml b/node/core/prospective-parachains/Cargo.toml new file mode 100644 index 000000000000..b088202d3736 --- /dev/null +++ b/node/core/prospective-parachains/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "polkadot-node-core-prospective-parachains" +version = "0.9.16" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +futures = "0.3.19" +gum = { package = "tracing-gum", path = "../../gum" } +parity-scale-codec = "2" +thiserror = "1.0.30" +fatality = "0.0.6" +bitvec = "1" + +polkadot-primitives = { path = "../../../primitives" } +polkadot-node-primitives = { path = "../../primitives" } +polkadot-node-subsystem = { path = "../../subsystem" } +polkadot-node-subsystem-util = { path = "../../subsystem-util" } + +[dev-dependencies] +assert_matches = "1" +polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } +polkadot-node-subsystem-types = { path = "../../subsystem-types" } +polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/node/core/prospective-parachains/src/error.rs b/node/core/prospective-parachains/src/error.rs new file mode 100644 index 000000000000..0ad98d1ff908 --- /dev/null +++ b/node/core/prospective-parachains/src/error.rs @@ -0,0 +1,87 @@ +// Copyright 2022 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 . + +//! Error types. + +use futures::channel::oneshot; + +use polkadot_node_subsystem::{ + errors::{ChainApiError, RuntimeApiError}, + SubsystemError, +}; +use polkadot_node_subsystem_util::runtime; + +use crate::LOG_TARGET; +use fatality::Nested; + +#[allow(missing_docs)] +#[fatality::fatality(splitable)] +pub enum Error { + #[fatal] + #[error("SubsystemError::Context error: {0}")] + SubsystemContext(String), + + #[fatal] + #[error("Spawning a task failed: {0}")] + SpawnFailed(SubsystemError), + + #[fatal] + #[error("Participation worker receiver exhausted.")] + ParticipationWorkerReceiverExhausted, + + #[fatal] + #[error("Receiving message from overseer failed: {0}")] + SubsystemReceive(#[source] SubsystemError), + + #[error("Error while accessing runtime information")] + Runtime(#[from] runtime::Error), + + #[error(transparent)] + RuntimeApi(#[from] RuntimeApiError), + + #[error(transparent)] + ChainApi(#[from] ChainApiError), + + #[error(transparent)] + Subsystem(SubsystemError), + + #[error("Request to chain API subsystem dropped")] + ChainApiRequestCanceled(oneshot::Canceled), + + #[error("Request to runtime API subsystem dropped")] + RuntimeApiRequestCanceled(oneshot::Canceled), +} + +/// General `Result` type. +pub type Result = std::result::Result; +/// Result for non-fatal only failures. +pub type JfyiErrorResult = std::result::Result; +/// Result for fatal only failures. +pub type FatalResult = std::result::Result; + +/// Utility for eating top level errors and log them. +/// +/// We basically always want to try and continue on error. This utility function is meant to +/// consume top-level errors by simply logging them +pub fn log_error(result: Result<()>, ctx: &'static str) -> FatalResult<()> { + match result.into_nested()? { + Ok(()) => Ok(()), + Err(jfyi) => { + gum::debug!(target: LOG_TARGET, error = ?jfyi, ctx); + Ok(()) + }, + } +} diff --git a/node/core/prospective-parachains/src/fragment_tree.rs b/node/core/prospective-parachains/src/fragment_tree.rs new file mode 100644 index 000000000000..ec06f2d6070e --- /dev/null +++ b/node/core/prospective-parachains/src/fragment_tree.rs @@ -0,0 +1,1991 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A tree utility for managing parachain fragments not referenced by the relay-chain. +//! +//! # Overview +//! +//! This module exposes two main types: [`FragmentTree`] and [`CandidateStorage`] which are meant to +//! be used in close conjunction. Each fragment tree is associated with a particular relay-parent +//! and each node in the tree represents a candidate. Each parachain has a single candidate storage, +//! but can have multiple trees for each relay chain block in the view. +//! +//! A tree has an associated [`Scope`] which defines limits on candidates within the tree. +//! Candidates themselves have their own [`Constraints`] which are either the constraints from the +//! scope, or, if there are previous nodes in the tree, a modified version of the previous +//! candidate's constraints. +//! +//! This module also makes use of types provided by the Inclusion Emulator module, such as +//! [`Fragment`] and [`Constraints`]. These perform the actual job of checking for validity of +//! prospective fragments. +//! +//! # Usage +//! +//! It's expected that higher-level code will have a tree for each relay-chain block which might +//! reasonably have blocks built upon it. +//! +//! Because a para only has a single candidate storage, trees only store indices into the storage. +//! The storage is meant to be pruned when trees are dropped by higher-level code. +//! +//! # Cycles +//! +//! Nodes do not uniquely refer to a parachain block for two reasons. +//! 1. There's no requirement that head-data is unique for a parachain. Furthermore, a parachain +//! is under no obligation to be acyclic, and this is mostly just because it's totally +//! inefficient to enforce it. Practical use-cases are acyclic, but there is still more than +//! one way to reach the same head-data. +//! 2. and candidates only refer to their parent by its head-data. This whole issue could be +//! resolved by having candidates reference their parent by candidate hash. +//! +//! The implication is that when we receive a candidate receipt, there are actually multiple +//! possibilities for any candidates between the para-head recorded in the relay parent's state +//! and the candidate in question. +//! +//! This means that our candidates need to handle multiple parents and that depth is an +//! attribute of a node in a tree, not a candidate. Put another way, the same candidate might +//! have different depths in different parts of the tree. +//! +//! As an extreme example, a candidate which produces head-data which is the same as its parent +//! can correspond to multiple nodes within the same [`FragmentTree`]. Such cycles are bounded +//! by the maximum depth allowed by the tree. An example with `max_depth: 4`: +//! +//! ```text +//! committed head +//! | +//! depth 0: head_a +//! | +//! depth 1: head_b +//! | +//! depth 2: head_a +//! | +//! depth 3: head_b +//! | +//! depth 4: head_a +//! ``` +//! +//! As long as the [`CandidateStorage`] has bounded input on the number of candidates supplied, +//! [`FragmentTree`] complexity is bounded. This means that higher-level code needs to be selective +//! about limiting the amount of candidates that are considered. +//! +//! The code in this module is not designed for speed or efficiency, but conceptual simplicity. +//! Our assumption is that the amount of candidates and parachains we consider will be reasonably +//! bounded and in practice will not exceed a few thousand at any time. This naive implementation +//! will still perform fairly well under these conditions, despite being somewhat wasteful of +//! memory. + +use std::{ + borrow::Cow, + collections::{ + hash_map::{Entry, HashMap}, + BTreeMap, HashSet, + }, +}; + +use super::LOG_TARGET; +use bitvec::prelude::*; +use polkadot_node_subsystem_util::inclusion_emulator::staging::{ + ConstraintModifications, Constraints, Fragment, ProspectiveCandidate, RelayChainBlockInfo, +}; +use polkadot_primitives::vstaging::{ + BlockNumber, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, + PersistedValidationData, +}; + +/// Kinds of failures to import a candidate into storage. +#[derive(Debug, Clone, PartialEq)] +pub enum CandidateStorageInsertionError { + /// An error indicating that a supplied candidate didn't match the persisted + /// validation data provided alongside it. + PersistedValidationDataMismatch, + /// The candidate was already known. + CandidateAlreadyKnown(CandidateHash), +} + +/// Stores candidates and information about them such as their relay-parents and their backing +/// states. +pub(crate) struct CandidateStorage { + // Index from head data hash to candidate hashes with that head data as a parent. + by_parent_head: HashMap>, + + // Index from head data hash to candidate hashes outputting that head data. + by_output_head: HashMap>, + + // Index from candidate hash to fragment node. + by_candidate_hash: HashMap, +} + +impl CandidateStorage { + /// Create a new `CandidateStorage`. + pub fn new() -> Self { + CandidateStorage { + by_parent_head: HashMap::new(), + by_output_head: HashMap::new(), + by_candidate_hash: HashMap::new(), + } + } + + /// Introduce a new candidate. + pub fn add_candidate( + &mut self, + candidate: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + ) -> Result { + let candidate_hash = candidate.hash(); + + if self.by_candidate_hash.contains_key(&candidate_hash) { + return Err(CandidateStorageInsertionError::CandidateAlreadyKnown(candidate_hash)) + } + + if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash { + return Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) + } + + let parent_head_hash = persisted_validation_data.parent_head.hash(); + let output_head_hash = candidate.commitments.head_data.hash(); + let entry = CandidateEntry { + candidate_hash, + relay_parent: candidate.descriptor.relay_parent, + state: CandidateState::Introduced, + candidate: ProspectiveCandidate { + commitments: Cow::Owned(candidate.commitments), + collator: candidate.descriptor.collator, + collator_signature: candidate.descriptor.signature, + persisted_validation_data, + pov_hash: candidate.descriptor.pov_hash, + validation_code_hash: candidate.descriptor.validation_code_hash, + }, + }; + + self.by_parent_head.entry(parent_head_hash).or_default().insert(candidate_hash); + self.by_output_head.entry(output_head_hash).or_default().insert(candidate_hash); + // sanity-checked already. + self.by_candidate_hash.insert(candidate_hash, entry); + + Ok(candidate_hash) + } + + /// Remove a candidate from the store. + pub fn remove_candidate(&mut self, candidate_hash: &CandidateHash) { + if let Some(entry) = self.by_candidate_hash.remove(candidate_hash) { + let parent_head_hash = entry.candidate.persisted_validation_data.parent_head.hash(); + if let Entry::Occupied(mut e) = self.by_parent_head.entry(parent_head_hash) { + e.get_mut().remove(&candidate_hash); + if e.get().is_empty() { + e.remove(); + } + } + } + } + + /// Note that an existing candidate has been seconded. + pub fn mark_seconded(&mut self, candidate_hash: &CandidateHash) { + if let Some(entry) = self.by_candidate_hash.get_mut(candidate_hash) { + if entry.state != CandidateState::Backed { + entry.state = CandidateState::Seconded; + } + } + } + + /// Note that an existing candidate has been backed. + pub fn mark_backed(&mut self, candidate_hash: &CandidateHash) { + if let Some(entry) = self.by_candidate_hash.get_mut(candidate_hash) { + entry.state = CandidateState::Backed; + } + } + + /// Whether a candidate is recorded as being backed. + pub fn is_backed(&self, candidate_hash: &CandidateHash) -> bool { + self.by_candidate_hash + .get(candidate_hash) + .map_or(false, |e| e.state == CandidateState::Backed) + } + + /// Whether a candidate is contained within the storage already. + pub fn contains(&self, candidate_hash: &CandidateHash) -> bool { + self.by_candidate_hash.contains_key(candidate_hash) + } + + /// Retain only candidates which pass the predicate. + pub(crate) fn retain(&mut self, pred: impl Fn(&CandidateHash) -> bool) { + self.by_candidate_hash.retain(|h, _v| pred(h)); + self.by_parent_head.retain(|_parent, children| { + children.retain(|h| pred(h)); + !children.is_empty() + }); + self.by_output_head.retain(|_output, candidates| { + candidates.retain(|h| pred(h)); + !candidates.is_empty() + }); + } + + /// Get head-data by hash. + pub(crate) fn head_data_by_hash(&self, hash: &Hash) -> Option<&HeadData> { + // First, search for candidates outputting this head data and extract the head data + // from their commitments if they exist. + // + // Otherwise, search for candidates building upon this head data and extract the head data + // from their persisted validation data if they exist. + self.by_output_head + .get(hash) + .and_then(|m| m.iter().next()) + .and_then(|a_candidate| self.by_candidate_hash.get(a_candidate)) + .map(|e| &e.candidate.commitments.head_data) + .or_else(|| { + self.by_parent_head + .get(hash) + .and_then(|m| m.iter().next()) + .and_then(|a_candidate| self.by_candidate_hash.get(a_candidate)) + .map(|e| &e.candidate.persisted_validation_data.parent_head) + }) + } + + /// Returns candidate's relay parent, if present. + pub(crate) fn relay_parent_by_candidate_hash( + &self, + candidate_hash: &CandidateHash, + ) -> Option { + self.by_candidate_hash.get(candidate_hash).map(|entry| entry.relay_parent) + } + + fn iter_para_children<'a>( + &'a self, + parent_head_hash: &Hash, + ) -> impl Iterator + 'a { + let by_candidate_hash = &self.by_candidate_hash; + self.by_parent_head + .get(parent_head_hash) + .into_iter() + .flat_map(|hashes| hashes.iter()) + .filter_map(move |h| by_candidate_hash.get(h)) + } + + fn get(&'_ self, candidate_hash: &CandidateHash) -> Option<&'_ CandidateEntry> { + self.by_candidate_hash.get(candidate_hash) + } + + #[cfg(test)] + pub fn len(&self) -> (usize, usize) { + (self.by_parent_head.len(), self.by_candidate_hash.len()) + } +} + +/// The state of a candidate. +/// +/// Candidates aren't even considered until they've at least been seconded. +#[derive(Debug, PartialEq)] +enum CandidateState { + /// The candidate has been introduced in a spam-protected way but + /// is not necessarily backed. + Introduced, + /// The candidate has been seconded. + Seconded, + /// The candidate has been completely backed by the group. + Backed, +} + +#[derive(Debug)] +struct CandidateEntry { + candidate_hash: CandidateHash, + relay_parent: Hash, + candidate: ProspectiveCandidate<'static>, + state: CandidateState, +} + +/// A candidate existing on-chain but pending availability, for special treatment +/// in the [`Scope`]. +#[derive(Debug, Clone)] +pub(crate) struct PendingAvailability { + /// The candidate hash. + pub candidate_hash: CandidateHash, + /// The block info of the relay parent. + pub relay_parent: RelayChainBlockInfo, +} + +/// The scope of a [`FragmentTree`]. +#[derive(Debug)] +pub(crate) struct Scope { + para: ParaId, + relay_parent: RelayChainBlockInfo, + ancestors: BTreeMap, + ancestors_by_hash: HashMap, + pending_availability: Vec, + base_constraints: Constraints, + max_depth: usize, +} + +/// An error variant indicating that ancestors provided to a scope +/// had unexpected order. +#[derive(Debug)] +pub struct UnexpectedAncestor { + /// The block number that this error occurred at. + pub number: BlockNumber, + /// The previous seen block number, which did not match `number`. + pub prev: BlockNumber, +} + +impl Scope { + /// Define a new [`Scope`]. + /// + /// All arguments are straightforward except the ancestors. + /// + /// Ancestors should be in reverse order, starting with the parent + /// of the `relay_parent`, and proceeding backwards in block number + /// increments of 1. Ancestors not following these conditions will be + /// rejected. + /// + /// This function will only consume ancestors up to the `min_relay_parent_number` of + /// the `base_constraints`. + /// + /// Only ancestors whose children have the same session as the relay-parent's + /// children should be provided. + /// + /// It is allowed to provide zero ancestors. + pub fn with_ancestors( + para: ParaId, + relay_parent: RelayChainBlockInfo, + base_constraints: Constraints, + pending_availability: Vec, + max_depth: usize, + ancestors: impl IntoIterator, + ) -> Result { + let mut ancestors_map = BTreeMap::new(); + let mut ancestors_by_hash = HashMap::new(); + { + let mut prev = relay_parent.number; + for ancestor in ancestors { + if prev == 0 { + return Err(UnexpectedAncestor { number: ancestor.number, prev }) + } else if ancestor.number != prev - 1 { + return Err(UnexpectedAncestor { number: ancestor.number, prev }) + } else if prev == base_constraints.min_relay_parent_number { + break + } else { + prev = ancestor.number; + ancestors_by_hash.insert(ancestor.hash, ancestor.clone()); + ancestors_map.insert(ancestor.number, ancestor); + } + } + } + + Ok(Scope { + para, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors: ancestors_map, + ancestors_by_hash, + }) + } + + /// Get the earliest relay-parent allowed in the scope of the fragment tree. + pub fn earliest_relay_parent(&self) -> RelayChainBlockInfo { + self.ancestors + .iter() + .next() + .map(|(_, v)| v.clone()) + .unwrap_or_else(|| self.relay_parent.clone()) + } + + /// Get the ancestor of the fragment tree by hash. + pub fn ancestor_by_hash(&self, hash: &Hash) -> Option { + if hash == &self.relay_parent.hash { + return Some(self.relay_parent.clone()) + } + + self.ancestors_by_hash.get(hash).map(|info| info.clone()) + } + + /// Whether the candidate in question is one pending availability in this scope. + pub fn get_pending_availability( + &self, + candidate_hash: &CandidateHash, + ) -> Option<&PendingAvailability> { + self.pending_availability.iter().find(|c| &c.candidate_hash == candidate_hash) + } + + /// Get the base constraints of the scope + pub fn base_constraints(&self) -> &Constraints { + &self.base_constraints + } +} + +/// We use indices into a flat vector to refer to nodes in the tree. +/// Every tree also has an implicit root. +#[derive(Debug, Clone, Copy, PartialEq)] +enum NodePointer { + Root, + Storage(usize), +} + +/// A hypothetical candidate, which may or may not exist in +/// the fragment tree already. +pub(crate) enum HypotheticalCandidate<'a> { + Complete { + receipt: Cow<'a, CommittedCandidateReceipt>, + persisted_validation_data: Cow<'a, PersistedValidationData>, + }, + Incomplete { + relay_parent: Hash, + parent_head_data_hash: Hash, + }, +} + +impl<'a> HypotheticalCandidate<'a> { + fn parent_head_data_hash(&self) -> Hash { + match *self { + HypotheticalCandidate::Complete { ref persisted_validation_data, .. } => + persisted_validation_data.as_ref().parent_head.hash(), + HypotheticalCandidate::Incomplete { ref parent_head_data_hash, .. } => + *parent_head_data_hash, + } + } + + fn relay_parent(&self) -> Hash { + match *self { + HypotheticalCandidate::Complete { ref receipt, .. } => + receipt.descriptor().relay_parent, + HypotheticalCandidate::Incomplete { ref relay_parent, .. } => *relay_parent, + } + } +} + +/// This is a tree of candidates based on some underlying storage of candidates and a scope. +/// +/// All nodes in the tree must be either pending availability or within the scope. Within the scope +/// means it's built off of the relay-parent or an ancestor. +pub(crate) struct FragmentTree { + scope: Scope, + + // Invariant: a contiguous prefix of the 'nodes' storage will contain + // the top-level children. + nodes: Vec, + + // The candidates stored in this tree, mapped to a bitvec indicating the depths + // where the candidate is stored. + candidates: HashMap>, +} + +impl FragmentTree { + /// Create a new [`FragmentTree`] with given scope and populated from the storage. + /// + /// Can be populated recursively (i.e. `populate` will pick up candidates that build on other + /// candidates). + pub fn populate(scope: Scope, storage: &CandidateStorage) -> Self { + gum::trace!( + target: LOG_TARGET, + relay_parent = ?scope.relay_parent.hash, + relay_parent_num = scope.relay_parent.number, + para_id = ?scope.para, + ancestors = scope.ancestors.len(), + "Instantiating Fragment Tree", + ); + + let mut tree = FragmentTree { scope, nodes: Vec::new(), candidates: HashMap::new() }; + + tree.populate_from_bases(storage, vec![NodePointer::Root]); + + tree + } + + /// Get the scope of the Fragment Tree. + pub fn scope(&self) -> &Scope { + &self.scope + } + + // Inserts a node and updates child references in a non-root parent. + fn insert_node(&mut self, node: FragmentNode) { + let pointer = NodePointer::Storage(self.nodes.len()); + let parent_pointer = node.parent; + let candidate_hash = node.candidate_hash; + + let max_depth = self.scope.max_depth; + + self.candidates + .entry(candidate_hash) + .or_insert_with(|| bitvec![u16, Msb0; 0; max_depth + 1]) + .set(node.depth, true); + + match parent_pointer { + NodePointer::Storage(ptr) => { + self.nodes.push(node); + self.nodes[ptr].children.push((pointer, candidate_hash)) + }, + NodePointer::Root => { + // Maintain the invariant of node storage beginning with depth-0. + if self.nodes.last().map_or(true, |last| last.parent == NodePointer::Root) { + self.nodes.push(node); + } else { + let pos = + self.nodes.iter().take_while(|n| n.parent == NodePointer::Root).count(); + self.nodes.insert(pos, node); + } + }, + } + } + + fn node_has_candidate_child( + &self, + pointer: NodePointer, + candidate_hash: &CandidateHash, + ) -> bool { + self.node_candidate_child(pointer, candidate_hash).is_some() + } + + fn node_candidate_child( + &self, + pointer: NodePointer, + candidate_hash: &CandidateHash, + ) -> Option { + match pointer { + NodePointer::Root => self + .nodes + .iter() + .take_while(|n| n.parent == NodePointer::Root) + .enumerate() + .find(|(_, n)| &n.candidate_hash == candidate_hash) + .map(|(i, _)| NodePointer::Storage(i)), + NodePointer::Storage(ptr) => + self.nodes.get(ptr).and_then(|n| n.candidate_child(candidate_hash)), + } + } + + /// Returns an O(n) iterator over the hashes of candidates contained in the + /// tree. + pub(crate) fn candidates(&self) -> impl Iterator + '_ { + self.candidates.keys().cloned() + } + + /// Whether the candidate exists and at what depths. + pub(crate) fn candidate(&self, candidate: &CandidateHash) -> Option> { + self.candidates.get(candidate).map(|d| d.iter_ones().collect()) + } + + /// Add a candidate and recursively populate from storage. + /// + /// Candidates can be added either as children of the root or children of other candidates. + pub(crate) fn add_and_populate(&mut self, hash: CandidateHash, storage: &CandidateStorage) { + let candidate_entry = match storage.get(&hash) { + None => return, + Some(e) => e, + }; + + let candidate_parent = &candidate_entry.candidate.persisted_validation_data.parent_head; + + // Select an initial set of bases, whose required relay-parent matches that of the + // candidate. + let root_base = if &self.scope.base_constraints.required_parent == candidate_parent { + Some(NodePointer::Root) + } else { + None + }; + + let non_root_bases = self + .nodes + .iter() + .enumerate() + .filter(|(_, n)| { + n.cumulative_modifications.required_parent.as_ref() == Some(candidate_parent) + }) + .map(|(i, _)| NodePointer::Storage(i)); + + let bases = root_base.into_iter().chain(non_root_bases).collect(); + + // Pass this into the population function, which will sanity-check stuff like depth, + // fragments, etc. and then recursively populate. + self.populate_from_bases(storage, bases); + } + + /// Returns `true` if the path from the root to the node's parent (inclusive) + /// only contains backed candidates, `false` otherwise. + fn path_contains_backed_only_candidates( + &self, + mut parent_pointer: NodePointer, + candidate_storage: &CandidateStorage, + ) -> bool { + while let NodePointer::Storage(ptr) = parent_pointer { + let node = &self.nodes[ptr]; + let candidate_hash = &node.candidate_hash; + + if candidate_storage.get(candidate_hash).map_or(true, |candidate_entry| { + !matches!(candidate_entry.state, CandidateState::Backed) + }) { + return false + } + parent_pointer = node.parent; + } + + true + } + + /// Returns the hypothetical depths where a candidate with the given hash and parent head data + /// would be added to the tree, without applying other candidates recursively on top of it. + /// + /// If the candidate is already known, this returns the actual depths where this + /// candidate is part of the tree. + /// + /// Setting `backed_in_path_only` to `true` ensures this function only returns such membership + /// that every candidate in the path from the root is backed. + pub(crate) fn hypothetical_depths( + &self, + hash: CandidateHash, + candidate: HypotheticalCandidate, + candidate_storage: &CandidateStorage, + backed_in_path_only: bool, + ) -> Vec { + // if `true`, we always have to traverse the tree. + if !backed_in_path_only { + // if known. + if let Some(depths) = self.candidates.get(&hash) { + return depths.iter_ones().collect() + } + } + + // if out of scope. + let candidate_relay_parent = candidate.relay_parent(); + let candidate_relay_parent = if self.scope.relay_parent.hash == candidate_relay_parent { + self.scope.relay_parent.clone() + } else if let Some(info) = self.scope.ancestors_by_hash.get(&candidate_relay_parent) { + info.clone() + } else { + return Vec::new() + }; + + let max_depth = self.scope.max_depth; + let mut depths = bitvec![u16, Msb0; 0; max_depth + 1]; + + // iterate over all nodes where parent head-data matches, + // relay-parent number is <= candidate, and depth < max_depth. + let node_pointers = (0..self.nodes.len()).map(NodePointer::Storage); + for parent_pointer in std::iter::once(NodePointer::Root).chain(node_pointers) { + let (modifications, child_depth, earliest_rp) = match parent_pointer { + NodePointer::Root => + (ConstraintModifications::identity(), 0, self.scope.earliest_relay_parent()), + NodePointer::Storage(ptr) => { + let node = &self.nodes[ptr]; + let parent_rp = self + .scope + .ancestor_by_hash(&node.relay_parent()) + .or_else(|| { + self.scope + .get_pending_availability(&node.candidate_hash) + .map(|_| self.scope.earliest_relay_parent()) + }) + .expect("All nodes in tree are either pending availability or within scope; qed"); + + (node.cumulative_modifications.clone(), node.depth + 1, parent_rp) + }, + }; + + if child_depth > max_depth { + continue + } + + if earliest_rp.number > candidate_relay_parent.number { + continue + } + + let child_constraints = + match self.scope.base_constraints.apply_modifications(&modifications) { + Err(e) => { + gum::debug!( + target: LOG_TARGET, + new_parent_head = ?modifications.required_parent, + err = ?e, + "Failed to apply modifications", + ); + + continue + }, + Ok(c) => c, + }; + + let parent_head_hash = candidate.parent_head_data_hash(); + if parent_head_hash != child_constraints.required_parent.hash() { + continue + } + + // We do additional checks for complete candidates. + if let HypotheticalCandidate::Complete { ref receipt, ref persisted_validation_data } = + candidate + { + let prospective_candidate = ProspectiveCandidate { + commitments: Cow::Borrowed(&receipt.commitments), + collator: receipt.descriptor().collator.clone(), + collator_signature: receipt.descriptor().signature.clone(), + persisted_validation_data: persisted_validation_data.as_ref().clone(), + pov_hash: receipt.descriptor().pov_hash, + validation_code_hash: receipt.descriptor().validation_code_hash, + }; + + if Fragment::new( + candidate_relay_parent.clone(), + child_constraints, + prospective_candidate, + ) + .is_err() + { + continue + } + } + + // Check that the path only contains backed candidates, if necessary. + if !backed_in_path_only || + self.path_contains_backed_only_candidates(parent_pointer, candidate_storage) + { + depths.set(child_depth, true); + } + } + + depths.iter_ones().collect() + } + + /// Select a candidate after the given `required_path` which passes + /// the predicate. + /// + /// If there are multiple possibilities, this will select the first one. + /// + /// This returns `None` if there is no candidate meeting those criteria. + /// + /// The intention of the `required_path` is to allow queries on the basis of + /// one or more candidates which were previously pending availability becoming + /// available and opening up more room on the core. + pub(crate) fn select_child( + &self, + required_path: &[CandidateHash], + pred: impl Fn(&CandidateHash) -> bool, + ) -> Option { + let base_node = { + // traverse the required path. + let mut node = NodePointer::Root; + for required_step in required_path { + node = self.node_candidate_child(node, &required_step)?; + } + + node + }; + + // TODO [now]: taking the first selection might introduce bias + // or become gameable. + // + // For plausibly unique parachains, this shouldn't matter much. + // figure out alternative selection criteria? + match base_node { + NodePointer::Root => self + .nodes + .iter() + .take_while(|n| n.parent == NodePointer::Root) + .filter(|n| self.scope.get_pending_availability(&n.candidate_hash).is_none()) + .filter(|n| pred(&n.candidate_hash)) + .map(|n| n.candidate_hash) + .next(), + NodePointer::Storage(ptr) => self.nodes[ptr] + .children + .iter() + .filter(|n| self.scope.get_pending_availability(&n.1).is_none()) + .filter(|n| pred(&n.1)) + .map(|n| n.1) + .next(), + } + } + + fn populate_from_bases(&mut self, storage: &CandidateStorage, initial_bases: Vec) { + // Populate the tree breadth-first. + let mut last_sweep_start = None; + + loop { + let sweep_start = self.nodes.len(); + + if Some(sweep_start) == last_sweep_start { + break + } + + let parents: Vec = if let Some(last_start) = last_sweep_start { + (last_start..self.nodes.len()).map(NodePointer::Storage).collect() + } else { + initial_bases.clone() + }; + + // 1. get parent head and find constraints + // 2. iterate all candidates building on the right head and viable relay parent + // 3. add new node + for parent_pointer in parents { + let (modifications, child_depth, earliest_rp) = match parent_pointer { + NodePointer::Root => + (ConstraintModifications::identity(), 0, self.scope.earliest_relay_parent()), + NodePointer::Storage(ptr) => { + let node = &self.nodes[ptr]; + let parent_rp = self + .scope + .ancestor_by_hash(&node.relay_parent()) + .or_else(|| { + // if the relay-parent is out of scope _and_ it is in the tree, + // it must be a candidate pending availability. + self.scope + .get_pending_availability(&node.candidate_hash) + .map(|c| c.relay_parent.clone()) + }) + .expect("All nodes in tree are either pending availability or within scope; qed"); + + (node.cumulative_modifications.clone(), node.depth + 1, parent_rp) + }, + }; + + if child_depth > self.scope.max_depth { + continue + } + + let child_constraints = + match self.scope.base_constraints.apply_modifications(&modifications) { + Err(e) => { + gum::debug!( + target: LOG_TARGET, + new_parent_head = ?modifications.required_parent, + err = ?e, + "Failed to apply modifications", + ); + + continue + }, + Ok(c) => c, + }; + + // Add nodes to tree wherever + // 1. parent hash is correct + // 2. relay-parent does not move backwards. + // 3. all non-pending-availability candidates have relay-parent in scope. + // 4. candidate outputs fulfill constraints + let required_head_hash = child_constraints.required_parent.hash(); + for candidate in storage.iter_para_children(&required_head_hash) { + let pending = self.scope.get_pending_availability(&candidate.candidate_hash); + let relay_parent = pending + .map(|p| p.relay_parent.clone()) + .or_else(|| self.scope.ancestor_by_hash(&candidate.relay_parent)); + + let relay_parent = match relay_parent { + Some(r) => r, + None => continue, + }; + + // require: pending availability candidates don't move backwards + // and only those can be out-of-scope. + // + // earliest_rp can be before the earliest relay parent in the scope + // when the parent is a pending availability candidate as well, but + // only other pending candidates can have a relay parent out of scope. + let min_relay_parent_number = pending + .map(|p| match parent_pointer { + NodePointer::Root => p.relay_parent.number, + NodePointer::Storage(_) => earliest_rp.number, + }) + .unwrap_or_else(|| { + std::cmp::max( + earliest_rp.number, + self.scope.earliest_relay_parent().number, + ) + }); + + if relay_parent.number < min_relay_parent_number { + continue // relay parent moved backwards. + } + + // don't add candidates where the parent already has it as a child. + if self.node_has_candidate_child(parent_pointer, &candidate.candidate_hash) { + continue + } + + let fragment = { + let mut constraints = child_constraints.clone(); + if let Some(ref p) = pending { + // overwrite for candidates pending availability as a special-case. + constraints.min_relay_parent_number = p.relay_parent.number; + } + + let f = Fragment::new( + relay_parent.clone(), + constraints, + candidate.candidate.partial_clone(), + ); + + match f { + Ok(f) => f.into_owned(), + Err(e) => { + gum::debug!( + target: LOG_TARGET, + err = ?e, + ?relay_parent, + candidate_hash = ?candidate.candidate_hash, + "Failed to instantiate fragment", + ); + + continue + }, + } + }; + + let mut cumulative_modifications = modifications.clone(); + cumulative_modifications.stack(fragment.constraint_modifications()); + + let node = FragmentNode { + parent: parent_pointer, + fragment, + candidate_hash: candidate.candidate_hash, + depth: child_depth, + cumulative_modifications, + children: Vec::new(), + }; + + self.insert_node(node); + } + } + + last_sweep_start = Some(sweep_start); + } + } +} + +struct FragmentNode { + // A pointer to the parent node. + parent: NodePointer, + fragment: Fragment<'static>, + candidate_hash: CandidateHash, + depth: usize, + cumulative_modifications: ConstraintModifications, + children: Vec<(NodePointer, CandidateHash)>, +} + +impl FragmentNode { + fn relay_parent(&self) -> Hash { + self.fragment.relay_parent().hash + } + + fn candidate_child(&self, candidate_hash: &CandidateHash) -> Option { + self.children.iter().find(|(_, c)| c == candidate_hash).map(|(p, _)| *p) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + use polkadot_node_subsystem_util::inclusion_emulator::staging::InboundHrmpLimitations; + use polkadot_primitives::vstaging::{ + BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData, + }; + use polkadot_primitives_test_helpers as test_helpers; + + fn make_constraints( + min_relay_parent_number: BlockNumber, + valid_watermarks: Vec, + required_parent: HeadData, + ) -> Constraints { + Constraints { + min_relay_parent_number, + max_pov_size: 1_000_000, + max_code_size: 1_000_000, + ump_remaining: 10, + ump_remaining_bytes: 1_000, + max_ump_num_per_candidate: 10, + dmp_remaining_messages: [0; 10].into(), + hrmp_inbound: InboundHrmpLimitations { valid_watermarks }, + hrmp_channels_out: HashMap::new(), + max_hrmp_num_per_candidate: 0, + required_parent, + validation_code_hash: Hash::repeat_byte(42).into(), + upgrade_restriction: None, + future_validation_code: None, + } + } + + fn make_committed_candidate( + para_id: ParaId, + relay_parent: Hash, + relay_parent_number: BlockNumber, + parent_head: HeadData, + para_head: HeadData, + hrmp_watermark: BlockNumber, + ) -> (PersistedValidationData, CommittedCandidateReceipt) { + let persisted_validation_data = PersistedValidationData { + parent_head, + relay_parent_number, + relay_parent_storage_root: Hash::repeat_byte(69), + max_pov_size: 1_000_000, + }; + + let candidate = CommittedCandidateReceipt { + descriptor: CandidateDescriptor { + para_id, + relay_parent, + collator: test_helpers::dummy_collator(), + persisted_validation_data_hash: persisted_validation_data.hash(), + pov_hash: Hash::repeat_byte(1), + erasure_root: Hash::repeat_byte(1), + signature: test_helpers::dummy_collator_signature(), + para_head: para_head.hash(), + validation_code_hash: Hash::repeat_byte(42).into(), + }, + commitments: CandidateCommitments { + upward_messages: Default::default(), + horizontal_messages: Default::default(), + new_validation_code: None, + head_data: para_head, + processed_downward_messages: 1, + hrmp_watermark, + }, + }; + + (persisted_validation_data, candidate) + } + + #[test] + fn scope_rejects_ancestors_that_skip_blocks() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 10, + hash: Hash::repeat_byte(10), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![RelayChainBlockInfo { + number: 8, + hash: Hash::repeat_byte(8), + storage_root: Hash::repeat_byte(69), + }]; + + let max_depth = 2; + let base_constraints = make_constraints(8, vec![8, 9], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + assert_matches!( + Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors + ), + Err(UnexpectedAncestor { number: 8, prev: 10 }) + ); + } + + #[test] + fn scope_rejects_ancestor_for_0_block() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 0, + hash: Hash::repeat_byte(0), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![RelayChainBlockInfo { + number: 99999, + hash: Hash::repeat_byte(99), + storage_root: Hash::repeat_byte(69), + }]; + + let max_depth = 2; + let base_constraints = make_constraints(0, vec![], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + assert_matches!( + Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors, + ), + Err(UnexpectedAncestor { number: 99999, prev: 0 }) + ); + } + + #[test] + fn scope_only_takes_ancestors_up_to_min() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 5, + hash: Hash::repeat_byte(0), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![ + RelayChainBlockInfo { + number: 4, + hash: Hash::repeat_byte(4), + storage_root: Hash::repeat_byte(69), + }, + RelayChainBlockInfo { + number: 3, + hash: Hash::repeat_byte(3), + storage_root: Hash::repeat_byte(69), + }, + RelayChainBlockInfo { + number: 2, + hash: Hash::repeat_byte(2), + storage_root: Hash::repeat_byte(69), + }, + ]; + + let max_depth = 2; + let base_constraints = make_constraints(3, vec![2], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + let scope = Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors, + ) + .unwrap(); + + assert_eq!(scope.ancestors.len(), 2); + assert_eq!(scope.ancestors_by_hash.len(), 2); + } + + #[test] + fn storage_add_candidate() { + let mut storage = CandidateStorage::new(); + let relay_parent = Hash::repeat_byte(69); + + let (pvd, candidate) = make_committed_candidate( + ParaId::from(5u32), + relay_parent, + 8, + vec![4, 5, 6].into(), + vec![1, 2, 3].into(), + 7, + ); + + let candidate_hash = candidate.hash(); + let parent_head_hash = pvd.parent_head.hash(); + + storage.add_candidate(candidate, pvd).unwrap(); + assert!(storage.contains(&candidate_hash)); + assert_eq!(storage.iter_para_children(&parent_head_hash).count(), 1); + + assert_eq!(storage.relay_parent_by_candidate_hash(&candidate_hash), Some(relay_parent)); + } + + #[test] + fn storage_retain() { + let mut storage = CandidateStorage::new(); + + let (pvd, candidate) = make_committed_candidate( + ParaId::from(5u32), + Hash::repeat_byte(69), + 8, + vec![4, 5, 6].into(), + vec![1, 2, 3].into(), + 7, + ); + + let candidate_hash = candidate.hash(); + let output_head_hash = candidate.commitments.head_data.hash(); + let parent_head_hash = pvd.parent_head.hash(); + + storage.add_candidate(candidate, pvd).unwrap(); + storage.retain(|_| true); + assert!(storage.contains(&candidate_hash)); + assert_eq!(storage.iter_para_children(&parent_head_hash).count(), 1); + assert!(storage.head_data_by_hash(&output_head_hash).is_some()); + + storage.retain(|_| false); + assert!(!storage.contains(&candidate_hash)); + assert_eq!(storage.iter_para_children(&parent_head_hash).count(), 0); + assert!(storage.head_data_by_hash(&output_head_hash).is_none()); + } + + // [`FragmentTree::populate`] should pick up candidates that build on other candidates. + #[test] + fn populate_works_recursively() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + let relay_parent_b = Hash::repeat_byte(2); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_b, + 1, + vec![0x0b].into(), + vec![0x0c].into(), + 1, + ); + let candidate_b_hash = candidate_b.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let ancestors = vec![RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }]; + + let relay_parent_b_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number, + hash: relay_parent_b, + storage_root: pvd_b.relay_parent_storage_root, + }; + + storage.add_candidate(candidate_a, pvd_a).unwrap(); + storage.add_candidate(candidate_b, pvd_b).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_b_info, + base_constraints, + pending_availability, + 4, + ancestors, + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 2); + assert!(candidates.contains(&candidate_a_hash)); + assert!(candidates.contains(&candidate_b_hash)); + + assert_eq!(tree.nodes.len(), 2); + assert_eq!(tree.nodes[0].parent, NodePointer::Root); + assert_eq!(tree.nodes[0].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[0].depth, 0); + + assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); + assert_eq!(tree.nodes[1].candidate_hash, candidate_b_hash); + assert_eq!(tree.nodes[1].depth, 1); + } + + #[test] + fn children_of_root_are_contiguous() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + let relay_parent_b = Hash::repeat_byte(2); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_b, + 1, + vec![0x0b].into(), + vec![0x0c].into(), + 1, + ); + + let (pvd_a2, candidate_a2) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b, 1].into(), + 0, + ); + let candidate_a2_hash = candidate_a2.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let ancestors = vec![RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }]; + + let relay_parent_b_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number, + hash: relay_parent_b, + storage_root: pvd_b.relay_parent_storage_root, + }; + + storage.add_candidate(candidate_a, pvd_a).unwrap(); + storage.add_candidate(candidate_b, pvd_b).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_b_info, + base_constraints, + pending_availability, + 4, + ancestors, + ) + .unwrap(); + let mut tree = FragmentTree::populate(scope, &storage); + + storage.add_candidate(candidate_a2, pvd_a2).unwrap(); + tree.add_and_populate(candidate_a2_hash, &storage); + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 3); + + assert_eq!(tree.nodes[0].parent, NodePointer::Root); + assert_eq!(tree.nodes[1].parent, NodePointer::Root); + assert_eq!(tree.nodes[2].parent, NodePointer::Storage(0)); + } + + #[test] + fn add_candidate_child_of_root() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0c].into(), + 0, + ); + let candidate_b_hash = candidate_b.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + storage.add_candidate(candidate_a, pvd_a).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + 4, + vec![], + ) + .unwrap(); + let mut tree = FragmentTree::populate(scope, &storage); + + storage.add_candidate(candidate_b, pvd_b).unwrap(); + tree.add_and_populate(candidate_b_hash, &storage); + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 2); + + assert_eq!(tree.nodes[0].parent, NodePointer::Root); + assert_eq!(tree.nodes[1].parent, NodePointer::Root); + } + + #[test] + fn add_candidate_child_of_non_root() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0b].into(), + vec![0x0c].into(), + 0, + ); + let candidate_b_hash = candidate_b.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + storage.add_candidate(candidate_a, pvd_a).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + 4, + vec![], + ) + .unwrap(); + let mut tree = FragmentTree::populate(scope, &storage); + + storage.add_candidate(candidate_b, pvd_b).unwrap(); + tree.add_and_populate(candidate_b_hash, &storage); + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 2); + + assert_eq!(tree.nodes[0].parent, NodePointer::Root); + assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); + } + + #[test] + fn graceful_cycle_of_0() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0a].into(), // input same as output + 0, + ); + let candidate_a_hash = candidate_a.hash(); + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 1); + assert_eq!(tree.nodes.len(), max_depth + 1); + + assert_eq!(tree.nodes[0].parent, NodePointer::Root); + assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); + assert_eq!(tree.nodes[2].parent, NodePointer::Storage(1)); + assert_eq!(tree.nodes[3].parent, NodePointer::Storage(2)); + assert_eq!(tree.nodes[4].parent, NodePointer::Storage(3)); + + assert_eq!(tree.nodes[0].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[1].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[2].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[3].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[4].candidate_hash, candidate_a_hash); + } + + #[test] + fn graceful_cycle_of_1() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), // input same as output + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0b].into(), + vec![0x0a].into(), // input same as output + 0, + ); + let candidate_b_hash = candidate_b.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a).unwrap(); + storage.add_candidate(candidate_b, pvd_b).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 2); + assert_eq!(tree.nodes.len(), max_depth + 1); + + assert_eq!(tree.nodes[0].parent, NodePointer::Root); + assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); + assert_eq!(tree.nodes[2].parent, NodePointer::Storage(1)); + assert_eq!(tree.nodes[3].parent, NodePointer::Storage(2)); + assert_eq!(tree.nodes[4].parent, NodePointer::Storage(3)); + + assert_eq!(tree.nodes[0].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[1].candidate_hash, candidate_b_hash); + assert_eq!(tree.nodes[2].candidate_hash, candidate_a_hash); + assert_eq!(tree.nodes[3].candidate_hash, candidate_b_hash); + assert_eq!(tree.nodes[4].candidate_hash, candidate_a_hash); + } + + #[test] + fn hypothetical_depths_known_and_unknown() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), // input same as output + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0b].into(), + vec![0x0a].into(), // input same as output + 0, + ); + let candidate_b_hash = candidate_b.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a).unwrap(); + storage.add_candidate(candidate_b, pvd_b).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 2); + assert_eq!(tree.nodes.len(), max_depth + 1); + + assert_eq!( + tree.hypothetical_depths( + candidate_a_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + false, + ), + vec![0, 2, 4], + ); + + assert_eq!( + tree.hypothetical_depths( + candidate_b_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + false, + ), + vec![1, 3], + ); + + assert_eq!( + tree.hypothetical_depths( + CandidateHash(Hash::repeat_byte(21)), + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + false, + ), + vec![0, 2, 4], + ); + + assert_eq!( + tree.hypothetical_depths( + CandidateHash(Hash::repeat_byte(22)), + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + false, + ), + vec![1, 3] + ); + } + + #[test] + fn hypothetical_depths_stricter_on_complete() { + let storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 1000, // watermark is illegal + ); + + let candidate_a_hash = candidate_a.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + assert_eq!( + tree.hypothetical_depths( + candidate_a_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + false, + ), + vec![0], + ); + + assert!(tree + .hypothetical_depths( + candidate_a_hash, + HypotheticalCandidate::Complete { + receipt: Cow::Owned(candidate_a), + persisted_validation_data: Cow::Owned(pvd_a), + }, + &storage, + false, + ) + .is_empty()); + } + + #[test] + fn hypothetical_depths_backed_in_path() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0b].into(), + vec![0x0c].into(), + 0, + ); + let candidate_b_hash = candidate_b.hash(); + + let (pvd_c, candidate_c) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0b].into(), + vec![0x0d].into(), + 0, + ); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a).unwrap(); + storage.add_candidate(candidate_b, pvd_b).unwrap(); + storage.add_candidate(candidate_c, pvd_c).unwrap(); + + // `A` and `B` are backed, `C` is not. + storage.mark_backed(&candidate_a_hash); + storage.mark_backed(&candidate_b_hash); + + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + max_depth, + vec![], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 3); + assert_eq!(tree.nodes.len(), 3); + + let candidate_d_hash = CandidateHash(Hash::repeat_byte(0xAA)); + + assert_eq!( + tree.hypothetical_depths( + candidate_d_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + true, + ), + vec![0], + ); + + assert_eq!( + tree.hypothetical_depths( + candidate_d_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + true, + ), + vec![2], + ); + + assert_eq!( + tree.hypothetical_depths( + candidate_d_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0d]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + true, + ), + Vec::::new(), + ); + + assert_eq!( + tree.hypothetical_depths( + candidate_d_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0d]).hash(), + relay_parent: relay_parent_a, + }, + &storage, + false, + ), + vec![2], // non-empty if `false`. + ); + } + + #[test] + fn pending_availability_in_scope() { + let mut storage = CandidateStorage::new(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + let relay_parent_b = Hash::repeat_byte(2); + let relay_parent_c = Hash::repeat_byte(3); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_b, + 1, + vec![0x0b].into(), + vec![0x0c].into(), + 1, + ); + + // Note that relay parent `a` is not allowed. + let base_constraints = make_constraints(1, vec![], vec![0x0a].into()); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + let pending_availability = vec![PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_a_info, + }]; + + let relay_parent_b_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number, + hash: relay_parent_b, + storage_root: pvd_b.relay_parent_storage_root, + }; + let relay_parent_c_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number + 1, + hash: relay_parent_c, + storage_root: Hash::zero(), + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a).unwrap(); + storage.add_candidate(candidate_b, pvd_b).unwrap(); + storage.mark_backed(&candidate_a_hash); + + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info, + base_constraints, + pending_availability, + max_depth, + vec![relay_parent_b_info], + ) + .unwrap(); + let tree = FragmentTree::populate(scope, &storage); + + let candidates: Vec<_> = tree.candidates().collect(); + assert_eq!(candidates.len(), 2); + assert_eq!(tree.nodes.len(), 2); + + let candidate_d_hash = CandidateHash(Hash::repeat_byte(0xAA)); + + assert_eq!( + tree.hypothetical_depths( + candidate_d_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), + relay_parent: relay_parent_c, + }, + &storage, + false, + ), + vec![1], + ); + + assert_eq!( + tree.hypothetical_depths( + candidate_d_hash, + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), + relay_parent: relay_parent_b, + }, + &storage, + false, + ), + vec![2], + ); + } +} diff --git a/node/core/prospective-parachains/src/lib.rs b/node/core/prospective-parachains/src/lib.rs new file mode 100644 index 000000000000..a7f37d873d6a --- /dev/null +++ b/node/core/prospective-parachains/src/lib.rs @@ -0,0 +1,939 @@ +// Copyright 2022-2023 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 . + +//! Implementation of the Prospective Parachains subsystem - this tracks and handles +//! prospective parachain fragments and informs other backing-stage subsystems +//! of work to be done. +//! +//! This is the main coordinator of work within the node for the collation and +//! backing phases of parachain consensus. +//! +//! This is primarily an implementation of "Fragment Trees", as described in +//! [`polkadot_node_subsystem_util::inclusion_emulator::staging`]. +//! +//! This subsystem also handles concerns such as the relay-chain being forkful and session changes. + +use std::{ + borrow::Cow, + collections::{HashMap, HashSet}, +}; + +use futures::{channel::oneshot, prelude::*}; + +use polkadot_node_subsystem::{ + messages::{ + ChainApiMessage, FragmentTreeMembership, HypotheticalCandidate, + HypotheticalFrontierRequest, IntroduceCandidateRequest, ProspectiveParachainsMessage, + ProspectiveValidationDataRequest, RuntimeApiMessage, RuntimeApiRequest, + }, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, +}; +use polkadot_node_subsystem_util::{ + inclusion_emulator::staging::{Constraints, RelayChainBlockInfo}, + request_session_index_for_child, + runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, +}; +use polkadot_primitives::vstaging::{ + BlockNumber, CandidateHash, CandidatePendingAvailability, CommittedCandidateReceipt, CoreState, + Hash, HeadData, Header, Id as ParaId, PersistedValidationData, +}; + +use crate::{ + error::{FatalError, FatalResult, JfyiError, JfyiErrorResult, Result}, + fragment_tree::{ + CandidateStorage, CandidateStorageInsertionError, FragmentTree, Scope as TreeScope, + }, +}; + +mod error; +mod fragment_tree; +#[cfg(test)] +mod tests; + +mod metrics; +use self::metrics::Metrics; + +const LOG_TARGET: &str = "parachain::prospective-parachains"; + +struct RelayBlockViewData { + // Scheduling info for paras and upcoming paras. + fragment_trees: HashMap, + pending_availability: HashSet, +} + +struct View { + // Active or recent relay-chain blocks by block hash. + active_leaves: HashMap, + candidate_storage: HashMap, +} + +impl View { + fn new() -> Self { + View { active_leaves: HashMap::new(), candidate_storage: HashMap::new() } + } +} + +/// The prospective parachains subsystem. +#[derive(Default)] +pub struct ProspectiveParachainsSubsystem { + metrics: Metrics, +} + +impl ProspectiveParachainsSubsystem { + /// Create a new instance of the `ProspectiveParachainsSubsystem`. + pub fn new(metrics: Metrics) -> Self { + Self { metrics } + } +} + +#[overseer::subsystem(ProspectiveParachains, error = SubsystemError, prefix = self::overseer)] +impl ProspectiveParachainsSubsystem +where + Context: Send + Sync, +{ + fn start(self, ctx: Context) -> SpawnedSubsystem { + SpawnedSubsystem { + future: run(ctx, self.metrics) + .map_err(|e| SubsystemError::with_origin("prospective-parachains", e)) + .boxed(), + name: "prospective-parachains-subsystem", + } + } +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn run(mut ctx: Context, metrics: Metrics) -> FatalResult<()> { + let mut view = View::new(); + loop { + crate::error::log_error( + run_iteration(&mut ctx, &mut view, &metrics).await, + "Encountered issue during run iteration", + )?; + } +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn run_iteration( + ctx: &mut Context, + view: &mut View, + metrics: &Metrics, +) -> Result<()> { + loop { + match ctx.recv().await.map_err(FatalError::SubsystemReceive)? { + FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), + FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { + handle_active_leaves_update(&mut *ctx, view, update, metrics).await?; + }, + FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {}, + FromOrchestra::Communication { msg } => match msg { + ProspectiveParachainsMessage::IntroduceCandidate(request, tx) => + handle_candidate_introduced(&mut *ctx, view, request, tx).await?, + ProspectiveParachainsMessage::CandidateSeconded(para, candidate_hash) => + handle_candidate_seconded(view, para, candidate_hash), + ProspectiveParachainsMessage::CandidateBacked(para, candidate_hash) => + handle_candidate_backed(&mut *ctx, view, para, candidate_hash).await?, + ProspectiveParachainsMessage::GetBackableCandidate( + relay_parent, + para, + required_path, + tx, + ) => answer_get_backable_candidate(&view, relay_parent, para, required_path, tx), + ProspectiveParachainsMessage::GetHypotheticalFrontier(request, tx) => + answer_hypothetical_frontier_request(&view, request, tx), + ProspectiveParachainsMessage::GetTreeMembership(para, candidate, tx) => + answer_tree_membership_request(&view, para, candidate, tx), + ProspectiveParachainsMessage::GetMinimumRelayParents(relay_parent, tx) => + answer_minimum_relay_parents_request(&view, relay_parent, tx), + ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx) => + answer_prospective_validation_data_request(&view, request, tx), + }, + } + } +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn handle_active_leaves_update( + ctx: &mut Context, + view: &mut View, + update: ActiveLeavesUpdate, + metrics: &Metrics, +) -> JfyiErrorResult<()> { + // 1. clean up inactive leaves + // 2. determine all scheduled para at new block + // 3. construct new fragment tree for each para for each new leaf + // 4. prune candidate storage. + + for deactivated in &update.deactivated { + view.active_leaves.remove(deactivated); + } + + let mut temp_header_cache = HashMap::new(); + for activated in update.activated.into_iter() { + let hash = activated.hash; + + let mode = prospective_parachains_mode(ctx.sender(), hash) + .await + .map_err(JfyiError::Runtime)?; + + let ProspectiveParachainsMode::Enabled { max_candidate_depth, allowed_ancestry_len } = mode + else { + gum::trace!( + target: LOG_TARGET, + block_hash = ?hash, + "Skipping leaf activation since async backing is disabled" + ); + + // Not a part of any allowed ancestry. + return Ok(()) + }; + + let mut pending_availability = HashSet::new(); + let scheduled_paras = + fetch_upcoming_paras(&mut *ctx, hash, &mut pending_availability).await?; + + let block_info: RelayChainBlockInfo = + match fetch_block_info(&mut *ctx, &mut temp_header_cache, hash).await? { + None => { + gum::warn!( + target: LOG_TARGET, + block_hash = ?hash, + "Failed to get block info for newly activated leaf block." + ); + + // `update.activated` is an option, but we can use this + // to exit the 'loop' and skip this block without skipping + // pruning logic. + continue + }, + Some(info) => info, + }; + + let ancestry = + fetch_ancestry(&mut *ctx, &mut temp_header_cache, hash, allowed_ancestry_len).await?; + + // Find constraints. + let mut fragment_trees = HashMap::new(); + for para in scheduled_paras { + let candidate_storage = + view.candidate_storage.entry(para).or_insert_with(CandidateStorage::new); + + let backing_state = fetch_backing_state(&mut *ctx, hash, para).await?; + + let (constraints, pending_availability) = match backing_state { + Some(c) => c, + None => { + // This indicates a runtime conflict of some kind. + + gum::debug!( + target: LOG_TARGET, + para_id = ?para, + relay_parent = ?hash, + "Failed to get inclusion backing state." + ); + + continue + }, + }; + + let pending_availability = preprocess_candidates_pending_availability( + ctx, + &mut temp_header_cache, + constraints.required_parent.clone(), + pending_availability, + ) + .await?; + let mut compact_pending = Vec::with_capacity(pending_availability.len()); + + for c in pending_availability { + let res = candidate_storage.add_candidate(c.candidate, c.persisted_validation_data); + let candidate_hash = c.compact.candidate_hash; + compact_pending.push(c.compact); + + match res { + Ok(_) | Err(CandidateStorageInsertionError::CandidateAlreadyKnown(_)) => { + // Anything on-chain is guaranteed to be backed. + candidate_storage.mark_backed(&candidate_hash); + }, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?candidate_hash, + para_id = ?para, + ?err, + "Scraped invalid candidate pending availability", + ); + }, + } + } + + let scope = TreeScope::with_ancestors( + para, + block_info.clone(), + constraints, + compact_pending, + max_candidate_depth, + ancestry.iter().cloned(), + ) + .expect("ancestors are provided in reverse order and correctly; qed"); + + let tree = FragmentTree::populate(scope, &*candidate_storage); + + fragment_trees.insert(para, tree); + } + + view.active_leaves + .insert(hash, RelayBlockViewData { fragment_trees, pending_availability }); + } + + if !update.deactivated.is_empty() { + // This has potential to be a hotspot. + prune_view_candidate_storage(view, metrics); + } + + Ok(()) +} + +fn prune_view_candidate_storage(view: &mut View, metrics: &Metrics) { + metrics.time_prune_view_candidate_storage(); + + let active_leaves = &view.active_leaves; + let mut live_candidates = HashSet::new(); + let mut live_paras = HashSet::new(); + for sub_view in active_leaves.values() { + for (para_id, fragment_tree) in &sub_view.fragment_trees { + live_candidates.extend(fragment_tree.candidates()); + live_paras.insert(*para_id); + } + + live_candidates.extend(sub_view.pending_availability.iter().cloned()); + } + + view.candidate_storage.retain(|para_id, storage| { + if !live_paras.contains(¶_id) { + return false + } + + storage.retain(|h| live_candidates.contains(&h)); + + // Even if `storage` is now empty, we retain. + // This maintains a convenient invariant that para-id storage exists + // as long as there's an active head which schedules the para. + true + }) +} + +struct ImportablePendingAvailability { + candidate: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + compact: crate::fragment_tree::PendingAvailability, +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn preprocess_candidates_pending_availability( + ctx: &mut Context, + cache: &mut HashMap, + required_parent: HeadData, + pending_availability: Vec, +) -> JfyiErrorResult> { + let mut required_parent = required_parent; + + let mut importable = Vec::new(); + let expected_count = pending_availability.len(); + + for (i, pending) in pending_availability.into_iter().enumerate() { + let relay_parent = + match fetch_block_info(ctx, cache, pending.descriptor.relay_parent).await? { + None => { + gum::debug!( + target: LOG_TARGET, + ?pending.candidate_hash, + ?pending.descriptor.para_id, + index = ?i, + ?expected_count, + "Had to stop processing pending candidates early due to missing info.", + ); + + break + }, + Some(b) => b, + }; + + let next_required_parent = pending.commitments.head_data.clone(); + importable.push(ImportablePendingAvailability { + candidate: CommittedCandidateReceipt { + descriptor: pending.descriptor, + commitments: pending.commitments, + }, + persisted_validation_data: PersistedValidationData { + parent_head: required_parent, + max_pov_size: pending.max_pov_size, + relay_parent_number: relay_parent.number, + relay_parent_storage_root: relay_parent.storage_root, + }, + compact: crate::fragment_tree::PendingAvailability { + candidate_hash: pending.candidate_hash, + relay_parent, + }, + }); + + required_parent = next_required_parent; + } + + Ok(importable) +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn handle_candidate_introduced( + _ctx: &mut Context, + view: &mut View, + request: IntroduceCandidateRequest, + tx: oneshot::Sender, +) -> JfyiErrorResult<()> { + let IntroduceCandidateRequest { + candidate_para: para, + candidate_receipt: candidate, + persisted_validation_data: pvd, + } = request; + + // Add the candidate to storage. + // Then attempt to add it to all trees. + let storage = match view.candidate_storage.get_mut(¶) { + None => { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + candidate_hash = ?candidate.hash(), + "Received seconded candidate for inactive para", + ); + + let _ = tx.send(Vec::new()); + return Ok(()) + }, + Some(storage) => storage, + }; + + let candidate_hash = match storage.add_candidate(candidate, pvd) { + Ok(c) => c, + Err(CandidateStorageInsertionError::CandidateAlreadyKnown(c)) => { + // Candidate known - return existing fragment tree membership. + let _ = tx.send(fragment_tree_membership(&view.active_leaves, para, c)); + return Ok(()) + }, + Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) => { + // We can't log the candidate hash without either doing more ~expensive + // hashing but this branch indicates something is seriously wrong elsewhere + // so it's doubtful that it would affect debugging. + + gum::warn!( + target: LOG_TARGET, + para = ?para, + "Received seconded candidate had mismatching validation data", + ); + + let _ = tx.send(Vec::new()); + return Ok(()) + }, + }; + + let mut membership = Vec::new(); + for (relay_parent, leaf_data) in &mut view.active_leaves { + if let Some(tree) = leaf_data.fragment_trees.get_mut(¶) { + tree.add_and_populate(candidate_hash, &*storage); + if let Some(depths) = tree.candidate(&candidate_hash) { + membership.push((*relay_parent, depths)); + } + } + } + + if membership.is_empty() { + storage.remove_candidate(&candidate_hash); + } + + let _ = tx.send(membership); + + Ok(()) +} + +fn handle_candidate_seconded(view: &mut View, para: ParaId, candidate_hash: CandidateHash) { + let storage = match view.candidate_storage.get_mut(¶) { + None => { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received instruction to second unknown candidate", + ); + + return + }, + Some(storage) => storage, + }; + + if !storage.contains(&candidate_hash) { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received instruction to second unknown candidate", + ); + + return + } + + storage.mark_seconded(&candidate_hash); +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn handle_candidate_backed( + _ctx: &mut Context, + view: &mut View, + para: ParaId, + candidate_hash: CandidateHash, +) -> JfyiErrorResult<()> { + let storage = match view.candidate_storage.get_mut(¶) { + None => { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received instruction to back unknown candidate", + ); + + return Ok(()) + }, + Some(storage) => storage, + }; + + if !storage.contains(&candidate_hash) { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received instruction to back unknown candidate", + ); + + return Ok(()) + } + + if storage.is_backed(&candidate_hash) { + gum::debug!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received redundant instruction to mark candidate as backed", + ); + + return Ok(()) + } + + storage.mark_backed(&candidate_hash); + Ok(()) +} + +fn answer_get_backable_candidate( + view: &View, + relay_parent: Hash, + para: ParaId, + required_path: Vec, + tx: oneshot::Sender>, +) { + let data = match view.active_leaves.get(&relay_parent) { + None => { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "Requested backable candidate for inactive relay-parent." + ); + + let _ = tx.send(None); + return + }, + Some(d) => d, + }; + + let tree = match data.fragment_trees.get(¶) { + None => { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "Requested backable candidate for inactive para." + ); + + let _ = tx.send(None); + return + }, + Some(tree) => tree, + }; + + let storage = match view.candidate_storage.get(¶) { + None => { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "No candidate storage for active para", + ); + + let _ = tx.send(None); + return + }, + Some(s) => s, + }; + + let Some(child_hash) = + tree.select_child(&required_path, |candidate| storage.is_backed(candidate)) + else { + let _ = tx.send(None); + return + }; + let Some(candidate_relay_parent) = storage.relay_parent_by_candidate_hash(&child_hash) else { + gum::error!( + target: LOG_TARGET, + ?child_hash, + para_id = ?para, + "Candidate is present in fragment tree but not in candidate's storage!", + ); + let _ = tx.send(None); + return + }; + + let _ = tx.send(Some((child_hash, candidate_relay_parent))); +} + +fn answer_hypothetical_frontier_request( + view: &View, + request: HypotheticalFrontierRequest, + tx: oneshot::Sender>, +) { + let mut response = Vec::with_capacity(request.candidates.len()); + for candidate in request.candidates { + response.push((candidate, Vec::new())); + } + + let required_active_leaf = request.fragment_tree_relay_parent; + for (active_leaf, leaf_view) in view + .active_leaves + .iter() + .filter(|(h, _)| required_active_leaf.as_ref().map_or(true, |x| h == &x)) + { + for &mut (ref c, ref mut membership) in &mut response { + let fragment_tree = match leaf_view.fragment_trees.get(&c.candidate_para()) { + None => continue, + Some(f) => f, + }; + let candidate_storage = match view.candidate_storage.get(&c.candidate_para()) { + None => continue, + Some(storage) => storage, + }; + + let candidate_hash = c.candidate_hash(); + let hypothetical = match c { + HypotheticalCandidate::Complete { receipt, persisted_validation_data, .. } => + fragment_tree::HypotheticalCandidate::Complete { + receipt: Cow::Borrowed(receipt), + persisted_validation_data: Cow::Borrowed(persisted_validation_data), + }, + HypotheticalCandidate::Incomplete { + parent_head_data_hash, + candidate_relay_parent, + .. + } => fragment_tree::HypotheticalCandidate::Incomplete { + relay_parent: *candidate_relay_parent, + parent_head_data_hash: *parent_head_data_hash, + }, + }; + + let depths = fragment_tree.hypothetical_depths( + candidate_hash, + hypothetical, + candidate_storage, + request.backed_in_path_only, + ); + + if !depths.is_empty() { + membership.push((*active_leaf, depths)); + } + } + } + + let _ = tx.send(response); +} + +fn fragment_tree_membership( + active_leaves: &HashMap, + para: ParaId, + candidate: CandidateHash, +) -> FragmentTreeMembership { + let mut membership = Vec::new(); + for (relay_parent, view_data) in active_leaves { + if let Some(tree) = view_data.fragment_trees.get(¶) { + if let Some(depths) = tree.candidate(&candidate) { + membership.push((*relay_parent, depths)); + } + } + } + membership +} + +fn answer_tree_membership_request( + view: &View, + para: ParaId, + candidate: CandidateHash, + tx: oneshot::Sender, +) { + let _ = tx.send(fragment_tree_membership(&view.active_leaves, para, candidate)); +} + +fn answer_minimum_relay_parents_request( + view: &View, + relay_parent: Hash, + tx: oneshot::Sender>, +) { + let mut v = Vec::new(); + if let Some(leaf_data) = view.active_leaves.get(&relay_parent) { + for (para_id, fragment_tree) in &leaf_data.fragment_trees { + v.push((*para_id, fragment_tree.scope().earliest_relay_parent().number)); + } + } + + let _ = tx.send(v); +} + +fn answer_prospective_validation_data_request( + view: &View, + request: ProspectiveValidationDataRequest, + tx: oneshot::Sender>, +) { + // 1. Try to get the head-data from the candidate store if known. + // 2. Otherwise, it might exist as the base in some relay-parent and we can find it by iterating + // fragment trees. + // 3. Otherwise, it is unknown. + // 4. Also try to find the relay parent block info by scanning fragment trees. + // 5. If head data and relay parent block info are found - success. Otherwise, failure. + + let storage = match view.candidate_storage.get(&request.para_id) { + None => { + let _ = tx.send(None); + return + }, + Some(s) => s, + }; + + let mut head_data = + storage.head_data_by_hash(&request.parent_head_data_hash).map(|x| x.clone()); + let mut relay_parent_info = None; + let mut max_pov_size = None; + + for fragment_tree in view + .active_leaves + .values() + .filter_map(|x| x.fragment_trees.get(&request.para_id)) + { + if head_data.is_some() && relay_parent_info.is_some() && max_pov_size.is_some() { + break + } + if relay_parent_info.is_none() { + relay_parent_info = + fragment_tree.scope().ancestor_by_hash(&request.candidate_relay_parent); + } + if head_data.is_none() { + let required_parent = &fragment_tree.scope().base_constraints().required_parent; + if required_parent.hash() == request.parent_head_data_hash { + head_data = Some(required_parent.clone()); + } + } + if max_pov_size.is_none() { + let contains_ancestor = fragment_tree + .scope() + .ancestor_by_hash(&request.candidate_relay_parent) + .is_some(); + if contains_ancestor { + // We are leaning hard on two assumptions here. + // 1. That the fragment tree never contains allowed relay-parents whose session for + // children is different from that of the base block's. + // 2. That the max_pov_size is only configurable per session. + max_pov_size = Some(fragment_tree.scope().base_constraints().max_pov_size); + } + } + } + + let _ = tx.send(match (head_data, relay_parent_info, max_pov_size) { + (Some(h), Some(i), Some(m)) => Some(PersistedValidationData { + parent_head: h, + relay_parent_number: i.number, + relay_parent_storage_root: i.storage_root, + max_pov_size: m as _, + }), + _ => None, + }); +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn fetch_backing_state( + ctx: &mut Context, + relay_parent: Hash, + para_id: ParaId, +) -> JfyiErrorResult)>> { + let (tx, rx) = oneshot::channel(); + ctx.send_message(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::StagingParaBackingState(para_id, tx), + )) + .await; + + Ok(rx + .await + .map_err(JfyiError::RuntimeApiRequestCanceled)?? + .map(|s| (From::from(s.constraints), s.pending_availability))) +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn fetch_upcoming_paras( + ctx: &mut Context, + relay_parent: Hash, + pending_availability: &mut HashSet, +) -> JfyiErrorResult> { + let (tx, rx) = oneshot::channel(); + + // This'll have to get more sophisticated with parathreads, + // but for now we can just use the `AvailabilityCores`. + ctx.send_message(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::AvailabilityCores(tx), + )) + .await; + + let cores = rx.await.map_err(JfyiError::RuntimeApiRequestCanceled)??; + let mut upcoming = HashSet::new(); + for core in cores { + match core { + CoreState::Occupied(occupied) => { + pending_availability.insert(occupied.candidate_hash); + + if let Some(next_up_on_available) = occupied.next_up_on_available { + upcoming.insert(next_up_on_available.para_id); + } + if let Some(next_up_on_time_out) = occupied.next_up_on_time_out { + upcoming.insert(next_up_on_time_out.para_id); + } + }, + CoreState::Scheduled(scheduled) => { + upcoming.insert(scheduled.para_id); + }, + CoreState::Free => {}, + } + } + + Ok(upcoming.into_iter().collect()) +} + +// Fetch ancestors in descending order, up to the amount requested. +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn fetch_ancestry( + ctx: &mut Context, + cache: &mut HashMap, + relay_hash: Hash, + ancestors: usize, +) -> JfyiErrorResult> { + if ancestors == 0 { + return Ok(Vec::new()) + } + + let (tx, rx) = oneshot::channel(); + ctx.send_message(ChainApiMessage::Ancestors { + hash: relay_hash, + k: ancestors, + response_channel: tx, + }) + .await; + + let hashes = rx.map_err(JfyiError::ChainApiRequestCanceled).await??; + let required_session = request_session_index_for_child(relay_hash, ctx.sender()) + .await + .await + .map_err(JfyiError::RuntimeApiRequestCanceled)??; + + let mut block_info = Vec::with_capacity(hashes.len()); + for hash in hashes { + let info = match fetch_block_info(ctx, cache, hash).await? { + None => { + gum::warn!( + target: LOG_TARGET, + relay_hash = ?hash, + "Failed to fetch info for hash returned from ancestry.", + ); + + // Return, however far we got. + break + }, + Some(info) => info, + }; + + // The relay chain cannot accept blocks backed from previous sessions, with + // potentially previous validators. This is a technical limitation we need to + // respect here. + + let session = request_session_index_for_child(hash, ctx.sender()) + .await + .await + .map_err(JfyiError::RuntimeApiRequestCanceled)??; + + if session == required_session { + block_info.push(info); + } else { + break + } + } + + Ok(block_info) +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn fetch_block_header_with_cache( + ctx: &mut Context, + cache: &mut HashMap, + relay_hash: Hash, +) -> JfyiErrorResult> { + if let Some(h) = cache.get(&relay_hash) { + return Ok(Some(h.clone())) + } + + let (tx, rx) = oneshot::channel(); + + ctx.send_message(ChainApiMessage::BlockHeader(relay_hash, tx)).await; + let header = rx.map_err(JfyiError::ChainApiRequestCanceled).await??; + if let Some(ref h) = header { + cache.insert(relay_hash, h.clone()); + } + Ok(header) +} + +#[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] +async fn fetch_block_info( + ctx: &mut Context, + cache: &mut HashMap, + relay_hash: Hash, +) -> JfyiErrorResult> { + let header = fetch_block_header_with_cache(ctx, cache, relay_hash).await?; + + Ok(header.map(|header| RelayChainBlockInfo { + hash: relay_hash, + number: header.number, + storage_root: header.state_root, + })) +} diff --git a/node/core/prospective-parachains/src/metrics.rs b/node/core/prospective-parachains/src/metrics.rs new file mode 100644 index 000000000000..d7a1760bb459 --- /dev/null +++ b/node/core/prospective-parachains/src/metrics.rs @@ -0,0 +1,52 @@ +// Copyright 2023 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 polkadot_node_subsystem_util::metrics::{self, prometheus}; + +#[derive(Clone)] +pub(crate) struct MetricsInner { + pub(crate) prune_view_candidate_storage: prometheus::Histogram, +} + +/// Candidate backing metrics. +#[derive(Default, Clone)] +pub struct Metrics(pub(crate) Option); + +impl Metrics { + /// Provide a timer for handling `prune_view_candidate_storage` which observes on drop. + pub fn time_prune_view_candidate_storage( + &self, + ) -> Option { + self.0 + .as_ref() + .map(|metrics| metrics.prune_view_candidate_storage.start_timer()) + } +} + +impl metrics::Metrics for Metrics { + fn try_register(registry: &prometheus::Registry) -> Result { + let metrics = MetricsInner { + prune_view_candidate_storage: prometheus::register( + prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( + "polkadot_parachain_prospective_parachains_prune_view_candidate_storage", + "Time spent within `prospective_parachains::prune_view_candidate_storage`", + ))?, + registry, + )?, + }; + Ok(Metrics(Some(metrics))) + } +} diff --git a/node/core/prospective-parachains/src/tests.rs b/node/core/prospective-parachains/src/tests.rs new file mode 100644 index 000000000000..de7a84d9a608 --- /dev/null +++ b/node/core/prospective-parachains/src/tests.rs @@ -0,0 +1,1652 @@ +// Copyright 2022 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 assert_matches::assert_matches; +use polkadot_node_subsystem::{ + errors::RuntimeApiError, + messages::{ + AllMessages, HypotheticalFrontierRequest, ProspectiveParachainsMessage, + ProspectiveValidationDataRequest, + }, +}; +use polkadot_node_subsystem_test_helpers as test_helpers; +use polkadot_node_subsystem_types::{jaeger, ActivatedLeaf, LeafStatus}; +use polkadot_primitives::{ + vstaging::{AsyncBackingParams, BackingState, Constraints, InboundHrmpLimitations}, + CommittedCandidateReceipt, HeadData, Header, PersistedValidationData, ScheduledCore, + ValidationCodeHash, +}; +use polkadot_primitives_test_helpers::make_candidate; +use std::sync::Arc; + +const ALLOWED_ANCESTRY_LEN: u32 = 3; +const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = + AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: ALLOWED_ANCESTRY_LEN }; + +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; + +const MAX_POV_SIZE: u32 = 1_000_000; + +type VirtualOverseer = test_helpers::TestSubsystemContextHandle; + +fn dummy_constraints( + min_relay_parent_number: BlockNumber, + valid_watermarks: Vec, + required_parent: HeadData, + validation_code_hash: ValidationCodeHash, +) -> Constraints { + Constraints { + min_relay_parent_number, + max_pov_size: MAX_POV_SIZE, + max_code_size: 1_000_000, + ump_remaining: 10, + ump_remaining_bytes: 1_000, + max_ump_num_per_candidate: 10, + dmp_remaining_messages: vec![], + hrmp_inbound: InboundHrmpLimitations { valid_watermarks }, + hrmp_channels_out: vec![], + max_hrmp_num_per_candidate: 0, + required_parent, + validation_code_hash, + upgrade_restriction: None, + future_validation_code: None, + } +} + +struct TestState { + availability_cores: Vec, + validation_code_hash: ValidationCodeHash, +} + +impl Default for TestState { + fn default() -> Self { + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + + let availability_cores = vec![ + CoreState::Scheduled(ScheduledCore { para_id: chain_a, collator: None }), + CoreState::Scheduled(ScheduledCore { para_id: chain_b, collator: None }), + ]; + let validation_code_hash = Hash::repeat_byte(42).into(); + + Self { availability_cores, validation_code_hash } + } +} + +fn get_parent_hash(hash: Hash) -> Hash { + Hash::from_low_u64_be(hash.to_low_u64_be() + 1) +} + +fn test_harness>( + test: impl FnOnce(VirtualOverseer) -> T, +) -> View { + let pool = sp_core::testing::TaskExecutor::new(); + + let (mut context, virtual_overseer) = test_helpers::make_subsystem_context(pool.clone()); + + let mut view = View::new(); + let subsystem = async move { + loop { + match run_iteration(&mut context, &mut view, &Metrics(None)).await { + Ok(()) => break, + Err(e) => panic!("{:?}", e), + } + } + + view + }; + + let test_fut = test(virtual_overseer); + + futures::pin_mut!(test_fut); + futures::pin_mut!(subsystem); + let (_, view) = futures::executor::block_on(future::join( + async move { + let mut virtual_overseer = test_fut.await; + virtual_overseer.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; + }, + subsystem, + )); + + view +} + +#[derive(Debug, Clone)] +struct PerParaData { + min_relay_parent: BlockNumber, + head_data: HeadData, + pending_availability: Vec, +} + +impl PerParaData { + pub fn new(min_relay_parent: BlockNumber, head_data: HeadData) -> Self { + Self { min_relay_parent, head_data, pending_availability: Vec::new() } + } + + pub fn new_with_pending( + min_relay_parent: BlockNumber, + head_data: HeadData, + pending: Vec, + ) -> Self { + Self { min_relay_parent, head_data, pending_availability: pending } + } +} + +struct TestLeaf { + number: BlockNumber, + hash: Hash, + para_data: Vec<(ParaId, PerParaData)>, +} + +impl TestLeaf { + pub fn para_data(&self, para_id: ParaId) -> &PerParaData { + self.para_data + .iter() + .find_map(|(p_id, data)| if *p_id == para_id { Some(data) } else { None }) + .unwrap() + } +} + +async fn send_block_header(virtual_overseer: &mut VirtualOverseer, hash: Hash, number: u32) { + let header = Header { + parent_hash: get_parent_hash(hash), + number, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + }; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ChainApi( + ChainApiMessage::BlockHeader(parent, tx) + ) if parent == hash => { + tx.send(Ok(Some(header))).unwrap(); + } + ); +} + +async fn activate_leaf( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + test_state: &TestState, +) { + activate_leaf_with_params(virtual_overseer, leaf, test_state, ASYNC_BACKING_PARAMETERS).await; +} + +async fn activate_leaf_with_params( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + test_state: &TestState, + async_backing_params: AsyncBackingParams, +) { + let TestLeaf { number, hash, .. } = leaf; + + let activated = ActivatedLeaf { + hash: *hash, + number: *number, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( + activated, + )))) + .await; + + handle_leaf_activation(virtual_overseer, leaf, test_state, async_backing_params).await; +} + +async fn handle_leaf_activation( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + test_state: &TestState, + async_backing_params: AsyncBackingParams, +) { + let TestLeaf { number, hash, para_data } = leaf; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) if parent == *hash => { + tx.send(Ok(async_backing_params)).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) + ) if parent == *hash => { + tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + } + ); + + send_block_header(virtual_overseer, *hash, *number).await; + + // Check that subsystem job issues a request for ancestors. + let min_min = para_data.iter().map(|(_, data)| data.min_relay_parent).min().unwrap_or(*number); + let ancestry_len = number - min_min; + let ancestry_hashes: Vec = + std::iter::successors(Some(*hash), |h| Some(get_parent_hash(*h))) + .skip(1) + .take(ancestry_len as usize) + .collect(); + let ancestry_numbers = (min_min..*number).rev(); + let ancestry_iter = ancestry_hashes.clone().into_iter().zip(ancestry_numbers).peekable(); + if ancestry_len > 0 { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ChainApi( + ChainApiMessage::Ancestors{hash: block_hash, k, response_channel: tx} + ) if block_hash == *hash && k == ALLOWED_ANCESTRY_LEN as usize => { + tx.send(Ok(ancestry_hashes.clone())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == *hash => { + tx.send(Ok(1)).unwrap(); + } + ); + } + + for (hash, number) in ancestry_iter { + send_block_header(virtual_overseer, hash, number).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + tx.send(Ok(1)).unwrap(); + } + ); + } + + for _ in 0..test_state.availability_cores.len() { + let message = virtual_overseer.recv().await; + // Get the para we are working with since the order is not deterministic. + let para_id = match message { + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::StagingParaBackingState(p_id, _), + )) => p_id, + _ => panic!("received unexpected message {:?}", message), + }; + + let PerParaData { min_relay_parent, head_data, pending_availability } = + leaf.para_data(para_id); + let constraints = dummy_constraints( + *min_relay_parent, + vec![*number], + head_data.clone(), + test_state.validation_code_hash, + ); + let backing_state = + BackingState { constraints, pending_availability: pending_availability.clone() }; + + assert_matches!( + message, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingParaBackingState(p_id, tx)) + ) if parent == *hash && p_id == para_id => { + tx.send(Ok(Some(backing_state))).unwrap(); + } + ); + + for pending in pending_availability { + send_block_header( + virtual_overseer, + pending.descriptor.relay_parent, + pending.relay_parent_number, + ) + .await; + } + } + + // Get minimum relay parents. + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::GetMinimumRelayParents(*hash, tx), + }) + .await; + let mut resp = rx.await.unwrap(); + resp.sort(); + let mrp_response: Vec<(ParaId, BlockNumber)> = para_data + .iter() + .map(|(para_id, data)| (*para_id, data.min_relay_parent)) + .collect(); + assert_eq!(resp, mrp_response); +} + +async fn deactivate_leaf(virtual_overseer: &mut VirtualOverseer, hash: Hash) { + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::stop_work( + hash, + )))) + .await; +} + +async fn introduce_candidate( + virtual_overseer: &mut VirtualOverseer, + candidate: CommittedCandidateReceipt, + pvd: PersistedValidationData, +) { + let req = IntroduceCandidateRequest { + candidate_para: candidate.descriptor().para_id, + candidate_receipt: candidate, + persisted_validation_data: pvd, + }; + let (tx, _) = oneshot::channel(); + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::IntroduceCandidate(req, tx), + }) + .await; +} + +async fn second_candidate( + virtual_overseer: &mut VirtualOverseer, + candidate: CommittedCandidateReceipt, +) { + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::CandidateSeconded( + candidate.descriptor.para_id, + candidate.hash(), + ), + }) + .await; +} + +async fn back_candidate( + virtual_overseer: &mut VirtualOverseer, + candidate: &CommittedCandidateReceipt, + candidate_hash: CandidateHash, +) { + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::CandidateBacked( + candidate.descriptor.para_id, + candidate_hash, + ), + }) + .await; +} + +async fn get_membership( + virtual_overseer: &mut VirtualOverseer, + para_id: ParaId, + candidate_hash: CandidateHash, + expected_membership_response: Vec<(Hash, Vec)>, +) { + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::GetTreeMembership(para_id, candidate_hash, tx), + }) + .await; + let resp = rx.await.unwrap(); + assert_eq!(resp, expected_membership_response); +} + +async fn get_backable_candidate( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + para_id: ParaId, + required_path: Vec, + expected_result: Option<(CandidateHash, Hash)>, +) { + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::GetBackableCandidate( + leaf.hash, + para_id, + required_path, + tx, + ), + }) + .await; + let resp = rx.await.unwrap(); + assert_eq!(resp, expected_result); +} + +async fn get_hypothetical_frontier( + virtual_overseer: &mut VirtualOverseer, + candidate_hash: CandidateHash, + receipt: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + fragment_tree_relay_parent: Hash, + backed_in_path_only: bool, + expected_depths: Vec, +) { + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash, + receipt: Arc::new(receipt), + persisted_validation_data, + }; + let request = HypotheticalFrontierRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_tree_relay_parent: Some(fragment_tree_relay_parent), + backed_in_path_only, + }; + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::GetHypotheticalFrontier(request, tx), + }) + .await; + let resp = rx.await.unwrap(); + let expected_frontier = if expected_depths.is_empty() { + vec![(hypothetical_candidate, vec![])] + } else { + vec![(hypothetical_candidate, vec![(fragment_tree_relay_parent, expected_depths)])] + }; + assert_eq!(resp, expected_frontier); +} + +async fn get_pvd( + virtual_overseer: &mut VirtualOverseer, + para_id: ParaId, + candidate_relay_parent: Hash, + parent_head_data: HeadData, + expected_pvd: Option, +) { + let request = ProspectiveValidationDataRequest { + para_id, + candidate_relay_parent, + parent_head_data_hash: parent_head_data.hash(), + }; + let (tx, rx) = oneshot::channel(); + virtual_overseer + .send(overseer::FromOrchestra::Communication { + msg: ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), + }) + .await; + let resp = rx.await.unwrap(); + assert_eq!(resp, expected_pvd); +} + +#[test] +fn should_do_no_work_if_async_backing_disabled_for_leaf() { + async fn activate_leaf_async_backing_disabled(virtual_overseer: &mut VirtualOverseer) { + let hash = Hash::from_low_u64_be(130); + + // Start work on some new parent. + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( + ActiveLeavesUpdate::start_work(ActivatedLeaf { + hash, + number: 1, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }), + ))) + .await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) if parent == hash => { + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + } + ); + } + + let view = test_harness(|mut virtual_overseer| async move { + activate_leaf_async_backing_disabled(&mut virtual_overseer).await; + + virtual_overseer + }); + + assert!(view.active_leaves.is_empty()); + assert!(view.candidate_storage.is_empty()); +} + +// Send some candidates and make sure all are found: +// - Two for the same leaf A +// - One for leaf B on parachain 1 +// - One for leaf C on parachain 2 +#[test] +fn send_candidates_and_check_if_found() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), + (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), + ], + }; + // Leaf C + let leaf_c = TestLeaf { + number: 102, + hash: Hash::from_low_u64_be(132), + para_data: vec![ + (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), + (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_c, &test_state).await; + + // Candidate A1 + let (candidate_a1, pvd_a1) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a1 = candidate_a1.hash(); + let response_a1 = vec![(leaf_a.hash, vec![0])]; + + // Candidate A2 + let (candidate_a2, pvd_a2) = make_candidate( + leaf_a.hash, + leaf_a.number, + 2.into(), + HeadData(vec![2, 3, 4]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + let candidate_hash_a2 = candidate_a2.hash(); + let response_a2 = vec![(leaf_a.hash, vec![0])]; + + // Candidate B + let (candidate_b, pvd_b) = make_candidate( + leaf_b.hash, + leaf_b.number, + 1.into(), + HeadData(vec![3, 4, 5]), + HeadData(vec![3]), + test_state.validation_code_hash, + ); + let candidate_hash_b = candidate_b.hash(); + let response_b = vec![(leaf_b.hash, vec![0])]; + + // Candidate C + let (candidate_c, pvd_c) = make_candidate( + leaf_c.hash, + leaf_c.number, + 2.into(), + HeadData(vec![6, 7, 8]), + HeadData(vec![4]), + test_state.validation_code_hash, + ); + let candidate_hash_c = candidate_c.hash(); + let response_c = vec![(leaf_c.hash, vec![0])]; + + // Introduce candidates. + introduce_candidate(&mut virtual_overseer, candidate_a1, pvd_a1).await; + introduce_candidate(&mut virtual_overseer, candidate_a2, pvd_a2).await; + introduce_candidate(&mut virtual_overseer, candidate_b, pvd_b).await; + introduce_candidate(&mut virtual_overseer, candidate_c, pvd_c).await; + + // Check candidate tree membership. + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, response_a1).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, response_a2).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, response_b).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, response_c).await; + + // The candidates should not be found on other parachains. + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a1, vec![]).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a2, vec![]).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_b, vec![]).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_c, vec![]).await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 3); + assert_eq!(view.candidate_storage.len(), 2); + // Two parents and two candidates per para. + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (2, 2)); +} + +// Send some candidates, check if the candidate won't be found once its relay parent leaves the +// view. +#[test] +fn check_candidate_parent_leaving_view() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), + (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), + ], + }; + // Leaf C + let leaf_c = TestLeaf { + number: 102, + hash: Hash::from_low_u64_be(132), + para_data: vec![ + (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), + (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_c, &test_state).await; + + // Candidate A1 + let (candidate_a1, pvd_a1) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a1 = candidate_a1.hash(); + + // Candidate A2 + let (candidate_a2, pvd_a2) = make_candidate( + leaf_a.hash, + leaf_a.number, + 2.into(), + HeadData(vec![2, 3, 4]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + let candidate_hash_a2 = candidate_a2.hash(); + + // Candidate B + let (candidate_b, pvd_b) = make_candidate( + leaf_b.hash, + leaf_b.number, + 1.into(), + HeadData(vec![3, 4, 5]), + HeadData(vec![3]), + test_state.validation_code_hash, + ); + let candidate_hash_b = candidate_b.hash(); + let response_b = vec![(leaf_b.hash, vec![0])]; + + // Candidate C + let (candidate_c, pvd_c) = make_candidate( + leaf_c.hash, + leaf_c.number, + 2.into(), + HeadData(vec![6, 7, 8]), + HeadData(vec![4]), + test_state.validation_code_hash, + ); + let candidate_hash_c = candidate_c.hash(); + let response_c = vec![(leaf_c.hash, vec![0])]; + + // Introduce candidates. + introduce_candidate(&mut virtual_overseer, candidate_a1, pvd_a1).await; + introduce_candidate(&mut virtual_overseer, candidate_a2, pvd_a2).await; + introduce_candidate(&mut virtual_overseer, candidate_b, pvd_b).await; + introduce_candidate(&mut virtual_overseer, candidate_c, pvd_c).await; + + // Deactivate leaf A. + deactivate_leaf(&mut virtual_overseer, leaf_a.hash).await; + + // Candidates A1 and A2 should be gone. Candidates B and C should remain. + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, vec![]).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, vec![]).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, response_b).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, response_c.clone()).await; + + // Deactivate leaf B. + deactivate_leaf(&mut virtual_overseer, leaf_b.hash).await; + + // Candidate B should be gone, C should remain. + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, vec![]).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, vec![]).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, vec![]).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, response_c).await; + + // Deactivate leaf C. + deactivate_leaf(&mut virtual_overseer, leaf_c.hash).await; + + // Candidate C should be gone. + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, vec![]).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, vec![]).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, vec![]).await; + get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, vec![]).await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 0); + assert_eq!(view.candidate_storage.len(), 0); +} + +// Introduce a candidate to multiple forks, see how the membership is returned. +#[test] +fn check_candidate_on_multiple_forks() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), + (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), + ], + }; + // Leaf C + let leaf_c = TestLeaf { + number: 102, + hash: Hash::from_low_u64_be(132), + para_data: vec![ + (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), + (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_c, &test_state).await; + + // Candidate on leaf A. + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + let response_a = vec![(leaf_a.hash, vec![0])]; + + // Candidate on leaf B. + let (candidate_b, pvd_b) = make_candidate( + leaf_b.hash, + leaf_b.number, + 1.into(), + HeadData(vec![3, 4, 5]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_b = candidate_b.hash(); + let response_b = vec![(leaf_b.hash, vec![0])]; + + // Candidate on leaf C. + let (candidate_c, pvd_c) = make_candidate( + leaf_c.hash, + leaf_c.number, + 1.into(), + HeadData(vec![5, 6, 7]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_c = candidate_c.hash(); + let response_c = vec![(leaf_c.hash, vec![0])]; + + // Introduce candidates on all three leaves. + introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; + introduce_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c).await; + + // Check candidate tree membership. + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a, response_a).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, response_b).await; + get_membership(&mut virtual_overseer, 1.into(), candidate_hash_c, response_c).await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 3); + assert_eq!(view.candidate_storage.len(), 2); + // Three parents and three candidates on para 1. + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (3, 3)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); +} + +// Backs some candidates and tests `GetBackableCandidate`. +#[test] +fn check_backable_query() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + + // Candidate A + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + + // Candidate B + let (mut candidate_b, pvd_b) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + // Set a field to make this candidate unique. + candidate_b.descriptor.para_head = Hash::from_low_u64_le(1000); + let candidate_hash_b = candidate_b.hash(); + + // Introduce candidates. + introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; + + // Should not get any backable candidates. + get_backable_candidate( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a], + None, + ) + .await; + + // Second candidates. + second_candidate(&mut virtual_overseer, candidate_a.clone()).await; + second_candidate(&mut virtual_overseer, candidate_b.clone()).await; + + // Should not get any backable candidates. + get_backable_candidate( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a], + None, + ) + .await; + + // Back candidates. + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; + + // Get backable candidate. + get_backable_candidate( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![], + Some((candidate_hash_a, leaf_a.hash)), + ) + .await; + get_backable_candidate( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a], + Some((candidate_hash_b, leaf_a.hash)), + ) + .await; + + // Should not get anything at the wrong path. + get_backable_candidate( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_b], + None, + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); + // Two parents and two candidates on para 1. + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); +} + +// Test depth query. +#[test] +fn check_hypothetical_frontier_query() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + + // Candidate A. + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + + // Candidate B. + let (candidate_b, pvd_b) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + let candidate_hash_b = candidate_b.hash(); + + // Candidate C. + let (candidate_c, pvd_c) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![2]), + HeadData(vec![3]), + test_state.validation_code_hash, + ); + let candidate_hash_c = candidate_c.hash(); + + // Get hypothetical frontier of candidate A before adding it. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_a, + candidate_a.clone(), + pvd_a.clone(), + leaf_a.hash, + false, + vec![0], + ) + .await; + // Should work with `backed_in_path_only: true`, too. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_a, + candidate_a.clone(), + pvd_a.clone(), + leaf_a.hash, + true, + vec![0], + ) + .await; + + // Add candidate A. + introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()).await; + + // Get frontier of candidate A after adding it. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_a, + candidate_a.clone(), + pvd_a.clone(), + leaf_a.hash, + false, + vec![0], + ) + .await; + + // Get hypothetical frontier of candidate B before adding it. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_b, + candidate_b.clone(), + pvd_b.clone(), + leaf_a.hash, + false, + vec![1], + ) + .await; + + // Add candidate B. + introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()).await; + + // Get frontier of candidate B after adding it. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_b, + candidate_b, + pvd_b.clone(), + leaf_a.hash, + false, + vec![1], + ) + .await; + + // Get hypothetical frontier of candidate C before adding it. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_c, + candidate_c.clone(), + pvd_c.clone(), + leaf_a.hash, + false, + vec![2], + ) + .await; + // Should be empty with `backed_in_path_only` because we haven't backed anything. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_c, + candidate_c.clone(), + pvd_c.clone(), + leaf_a.hash, + true, + vec![], + ) + .await; + + // Add candidate C. + introduce_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c.clone()).await; + + // Get frontier of candidate C after adding it. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_c, + candidate_c.clone(), + pvd_c.clone(), + leaf_a.hash, + false, + vec![2], + ) + .await; + // Should be empty with `backed_in_path_only` because we haven't backed anything. + get_hypothetical_frontier( + &mut virtual_overseer, + candidate_hash_c, + candidate_c.clone(), + pvd_c.clone(), + leaf_a.hash, + true, + vec![], + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); +} + +#[test] +fn check_pvd_query() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + + // Candidate A. + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + + // Candidate B. + let (candidate_b, pvd_b) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + + // Candidate C. + let (candidate_c, pvd_c) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![2]), + HeadData(vec![3]), + test_state.validation_code_hash, + ); + + // Get pvd of candidate A before adding it. + get_pvd( + &mut virtual_overseer, + 1.into(), + leaf_a.hash, + HeadData(vec![1, 2, 3]), + Some(pvd_a.clone()), + ) + .await; + + // Add candidate A. + introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()).await; + back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; + + // Get pvd of candidate A after adding it. + get_pvd( + &mut virtual_overseer, + 1.into(), + leaf_a.hash, + HeadData(vec![1, 2, 3]), + Some(pvd_a.clone()), + ) + .await; + + // Get pvd of candidate B before adding it. + get_pvd( + &mut virtual_overseer, + 1.into(), + leaf_a.hash, + HeadData(vec![1]), + Some(pvd_b.clone()), + ) + .await; + + // Add candidate B. + introduce_candidate(&mut virtual_overseer, candidate_b, pvd_b.clone()).await; + + // Get pvd of candidate B after adding it. + get_pvd( + &mut virtual_overseer, + 1.into(), + leaf_a.hash, + HeadData(vec![1]), + Some(pvd_b.clone()), + ) + .await; + + // Get pvd of candidate C before adding it. + get_pvd( + &mut virtual_overseer, + 1.into(), + leaf_a.hash, + HeadData(vec![2]), + Some(pvd_c.clone()), + ) + .await; + + // Add candidate C. + introduce_candidate(&mut virtual_overseer, candidate_c, pvd_c.clone()).await; + + // Get pvd of candidate C after adding it. + get_pvd( + &mut virtual_overseer, + 1.into(), + leaf_a.hash, + HeadData(vec![2]), + Some(pvd_c.clone()), + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); +} + +// Test simultaneously activating and deactivating leaves, and simultaneously deactivating multiple +// leaves. +#[test] +fn correctly_updates_leaves() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: Hash::from_low_u64_be(130), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), + (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), + ], + }; + // Leaf C + let leaf_c = TestLeaf { + number: 102, + hash: Hash::from_low_u64_be(132), + para_data: vec![ + (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), + (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + + // Try activating a duplicate leaf. + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + + // Pass in an empty update. + let update = ActiveLeavesUpdate::default(); + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) + .await; + + // Activate a leaf and remove one at the same time. + let activated = ActivatedLeaf { + hash: leaf_c.hash, + number: leaf_c.number, + span: Arc::new(jaeger::Span::Disabled), + status: LeafStatus::Fresh, + }; + let update = ActiveLeavesUpdate { + activated: Some(activated), + deactivated: [leaf_b.hash][..].into(), + }; + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) + .await; + handle_leaf_activation( + &mut virtual_overseer, + &leaf_c, + &test_state, + ASYNC_BACKING_PARAMETERS, + ) + .await; + + // Remove all remaining leaves. + let update = ActiveLeavesUpdate { + deactivated: [leaf_a.hash, leaf_c.hash][..].into(), + ..Default::default() + }; + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) + .await; + + // Activate and deactivate the same leaf. + let activated = ActivatedLeaf { + hash: leaf_a.hash, + number: leaf_a.number, + span: Arc::new(jaeger::Span::Disabled), + status: LeafStatus::Fresh, + }; + let update = ActiveLeavesUpdate { + activated: Some(activated), + deactivated: [leaf_a.hash][..].into(), + }; + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) + .await; + handle_leaf_activation( + &mut virtual_overseer, + &leaf_a, + &test_state, + ASYNC_BACKING_PARAMETERS, + ) + .await; + + // Remove the leaf again. Send some unnecessary hashes. + let update = ActiveLeavesUpdate { + deactivated: [leaf_a.hash, leaf_b.hash, leaf_c.hash][..].into(), + ..Default::default() + }; + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 0); + assert_eq!(view.candidate_storage.len(), 0); +} + +#[test] +fn persists_pending_availability_candidate() { + let mut test_state = TestState::default(); + let para_id = ParaId::from(1); + test_state.availability_cores = test_state + .availability_cores + .into_iter() + .filter(|core| core.para_id().map_or(false, |id| id == para_id)) + .collect(); + assert_eq!(test_state.availability_cores.len(), 1); + + test_harness(|mut virtual_overseer| async move { + let para_head = HeadData(vec![1, 2, 3]); + + // Min allowed relay parent for leaf `a` which goes out of scope in the test. + let candidate_relay_parent = Hash::from_low_u64_be(5); + let candidate_relay_parent_number = 97; + + let leaf_a = TestLeaf { + number: candidate_relay_parent_number + ALLOWED_ANCESTRY_LEN, + hash: Hash::from_low_u64_be(2), + para_data: vec![( + para_id, + PerParaData::new(candidate_relay_parent_number, para_head.clone()), + )], + }; + + let leaf_b_hash = Hash::from_low_u64_be(1); + let leaf_b_number = leaf_a.number + 1; + + // Activate leaf. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + + // Candidate A + let (candidate_a, pvd_a) = make_candidate( + candidate_relay_parent, + candidate_relay_parent_number, + para_id, + para_head.clone(), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + + // Candidate B, built on top of the candidate which is out of scope but pending + // availability. + let (candidate_b, pvd_b) = make_candidate( + leaf_b_hash, + leaf_b_number, + para_id, + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + let candidate_hash_b = candidate_b.hash(); + + introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + second_candidate(&mut virtual_overseer, candidate_a.clone()).await; + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; + + let candidate_a_pending_av = CandidatePendingAvailability { + candidate_hash: candidate_hash_a, + descriptor: candidate_a.descriptor.clone(), + commitments: candidate_a.commitments.clone(), + relay_parent_number: candidate_relay_parent_number, + max_pov_size: MAX_POV_SIZE, + }; + let leaf_b = TestLeaf { + number: leaf_b_number, + hash: leaf_b_hash, + para_data: vec![( + 1.into(), + PerParaData::new_with_pending( + candidate_relay_parent_number + 1, + para_head.clone(), + vec![candidate_a_pending_av], + ), + )], + }; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + + introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; + second_candidate(&mut virtual_overseer, candidate_b.clone()).await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; + + get_backable_candidate( + &mut virtual_overseer, + &leaf_b, + para_id, + vec![candidate_hash_a], + Some((candidate_hash_b, leaf_b_hash)), + ) + .await; + + virtual_overseer + }); +} + +#[test] +fn backwards_compatible() { + let mut test_state = TestState::default(); + let para_id = ParaId::from(1); + test_state.availability_cores = test_state + .availability_cores + .into_iter() + .filter(|core| core.para_id().map_or(false, |id| id == para_id)) + .collect(); + assert_eq!(test_state.availability_cores.len(), 1); + + test_harness(|mut virtual_overseer| async move { + let para_head = HeadData(vec![1, 2, 3]); + + let leaf_b_hash = Hash::repeat_byte(15); + let candidate_relay_parent = get_parent_hash(leaf_b_hash); + let candidate_relay_parent_number = 100; + + let leaf_a = TestLeaf { + number: candidate_relay_parent_number, + hash: candidate_relay_parent, + para_data: vec![( + para_id, + PerParaData::new(candidate_relay_parent_number, para_head.clone()), + )], + }; + + // Activate leaf. + activate_leaf_with_params( + &mut virtual_overseer, + &leaf_a, + &test_state, + AsyncBackingParams { allowed_ancestry_len: 0, max_candidate_depth: 0 }, + ) + .await; + + // Candidate A + let (candidate_a, pvd_a) = make_candidate( + candidate_relay_parent, + candidate_relay_parent_number, + para_id, + para_head.clone(), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + + introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + second_candidate(&mut virtual_overseer, candidate_a.clone()).await; + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; + + get_backable_candidate( + &mut virtual_overseer, + &leaf_a, + para_id, + vec![], + Some((candidate_hash_a, candidate_relay_parent)), + ) + .await; + + let leaf_b = TestLeaf { + number: candidate_relay_parent_number + 1, + hash: leaf_b_hash, + para_data: vec![( + para_id, + PerParaData::new(candidate_relay_parent_number + 1, para_head.clone()), + )], + }; + activate_leaf_with_params( + &mut virtual_overseer, + &leaf_b, + &test_state, + AsyncBackingParams { allowed_ancestry_len: 0, max_candidate_depth: 0 }, + ) + .await; + + get_backable_candidate(&mut virtual_overseer, &leaf_b, para_id, vec![], None).await; + + virtual_overseer + }); +} + +#[test] +fn uses_ancestry_only_within_session() { + test_harness(|mut virtual_overseer| async move { + let number = 5; + let hash = Hash::repeat_byte(5); + let ancestry_len = 3; + let session = 2; + + let ancestry_hashes = + vec![Hash::repeat_byte(4), Hash::repeat_byte(3), Hash::repeat_byte(2)]; + let session_change_hash = Hash::repeat_byte(3); + + let activated = ActivatedLeaf { + hash, + number, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( + ActiveLeavesUpdate::start_work(activated), + ))) + .await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) if parent == hash => { + tx.send(Ok(AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: ancestry_len })).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) + ) if parent == hash => { + tx.send(Ok(Vec::new())).unwrap(); + } + ); + + send_block_header(&mut virtual_overseer, hash, number).await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ChainApi( + ChainApiMessage::Ancestors{hash: block_hash, k, response_channel: tx} + ) if block_hash == hash && k == ancestry_len as usize => { + tx.send(Ok(ancestry_hashes.clone())).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + tx.send(Ok(session)).unwrap(); + } + ); + + for (i, hash) in ancestry_hashes.into_iter().enumerate() { + let number = number - (i + 1) as BlockNumber; + send_block_header(&mut virtual_overseer, hash, number).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + if hash == session_change_hash { + tx.send(Ok(session - 1)).unwrap(); + break + } else { + tx.send(Ok(session)).unwrap(); + } + } + ); + } + + virtual_overseer + }); +} diff --git a/node/core/provisioner/src/error.rs b/node/core/provisioner/src/error.rs index 5645ed2762bc..376d69f276fc 100644 --- a/node/core/provisioner/src/error.rs +++ b/node/core/provisioner/src/error.rs @@ -28,6 +28,10 @@ pub type Result = std::result::Result; #[allow(missing_docs)] #[fatality::fatality(splitable)] pub enum Error { + #[fatal(forward)] + #[error("Error while accessing runtime information")] + Runtime(#[from] util::runtime::Error), + #[error(transparent)] Util(#[from] util::Error), @@ -46,11 +50,14 @@ pub enum Error { #[error("failed to get votes on dispute")] CanceledCandidateVotes(#[source] oneshot::Canceled), + #[error("failed to get backable candidate from prospective parachains")] + CanceledBackableCandidate(#[source] oneshot::Canceled), + #[error(transparent)] ChainApi(#[from] ChainApiError), #[error(transparent)] - Runtime(#[from] RuntimeApiError), + RuntimeApi(#[from] RuntimeApiError), #[error("failed to send message to ChainAPI")] ChainApiMessageSend(#[source] mpsc::SendError), diff --git a/node/core/provisioner/src/lib.rs b/node/core/provisioner/src/lib.rs index b5073763dfab..f81e5550b15d 100644 --- a/node/core/provisioner/src/lib.rs +++ b/node/core/provisioner/src/lib.rs @@ -28,18 +28,20 @@ use futures_timer::Delay; use polkadot_node_subsystem::{ jaeger, messages::{ - CandidateBackingMessage, ChainApiMessage, ProvisionableData, ProvisionerInherentData, - ProvisionerMessage, RuntimeApiMessage, RuntimeApiRequest, + CandidateBackingMessage, ChainApiMessage, ProspectiveParachainsMessage, ProvisionableData, + ProvisionerInherentData, ProvisionerMessage, RuntimeApiMessage, RuntimeApiRequest, }, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, LeafStatus, OverseerSignal, PerLeafSpan, RuntimeApiError, SpawnedSubsystem, SubsystemError, }; use polkadot_node_subsystem_util::{ - request_availability_cores, request_persisted_validation_data, TimeoutExt, + request_availability_cores, request_persisted_validation_data, + runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, + TimeoutExt, }; use polkadot_primitives::{ - BackedCandidate, BlockNumber, CandidateReceipt, CoreState, Hash, OccupiedCoreAssumption, - SignedAvailabilityBitfield, ValidatorIndex, + BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, CoreState, Hash, Id as ParaId, + OccupiedCoreAssumption, SignedAvailabilityBitfield, ValidatorIndex, }; use std::collections::{BTreeMap, HashMap}; @@ -79,6 +81,7 @@ impl ProvisionerSubsystem { pub struct PerRelayParent { leaf: ActivatedLeaf, backed_candidates: Vec, + prospective_parachains_mode: ProspectiveParachainsMode, signed_bitfields: Vec, is_inherent_ready: bool, awaiting_inherent: Vec>, @@ -86,12 +89,13 @@ pub struct PerRelayParent { } impl PerRelayParent { - fn new(leaf: ActivatedLeaf) -> Self { + fn new(leaf: ActivatedLeaf, prospective_parachains_mode: ProspectiveParachainsMode) -> Self { let span = PerLeafSpan::new(leaf.span.clone(), "provisioner"); Self { leaf, backed_candidates: Vec::new(), + prospective_parachains_mode, signed_bitfields: Vec::new(), is_inherent_ready: false, awaiting_inherent: Vec::new(), @@ -147,7 +151,7 @@ async fn run_iteration( // Map the error to ensure that the subsystem exits when the overseer is gone. match from_overseer.map_err(Error::OverseerExited)? { FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => - handle_active_leaves_update(update, per_relay_parent, inherent_delays), + handle_active_leaves_update(ctx.sender(), update, per_relay_parent, inherent_delays).await?, FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {}, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), FromOrchestra::Communication { msg } => { @@ -175,11 +179,12 @@ async fn run_iteration( } } -fn handle_active_leaves_update( +async fn handle_active_leaves_update( + sender: &mut impl overseer::ProvisionerSenderTrait, update: ActiveLeavesUpdate, per_relay_parent: &mut HashMap, inherent_delays: &mut InherentDelays, -) { +) -> Result<(), Error> { gum::trace!(target: LOG_TARGET, "Handle ActiveLeavesUpdate"); for deactivated in &update.deactivated { per_relay_parent.remove(deactivated); @@ -187,10 +192,13 @@ fn handle_active_leaves_update( if let Some(leaf) = update.activated { gum::trace!(target: LOG_TARGET, leaf_hash=?leaf.hash, "Adding delay"); + let prospective_parachains_mode = prospective_parachains_mode(sender, leaf.hash).await?; let delay_fut = Delay::new(PRE_PROPOSE_TIMEOUT).map(move |_| leaf.hash).boxed(); - per_relay_parent.insert(leaf.hash, PerRelayParent::new(leaf)); + per_relay_parent.insert(leaf.hash, PerRelayParent::new(leaf, prospective_parachains_mode)); inherent_delays.push(delay_fut); } + + Ok(()) } #[overseer::contextbounds(Provisioner, prefix = self::overseer)] @@ -244,6 +252,7 @@ async fn send_inherent_data_bg( let leaf = per_relay_parent.leaf.clone(); let signed_bitfields = per_relay_parent.signed_bitfields.clone(); let backed_candidates = per_relay_parent.backed_candidates.clone(); + let mode = per_relay_parent.prospective_parachains_mode; let span = per_relay_parent.span.child("req-inherent-data"); let mut sender = ctx.sender().clone(); @@ -262,6 +271,7 @@ async fn send_inherent_data_bg( &leaf, &signed_bitfields, &backed_candidates, + mode, return_senders, &mut sender, &metrics, @@ -290,7 +300,6 @@ async fn send_inherent_data_bg( gum::debug!( target: LOG_TARGET, signed_bitfield_count = signed_bitfields.len(), - backed_candidates_count = backed_candidates.len(), leaf_hash = ?leaf.hash, "inherent data sent successfully" ); @@ -325,7 +334,7 @@ fn note_provisionable_data( .child("provisionable-backed") .with_candidate(candidate_hash) .with_para_id(backed_candidate.descriptor().para_id); - per_relay_parent.backed_candidates.push(backed_candidate) + per_relay_parent.backed_candidates.push(backed_candidate); }, // We choose not to punish these forms of misbehavior for the time being. // Risks from misbehavior are sufficiently mitigated at the protocol level @@ -373,6 +382,7 @@ async fn send_inherent_data( leaf: &ActivatedLeaf, bitfields: &[SignedAvailabilityBitfield], candidates: &[CandidateReceipt], + prospective_parachains_mode: ProspectiveParachainsMode, return_senders: Vec>, from_job: &mut impl overseer::ProvisionerSenderTrait, metrics: &Metrics, @@ -424,8 +434,16 @@ async fn send_inherent_data( relay_parent = ?leaf.hash, "Selected bitfields" ); - let candidates = - select_candidates(&availability_cores, &bitfields, candidates, leaf.hash, from_job).await?; + + let candidates = select_candidates( + &availability_cores, + &bitfields, + candidates, + prospective_parachains_mode, + leaf.hash, + from_job, + ) + .await?; gum::trace!( target: LOG_TARGET, @@ -532,15 +550,16 @@ fn select_availability_bitfields( selected.into_values().collect() } -/// Determine which cores are free, and then to the degree possible, pick a candidate appropriate to -/// each free core. -async fn select_candidates( +/// Selects candidates from tracked ones to note in a relay chain block. +/// +/// Should be called when prospective parachains are disabled. +async fn select_candidate_hashes_from_tracked( availability_cores: &[CoreState], bitfields: &[SignedAvailabilityBitfield], candidates: &[CandidateReceipt], relay_parent: Hash, sender: &mut impl overseer::ProvisionerSenderTrait, -) -> Result, Error> { +) -> Result, Error> { let block_number = get_block_number_under_construction(relay_parent, sender).await?; let mut selected_candidates = @@ -611,18 +630,112 @@ async fn select_candidates( "Selected candidate receipt", ); - selected_candidates.push(candidate_hash); + selected_candidates.push((candidate_hash, candidate.descriptor.relay_parent)); + } + } + + Ok(selected_candidates) +} + +/// Requests backable candidates from Prospective Parachains subsystem +/// based on core states. +/// +/// Should be called when prospective parachains are enabled. +async fn request_backable_candidates( + availability_cores: &[CoreState], + bitfields: &[SignedAvailabilityBitfield], + relay_parent: Hash, + sender: &mut impl overseer::ProvisionerSenderTrait, +) -> Result, Error> { + let block_number = get_block_number_under_construction(relay_parent, sender).await?; + + let mut selected_candidates = Vec::with_capacity(availability_cores.len()); + + for (core_idx, core) in availability_cores.iter().enumerate() { + let (para_id, required_path) = match core { + CoreState::Scheduled(scheduled_core) => { + // The core is free, pick the first eligible candidate from + // the fragment tree. + (scheduled_core.para_id, Vec::new()) + }, + CoreState::Occupied(occupied_core) => { + if bitfields_indicate_availability(core_idx, bitfields, &occupied_core.availability) + { + if let Some(ref scheduled_core) = occupied_core.next_up_on_available { + // The candidate occupying the core is available, choose its + // child in the fragment tree. + // + // TODO: doesn't work for on-demand parachains. We lean hard on the + // assumption that cores are fixed to specific parachains within a session. + // https://github.com/paritytech/polkadot/issues/5492 + (scheduled_core.para_id, vec![occupied_core.candidate_hash]) + } else { + continue + } + } else { + if occupied_core.time_out_at != block_number { + continue + } + if let Some(ref scheduled_core) = occupied_core.next_up_on_time_out { + // Candidate's availability timed out, practically same as scheduled. + (scheduled_core.para_id, Vec::new()) + } else { + continue + } + } + }, + CoreState::Free => continue, + }; + + let response = get_backable_candidate(relay_parent, para_id, required_path, sender).await?; + + match response { + Some((hash, relay_parent)) => selected_candidates.push((hash, relay_parent)), + None => { + gum::debug!( + target: LOG_TARGET, + leaf_hash = ?relay_parent, + core = core_idx, + "No backable candidate returned by prospective parachains", + ); + }, } } + Ok(selected_candidates) +} + +/// Determine which cores are free, and then to the degree possible, pick a candidate appropriate to +/// each free core. +async fn select_candidates( + availability_cores: &[CoreState], + bitfields: &[SignedAvailabilityBitfield], + candidates: &[CandidateReceipt], + prospective_parachains_mode: ProspectiveParachainsMode, + relay_parent: Hash, + sender: &mut impl overseer::ProvisionerSenderTrait, +) -> Result, Error> { gum::trace!(target: LOG_TARGET, leaf_hash=?relay_parent, "before GetBackedCandidates"); + let selected_candidates = match prospective_parachains_mode { + ProspectiveParachainsMode::Enabled { .. } => + request_backable_candidates(availability_cores, bitfields, relay_parent, sender).await?, + ProspectiveParachainsMode::Disabled => + select_candidate_hashes_from_tracked( + availability_cores, + bitfields, + &candidates, + relay_parent, + sender, + ) + .await?, + }; + // now get the backed candidates corresponding to these candidate receipts let (tx, rx) = oneshot::channel(); sender.send_unbounded_message(CandidateBackingMessage::GetBackedCandidates( - relay_parent, selected_candidates.clone(), tx, )); @@ -638,7 +751,7 @@ async fn select_candidates( // checking them in order, we can ensure that the backed candidates are also in order. let mut backed_idx = 0; for selected in selected_candidates { - if selected == + if selected.0 == candidates.get(backed_idx).ok_or(Error::BackedCandidateOrderingProblem)?.hash() { backed_idx += 1; @@ -689,6 +802,27 @@ async fn get_block_number_under_construction( } } +/// Requests backable candidate from Prospective Parachains based on +/// the given path in the fragment tree. +async fn get_backable_candidate( + relay_parent: Hash, + para_id: ParaId, + required_path: Vec, + sender: &mut impl overseer::ProvisionerSenderTrait, +) -> Result, Error> { + let (tx, rx) = oneshot::channel(); + sender + .send_message(ProspectiveParachainsMessage::GetBackableCandidate( + relay_parent, + para_id, + required_path, + tx, + )) + .await; + + rx.await.map_err(Error::CanceledBackableCandidate) +} + /// The availability bitfield for a given core is the transpose /// of a set of signed availability bitfields. It goes like this: /// diff --git a/node/core/provisioner/src/tests.rs b/node/core/provisioner/src/tests.rs index 4a469a43c893..1d7bdfcfcb89 100644 --- a/node/core/provisioner/src/tests.rs +++ b/node/core/provisioner/src/tests.rs @@ -19,6 +19,8 @@ use ::test_helpers::{dummy_candidate_descriptor, dummy_hash}; use bitvec::bitvec; use polkadot_primitives::{OccupiedCore, ScheduledCore}; +const MOCK_GROUP_SIZE: usize = 5; + pub fn occupied_core(para_id: u32) -> CoreState { CoreState::Occupied(OccupiedCore { group_responsible: para_id.into(), @@ -46,8 +48,8 @@ where CoreState::Occupied(core) } -pub fn default_bitvec(n_cores: usize) -> CoreAvailability { - bitvec![u8, bitvec::order::Lsb0; 0; n_cores] +pub fn default_bitvec(size: usize) -> CoreAvailability { + bitvec![u8, bitvec::order::Lsb0; 0; size] } pub fn scheduled_core(id: u32) -> ScheduledCore { @@ -237,7 +239,7 @@ pub(crate) mod common { mod select_candidates { use super::{ super::*, build_occupied_core, common::test_harness, default_bitvec, occupied_core, - scheduled_core, + scheduled_core, MOCK_GROUP_SIZE, }; use ::test_helpers::{dummy_candidate_descriptor, dummy_hash}; use futures::channel::mpsc; @@ -248,6 +250,7 @@ mod select_candidates { }, }; use polkadot_node_subsystem_test_helpers::TestSubsystemSender; + use polkadot_node_subsystem_util::runtime::ProspectiveParachainsMode; use polkadot_primitives::{ BlockNumber, CandidateCommitments, CommittedCandidateReceipt, PersistedValidationData, }; @@ -333,10 +336,17 @@ mod select_candidates { async fn mock_overseer( mut receiver: mpsc::UnboundedReceiver, expected: Vec, + prospective_parachains_mode: ProspectiveParachainsMode, ) { use ChainApiMessage::BlockNumber; use RuntimeApiMessage::Request; + let mut candidates_iter = expected + .iter() + .map(|candidate| (candidate.hash(), candidate.descriptor().relay_parent)); + + let mut backed_iter = expected.clone().into_iter(); + while let Some(from_job) = receiver.next().await { match from_job { AllMessages::ChainApi(BlockNumber(_relay_parent, tx)) => @@ -348,11 +358,28 @@ mod select_candidates { AllMessages::RuntimeApi(Request(_parent_hash, AvailabilityCores(tx))) => tx.send(Ok(mock_availability_cores())).unwrap(), AllMessages::CandidateBacking(CandidateBackingMessage::GetBackedCandidates( - _, - _, + hashes, sender, )) => { - let _ = sender.send(expected.clone()); + let response: Vec = + backed_iter.by_ref().take(hashes.len()).collect(); + let expected_hashes: Vec<(CandidateHash, Hash)> = response + .iter() + .map(|candidate| (candidate.hash(), candidate.descriptor().relay_parent)) + .collect(); + + assert_eq!(expected_hashes, hashes); + + let _ = sender.send(response); + }, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetBackableCandidate(.., tx), + ) => match prospective_parachains_mode { + ProspectiveParachainsMode::Enabled { .. } => { + let _ = tx.send(candidates_iter.next()); + }, + ProspectiveParachainsMode::Disabled => + panic!("unexpected prospective parachains request"), }, _ => panic!("Unexpected message: {:?}", from_job), } @@ -362,9 +389,19 @@ mod select_candidates { #[test] fn can_succeed() { test_harness( - |r| mock_overseer(r, Vec::new()), + |r| mock_overseer(r, Vec::new(), ProspectiveParachainsMode::Disabled), |mut tx: TestSubsystemSender| async move { - select_candidates(&[], &[], &[], Default::default(), &mut tx).await.unwrap(); + let prospective_parachains_mode = ProspectiveParachainsMode::Disabled; + select_candidates( + &[], + &[], + &[], + prospective_parachains_mode, + Default::default(), + &mut tx, + ) + .await + .unwrap(); }, ) } @@ -375,7 +412,6 @@ mod select_candidates { #[test] fn selects_correct_candidates() { let mock_cores = mock_availability_cores(); - let n_cores = mock_cores.len(); let empty_hash = PersistedValidationData::::default().hash(); @@ -415,6 +451,7 @@ mod select_candidates { // why those particular indices? see the comments on mock_availability_cores() let expected_candidates: Vec<_> = [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); + let prospective_parachains_mode = ProspectiveParachainsMode::Disabled; let expected_backed = expected_candidates .iter() @@ -424,17 +461,23 @@ mod select_candidates { commitments: Default::default(), }, validity_votes: Vec::new(), - validator_indices: default_bitvec(n_cores), + validator_indices: default_bitvec(MOCK_GROUP_SIZE), }) .collect(); test_harness( - |r| mock_overseer(r, expected_backed), + |r| mock_overseer(r, expected_backed, prospective_parachains_mode), |mut tx: TestSubsystemSender| async move { - let result = - select_candidates(&mock_cores, &[], &candidates, Default::default(), &mut tx) - .await - .unwrap(); + let result = select_candidates( + &mock_cores, + &[], + &candidates, + prospective_parachains_mode, + Default::default(), + &mut tx, + ) + .await + .unwrap(); result.into_iter().for_each(|c| { assert!( @@ -450,15 +493,16 @@ mod select_candidates { #[test] fn selects_max_one_code_upgrade() { let mock_cores = mock_availability_cores(); - let n_cores = mock_cores.len(); let empty_hash = PersistedValidationData::::default().hash(); // why those particular indices? see the comments on mock_availability_cores() // the first candidate with code is included out of [1, 4, 7, 8, 10]. - let cores = [1, 7, 10]; + let cores = [1, 4, 7, 8, 10]; let cores_with_code = [1, 4, 8]; + let expected_cores = [1, 7, 10]; + let committed_receipts: Vec<_> = (0..mock_cores.len()) .map(|i| { let mut descriptor = dummy_candidate_descriptor(dummy_hash()); @@ -478,27 +522,173 @@ mod select_candidates { }) .collect(); + // Input to select_candidates let candidates: Vec<_> = committed_receipts.iter().map(|r| r.to_plain()).collect(); + // Build possible outputs from select_candidates + let backed_candidates: Vec<_> = committed_receipts + .iter() + .map(|committed_receipt| BackedCandidate { + candidate: committed_receipt.clone(), + validity_votes: Vec::new(), + validator_indices: default_bitvec(MOCK_GROUP_SIZE), + }) + .collect(); + + // First, provisioner will request backable candidates for each scheduled core. + // Then, some of them get filtered due to new validation code rule. + let expected_backed: Vec<_> = + cores.iter().map(|&idx| backed_candidates[idx].clone()).collect(); + let expected_backed_filtered: Vec<_> = + expected_cores.iter().map(|&idx| candidates[idx].clone()).collect(); + let prospective_parachains_mode = ProspectiveParachainsMode::Disabled; + + test_harness( + |r| mock_overseer(r, expected_backed, prospective_parachains_mode), + |mut tx: TestSubsystemSender| async move { + let result = select_candidates( + &mock_cores, + &[], + &candidates, + prospective_parachains_mode, + Default::default(), + &mut tx, + ) + .await + .unwrap(); + + assert_eq!(result.len(), 3); + + result.into_iter().for_each(|c| { + assert!( + expected_backed_filtered.iter().any(|c2| c.candidate.corresponds_to(c2)), + "Failed to find candidate: {:?}", + c, + ) + }); + }, + ) + } + + #[test] + fn request_from_prospective_parachains() { + let mock_cores = mock_availability_cores(); + let empty_hash = PersistedValidationData::::default().hash(); + + let mut descriptor_template = dummy_candidate_descriptor(dummy_hash()); + descriptor_template.persisted_validation_data_hash = empty_hash; + let candidate_template = CandidateReceipt { + descriptor: descriptor_template, + commitments_hash: CandidateCommitments::default().hash(), + }; + + let candidates: Vec<_> = std::iter::repeat(candidate_template) + .take(mock_cores.len()) + .enumerate() + .map(|(idx, mut candidate)| { + candidate.descriptor.para_id = idx.into(); + candidate + }) + .collect(); + + // why those particular indices? see the comments on mock_availability_cores() let expected_candidates: Vec<_> = - cores.iter().map(|&idx| candidates[idx].clone()).collect(); + [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); + // Expect prospective parachains subsystem requests. + let prospective_parachains_mode = + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; - let expected_backed: Vec<_> = cores + let expected_backed = expected_candidates .iter() - .map(|&idx| BackedCandidate { - candidate: committed_receipts[idx].clone(), + .map(|c| BackedCandidate { + candidate: CommittedCandidateReceipt { + descriptor: c.descriptor.clone(), + commitments: Default::default(), + }, + validity_votes: Vec::new(), + validator_indices: default_bitvec(MOCK_GROUP_SIZE), + }) + .collect(); + + test_harness( + |r| mock_overseer(r, expected_backed, prospective_parachains_mode), + |mut tx: TestSubsystemSender| async move { + let result = select_candidates( + &mock_cores, + &[], + &[], + prospective_parachains_mode, + Default::default(), + &mut tx, + ) + .await + .unwrap(); + + result.into_iter().for_each(|c| { + assert!( + expected_candidates.iter().any(|c2| c.candidate.corresponds_to(c2)), + "Failed to find candidate: {:?}", + c, + ) + }); + }, + ) + } + + #[test] + fn request_receipts_based_on_relay_parent() { + let mock_cores = mock_availability_cores(); + let empty_hash = PersistedValidationData::::default().hash(); + + let mut descriptor_template = dummy_candidate_descriptor(dummy_hash()); + descriptor_template.persisted_validation_data_hash = empty_hash; + let candidate_template = CandidateReceipt { + descriptor: descriptor_template, + commitments_hash: CandidateCommitments::default().hash(), + }; + + let candidates: Vec<_> = std::iter::repeat(candidate_template) + .take(mock_cores.len()) + .enumerate() + .map(|(idx, mut candidate)| { + candidate.descriptor.para_id = idx.into(); + candidate.descriptor.relay_parent = Hash::repeat_byte(idx as u8); + candidate + }) + .collect(); + + // why those particular indices? see the comments on mock_availability_cores() + let expected_candidates: Vec<_> = + [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); + // Expect prospective parachains subsystem requests. + let prospective_parachains_mode = + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; + + let expected_backed = expected_candidates + .iter() + .map(|c| BackedCandidate { + candidate: CommittedCandidateReceipt { + descriptor: c.descriptor.clone(), + commitments: Default::default(), + }, validity_votes: Vec::new(), - validator_indices: default_bitvec(n_cores), + validator_indices: default_bitvec(MOCK_GROUP_SIZE), }) .collect(); test_harness( - |r| mock_overseer(r, expected_backed), + |r| mock_overseer(r, expected_backed, prospective_parachains_mode), |mut tx: TestSubsystemSender| async move { - let result = - select_candidates(&mock_cores, &[], &candidates, Default::default(), &mut tx) - .await - .unwrap(); + let result = select_candidates( + &mock_cores, + &[], + &[], + prospective_parachains_mode, + Default::default(), + &mut tx, + ) + .await + .unwrap(); result.into_iter().for_each(|c| { assert!( diff --git a/node/core/runtime-api/src/cache.rs b/node/core/runtime-api/src/cache.rs index 4c23ce2fa3c7..26aaf3fb6ec8 100644 --- a/node/core/runtime-api/src/cache.rs +++ b/node/core/runtime-api/src/cache.rs @@ -68,6 +68,9 @@ pub(crate) struct RequestResultCache { LruCache>, key_ownership_proof: LruCache<(Hash, ValidatorId), Option>, + + staging_para_backing_state: LruCache<(Hash, ParaId), Option>, + staging_async_backing_params: LruCache, } impl Default for RequestResultCache { @@ -97,6 +100,9 @@ impl Default for RequestResultCache { disputes: LruCache::new(DEFAULT_CACHE_CAP), unapplied_slashes: LruCache::new(DEFAULT_CACHE_CAP), key_ownership_proof: LruCache::new(DEFAULT_CACHE_CAP), + + staging_para_backing_state: LruCache::new(DEFAULT_CACHE_CAP), + staging_async_backing_params: LruCache::new(DEFAULT_CACHE_CAP), } } } @@ -430,6 +436,36 @@ impl RequestResultCache { ) -> Option<&Option<()>> { None } + + pub(crate) fn staging_para_backing_state( + &mut self, + key: (Hash, ParaId), + ) -> Option<&Option> { + self.staging_para_backing_state.get(&key) + } + + pub(crate) fn cache_staging_para_backing_state( + &mut self, + key: (Hash, ParaId), + value: Option, + ) { + self.staging_para_backing_state.put(key, value); + } + + pub(crate) fn staging_async_backing_params( + &mut self, + key: &Hash, + ) -> Option<&vstaging::AsyncBackingParams> { + self.staging_async_backing_params.get(key) + } + + pub(crate) fn cache_staging_async_backing_params( + &mut self, + key: Hash, + value: vstaging::AsyncBackingParams, + ) { + self.staging_async_backing_params.put(key, value); + } } pub(crate) enum RequestResult { @@ -476,4 +512,7 @@ pub(crate) enum RequestResult { vstaging::slashing::OpaqueKeyOwnershipProof, Option<()>, ), + + StagingParaBackingState(Hash, ParaId, Option), + StagingAsyncBackingParams(Hash, vstaging::AsyncBackingParams), } diff --git a/node/core/runtime-api/src/lib.rs b/node/core/runtime-api/src/lib.rs index 0ee5ca24ceee..78531d41272b 100644 --- a/node/core/runtime-api/src/lib.rs +++ b/node/core/runtime-api/src/lib.rs @@ -163,6 +163,12 @@ where .requests_cache .cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof), SubmitReportDisputeLost(_, _, _, _) => {}, + + StagingParaBackingState(relay_parent, para_id, constraints) => self + .requests_cache + .cache_staging_para_backing_state((relay_parent, para_id), constraints), + StagingAsyncBackingParams(relay_parent, params) => + self.requests_cache.cache_staging_async_backing_params(relay_parent, params), } } @@ -288,6 +294,13 @@ where Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) }, ), + + Request::StagingParaBackingState(para, sender) => + query!(staging_para_backing_state(para), sender) + .map(|sender| Request::StagingParaBackingState(para, sender)), + Request::StagingAsyncBackingParams(sender) => + query!(staging_async_backing_params(), sender) + .map(|sender| Request::StagingAsyncBackingParams(sender)), } } @@ -538,5 +551,22 @@ where ver = Request::SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT, sender ), + + Request::StagingParaBackingState(para, sender) => { + query!( + StagingParaBackingState, + staging_para_backing_state(para), + ver = Request::STAGING_BACKING_STATE, + sender + ) + }, + Request::StagingAsyncBackingParams(sender) => { + query!( + StagingAsyncBackingParams, + staging_async_backing_params(), + ver = Request::STAGING_BACKING_STATE, + sender + ) + }, } } diff --git a/node/core/runtime-api/src/tests.rs b/node/core/runtime-api/src/tests.rs index 53b3fd56bf3e..c3f8108312be 100644 --- a/node/core/runtime-api/src/tests.rs +++ b/node/core/runtime-api/src/tests.rs @@ -249,6 +249,21 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { async fn authorities(&self, _: Hash) -> Result, ApiError> { Ok(self.authorities.clone()) } + + async fn staging_async_backing_params( + &self, + _: Hash, + ) -> Result { + todo!("Not required for tests") + } + + async fn staging_para_backing_state( + &self, + _: Hash, + _: ParaId, + ) -> Result, ApiError> { + todo!("Not required for tests") + } } #[test] diff --git a/node/malus/integrationtests/0001-dispute-valid-block.zndsl b/node/malus/integrationtests/0001-dispute-valid-block.zndsl index f778b0231ba9..737cd4ebd521 100644 --- a/node/malus/integrationtests/0001-dispute-valid-block.zndsl +++ b/node/malus/integrationtests/0001-dispute-valid-block.zndsl @@ -16,14 +16,14 @@ bob: reports block height is at least 2 bob: reports peers count is at least 2 charlie: reports block height is at least 2 charlie: reports peers count is at least 2 -alice: reports parachain_candidate_disputes_total is at least 1 within 250 seconds -bob: reports parachain_candidate_disputes_total is at least 1 within 90 seconds -charlie: reports parachain_candidate_disputes_total is at least 1 within 90 seconds -alice: reports parachain_candidate_dispute_votes{validity="valid"} is at least 1 within 90 seconds -bob: reports parachain_candidate_dispute_votes{validity="valid"} is at least 2 within 90 seconds -charlie: reports parachain_candidate_dispute_votes{validity="valid"} is at least 2 within 90 seconds -alice: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds -alice: reports parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 90 seconds -bob: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds -charlie: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds -charlie: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds +alice: reports polkadot_parachain_candidate_disputes_total is at least 1 within 250 seconds +bob: reports polkadot_parachain_candidate_disputes_total is at least 1 within 90 seconds +charlie: reports polkadot_parachain_candidate_disputes_total is at least 1 within 90 seconds +alice: reports polkadot_parachain_candidate_dispute_votes{validity="valid"} is at least 1 within 90 seconds +bob: reports polkadot_parachain_candidate_dispute_votes{validity="valid"} is at least 2 within 90 seconds +charlie: reports polkadot_parachain_candidate_dispute_votes{validity="valid"} is at least 2 within 90 seconds +alice: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds +alice: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 90 seconds +bob: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds +charlie: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds +charlie: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is at least 1 within 90 seconds diff --git a/node/malus/src/variants/common.rs b/node/malus/src/variants/common.rs index 6bc889595362..475ca8f31452 100644 --- a/node/malus/src/variants/common.rs +++ b/node/malus/src/variants/common.rs @@ -30,6 +30,7 @@ use polkadot_node_subsystem::{ use polkadot_primitives::{ CandidateCommitments, CandidateDescriptor, CandidateReceipt, PersistedValidationData, + PvfExecTimeoutKind, }; use futures::channel::oneshot; @@ -48,6 +49,55 @@ pub enum FakeCandidateValidation { BackingAndApprovalValid, } +impl FakeCandidateValidation { + fn misbehaves_valid(&self) -> bool { + use FakeCandidateValidation::*; + + match *self { + BackingValid | ApprovalValid | BackingAndApprovalValid => true, + _ => false, + } + } + + fn misbehaves_invalid(&self) -> bool { + use FakeCandidateValidation::*; + + match *self { + BackingInvalid | ApprovalInvalid | BackingAndApprovalInvalid => true, + _ => false, + } + } + + fn includes_backing(&self) -> bool { + use FakeCandidateValidation::*; + + match *self { + BackingInvalid | BackingAndApprovalInvalid | BackingValid | BackingAndApprovalValid => + true, + _ => false, + } + } + + fn includes_approval(&self) -> bool { + use FakeCandidateValidation::*; + + match *self { + ApprovalInvalid | + BackingAndApprovalInvalid | + ApprovalValid | + BackingAndApprovalValid => true, + _ => false, + } + } + + fn should_misbehave(&self, timeout: PvfExecTimeoutKind) -> bool { + match timeout { + PvfExecTimeoutKind::Backing => self.includes_backing(), + PvfExecTimeoutKind::Approval => self.includes_approval(), + } + } +} + /// Candidate invalidity details #[derive(clap::ValueEnum, Clone, Copy, Debug, PartialEq)] #[value(rename_all = "kebab-case")] @@ -162,11 +212,20 @@ where pub fn create_fake_candidate_commitments( persisted_validation_data: &PersistedValidationData, ) -> CandidateCommitments { + // Backing rejects candidates which output the same head as the parent, + // therefore we must create a new head which is not equal to the parent. + let mut head_data = persisted_validation_data.parent_head.clone(); + if head_data.0.is_empty() { + head_data.0.push(0); + } else { + head_data.0[0] = head_data.0[0].wrapping_add(1); + }; + CandidateCommitments { upward_messages: Default::default(), horizontal_messages: Default::default(), new_validation_code: None, - head_data: persisted_validation_data.parent_head.clone(), + head_data, processed_downward_messages: 0, hrmp_watermark: persisted_validation_data.relay_parent_number, } @@ -224,8 +283,7 @@ where ), } => { match self.fake_validation { - FakeCandidateValidation::ApprovalValid | - FakeCandidateValidation::BackingAndApprovalValid => { + x if x.misbehaves_valid() && x.should_misbehave(timeout) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { @@ -278,8 +336,7 @@ where }, } }, - FakeCandidateValidation::ApprovalInvalid | - FakeCandidateValidation::BackingAndApprovalInvalid => { + x if x.misbehaves_invalid() && x.should_misbehave(timeout) => { // Set the validation result to invalid with probability `p` and trigger a // dispute let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); @@ -342,8 +399,7 @@ where ), } => { match self.fake_validation { - FakeCandidateValidation::BackingValid | - FakeCandidateValidation::BackingAndApprovalValid => { + x if x.misbehaves_valid() && x.should_misbehave(timeout) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { @@ -385,8 +441,7 @@ where }), } }, - FakeCandidateValidation::BackingInvalid | - FakeCandidateValidation::BackingAndApprovalInvalid => { + x if x.misbehaves_invalid() && x.should_misbehave(timeout) => { // Maliciously set the validation result to invalid for a valid candidate // with probability `p` let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); diff --git a/node/malus/src/variants/suggest_garbage_candidate.rs b/node/malus/src/variants/suggest_garbage_candidate.rs index b0290fff949d..cf0ff5f809d8 100644 --- a/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/node/malus/src/variants/suggest_garbage_candidate.rs @@ -79,7 +79,13 @@ where ) -> Option> { match msg { FromOrchestra::Communication { - msg: CandidateBackingMessage::Second(relay_parent, ref candidate, ref _pov), + msg: + CandidateBackingMessage::Second( + relay_parent, + ref candidate, + ref _validation_data, + ref _pov, + ), } => { gum::debug!( target: MALUS, @@ -156,8 +162,10 @@ where "Fetched validation data." ); - let malicious_available_data = - AvailableData { pov: Arc::new(pov.clone()), validation_data }; + let malicious_available_data = AvailableData { + pov: Arc::new(pov.clone()), + validation_data: validation_data.clone(), + }; let pov_hash = pov.hash(); let erasure_root = { @@ -211,6 +219,7 @@ where msg: CandidateBackingMessage::Second( relay_parent, malicious_candidate, + validation_data, pov, ), }; diff --git a/node/network/approval-distribution/src/lib.rs b/node/network/approval-distribution/src/lib.rs index b94ebb282219..ac525ea6faf3 100644 --- a/node/network/approval-distribution/src/lib.rs +++ b/node/network/approval-distribution/src/lib.rs @@ -25,8 +25,9 @@ use polkadot_node_jaeger as jaeger; use polkadot_node_network_protocol::{ self as net_protocol, grid_topology::{RandomRouting, RequiredRouting, SessionGridTopologies, SessionGridTopology}, - peer_set::MAX_NOTIFICATION_SIZE, - v1 as protocol_v1, PeerId, UnifiedReputationChange as Rep, Versioned, View, + peer_set::{ValidationVersion, MAX_NOTIFICATION_SIZE}, + v1 as protocol_v1, vstaging as protocol_vstaging, PeerId, UnifiedReputationChange as Rep, + Versioned, VersionedValidationProtocol, View, }; use polkadot_node_primitives::approval::{ AssignmentCert, BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote, @@ -159,6 +160,15 @@ enum Resend { No, } +/// Data stored on a per-peer basis. +#[derive(Debug)] +struct PeerData { + /// The peer's view. + view: View, + /// The peer's protocol version. + version: ValidationVersion, +} + /// The [`State`] struct is responsible for tracking the overall state of the subsystem. /// /// It tracks metadata about our view of the unfinalized chain, @@ -179,7 +189,7 @@ struct State { pending_known: HashMap>, /// Peer data is partially stored here, and partially inline within the [`BlockEntry`]s - peer_views: HashMap, + peer_data: HashMap, /// Keeps a topology for various different sessions. topologies: SessionGridTopologies, @@ -349,14 +359,30 @@ impl State { rng: &mut (impl CryptoRng + Rng), ) { match event { - NetworkBridgeEvent::PeerConnected(peer_id, role, _, _) => { + NetworkBridgeEvent::PeerConnected(peer_id, role, version, _) => { // insert a blank view if none already present gum::trace!(target: LOG_TARGET, ?peer_id, ?role, "Peer connected"); - self.peer_views.entry(peer_id).or_default(); + let version = match ValidationVersion::try_from(version).ok() { + Some(v) => v, + None => { + // sanity: network bridge is supposed to detect this already. + gum::error!( + target: LOG_TARGET, + ?peer_id, + ?version, + "Unsupported protocol version" + ); + return + }, + }; + + self.peer_data + .entry(peer_id) + .or_insert_with(|| PeerData { version, view: Default::default() }); }, NetworkBridgeEvent::PeerDisconnected(peer_id) => { gum::trace!(target: LOG_TARGET, ?peer_id, "Peer disconnected"); - self.peer_views.remove(&peer_id); + self.peer_data.remove(&peer_id); self.blocks.iter_mut().for_each(|(_hash, entry)| { entry.known_by.remove(&peer_id); }) @@ -393,12 +419,12 @@ impl State { live }); }, + NetworkBridgeEvent::PeerMessage(peer_id, msg) => { + self.process_incoming_peer_message(ctx, metrics, peer_id, msg, rng).await; + }, NetworkBridgeEvent::UpdatedAuthorityIds { .. } => { // The approval-distribution subsystem doesn't deal with `AuthorityDiscoveryId`s. }, - NetworkBridgeEvent::PeerMessage(peer_id, Versioned::V1(msg)) => { - self.process_incoming_peer_message(ctx, metrics, peer_id, msg, rng).await; - }, } } @@ -455,16 +481,18 @@ impl State { { let sender = ctx.sender(); - for (peer_id, view) in self.peer_views.iter() { - let intersection = view.iter().filter(|h| new_hashes.contains(h)); - let view_intersection = View::new(intersection.cloned(), view.finalized_number); + for (peer_id, data) in self.peer_data.iter() { + let intersection = data.view.iter().filter(|h| new_hashes.contains(h)); + let view_intersection = + View::new(intersection.cloned(), data.view.finalized_number); Self::unify_with_peer( sender, metrics, &mut self.blocks, &self.topologies, - self.peer_views.len(), + self.peer_data.len(), *peer_id, + data.version, view_intersection, rng, ) @@ -547,6 +575,7 @@ impl State { adjust_required_routing_and_propagate( ctx, + &self.peer_data, &mut self.blocks, &self.topologies, |block_entry| block_entry.session == session, @@ -566,13 +595,16 @@ impl State { ctx: &mut Context, metrics: &Metrics, peer_id: PeerId, - msg: protocol_v1::ApprovalDistributionMessage, + msg: net_protocol::ApprovalDistributionMessage, rng: &mut R, ) where R: CryptoRng + Rng, { match msg { - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) => { + Versioned::V1(protocol_v1::ApprovalDistributionMessage::Assignments(assignments)) | + Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Assignments( + assignments, + )) => { gum::trace!( target: LOG_TARGET, peer_id = %peer_id, @@ -611,7 +643,10 @@ impl State { .await; } }, - protocol_v1::ApprovalDistributionMessage::Approvals(approvals) => { + Versioned::V1(protocol_v1::ApprovalDistributionMessage::Approvals(approvals)) | + Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Approvals( + approvals, + )) => { gum::trace!( target: LOG_TARGET, peer_id = %peer_id, @@ -664,9 +699,14 @@ impl State { { gum::trace!(target: LOG_TARGET, ?view, "Peer view change"); let finalized_number = view.finalized_number; - let old_view = - self.peer_views.get_mut(&peer_id).map(|d| std::mem::replace(d, view.clone())); - let old_finalized_number = old_view.map(|v| v.finalized_number).unwrap_or(0); + let (peer_protocol_version, old_finalized_number) = match self + .peer_data + .get_mut(&peer_id) + .map(|d| (d.version, std::mem::replace(&mut d.view, view.clone()))) + { + Some((v, view)) => (v, view.finalized_number), + None => return, // unknown peer + }; // we want to prune every block known_by peer up to (including) view.finalized_number let blocks = &mut self.blocks; @@ -691,8 +731,9 @@ impl State { metrics, &mut self.blocks, &self.topologies, - self.peer_views.len(), + self.peer_data.len(), peer_id, + peer_protocol_version, view, rng, ) @@ -992,7 +1033,7 @@ impl State { // then messages will be sent when we get it. let assignments = vec![(assignment, claimed_candidate_index)]; - let n_peers_total = self.peer_views.len(); + let n_peers_total = self.peer_data.len(); let source_peer = source.peer_id(); let mut peer_filter = move |peer| { @@ -1019,31 +1060,53 @@ impl State { route_random }; - let peers = entry.known_by.keys().filter(|p| peer_filter(p)).cloned().collect::>(); + let (v1_peers, vstaging_peers) = { + let peer_data = &self.peer_data; + let peers = entry + .known_by + .keys() + .filter_map(|p| peer_data.get_key_value(p)) + .filter(|(p, _)| peer_filter(p)) + .map(|(p, peer_data)| (*p, peer_data.version)) + .collect::>(); + + // Add the metadata of the assignment to the knowledge of each peer. + for (peer, _) in peers.iter() { + // we already filtered peers above, so this should always be Some + if let Some(peer_knowledge) = entry.known_by.get_mut(peer) { + peer_knowledge.sent.insert(message_subject.clone(), message_kind); + } + } - // Add the metadata of the assignment to the knowledge of each peer. - for peer in peers.iter() { - // we already filtered peers above, so this should always be Some - if let Some(peer_knowledge) = entry.known_by.get_mut(peer) { - peer_knowledge.sent.insert(message_subject.clone(), message_kind); + if !peers.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?block_hash, + ?claimed_candidate_index, + local = source.peer_id().is_none(), + num_peers = peers.len(), + "Sending an assignment to peers", + ); } - } - if !peers.is_empty() { - gum::trace!( - target: LOG_TARGET, - ?block_hash, - ?claimed_candidate_index, - local = source.peer_id().is_none(), - num_peers = peers.len(), - "Sending an assignment to peers", - ); + let v1_peers = filter_peers_by_version(&peers, ValidationVersion::V1); + let vstaging_peers = filter_peers_by_version(&peers, ValidationVersion::VStaging); + (v1_peers, vstaging_peers) + }; + + if !v1_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments), - )), + v1_peers, + versioned_assignments_packet(ValidationVersion::V1, assignments.clone()), + )) + .await; + } + + if !vstaging_peers.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vstaging_peers, + versioned_assignments_packet(ValidationVersion::VStaging, assignments.clone()), )) .await; } @@ -1332,38 +1395,55 @@ impl State { in_topology || knowledge.sent.contains(message_subject, MessageKind::Assignment) }; - let peers = entry - .known_by - .iter() - .filter(|(p, k)| peer_filter(p, k)) - .map(|(p, _)| p) - .cloned() - .collect::>(); - - // Add the metadata of the assignment to the knowledge of each peer. - for peer in peers.iter() { - // we already filtered peers above, so this should always be Some - if let Some(entry) = entry.known_by.get_mut(peer) { - entry.sent.insert(message_subject.clone(), message_kind); + let (v1_peers, vstaging_peers) = { + let peer_data = &self.peer_data; + let peers = entry + .known_by + .iter() + .filter_map(|(p, k)| peer_data.get(&p).map(|pd| (p, k, pd.version))) + .filter(|(p, k, _)| peer_filter(p, k)) + .map(|(p, _, v)| (*p, v)) + .collect::>(); + + // Add the metadata of the assignment to the knowledge of each peer. + for (peer, _) in peers.iter() { + // we already filtered peers above, so this should always be Some + if let Some(peer_knowledge) = entry.known_by.get_mut(peer) { + peer_knowledge.sent.insert(message_subject.clone(), message_kind); + } } - } - if !peers.is_empty() { - let approvals = vec![vote]; - gum::trace!( - target: LOG_TARGET, - ?block_hash, - ?candidate_index, - local = source.peer_id().is_none(), - num_peers = peers.len(), - "Sending an approval to peers", - ); + if !peers.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?block_hash, + ?candidate_index, + local = source.peer_id().is_none(), + num_peers = peers.len(), + "Sending an approval to peers", + ); + } + + let v1_peers = filter_peers_by_version(&peers, ValidationVersion::V1); + let vstaging_peers = filter_peers_by_version(&peers, ValidationVersion::VStaging); + + (v1_peers, vstaging_peers) + }; + + let approvals = vec![vote]; + + if !v1_peers.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + v1_peers, + versioned_approvals_packet(ValidationVersion::V1, approvals.clone()), + )) + .await; + } + if !vstaging_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(approvals), - )), + vstaging_peers, + versioned_approvals_packet(ValidationVersion::VStaging, approvals), )) .await; } @@ -1427,6 +1507,7 @@ impl State { topologies: &SessionGridTopologies, total_peers: usize, peer_id: PeerId, + peer_protocol_version: ValidationVersion, view: View, rng: &mut (impl CryptoRng + Rng), ) { @@ -1536,7 +1617,8 @@ impl State { "Sending assignments to unified peer", ); - send_assignments_batched(sender, assignments_to_send, peer_id).await; + send_assignments_batched(sender, assignments_to_send, peer_id, peer_protocol_version) + .await; } if !approvals_to_send.is_empty() { @@ -1547,7 +1629,7 @@ impl State { "Sending approvals to unified peer", ); - send_approvals_batched(sender, approvals_to_send, peer_id).await; + send_approvals_batched(sender, approvals_to_send, peer_id, peer_protocol_version).await; } } @@ -1583,6 +1665,7 @@ impl State { adjust_required_routing_and_propagate( ctx, + &self.peer_data, &mut self.blocks, &self.topologies, |block_entry| { @@ -1610,6 +1693,7 @@ impl State { adjust_required_routing_and_propagate( ctx, + &self.peer_data, &mut self.blocks, &self.topologies, |block_entry| { @@ -1669,6 +1753,7 @@ impl State { #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] async fn adjust_required_routing_and_propagate( ctx: &mut Context, + peer_data: &HashMap, blocks: &mut HashMap, topologies: &SessionGridTopologies, block_filter: BlockFilter, @@ -1758,11 +1843,22 @@ async fn adjust_required_routing_and_propagate continue, + Some(v) => v, + }; + + send_assignments_batched(ctx.sender(), assignments_packet, peer, peer_protocol_version) + .await; } for (peer, approvals_packet) in peer_approvals { - send_approvals_batched(ctx.sender(), approvals_packet, peer).await; + let peer_protocol_version = match peer_data.get(&peer).map(|pd| pd.version) { + None => continue, + Some(v) => v, + }; + + send_approvals_batched(ctx.sender(), approvals_packet, peer, peer_protocol_version).await; } } @@ -1912,6 +2008,49 @@ impl ApprovalDistribution { } } +fn versioned_approvals_packet( + version: ValidationVersion, + approvals: Vec, +) -> VersionedValidationProtocol { + match version { + ValidationVersion::V1 => + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(approvals), + )), + ValidationVersion::VStaging => + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Approvals(approvals), + )), + } +} + +fn versioned_assignments_packet( + version: ValidationVersion, + assignments: Vec<(IndirectAssignmentCert, CandidateIndex)>, +) -> VersionedValidationProtocol { + match version { + ValidationVersion::V1 => + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments), + )), + ValidationVersion::VStaging => + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments), + )), + } +} + +fn filter_peers_by_version( + peers: &[(PeerId, ValidationVersion)], + version: ValidationVersion, +) -> Vec { + peers + .iter() + .filter(|(_, v)| v == &version) + .map(|(peer_id, _)| *peer_id) + .collect() +} + #[overseer::subsystem(ApprovalDistribution, error=SubsystemError, prefix=self::overseer)] impl ApprovalDistribution { fn start(self, ctx: Context) -> SpawnedSubsystem { @@ -1954,19 +2093,16 @@ pub(crate) async fn send_assignments_batched( sender: &mut impl overseer::ApprovalDistributionSenderTrait, assignments: Vec<(IndirectAssignmentCert, CandidateIndex)>, peer: PeerId, + protocol_version: ValidationVersion, ) { let mut batches = assignments.into_iter().peekable(); while batches.peek().is_some() { let batch: Vec<_> = batches.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect(); + let versioned = versioned_assignments_packet(protocol_version, batch); sender - .send_message(NetworkBridgeTxMessage::SendValidationMessage( - vec![peer], - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(batch), - )), - )) + .send_message(NetworkBridgeTxMessage::SendValidationMessage(vec![peer], versioned)) .await; } } @@ -1976,19 +2112,16 @@ pub(crate) async fn send_approvals_batched( sender: &mut impl overseer::ApprovalDistributionSenderTrait, approvals: Vec, peer: PeerId, + protocol_version: ValidationVersion, ) { let mut batches = approvals.into_iter().peekable(); while batches.peek().is_some() { let batch: Vec<_> = batches.by_ref().take(MAX_APPROVAL_BATCH_SIZE).collect(); + let versioned = versioned_approvals_packet(protocol_version, batch); sender - .send_message(NetworkBridgeTxMessage::SendValidationMessage( - vec![peer], - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(batch), - )), - )) + .send_message(NetworkBridgeTxMessage::SendValidationMessage(vec![peer], versioned)) .await; } } diff --git a/node/network/approval-distribution/src/tests.rs b/node/network/approval-distribution/src/tests.rs index bfd7c945069c..1e9ae7b62007 100644 --- a/node/network/approval-distribution/src/tests.rs +++ b/node/network/approval-distribution/src/tests.rs @@ -219,6 +219,7 @@ async fn setup_gossip_topology( async fn setup_peer_with_view( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, + validation_version: ValidationVersion, view: View, ) { overseer_send( @@ -226,7 +227,7 @@ async fn setup_peer_with_view( ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( *peer_id, ObservedRole::Full, - ValidationVersion::V1.into(), + validation_version.into(), None, )), ) @@ -243,13 +244,12 @@ async fn setup_peer_with_view( async fn send_message_from_peer( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, - msg: protocol_v1::ApprovalDistributionMessage, + msg: net_protocol::ApprovalDistributionMessage, ) { overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - *peer_id, - Versioned::V1(msg), + *peer_id, msg, )), ) .await; @@ -331,9 +331,9 @@ fn try_import_the_same_assignment() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup peers - setup_peer_with_view(overseer, &peer_a, view![]).await; - setup_peer_with_view(overseer, &peer_b, view![hash]).await; - setup_peer_with_view(overseer, &peer_c, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await; + setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, &peer_c, ValidationVersion::V1, view![hash]).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -353,7 +353,7 @@ fn try_import_the_same_assignment() { let assignments = vec![(cert.clone(), 0u32)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, &peer_a, msg).await; + send_message_from_peer(overseer, &peer_a, Versioned::V1(msg)).await; expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; @@ -386,11 +386,11 @@ fn try_import_the_same_assignment() { ); // setup new peer - setup_peer_with_view(overseer, &peer_d, view![]).await; + setup_peer_with_view(overseer, &peer_d, ValidationVersion::V1, view![]).await; // send the same assignment from peer_d let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, &peer_d, msg).await; + send_message_from_peer(overseer, &peer_d, Versioned::V1(msg)).await; expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; @@ -413,7 +413,7 @@ fn delay_reputation_change() { let overseer = &mut virtual_overseer; // Setup peers - setup_peer_with_view(overseer, &peer, view![]).await; + setup_peer_with_view(overseer, &peer, ValidationVersion::V1, view![]).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -433,7 +433,7 @@ fn delay_reputation_change() { let assignments = vec![(cert.clone(), 0u32)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, &peer, msg).await; + send_message_from_peer(overseer, &peer, Versioned::V1(msg)).await; // send an `Accept` message from the Approval Voting subsystem assert_matches!( @@ -474,7 +474,7 @@ fn spam_attack_results_in_negative_reputation_change() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; let peer = &peer_a; - setup_peer_with_view(overseer, peer, view![]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![]).await; // new block `hash_b` with 20 candidates let candidates_count = 20; @@ -501,7 +501,7 @@ fn spam_attack_results_in_negative_reputation_change() { .collect(); let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, msg.clone()).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; for i in 0..candidates_count { expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; @@ -533,7 +533,7 @@ fn spam_attack_results_in_negative_reputation_change() { .await; // send the assignments again - send_message_from_peer(overseer, peer, msg.clone()).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; // each of them will incur `COST_UNEXPECTED_MESSAGE`, not only the first one for _ in 0..candidates_count { @@ -558,7 +558,7 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; let peer = &peer_a; - setup_peer_with_view(overseer, peer, view![]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![]).await; // new block `hash` with 1 candidates let meta = BlockApprovalMeta { @@ -610,12 +610,12 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { // the peer could send us it as well let assignments = vec![(cert, candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, peer, msg.clone()).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "we should not punish the peer"); // send the assignments again - send_message_from_peer(overseer, peer, msg).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg)).await; // now we should expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await; @@ -634,9 +634,9 @@ fn import_approval_happy_path() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup peers - setup_peer_with_view(overseer, &peer_a, view![]).await; - setup_peer_with_view(overseer, &peer_b, view![hash]).await; - setup_peer_with_view(overseer, &peer_c, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await; + setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, &peer_c, ValidationVersion::V1, view![hash]).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -681,7 +681,7 @@ fn import_approval_happy_path() { signature: dummy_signature(), }; let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, msg).await; + send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, @@ -722,8 +722,8 @@ fn import_approval_bad() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup peers - setup_peer_with_view(overseer, &peer_a, view![]).await; - setup_peer_with_view(overseer, &peer_b, view![hash]).await; + setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await; + setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -749,14 +749,14 @@ fn import_approval_bad() { signature: dummy_signature(), }; let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, msg).await; + send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; expect_reputation_change(overseer, &peer_b, COST_UNEXPECTED_MESSAGE).await; // now import an assignment from peer_b let assignments = vec![(cert.clone(), candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, &peer_b, msg).await; + send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, @@ -775,7 +775,7 @@ fn import_approval_bad() { // and try again let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, msg).await; + send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, @@ -916,7 +916,7 @@ fn update_peer_view() { overseer_send(overseer, ApprovalDistributionMessage::DistributeAssignment(cert_b, 0)).await; // connect a peer - setup_peer_with_view(overseer, peer, view![hash_a]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash_a]).await; // we should send relevant assignments to the peer assert_matches!( @@ -934,7 +934,7 @@ fn update_peer_view() { virtual_overseer }); - assert_eq!(state.peer_views.get(peer).map(|v| v.finalized_number), Some(0)); + assert_eq!(state.peer_data.get(peer).map(|data| data.view.finalized_number), Some(0)); assert_eq!( state .blocks @@ -986,7 +986,7 @@ fn update_peer_view() { virtual_overseer }); - assert_eq!(state.peer_views.get(peer).map(|v| v.finalized_number), Some(2)); + assert_eq!(state.peer_data.get(peer).map(|data| data.view.finalized_number), Some(2)); assert_eq!( state .blocks @@ -1016,7 +1016,10 @@ fn update_peer_view() { virtual_overseer }); - assert_eq!(state.peer_views.get(peer).map(|v| v.finalized_number), Some(finalized_number)); + assert_eq!( + state.peer_data.get(peer).map(|data| data.view.finalized_number), + Some(finalized_number) + ); assert!(state.blocks.get(&hash_c).unwrap().known_by.get(peer).is_none()); } @@ -1031,7 +1034,7 @@ fn import_remotely_then_locally() { let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup the peer - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -1051,7 +1054,7 @@ fn import_remotely_then_locally() { let cert = fake_assignment_cert(hash, validator_index); let assignments = vec![(cert.clone(), candidate_index)]; let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, msg).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg)).await; // send an `Accept` message from the Approval Voting subsystem assert_matches!( @@ -1086,7 +1089,7 @@ fn import_remotely_then_locally() { signature: dummy_signature(), }; let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, peer, msg).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, @@ -1152,7 +1155,7 @@ fn sends_assignments_even_when_state_is_approved() { .await; // connect the peer. - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; @@ -1216,7 +1219,7 @@ fn race_condition_in_local_vs_remote_view_update() { }; // This will send a peer view that is ahead of our view - setup_peer_with_view(overseer, peer, view![hash_b]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash_b]).await; // Send our view update to include a new head overseer_send( @@ -1237,7 +1240,7 @@ fn race_condition_in_local_vs_remote_view_update() { .collect(); let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, msg.clone()).await; + send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await; // This will handle pending messages being processed let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); @@ -1280,7 +1283,7 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { // Connect all peers. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // Set up a gossip topology. @@ -1385,7 +1388,7 @@ fn propagates_assignments_along_unshared_dimension() { // Connect all peers. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // Set up a gossip topology. @@ -1421,7 +1424,7 @@ fn propagates_assignments_along_unshared_dimension() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; + send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -1470,7 +1473,7 @@ fn propagates_assignments_along_unshared_dimension() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; + send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -1527,7 +1530,7 @@ fn propagates_to_required_after_connect() { // Connect all peers except omitted. for (i, (peer, _)) in peers.iter().enumerate() { if !omitted.contains(&i) { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } } @@ -1616,7 +1619,7 @@ fn propagates_to_required_after_connect() { ); for i in omitted.iter().copied() { - setup_peer_with_view(overseer, &peers[i].0, view![hash]).await; + setup_peer_with_view(overseer, &peers[i].0, ValidationVersion::V1, view![hash]).await; assert_matches!( overseer_recv(overseer).await, @@ -1665,7 +1668,7 @@ fn sends_to_more_peers_after_getting_topology() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // new block `hash_a` with 1 candidates @@ -1817,7 +1820,7 @@ fn originator_aggression_l1() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // new block `hash_a` with 1 candidates @@ -1976,7 +1979,7 @@ fn non_originator_aggression_l1() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // new block `hash_a` with 1 candidates @@ -2010,7 +2013,7 @@ fn non_originator_aggression_l1() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; + send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -2081,7 +2084,7 @@ fn non_originator_aggression_l2() { // Connect all peers except omitted. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // new block `hash_a` with 1 candidates @@ -2115,7 +2118,7 @@ fn non_originator_aggression_l2() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; + send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -2246,7 +2249,7 @@ fn resends_messages_periodically() { // Connect all peers. for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash]).await; + setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await; } // Set up a gossip topology. @@ -2281,7 +2284,7 @@ fn resends_messages_periodically() { // Issuer of the message is important, not the peer we receive from. // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; + send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await; assert_matches!( overseer_recv(overseer).await, AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( @@ -2372,6 +2375,126 @@ fn resends_messages_periodically() { }); } +/// Tests that peers correctly receive versioned messages. +#[test] +fn import_versioned_approval() { + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let state = state_without_reputation_delay(); + let _ = test_harness(state, |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // All peers are aware of relay parent. + setup_peer_with_view(overseer, &peer_a, ValidationVersion::VStaging, view![hash]).await; + setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await; + setup_peer_with_view(overseer, &peer_c, ValidationVersion::VStaging, view![hash]).await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + let cert = fake_assignment_cert(hash, validator_index); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index), + ) + .await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers, vec![peer_b]); + assert_eq!(assignments.len(), 1); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert!(peers.contains(&peer_a)); + assert!(peers.contains(&peer_c)); + + assert_eq!(assignments.len(), 1); + } + ); + + // send the an approval from peer_a + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: dummy_signature(), + }; + let msg = protocol_vstaging::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer(overseer, &peer_a, Versioned::VStaging(msg)).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( + vote, + tx, + )) => { + assert_eq!(vote, approval); + tx.send(ApprovalCheckResult::Accepted).unwrap(); + } + ); + + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + + // Peers b and c receive versioned approval messages. + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert_eq!(peers, vec![peer_b]); + assert_eq!(approvals.len(), 1); + } + ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( + protocol_vstaging::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(approvals.len(), 1); + } + ); + virtual_overseer + }); +} + fn batch_test_round(message_count: usize) { use polkadot_node_subsystem::SubsystemContext; let pool = sp_core::testing::TaskExecutor::new(); @@ -2402,8 +2525,9 @@ fn batch_test_round(message_count: usize) { .collect(); let peer = PeerId::random(); - send_assignments_batched(&mut sender, assignments.clone(), peer).await; - send_approvals_batched(&mut sender, approvals.clone(), peer).await; + send_assignments_batched(&mut sender, assignments.clone(), peer, ValidationVersion::V1) + .await; + send_approvals_batched(&mut sender, approvals.clone(), peer, ValidationVersion::V1).await; // Check expected assignments batches. for assignment_index in (0..assignments.len()).step_by(super::MAX_ASSIGNMENT_BATCH_SIZE) { diff --git a/node/network/bitfield-distribution/Cargo.toml b/node/network/bitfield-distribution/Cargo.toml index 6f0f3eea2c9b..9dd5d9bbf044 100644 --- a/node/network/bitfield-distribution/Cargo.toml +++ b/node/network/bitfield-distribution/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] +always-assert = "0.1" futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/node/network/bitfield-distribution/src/lib.rs b/node/network/bitfield-distribution/src/lib.rs index ddb1d83b8a05..c85d874bc4db 100644 --- a/node/network/bitfield-distribution/src/lib.rs +++ b/node/network/bitfield-distribution/src/lib.rs @@ -22,6 +22,7 @@ #![deny(unused_crate_dependencies)] +use always_assert::never; use futures::{channel::oneshot, FutureExt}; use polkadot_node_network_protocol::{ @@ -29,7 +30,9 @@ use polkadot_node_network_protocol::{ grid_topology::{ GridNeighbors, RandomRouting, RequiredRouting, SessionBoundGridTopologyStorage, }, - v1 as protocol_v1, OurView, PeerId, UnifiedReputationChange as Rep, Versioned, View, + peer_set::{ProtocolVersion, ValidationVersion}, + v1 as protocol_v1, vstaging as protocol_vstaging, OurView, PeerId, + UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_subsystem::{ jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, @@ -76,25 +79,63 @@ struct BitfieldGossipMessage { } impl BitfieldGossipMessage { - fn into_validation_protocol(self) -> net_protocol::VersionedValidationProtocol { - self.into_network_message().into() + fn into_validation_protocol( + self, + recipient_version: ProtocolVersion, + ) -> net_protocol::VersionedValidationProtocol { + self.into_network_message(recipient_version).into() } - fn into_network_message(self) -> net_protocol::BitfieldDistributionMessage { - Versioned::V1(protocol_v1::BitfieldDistributionMessage::Bitfield( - self.relay_parent, - self.signed_availability.into(), - )) + fn into_network_message( + self, + recipient_version: ProtocolVersion, + ) -> net_protocol::BitfieldDistributionMessage { + match ValidationVersion::try_from(recipient_version).ok() { + Some(ValidationVersion::V1) => + Versioned::V1(protocol_v1::BitfieldDistributionMessage::Bitfield( + self.relay_parent, + self.signed_availability.into(), + )), + Some(ValidationVersion::VStaging) => + Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + self.relay_parent, + self.signed_availability.into(), + )), + None => { + never!("Peers should only have supported protocol versions."); + + gum::warn!( + target: LOG_TARGET, + version = ?recipient_version, + "Unknown protocol version provided for message recipient" + ); + + // fall back to v1 to avoid + Versioned::V1(protocol_v1::BitfieldDistributionMessage::Bitfield( + self.relay_parent, + self.signed_availability.into(), + )) + }, + } } } +/// Data stored on a per-peer basis. +#[derive(Debug)] +pub struct PeerData { + /// The peer's view. + view: View, + /// The peer's protocol version. + version: ProtocolVersion, +} + /// Data used to track information of peers and relay parents the /// overseer ordered us to work on. #[derive(Default, Debug)] struct ProtocolState { /// Track all active peers and their views /// to determine what is relevant to them. - peer_views: HashMap, + peer_data: HashMap, /// The current and previous gossip topologies topologies: SessionBoundGridTopologyStorage, @@ -357,7 +398,7 @@ async fn handle_bitfield_distribution( ctx, job_data, topology, - &mut state.peer_views, + &mut state.peer_data, validator, msg, required_routing, @@ -376,7 +417,7 @@ async fn relay_message( ctx: &mut Context, job_data: &mut PerRelayParentData, topology_neighbors: &GridNeighbors, - peer_views: &mut HashMap, + peers: &mut HashMap, validator: ValidatorId, message: BitfieldGossipMessage, required_routing: RequiredRouting, @@ -394,16 +435,16 @@ async fn relay_message( .await; drop(_span); - let total_peers = peer_views.len(); + let total_peers = peers.len(); let mut random_routing: RandomRouting = Default::default(); let _span = span.child("interested-peers"); // pass on the bitfield distribution to all interested peers - let interested_peers = peer_views + let interested_peers = peers .iter() - .filter_map(|(peer, view)| { + .filter_map(|(peer, data)| { // check interest in the peer in this message's relay parent - if view.contains(&message.relay_parent) { + if data.view.contains(&message.relay_parent) { let message_needed = job_data.message_from_validator_needed_by_peer(&peer, &validator); if message_needed { @@ -418,7 +459,7 @@ async fn relay_message( }; if need_routing { - Some(*peer) + Some((*peer, data.version)) } else { None } @@ -429,9 +470,9 @@ async fn relay_message( None } }) - .collect::>(); + .collect::>(); - interested_peers.iter().for_each(|peer| { + interested_peers.iter().for_each(|(peer, _)| { // track the message as sent for this peer job_data .message_sent_to_peer @@ -450,11 +491,35 @@ async fn relay_message( ); } else { let _span = span.child("gossip"); - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - interested_peers, - message.into_validation_protocol(), - )) - .await; + + let filter_by_version = |peers: &[(PeerId, ProtocolVersion)], + version: ValidationVersion| { + peers + .iter() + .filter(|(_, v)| v == &version.into()) + .map(|(peer_id, _)| *peer_id) + .collect::>() + }; + + let v1_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V1); + let vstaging_interested_peers = + filter_by_version(&interested_peers, ValidationVersion::VStaging); + + if !v1_interested_peers.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + v1_interested_peers, + message.clone().into_validation_protocol(ValidationVersion::V1.into()), + )) + .await; + } + + if !vstaging_interested_peers.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vstaging_interested_peers, + message.into_validation_protocol(ValidationVersion::VStaging.into()), + )) + .await + } } } @@ -465,10 +530,20 @@ async fn process_incoming_peer_message( state: &mut ProtocolState, metrics: &Metrics, origin: PeerId, - message: protocol_v1::BitfieldDistributionMessage, + message: net_protocol::BitfieldDistributionMessage, rng: &mut (impl CryptoRng + Rng), ) { - let protocol_v1::BitfieldDistributionMessage::Bitfield(relay_parent, bitfield) = message; + let (relay_parent, bitfield) = match message { + Versioned::V1(protocol_v1::BitfieldDistributionMessage::Bitfield( + relay_parent, + bitfield, + )) => (relay_parent, bitfield), + Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + relay_parent, + bitfield, + )) => (relay_parent, bitfield), + }; + gum::trace!( target: LOG_TARGET, peer = %origin, @@ -616,7 +691,7 @@ async fn process_incoming_peer_message( ctx, job_data, topology, - &mut state.peer_views, + &mut state.peer_data, validator, message, required_routing, @@ -647,15 +722,18 @@ async fn handle_network_msg( let _timer = metrics.time_handle_network_msg(); match bridge_message { - NetworkBridgeEvent::PeerConnected(peer, role, _, _) => { + NetworkBridgeEvent::PeerConnected(peer, role, version, _) => { gum::trace!(target: LOG_TARGET, ?peer, ?role, "Peer connected"); // insert if none already present - state.peer_views.entry(peer).or_default(); + state + .peer_data + .entry(peer) + .or_insert_with(|| PeerData { view: View::default(), version }); }, NetworkBridgeEvent::PeerDisconnected(peer) => { gum::trace!(target: LOG_TARGET, ?peer, "Peer disconnected"); // get rid of superfluous data - state.peer_views.remove(&peer); + state.peer_data.remove(&peer); }, NetworkBridgeEvent::NewGossipTopology(gossip_topology) => { let session_index = gossip_topology.session; @@ -680,12 +758,21 @@ async fn handle_network_msg( ); for new_peer in newly_added { - // in case we already knew that peer in the past - // it might have had an existing view, we use to initialize - // and minimize the delta on `PeerViewChange` to be sent - if let Some(old_view) = state.peer_views.remove(&new_peer) { - handle_peer_view_change(ctx, state, new_peer, old_view, rng).await; - } + let old_view = match state.peer_data.get_mut(&new_peer) { + Some(d) => { + // in case we already knew that peer in the past + // it might have had an existing view, we use to initialize + // and minimize the delta on `PeerViewChange` to be sent + std::mem::replace(&mut d.view, Default::default()) + }, + None => { + // For peers which are currently unknown, we'll send topology-related + // messages to them when they connect and send their first view update. + continue + }, + }; + + handle_peer_view_change(ctx, state, new_peer, old_view, rng).await; } }, NetworkBridgeEvent::PeerViewChange(peerid, new_view) => { @@ -696,7 +783,7 @@ async fn handle_network_msg( gum::trace!(target: LOG_TARGET, ?new_view, "Our view change"); handle_our_view_change(state, new_view); }, - NetworkBridgeEvent::PeerMessage(remote, Versioned::V1(message)) => + NetworkBridgeEvent::PeerMessage(remote, message) => process_incoming_peer_message(ctx, state, metrics, remote, message, rng).await, NetworkBridgeEvent::UpdatedAuthorityIds { .. } => { // The bitfield-distribution subsystem doesn't deal with `AuthorityDiscoveryId`s. @@ -728,6 +815,9 @@ fn handle_our_view_change(state: &mut ProtocolState, view: OurView) { // Send the difference between two views which were not sent // to that particular peer. +// +// This requires that there is an entry in the `peer_data` field for the +// peer. #[overseer::contextbounds(BitfieldDistribution, prefix=self::overseer)] async fn handle_peer_view_change( ctx: &mut Context, @@ -736,13 +826,20 @@ async fn handle_peer_view_change( view: View, rng: &mut (impl CryptoRng + Rng), ) { - let added = state - .peer_views - .entry(origin) - .or_default() - .replace_difference(view) - .cloned() - .collect::>(); + let peer_data = match state.peer_data.get_mut(&origin) { + None => { + gum::warn!( + target: LOG_TARGET, + peer = ?origin, + "Attempted to update peer view for unknown peer." + ); + + return + }, + Some(pd) => pd, + }; + + let added = peer_data.view.replace_difference(view).cloned().collect::>(); let topology = state.topologies.get_current_topology().local_grid_neighbors(); let is_gossip_peer = topology.route_to_peer(RequiredRouting::GridXY, &origin); @@ -808,11 +905,14 @@ async fn send_tracked_gossip_message( "Sending gossip message" ); + let version = + if let Some(peer_data) = state.peer_data.get(&dest) { peer_data.version } else { return }; + job_data.message_sent_to_peer.entry(dest).or_default().insert(validator.clone()); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( vec![dest], - message.into_validation_protocol(), + message.into_validation_protocol(version), )) .await; } diff --git a/node/network/bitfield-distribution/src/tests.rs b/node/network/bitfield-distribution/src/tests.rs index 9aea5a7178b7..d6795247e786 100644 --- a/node/network/bitfield-distribution/src/tests.rs +++ b/node/network/bitfield-distribution/src/tests.rs @@ -56,6 +56,10 @@ fn dummy_rng() -> ChaCha12Rng { rand_chacha::ChaCha12Rng::seed_from_u64(12345) } +fn peer_data_v1(view: View) -> PeerData { + PeerData { view, version: ValidationVersion::V1.into() } +} + /// A very limited state, only interested in the relay parent of the /// given message, which must be signed by `validator` and a set of peers /// which are also only interested in that relay parent. @@ -85,7 +89,11 @@ fn prewarmed_state( span: PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"), }, }, - peer_views: peers.iter().cloned().map(|peer| (peer, view!(relay_parent))).collect(), + peer_data: peers + .iter() + .cloned() + .map(|peer| (peer, peer_data_v1(view![relay_parent]))) + .collect(), topologies, view: our_view!(relay_parent), reputation: ReputationAggregator::new(|_| true), @@ -211,7 +219,10 @@ fn receive_invalid_signature() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, invalid_msg.into_network_message()), + NetworkBridgeEvent::PeerMessage( + peer_b, + invalid_msg.into_network_message(ValidationVersion::V1.into()) + ), &mut rng, )); @@ -222,7 +233,10 @@ fn receive_invalid_signature() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, invalid_msg_2.into_network_message()), + NetworkBridgeEvent::PeerMessage( + peer_b, + invalid_msg_2.into_network_message(ValidationVersion::V1.into()) + ), &mut rng, )); // reputation change due to invalid signature @@ -256,7 +270,7 @@ fn receive_invalid_validator_index() { let (mut state, signing_context, keystore, validator) = state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true)); - state.peer_views.insert(peer_b, view![hash_a]); + state.peer_data.insert(peer_b, peer_data_v1(view![hash_a])); let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); let signed = Signed::::sign( @@ -281,7 +295,10 @@ fn receive_invalid_validator_index() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, msg.into_network_message()), + NetworkBridgeEvent::PeerMessage( + peer_b, + msg.into_network_message(ValidationVersion::V1.into()) + ), &mut rng, )); @@ -344,7 +361,10 @@ fn receive_duplicate_messages() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_b, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -377,7 +397,10 @@ fn receive_duplicate_messages() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_a, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_a, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -396,7 +419,10 @@ fn receive_duplicate_messages() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_b, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -463,7 +489,10 @@ fn delay_reputation_change() { handle .send(FromOrchestra::Communication { msg: BitfieldDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(peer, msg.clone().into_network_message()), + NetworkBridgeEvent::PeerMessage( + peer, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), ), }) .await; @@ -486,7 +515,10 @@ fn delay_reputation_change() { handle .send(FromOrchestra::Communication { msg: BitfieldDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(peer, msg.clone().into_network_message()), + NetworkBridgeEvent::PeerMessage( + peer, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), ), }) .await; @@ -546,8 +578,8 @@ fn do_not_relay_message_twice() { .flatten() .expect("should be signed"); - state.peer_views.insert(peer_b, view![hash]); - state.peer_views.insert(peer_a, view![hash]); + state.peer_data.insert(peer_b, peer_data_v1(view![hash])); + state.peer_data.insert(peer_a, peer_data_v1(view![hash])); let msg = BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() }; @@ -564,7 +596,7 @@ fn do_not_relay_message_twice() { &mut ctx, state.per_relay_parent.get_mut(&hash).unwrap(), &gossip_peers, - &mut state.peer_views, + &mut state.peer_data, validator.clone(), msg.clone(), RequiredRouting::GridXY, @@ -591,7 +623,7 @@ fn do_not_relay_message_twice() { assert_eq!(2, peers.len()); assert!(peers.contains(&peer_a)); assert!(peers.contains(&peer_b)); - assert_eq!(send_msg, msg.clone().into_validation_protocol()); + assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into())); } ); @@ -600,7 +632,7 @@ fn do_not_relay_message_twice() { &mut ctx, state.per_relay_parent.get_mut(&hash).unwrap(), &gossip_peers, - &mut state.peer_views, + &mut state.peer_data, validator.clone(), msg.clone(), RequiredRouting::GridXY, @@ -687,14 +719,17 @@ fn changing_view() { &mut rng, )); - assert!(state.peer_views.contains_key(&peer_b)); + assert!(state.peer_data.contains_key(&peer_b)); // recv a first message from the network launch!(handle_network_msg( &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_b, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -729,8 +764,11 @@ fn changing_view() { &mut rng, )); - assert!(state.peer_views.contains_key(&peer_b)); - assert_eq!(state.peer_views.get(&peer_b).expect("Must contain value for peer B"), &view![]); + assert!(state.peer_data.contains_key(&peer_b)); + assert_eq!( + &state.peer_data.get(&peer_b).expect("Must contain value for peer B").view, + &view![] + ); // on rx of the same message, since we are not interested, // should give penalty @@ -738,7 +776,10 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_b, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -770,7 +811,10 @@ fn changing_view() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_a, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_a, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -817,8 +861,8 @@ fn do_not_send_message_back_to_origin() { .flatten() .expect("should be signed"); - state.peer_views.insert(peer_b, view![hash]); - state.peer_views.insert(peer_a, view![hash]); + state.peer_data.insert(peer_b, peer_data_v1(view![hash])); + state.peer_data.insert(peer_a, peer_data_v1(view![hash])); let msg = BitfieldGossipMessage { relay_parent: hash, signed_availability: signed_bitfield.clone() }; @@ -833,7 +877,10 @@ fn do_not_send_message_back_to_origin() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peer_b, msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peer_b, + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -855,7 +902,7 @@ fn do_not_send_message_back_to_origin() { ) => { assert_eq!(1, peers.len()); assert!(peers.contains(&peer_a)); - assert_eq!(send_msg, msg.clone().into_validation_protocol()); + assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into())); } ); @@ -932,7 +979,7 @@ fn topology_test() { .expect("should be signed"); peers_x.iter().chain(peers_y.iter()).for_each(|peer| { - state.peer_views.insert(*peer, view![hash]); + state.peer_data.insert(*peer, peer_data_v1(view![hash])); }); let msg = @@ -948,7 +995,10 @@ fn topology_test() { &mut ctx, &mut state, &Default::default(), - NetworkBridgeEvent::PeerMessage(peers_x[0], msg.clone().into_network_message(),), + NetworkBridgeEvent::PeerMessage( + peers_x[0], + msg.clone().into_network_message(ValidationVersion::V1.into()), + ), &mut rng, )); @@ -975,7 +1025,7 @@ fn topology_test() { assert!(topology.peers_x.iter().filter(|peer| peers.contains(&peer)).count() == 4); // Must never include originator assert!(!peers.contains(&peers_x[0])); - assert_eq!(send_msg, msg.clone().into_validation_protocol()); + assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into())); } ); @@ -1050,3 +1100,127 @@ fn need_message_works() { // also not ok for Bob assert!(!pretend_send(&mut state, peer_b, &validator_set[1])); } + +#[test] +fn network_protocol_versioning() { + let hash_a: Hash = [0; 32].into(); + let hash_b: Hash = [1; 32].into(); + + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + let peers = [ + (peer_a, ValidationVersion::VStaging), + (peer_b, ValidationVersion::V1), + (peer_c, ValidationVersion::VStaging), + ]; + + // validator 0 key pair + let (mut state, signing_context, keystore, validator) = + state_with_view(our_view![hash_a, hash_b], hash_a, ReputationAggregator::new(|_| true)); + + let pool = sp_core::testing::TaskExecutor::new(); + let (mut ctx, mut handle) = make_subsystem_context::(pool); + let mut rng = dummy_rng(); + + executor::block_on(async move { + // create a signed message by validator 0 + let payload = AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); + let signed_bitfield = Signed::::sign( + &keystore, + payload, + &signing_context, + ValidatorIndex(0), + &validator, + ) + .ok() + .flatten() + .expect("should be signed"); + let msg = BitfieldGossipMessage { + relay_parent: hash_a, + signed_availability: signed_bitfield.clone(), + }; + + for (peer, protocol_version) in peers { + launch!(handle_network_msg( + &mut ctx, + &mut state, + &Default::default(), + NetworkBridgeEvent::PeerConnected( + peer, + ObservedRole::Full, + protocol_version.into(), + None + ), + &mut rng, + )); + + launch!(handle_network_msg( + &mut ctx, + &mut state, + &Default::default(), + NetworkBridgeEvent::PeerViewChange(peer, view![hash_a, hash_b]), + &mut rng, + )); + + assert!(state.peer_data.contains_key(&peer)); + } + + launch!(handle_network_msg( + &mut ctx, + &mut state, + &Default::default(), + NetworkBridgeEvent::PeerMessage( + peer_a, + msg.clone().into_network_message(ValidationVersion::VStaging.into()), + ), + &mut rng, + )); + + // gossip to the overseer + assert_matches!( + handle.recv().await, + AllMessages::Provisioner(ProvisionerMessage::ProvisionableData( + _, + ProvisionableData::Bitfield(hash, signed) + )) => { + assert_eq!(hash, hash_a); + assert_eq!(signed, signed_bitfield) + } + ); + + // v1 gossip + assert_matches!( + handle.recv().await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg), + ) => { + assert_eq!(peers, vec![peer_b]); + assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::V1.into())); + } + ); + + // vstaging gossip + assert_matches!( + handle.recv().await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage(peers, send_msg), + ) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(send_msg, msg.clone().into_validation_protocol(ValidationVersion::VStaging.into())); + } + ); + + // reputation change + assert_matches!( + handle.recv().await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep)) + ) => { + assert_eq!(peer, peer_a); + assert_eq!(rep, BENEFIT_VALID_MESSAGE_FIRST.into()) + } + ); + }); +} diff --git a/node/network/bridge/src/network.rs b/node/network/bridge/src/network.rs index 04026197f6eb..4f21212dcb64 100644 --- a/node/network/bridge/src/network.rs +++ b/node/network/bridge/src/network.rs @@ -55,6 +55,9 @@ pub(crate) fn send_message( ) where M: Encode + Clone, { + if peers.is_empty() { + return + } let message = { let encoded = message.encode(); metrics.on_notification_sent(peer_set, version, encoded.len(), peers.len()); @@ -65,8 +68,11 @@ pub(crate) fn send_message( // list. The message payload can be quite large. If the underlying // network used `Bytes` this would not be necessary. let last_peer = peers.pop(); - // optimization: generate the protocol name once. - let protocol_name = protocol_names.get_name(peer_set, version); + + // We always send messages on the "main" name even when a negotiated + // fallback is used. The libp2p implementation handles the fallback + // under the hood. + let protocol_name = protocol_names.get_main_name(peer_set); peers.into_iter().for_each(|peer| { net.write_notification(peer, protocol_name.clone(), message.clone()); }); diff --git a/node/network/bridge/src/rx/mod.rs b/node/network/bridge/src/rx/mod.rs index 950bb3d6e6da..002919c5b0e5 100644 --- a/node/network/bridge/src/rx/mod.rs +++ b/node/network/bridge/src/rx/mod.rs @@ -33,7 +33,8 @@ use polkadot_node_network_protocol::{ CollationVersion, PeerSet, PeerSetProtocolNames, PerPeerSet, ProtocolVersion, ValidationVersion, }, - v1 as protocol_v1, ObservedRole, OurView, PeerId, UnifiedReputationChange as Rep, View, + v1 as protocol_v1, vstaging as protocol_vstaging, ObservedRole, OurView, PeerId, + UnifiedReputationChange as Rep, View, }; use polkadot_node_subsystem::{ @@ -246,15 +247,32 @@ where ) .await; - send_message( - &mut network_service, - vec![peer], - PeerSet::Validation, - version, - &peerset_protocol_names, - WireMessage::::ViewUpdate(local_view), - &metrics, - ); + match ValidationVersion::try_from(version) + .expect("try_get_protocol has already checked version is known; qed") + { + ValidationVersion::V1 => send_message( + &mut network_service, + vec![peer], + PeerSet::Validation, + version, + &peerset_protocol_names, + WireMessage::::ViewUpdate( + local_view, + ), + &metrics, + ), + ValidationVersion::VStaging => send_message( + &mut network_service, + vec![peer], + PeerSet::Validation, + version, + &peerset_protocol_names, + WireMessage::::ViewUpdate( + local_view, + ), + &metrics, + ), + } }, PeerSet::Collation => { dispatch_collation_events_to_all( @@ -271,15 +289,32 @@ where ) .await; - send_message( - &mut network_service, - vec![peer], - PeerSet::Collation, - version, - &peerset_protocol_names, - WireMessage::::ViewUpdate(local_view), - &metrics, - ); + match CollationVersion::try_from(version) + .expect("try_get_protocol has already checked version is known; qed") + { + CollationVersion::V1 => send_message( + &mut network_service, + vec![peer], + PeerSet::Collation, + version, + &peerset_protocol_names, + WireMessage::::ViewUpdate( + local_view, + ), + &metrics, + ), + CollationVersion::VStaging => send_message( + &mut network_service, + vec![peer], + PeerSet::Collation, + version, + &peerset_protocol_names, + WireMessage::::ViewUpdate( + local_view, + ), + &metrics, + ), + } }, } }, @@ -417,30 +452,39 @@ where ); if !v_messages.is_empty() { - let (events, reports) = - if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::V1.into()) - { - handle_v1_peer_messages::( - remote, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - v_messages, - &metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Validation], - "Major logic bug. Peer somehow has unsupported validation protocol version." - ); + let (events, reports) = if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::V1.into()) + { + handle_peer_messages::( + remote, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + v_messages, + &metrics, + ) + } else if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::VStaging.into()) + { + handle_peer_messages::( + remote, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + v_messages, + &metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Validation], + "Major logic bug. Peer somehow has unsupported validation protocol version." + ); - never!("Only version 1 is supported; peer set connection checked above; qed"); + never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) + }; for report in reports { network_service.report_peer(remote, report.into()); @@ -450,30 +494,39 @@ where } if !c_messages.is_empty() { - let (events, reports) = - if expected_versions[PeerSet::Collation] == - Some(CollationVersion::V1.into()) - { - handle_v1_peer_messages::( - remote, - PeerSet::Collation, - &mut shared.0.lock().collation_peers, - c_messages, - &metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Collation], - "Major logic bug. Peer somehow has unsupported collation protocol version." - ); + let (events, reports) = if expected_versions[PeerSet::Collation] == + Some(CollationVersion::V1.into()) + { + handle_peer_messages::( + remote, + PeerSet::Collation, + &mut shared.0.lock().collation_peers, + c_messages, + &metrics, + ) + } else if expected_versions[PeerSet::Collation] == + Some(CollationVersion::VStaging.into()) + { + handle_peer_messages::( + remote, + PeerSet::Collation, + &mut shared.0.lock().collation_peers, + c_messages, + &metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Collation], + "Major logic bug. Peer somehow has unsupported collation protocol version." + ); - never!("Only version 1 is supported; peer set connection checked above; qed"); + never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) + }; for report in reports { network_service.report_peer(remote, report.into()); @@ -738,14 +791,34 @@ fn update_our_view( } ( - shared.validation_peers.keys().cloned().collect::>(), - shared.collation_peers.keys().cloned().collect::>(), + shared + .validation_peers + .iter() + .map(|(peer_id, data)| (*peer_id, data.version)) + .collect::>(), + shared + .collation_peers + .iter() + .map(|(peer_id, data)| (*peer_id, data.version)) + .collect::>(), ) }; + let filter_by_version = |peers: &[(PeerId, ProtocolVersion)], version| { + peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::>() + }; + + let v1_validation_peers = filter_by_version(&validation_peers, ValidationVersion::V1.into()); + let v1_collation_peers = filter_by_version(&collation_peers, CollationVersion::V1.into()); + + let vstaging_validation_peers = + filter_by_version(&validation_peers, ValidationVersion::VStaging.into()); + let vstaging_collation_peers = + filter_by_version(&collation_peers, ValidationVersion::VStaging.into()); + send_validation_message_v1( net, - validation_peers, + v1_validation_peers, peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, @@ -753,7 +826,23 @@ fn update_our_view( send_collation_message_v1( net, - collation_peers, + v1_collation_peers, + peerset_protocol_names, + WireMessage::ViewUpdate(new_view.clone()), + metrics, + ); + + send_validation_message_vstaging( + net, + vstaging_validation_peers, + peerset_protocol_names, + WireMessage::ViewUpdate(new_view.clone()), + metrics, + ); + + send_collation_message_vstaging( + net, + vstaging_collation_peers, peerset_protocol_names, WireMessage::ViewUpdate(new_view), metrics, @@ -777,7 +866,7 @@ fn update_our_view( // Handle messages on a specific v1 peer-set. The peer is expected to be connected on that // peer-set. -fn handle_v1_peer_messages>( +fn handle_peer_messages>( peer: PeerId, peer_set: PeerSet, peers: &mut HashMap, @@ -864,6 +953,42 @@ fn send_collation_message_v1( ); } +fn send_validation_message_vstaging( + net: &mut impl Network, + peers: Vec, + protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Validation, + ValidationVersion::VStaging.into(), + protocol_names, + message, + metrics, + ); +} + +fn send_collation_message_vstaging( + net: &mut impl Network, + peers: Vec, + protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Collation, + CollationVersion::VStaging.into(), + protocol_names, + message, + metrics, + ); +} + async fn dispatch_validation_event_to_all( event: NetworkBridgeEvent, ctx: &mut impl overseer::NetworkBridgeRxSenderTrait, diff --git a/node/network/bridge/src/rx/tests.rs b/node/network/bridge/src/rx/tests.rs index b04884edefaa..88a4b247fdc6 100644 --- a/node/network/bridge/src/rx/tests.rs +++ b/node/network/bridge/src/rx/tests.rs @@ -25,6 +25,7 @@ use parking_lot::Mutex; use std::{ collections::HashSet, sync::atomic::{AtomicBool, Ordering}, + task::Poll, }; use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; @@ -46,7 +47,7 @@ use polkadot_node_subsystem_test_helpers::{ SingleItemSink, SingleItemStream, TestSubsystemContextHandle, }; use polkadot_node_subsystem_util::metered; -use polkadot_primitives::{AuthorityDiscoveryId, Hash}; +use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, Hash}; use sc_network::Multiaddr; use sp_keyring::Sr25519Keyring; @@ -142,8 +143,7 @@ impl Network for TestNetwork { } fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let (peer_set, version) = self.protocol_names.try_get_protocol(&protocol).unwrap(); - assert_eq!(version, peer_set.get_main_version()); + let (peer_set, _) = self.protocol_names.try_get_protocol(&protocol).unwrap(); self.action_tx .lock() @@ -152,8 +152,7 @@ impl Network for TestNetwork { } fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - let (peer_set, version) = self.protocol_names.try_get_protocol(&protocol).unwrap(); - assert_eq!(version, peer_set.get_main_version()); + let (peer_set, _) = self.protocol_names.try_get_protocol(&protocol).unwrap(); self.action_tx .lock() @@ -195,10 +194,17 @@ impl TestNetworkHandle { v } - async fn connect_peer(&mut self, peer: PeerId, peer_set: PeerSet, role: ObservedRole) { + async fn connect_peer( + &mut self, + peer: PeerId, + protocol_version: ValidationVersion, + peer_set: PeerSet, + role: ObservedRole, + ) { + let protocol_version = ProtocolVersion::from(protocol_version); self.send_network_event(NetworkEvent::NotificationStreamOpened { remote: peer, - protocol: self.protocol_names.get_main_name(peer_set), + protocol: self.protocol_names.get_name(peer_set, protocol_version), negotiated_fallback: None, role: role.into(), received_handshake: vec![], @@ -432,8 +438,12 @@ fn send_our_view_upon_connection() { handle.await_mode_switch().await; - network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; - network_handle.connect_peer(peer, PeerSet::Collation, ObservedRole::Full).await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) + .await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) + .await; await_peer_connections(&shared, 1, 1).await; @@ -478,10 +488,10 @@ fn sends_view_updates_to_peers() { handle.await_mode_switch().await; network_handle - .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b, PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer_b, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 1).await; @@ -541,10 +551,10 @@ fn do_not_send_view_update_until_synced() { assert_ne!(peer_a, peer_b); network_handle - .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b, PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer_b, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 1).await; @@ -636,10 +646,10 @@ fn do_not_send_view_update_when_only_finalized_block_changed() { let peer_b = PeerId::random(); network_handle - .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_b, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; await_peer_connections(&shared, 2, 0).await; @@ -696,7 +706,9 @@ fn peer_view_updates_sent_via_overseer() { let peer = PeerId::random(); - network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) + .await; await_peer_connections(&shared, 1, 0).await; @@ -746,7 +758,9 @@ fn peer_messages_sent_via_overseer() { let peer = PeerId::random(); - network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) + .await; await_peer_connections(&shared, 1, 0).await; @@ -819,8 +833,12 @@ fn peer_disconnect_from_just_one_peerset() { let peer = PeerId::random(); - network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; - network_handle.connect_peer(peer, PeerSet::Collation, ObservedRole::Full).await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) + .await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) + .await; await_peer_connections(&shared, 1, 1).await; @@ -907,10 +925,10 @@ fn relays_collation_protocol_messages() { let peer_b = PeerId::random(); network_handle - .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; network_handle - .connect_peer(peer_b, PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer_b, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 1).await; @@ -1011,8 +1029,12 @@ fn different_views_on_different_peer_sets() { let peer = PeerId::random(); - network_handle.connect_peer(peer, PeerSet::Validation, ObservedRole::Full).await; - network_handle.connect_peer(peer, PeerSet::Collation, ObservedRole::Full).await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) + .await; + network_handle + .connect_peer(peer, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) + .await; await_peer_connections(&shared, 1, 1).await; @@ -1097,7 +1119,7 @@ fn sent_views_include_finalized_number_update() { let peer_a = PeerId::random(); network_handle - .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 0).await; @@ -1140,7 +1162,7 @@ fn view_finalized_number_can_not_go_down() { let peer_a = PeerId::random(); network_handle - .connect_peer(peer_a, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer_a, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .await; await_peer_connections(&shared, 1, 0).await; @@ -1225,3 +1247,164 @@ fn our_view_updates_decreasing_order_and_limited_to_max() { virtual_overseer }); } + +#[test] +fn network_protocol_versioning_view_update() { + let (oracle, handle) = make_sync_oracle(false); + test_harness(Box::new(oracle), |test_harness| async move { + let TestHarness { mut network_handle, mut virtual_overseer, .. } = test_harness; + + let peer_ids: Vec<_> = (0..4).map(|_| PeerId::random()).collect(); + let peers = [ + (peer_ids[0], PeerSet::Validation, ValidationVersion::VStaging), + (peer_ids[1], PeerSet::Collation, ValidationVersion::V1), + (peer_ids[2], PeerSet::Validation, ValidationVersion::V1), + (peer_ids[3], PeerSet::Collation, ValidationVersion::VStaging), + ]; + + let head = Hash::repeat_byte(1); + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( + ActiveLeavesUpdate::start_work(ActivatedLeaf { + hash: head, + number: 1, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }), + ))) + .await; + + handle.await_mode_switch().await; + + for &(peer_id, peer_set, version) in &peers { + network_handle + .connect_peer(peer_id, version, peer_set, ObservedRole::Full) + .await; + } + + let view = view![head]; + let actions = network_handle.next_network_actions(4).await; + + for &(peer_id, peer_set, version) in &peers { + let wire_msg = match version { + ValidationVersion::V1 => + WireMessage::::ViewUpdate(view.clone()) + .encode(), + ValidationVersion::VStaging => + WireMessage::::ViewUpdate(view.clone()) + .encode(), + }; + assert_network_actions_contains( + &actions, + &NetworkAction::WriteNotification(peer_id, peer_set, wire_msg), + ); + } + + virtual_overseer + }); +} + +#[test] +fn network_protocol_versioning_subsystem_msg() { + let (oracle, _handle) = make_sync_oracle(false); + test_harness(Box::new(oracle), |test_harness| async move { + let TestHarness { mut network_handle, mut virtual_overseer, .. } = test_harness; + + let peer = PeerId::random(); + + network_handle + .connect_peer( + peer, + ValidationVersion::VStaging, + PeerSet::Validation, + ObservedRole::Full, + ) + .await; + + // bridge will inform about all connected peers. + { + assert_sends_validation_event_to_all( + NetworkBridgeEvent::PeerConnected( + peer, + ObservedRole::Full, + ValidationVersion::VStaging.into(), + None, + ), + &mut virtual_overseer, + ) + .await; + + assert_sends_validation_event_to_all( + NetworkBridgeEvent::PeerViewChange(peer, View::default()), + &mut virtual_overseer, + ) + .await; + } + + let approval_distribution_message = + protocol_vstaging::ApprovalDistributionMessage::Approvals(Vec::new()); + + let msg = protocol_vstaging::ValidationProtocol::ApprovalDistribution( + approval_distribution_message.clone(), + ); + + network_handle + .peer_message( + peer, + PeerSet::Validation, + WireMessage::ProtocolMessage(msg.clone()).encode(), + ) + .await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ApprovalDistribution( + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerMessage(p, Versioned::VStaging(m)) + ) + ) => { + assert_eq!(p, peer); + assert_eq!(m, approval_distribution_message); + } + ); + + let metadata = protocol_v1::StatementMetadata { + relay_parent: Hash::zero(), + candidate_hash: CandidateHash::default(), + signed_by: ValidatorIndex(0), + signature: sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]), + }; + let statement_distribution_message = + protocol_vstaging::StatementDistributionMessage::V1Compatibility( + protocol_v1::StatementDistributionMessage::LargeStatement(metadata), + ); + let msg = protocol_vstaging::ValidationProtocol::StatementDistribution( + statement_distribution_message.clone(), + ); + + network_handle + .peer_message( + peer, + PeerSet::Validation, + WireMessage::ProtocolMessage(msg.clone()).encode(), + ) + .await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerMessage(p, Versioned::VStaging(m)) + ) + ) => { + assert_eq!(p, peer); + assert_eq!(m, statement_distribution_message); + } + ); + + // No more messages. + assert_matches!(futures::poll!(virtual_overseer.recv().boxed()), Poll::Pending); + + virtual_overseer + }); +} diff --git a/node/network/bridge/src/tx/mod.rs b/node/network/bridge/src/tx/mod.rs index 93916dd70fec..e0ca633547f4 100644 --- a/node/network/bridge/src/tx/mod.rs +++ b/node/network/bridge/src/tx/mod.rs @@ -20,7 +20,7 @@ use super::*; use polkadot_node_network_protocol::{ peer_set::{CollationVersion, PeerSet, PeerSetProtocolNames, ValidationVersion}, request_response::ReqProtocolNames, - v1 as protocol_v1, PeerId, Versioned, + v1 as protocol_v1, vstaging as protocol_vstaging, PeerId, Versioned, }; use polkadot_node_subsystem::{ @@ -197,6 +197,13 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), + Versioned::VStaging(msg) => send_validation_message_vstaging( + &mut network_service, + peers, + peerset_protocol_names, + WireMessage::ProtocolMessage(msg), + &metrics, + ), } }, NetworkBridgeTxMessage::SendValidationMessages(msgs) => { @@ -215,6 +222,13 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), + Versioned::VStaging(msg) => send_validation_message_vstaging( + &mut network_service, + peers, + peerset_protocol_names, + WireMessage::ProtocolMessage(msg), + &metrics, + ), } } }, @@ -233,6 +247,13 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), + Versioned::VStaging(msg) => send_collation_message_vstaging( + &mut network_service, + peers, + peerset_protocol_names, + WireMessage::ProtocolMessage(msg), + &metrics, + ), } }, NetworkBridgeTxMessage::SendCollationMessages(msgs) => { @@ -251,6 +272,13 @@ where WireMessage::ProtocolMessage(msg), &metrics, ), + Versioned::VStaging(msg) => send_collation_message_vstaging( + &mut network_service, + peers, + peerset_protocol_names, + WireMessage::ProtocolMessage(msg), + &metrics, + ), } } }, @@ -381,3 +409,39 @@ fn send_collation_message_v1( metrics, ); } + +fn send_validation_message_vstaging( + net: &mut impl Network, + peers: Vec, + protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Validation, + ValidationVersion::VStaging.into(), + protocol_names, + message, + metrics, + ); +} + +fn send_collation_message_vstaging( + net: &mut impl Network, + peers: Vec, + protocol_names: &PeerSetProtocolNames, + message: WireMessage, + metrics: &Metrics, +) { + send_message( + net, + peers, + PeerSet::Collation, + CollationVersion::VStaging.into(), + protocol_names, + message, + metrics, + ); +} diff --git a/node/network/bridge/src/tx/tests.rs b/node/network/bridge/src/tx/tests.rs index e851cb0dee6f..21cd134c54f2 100644 --- a/node/network/bridge/src/tx/tests.rs +++ b/node/network/bridge/src/tx/tests.rs @@ -130,8 +130,7 @@ impl Network for TestNetwork { } fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let (peer_set, version) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); - assert_eq!(version, peer_set.get_main_version()); + let (peer_set, _) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); self.action_tx .lock() @@ -140,8 +139,7 @@ impl Network for TestNetwork { } fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - let (peer_set, version) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); - assert_eq!(version, peer_set.get_main_version()); + let (peer_set, _) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); self.action_tx .lock() @@ -173,10 +171,17 @@ impl TestNetworkHandle { self.action_rx.next().await.expect("subsystem concluded early") } - async fn connect_peer(&mut self, peer: PeerId, peer_set: PeerSet, role: ObservedRole) { + async fn connect_peer( + &mut self, + peer: PeerId, + protocol_version: ValidationVersion, + peer_set: PeerSet, + role: ObservedRole, + ) { + let protocol_version = ProtocolVersion::from(protocol_version); self.send_network_event(NetworkEvent::NotificationStreamOpened { remote: peer, - protocol: self.peerset_protocol_names.get_main_name(peer_set), + protocol: self.peerset_protocol_names.get_name(peer_set, protocol_version), negotiated_fallback: None, role: role.into(), received_handshake: vec![], @@ -242,7 +247,7 @@ fn send_messages_to_peers() { let peer = PeerId::random(); network_handle - .connect_peer(peer, PeerSet::Validation, ObservedRole::Full) + .connect_peer(peer, ValidationVersion::V1, PeerSet::Validation, ObservedRole::Full) .timeout(TIMEOUT) .await .expect("Timeout does not occur"); @@ -251,7 +256,7 @@ fn send_messages_to_peers() { // so the single item sink has to be free explicitly network_handle - .connect_peer(peer, PeerSet::Collation, ObservedRole::Full) + .connect_peer(peer, ValidationVersion::V1, PeerSet::Collation, ObservedRole::Full) .timeout(TIMEOUT) .await .expect("Timeout does not occur"); @@ -328,3 +333,107 @@ fn send_messages_to_peers() { virtual_overseer }); } + +#[test] +fn network_protocol_versioning_send() { + test_harness(|test_harness| async move { + let TestHarness { mut network_handle, mut virtual_overseer } = test_harness; + + let peer_ids: Vec<_> = (0..4).map(|_| PeerId::random()).collect(); + let peers = [ + (peer_ids[0], PeerSet::Validation, ValidationVersion::VStaging), + (peer_ids[1], PeerSet::Collation, ValidationVersion::V1), + (peer_ids[2], PeerSet::Validation, ValidationVersion::V1), + (peer_ids[3], PeerSet::Collation, ValidationVersion::VStaging), + ]; + + for &(peer_id, peer_set, version) in &peers { + network_handle + .connect_peer(peer_id, version, peer_set, ObservedRole::Full) + .timeout(TIMEOUT) + .await + .expect("Timeout does not occur"); + } + + // send a validation protocol message. + + { + let approval_distribution_message = + protocol_vstaging::ApprovalDistributionMessage::Approvals(Vec::new()); + + let msg = protocol_vstaging::ValidationProtocol::ApprovalDistribution( + approval_distribution_message.clone(), + ); + + // Note that bridge doesn't ensure neither peer's protocol version + // or peer set match the message. + let receivers = vec![peer_ids[0], peer_ids[3]]; + virtual_overseer + .send(FromOrchestra::Communication { + msg: NetworkBridgeTxMessage::SendValidationMessage( + receivers.clone(), + Versioned::VStaging(msg.clone()), + ), + }) + .timeout(TIMEOUT) + .await + .expect("Timeout does not occur"); + + for peer in &receivers { + assert_eq!( + network_handle + .next_network_action() + .timeout(TIMEOUT) + .await + .expect("Timeout does not occur"), + NetworkAction::WriteNotification( + *peer, + PeerSet::Validation, + WireMessage::ProtocolMessage(msg.clone()).encode(), + ) + ); + } + } + + // send a collation protocol message. + + { + let collator_protocol_message = protocol_vstaging::CollatorProtocolMessage::Declare( + Sr25519Keyring::Alice.public().into(), + 0_u32.into(), + dummy_collator_signature(), + ); + + let msg = protocol_vstaging::CollationProtocol::CollatorProtocol( + collator_protocol_message.clone(), + ); + + let receivers = vec![peer_ids[1], peer_ids[2]]; + + virtual_overseer + .send(FromOrchestra::Communication { + msg: NetworkBridgeTxMessage::SendCollationMessages(vec![( + receivers.clone(), + Versioned::VStaging(msg.clone()), + )]), + }) + .await; + + for peer in &receivers { + assert_eq!( + network_handle + .next_network_action() + .timeout(TIMEOUT) + .await + .expect("Timeout does not occur"), + NetworkAction::WriteNotification( + *peer, + PeerSet::Collation, + WireMessage::ProtocolMessage(msg.clone()).encode(), + ) + ); + } + } + virtual_overseer + }); +} diff --git a/node/network/collator-protocol/Cargo.toml b/node/network/collator-protocol/Cargo.toml index 4f6adba5487f..e73de15d1ecb 100644 --- a/node/network/collator-protocol/Cargo.toml +++ b/node/network/collator-protocol/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true [dependencies] -always-assert = "0.1.2" bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] } futures = "0.3.21" futures-timer = "3" @@ -23,6 +22,7 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-subsystem = {path = "../../subsystem" } fatality = "0.0.6" thiserror = "1.0.31" +tokio-util = "0.7.1" [dev-dependencies] log = "0.4.17" @@ -31,6 +31,7 @@ assert_matches = "1.4.0" sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } parity-scale-codec = { version = "3.6.1", features = ["std"] } diff --git a/node/network/collator-protocol/src/collator_side/collation.rs b/node/network/collator-protocol/src/collator_side/collation.rs new file mode 100644 index 000000000000..28dd9e0a959e --- /dev/null +++ b/node/network/collator-protocol/src/collator_side/collation.rs @@ -0,0 +1,162 @@ +// Copyright 2022 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 . + +//! Primitives for tracking collations-related data. + +use std::collections::{HashSet, VecDeque}; + +use futures::{future::BoxFuture, stream::FuturesUnordered}; + +use polkadot_node_network_protocol::{ + request_response::{ + incoming::OutgoingResponse, v1 as protocol_v1, vstaging as protocol_vstaging, + IncomingRequest, + }, + PeerId, +}; +use polkadot_node_primitives::PoV; +use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, Id as ParaId}; + +/// The status of a collation as seen from the collator. +pub enum CollationStatus { + /// The collation was created, but we did not advertise it to any validator. + Created, + /// The collation was advertised to at least one validator. + Advertised, + /// The collation was requested by at least one validator. + Requested, +} + +impl CollationStatus { + /// Advance to the [`Self::Advertised`] status. + /// + /// This ensures that `self` isn't already [`Self::Requested`]. + pub fn advance_to_advertised(&mut self) { + if !matches!(self, Self::Requested) { + *self = Self::Advertised; + } + } + + /// Advance to the [`Self::Requested`] status. + pub fn advance_to_requested(&mut self) { + *self = Self::Requested; + } +} + +/// A collation built by the collator. +pub struct Collation { + /// Candidate receipt. + pub receipt: CandidateReceipt, + /// Parent head-data hash. + pub parent_head_data_hash: Hash, + /// Proof to verify the state transition of the parachain. + pub pov: PoV, + /// Collation status. + pub status: CollationStatus, +} + +/// Stores the state for waiting collation fetches per relay parent. +#[derive(Default)] +pub struct WaitingCollationFetches { + /// A flag indicating that we have an ongoing request. + /// This limits the number of collations being sent at any moment + /// of time to 1 for each relay parent. + /// + /// If set to `true`, any new request will be queued. + pub collation_fetch_active: bool, + /// The collation fetches waiting to be fulfilled. + pub req_queue: VecDeque, + /// All peers that are waiting or actively uploading. + /// + /// We will not accept multiple requests from the same peer, otherwise our DoS protection of + /// moving on to the next peer after `MAX_UNSHARED_UPLOAD_TIME` would be pointless. + pub waiting_peers: HashSet<(PeerId, CandidateHash)>, +} + +/// Backwards-compatible wrapper for incoming collations requests. +pub enum VersionedCollationRequest { + V1(IncomingRequest), + VStaging(IncomingRequest), +} + +impl From> for VersionedCollationRequest { + fn from(req: IncomingRequest) -> Self { + Self::V1(req) + } +} + +impl From> + for VersionedCollationRequest +{ + fn from(req: IncomingRequest) -> Self { + Self::VStaging(req) + } +} + +impl VersionedCollationRequest { + /// Returns parachain id from the request payload. + pub fn para_id(&self) -> ParaId { + match self { + VersionedCollationRequest::V1(req) => req.payload.para_id, + VersionedCollationRequest::VStaging(req) => req.payload.para_id, + } + } + + /// Returns relay parent from the request payload. + pub fn relay_parent(&self) -> Hash { + match self { + VersionedCollationRequest::V1(req) => req.payload.relay_parent, + VersionedCollationRequest::VStaging(req) => req.payload.relay_parent, + } + } + + /// Returns id of the peer the request was received from. + pub fn peer_id(&self) -> PeerId { + match self { + VersionedCollationRequest::V1(req) => req.peer, + VersionedCollationRequest::VStaging(req) => req.peer, + } + } + + /// Sends the response back to requester. + pub fn send_outgoing_response( + self, + response: OutgoingResponse, + ) -> Result<(), ()> { + match self { + VersionedCollationRequest::V1(req) => req.send_outgoing_response(response), + VersionedCollationRequest::VStaging(req) => req.send_outgoing_response(response), + } + } +} + +/// Result of the finished background send-collation task. +/// +/// Note that if the timeout was hit the request doesn't get +/// aborted, it only indicates that we should start processing +/// the next one from the queue. +pub struct CollationSendResult { + /// Candidate's relay parent. + pub relay_parent: Hash, + /// Candidate hash. + pub candidate_hash: CandidateHash, + /// Peer id. + pub peer_id: PeerId, + /// Whether the max unshared timeout was hit. + pub timed_out: bool, +} + +pub type ActiveCollationFetches = FuturesUnordered>; diff --git a/node/network/collator-protocol/src/collator_side/metrics.rs b/node/network/collator-protocol/src/collator_side/metrics.rs index 3b5758ccc7b6..589c19b4f90d 100644 --- a/node/network/collator-protocol/src/collator_side/metrics.rs +++ b/node/network/collator-protocol/src/collator_side/metrics.rs @@ -20,7 +20,7 @@ use polkadot_node_subsystem_util::metrics::{self, prometheus}; pub struct Metrics(Option); impl Metrics { - pub fn on_advertisment_made(&self) { + pub fn on_advertisement_made(&self) { if let Some(metrics) = &self.0 { metrics.advertisements_made.inc(); } diff --git a/node/network/collator-protocol/src/collator_side/mod.rs b/node/network/collator-protocol/src/collator_side/mod.rs index e4adfdc9d941..96978f39a532 100644 --- a/node/network/collator-protocol/src/collator_side/mod.rs +++ b/node/network/collator-protocol/src/collator_side/mod.rs @@ -15,25 +15,26 @@ // along with Polkadot. If not, see . use std::{ - collections::{HashMap, HashSet, VecDeque}, - pin::Pin, - time::{Duration, Instant}, + collections::{HashMap, HashSet}, + convert::TryInto, + time::Duration, }; +use bitvec::{bitvec, vec::BitVec}; use futures::{ - channel::oneshot, pin_mut, select, stream::FuturesUnordered, Future, FutureExt, StreamExt, + channel::oneshot, future::Fuse, pin_mut, select, stream::FuturesUnordered, FutureExt, StreamExt, }; use sp_core::Pair; use polkadot_node_network_protocol::{ self as net_protocol, - peer_set::PeerSet, + peer_set::{CollationVersion, PeerSet}, request_response::{ incoming::{self, OutgoingResponse}, - v1::{self as request_v1, CollationFetchingRequest, CollationFetchingResponse}, - IncomingRequest, IncomingRequestReceiver, + v1 as request_v1, vstaging as request_vstaging, IncomingRequestReceiver, }, - v1 as protocol_v1, OurView, PeerId, UnifiedReputationChange as Rep, Versioned, View, + v1 as protocol_v1, vstaging as protocol_vstaging, OurView, PeerId, + UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::{CollationSecondedSignal, PoV, Statement}; use polkadot_node_subsystem::{ @@ -41,11 +42,15 @@ use polkadot_node_subsystem::{ messages::{ CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeTxMessage, RuntimeApiMessage, }, - overseer, FromOrchestra, OverseerSignal, PerLeafSpan, + overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, PerLeafSpan, }; use polkadot_node_subsystem_util::{ + backing_implicit_view::View as ImplicitView, reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, - runtime::{get_availability_cores, get_group_rotation_info, RuntimeInfo}, + runtime::{ + get_availability_cores, get_group_rotation_info, prospective_parachains_mode, + ProspectiveParachainsMode, RuntimeInfo, + }, TimeoutExt, }; use polkadot_primitives::{ @@ -58,18 +63,23 @@ use crate::{ error::{log_error, Error, FatalError, Result}, modify_reputation, }; -use fatality::Split; +mod collation; mod metrics; +#[cfg(test)] +mod tests; mod validators_buffer; -use validators_buffer::{ValidatorGroupsBuffer, VALIDATORS_BUFFER_CAPACITY}; +use collation::{ + ActiveCollationFetches, Collation, CollationSendResult, CollationStatus, + VersionedCollationRequest, WaitingCollationFetches, +}; +use validators_buffer::{ + ResetInterestTimeout, ValidatorGroupsBuffer, RESET_INTEREST_TIMEOUT, VALIDATORS_BUFFER_CAPACITY, +}; pub use metrics::Metrics; -#[cfg(test)] -mod tests; - const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Peer sent unparsable request"); const COST_UNEXPECTED_MESSAGE: Rep = Rep::CostMinor("An unexpected message"); const COST_APPARENT_FLOOD: Rep = @@ -91,108 +101,112 @@ const MAX_UNSHARED_UPLOAD_TIME: Duration = Duration::from_millis(150); /// Validators are obtained from [`ValidatorGroupsBuffer::validators_to_connect`]. const RECONNECT_TIMEOUT: Duration = Duration::from_secs(12); -/// How often to check for reconnect timeout. -const RECONNECT_POLL: Duration = Duration::from_secs(1); +/// Future that when resolved indicates that we should update reserved peer-set +/// of validators we want to be connected to. +/// +/// `Pending` variant never finishes and should be used when there're no peers +/// connected. +type ReconnectTimeout = Fuse; /// Info about validators we are currently connected to. /// /// It keeps track to which validators we advertised our collation. -#[derive(Debug)] +#[derive(Debug, Default)] struct ValidatorGroup { - /// All [`ValidatorId`]'s of the current group to that we advertised our collation. - advertised_to: HashSet, + /// Validators discovery ids. Lazily initialized when first + /// distributing a collation. + validators: Vec, + + /// Bits indicating which validators have already seen the announcement + /// per candidate. + advertised_to: HashMap, } impl ValidatorGroup { - /// Create a new `ValidatorGroup` - /// - /// without any advertisements. - fn new() -> Self { - Self { advertised_to: HashSet::new() } - } - /// Returns `true` if we should advertise our collation to the given peer. fn should_advertise_to( &self, + candidate_hash: &CandidateHash, peer_ids: &HashMap>, peer: &PeerId, ) -> bool { - match peer_ids.get(peer) { - Some(discovery_ids) => !discovery_ids.iter().any(|d| self.advertised_to.contains(d)), - None => false, + let authority_ids = match peer_ids.get(peer) { + Some(authority_ids) => authority_ids, + None => return false, + }; + + for id in authority_ids { + // One peer id may correspond to different discovery ids across sessions, + // having a non-empty intersection is sufficient to assume that this peer + // belongs to this particular validator group. + let validator_index = match self.validators.iter().position(|v| v == id) { + Some(idx) => idx, + None => continue, + }; + + // Either the candidate is unseen by this validator group + // or the corresponding bit is not set. + if self + .advertised_to + .get(candidate_hash) + .map_or(true, |advertised| !advertised[validator_index]) + { + return true + } } + + false } /// Should be called after we advertised our collation to the given `peer` to keep track of it. fn advertised_to_peer( &mut self, + candidate_hash: &CandidateHash, peer_ids: &HashMap>, peer: &PeerId, ) { if let Some(authority_ids) = peer_ids.get(peer) { - authority_ids.iter().for_each(|a| { - self.advertised_to.insert(a.clone()); - }); - } - } -} - -/// The status of a collation as seen from the collator. -enum CollationStatus { - /// The collation was created, but we did not advertise it to any validator. - Created, - /// The collation was advertised to at least one validator. - Advertised, - /// The collation was requested by at least one validator. - Requested, -} - -impl CollationStatus { - /// Advance to the [`Self::Advertised`] status. - /// - /// This ensures that `self` isn't already [`Self::Requested`]. - fn advance_to_advertised(&mut self) { - if !matches!(self, Self::Requested) { - *self = Self::Advertised; + for id in authority_ids { + let validator_index = match self.validators.iter().position(|v| v == id) { + Some(idx) => idx, + None => continue, + }; + self.advertised_to + .entry(*candidate_hash) + .or_insert_with(|| bitvec![0; self.validators.len()]) + .set(validator_index, true); + } } } - - /// Advance to the [`Self::Requested`] status. - fn advance_to_requested(&mut self) { - *self = Self::Requested; - } } -/// A collation built by the collator. -struct Collation { - receipt: CandidateReceipt, - pov: PoV, - status: CollationStatus, +#[derive(Debug)] +struct PeerData { + /// Peer's view. + view: View, + /// Network protocol version. + version: CollationVersion, } -/// Stores the state for waiting collation fetches. -#[derive(Default)] -struct WaitingCollationFetches { - /// Is there currently a collation getting fetched? - collation_fetch_active: bool, - /// The collation fetches waiting to be fulfilled. - waiting: VecDeque>, - /// All peers that are waiting or actively uploading. - /// - /// We will not accept multiple requests from the same peer, otherwise our DoS protection of - /// moving on to the next peer after `MAX_UNSHARED_UPLOAD_TIME` would be pointless. - waiting_peers: HashSet, +struct PerRelayParent { + prospective_parachains_mode: ProspectiveParachainsMode, + /// Validators group responsible for backing candidates built + /// on top of this relay parent. + validator_group: ValidatorGroup, + /// Distributed collations. + collations: HashMap, } -struct CollationSendResult { - relay_parent: Hash, - peer_id: PeerId, - timed_out: bool, +impl PerRelayParent { + fn new(mode: ProspectiveParachainsMode) -> Self { + Self { + prospective_parachains_mode: mode, + validator_group: ValidatorGroup::default(), + collations: HashMap::new(), + } + } } -type ActiveCollationFetches = - FuturesUnordered + Send + 'static>>>; - struct State { /// Our network peer id. local_peer_id: PeerId, @@ -206,25 +220,34 @@ struct State { /// Track all active peers and their views /// to determine what is relevant to them. - peer_views: HashMap, + peer_data: HashMap, - /// Our own view. - view: OurView, + /// Leaves that do support asynchronous backing along with + /// implicit ancestry. Leaves from the implicit view are present in + /// `active_leaves`, the opposite doesn't hold true. + /// + /// Relay-chain blocks which don't support prospective parachains are + /// never included in the fragment trees of active leaves which do. In + /// particular, this means that if a given relay parent belongs to implicit + /// ancestry of some active leaf, then it does support prospective parachains. + implicit_view: ImplicitView, + + /// All active leaves observed by us, including both that do and do not + /// support prospective parachains. This mapping works as a replacement for + /// [`polkadot_node_network_protocol::View`] and can be dropped once the transition + /// to asynchronous backing is done. + active_leaves: HashMap, + + /// Validators and distributed collations tracked for each relay parent from + /// our view, including both leaves and implicit ancestry. + per_relay_parent: HashMap, /// Span per relay parent. span_per_relay_parent: HashMap, - /// Possessed collations. - /// - /// We will keep up to one local collation per relay-parent. - collations: HashMap, - /// The result senders per collation. collation_result_senders: HashMap>, - /// Our validator groups per active leaf. - our_validators_groups: HashMap, - /// The mapping from [`PeerId`] to [`HashSet`]. This is filled over time /// as we learn the [`PeerId`]'s by `PeerConnected` events. peer_ids: HashMap>, @@ -232,9 +255,9 @@ struct State { /// Tracks which validators we want to stay connected to. validator_groups_buf: ValidatorGroupsBuffer, - /// Timestamp of the last connection request to a non-empty list of validators, - /// `None` otherwise. - last_connected_at: Option, + /// Timeout-future that enforces collator to update the peer-set at least once + /// every [`RECONNECT_TIMEOUT`] seconds. + reconnect_timeout: ReconnectTimeout, /// Metrics. metrics: Metrics, @@ -250,6 +273,14 @@ struct State { /// Each future returns the relay parent of the finished collation fetch. active_collation_fetches: ActiveCollationFetches, + /// Time limits for validators to fetch the collation once the advertisement + /// was sent. + /// + /// Given an implicit view a collation may stay in memory for significant amount + /// of time, if we don't timeout validators the node will keep attempting to connect + /// to unneeded peers. + advertisement_timeouts: FuturesUnordered, + /// Aggregated reputation change reputation: ReputationAggregator, } @@ -268,29 +299,21 @@ impl State { collator_pair, metrics, collating_on: Default::default(), - peer_views: Default::default(), - view: Default::default(), + peer_data: Default::default(), + implicit_view: Default::default(), + active_leaves: Default::default(), + per_relay_parent: Default::default(), span_per_relay_parent: Default::default(), - collations: Default::default(), collation_result_senders: Default::default(), - our_validators_groups: Default::default(), peer_ids: Default::default(), validator_groups_buf: ValidatorGroupsBuffer::with_capacity(VALIDATORS_BUFFER_CAPACITY), - last_connected_at: None, + reconnect_timeout: Fuse::terminated(), waiting_collation_fetches: Default::default(), active_collation_fetches: Default::default(), + advertisement_timeouts: Default::default(), reputation, } } - - /// Get all peers which have the given relay parent in their view. - fn peers_interested_in_leaf(&self, relay_parent: &Hash) -> Vec { - self.peer_views - .iter() - .filter(|(_, v)| v.contains(relay_parent)) - .map(|(peer, _)| *peer) - .collect() - } } /// Distribute a collation. @@ -308,52 +331,77 @@ async fn distribute_collation( state: &mut State, id: ParaId, receipt: CandidateReceipt, + parent_head_data_hash: Hash, pov: PoV, result_sender: Option>, ) -> Result<()> { - let relay_parent = receipt.descriptor.relay_parent; + let candidate_relay_parent = receipt.descriptor.relay_parent; let candidate_hash = receipt.hash(); - // This collation is not in the active-leaves set. - if !state.view.contains(&relay_parent) { - gum::warn!( + let per_relay_parent = match state.per_relay_parent.get_mut(&candidate_relay_parent) { + Some(per_relay_parent) => per_relay_parent, + None => { + gum::debug!( + target: LOG_TARGET, + para_id = %id, + candidate_relay_parent = %candidate_relay_parent, + candidate_hash = ?candidate_hash, + "Candidate relay parent is out of our view", + ); + return Ok(()) + }, + }; + let relay_parent_mode = per_relay_parent.prospective_parachains_mode; + + let collations_limit = match relay_parent_mode { + ProspectiveParachainsMode::Disabled => 1, + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth + 1, + }; + + if per_relay_parent.collations.len() >= collations_limit { + gum::debug!( target: LOG_TARGET, - ?relay_parent, - "distribute collation message parent is outside of our view", + ?candidate_relay_parent, + ?relay_parent_mode, + "The limit of {} collations per relay parent is already reached", + collations_limit, ); - return Ok(()) } // We have already seen collation for this relay parent. - if state.collations.contains_key(&relay_parent) { + if per_relay_parent.collations.contains_key(&candidate_hash) { gum::debug!( target: LOG_TARGET, - ?relay_parent, - "Already seen collation for this relay parent", + ?candidate_relay_parent, + ?candidate_hash, + "Already seen this candidate", ); return Ok(()) } // Determine which core the para collated-on is assigned to. // If it is not scheduled then ignore the message. - let (our_core, num_cores) = match determine_core(ctx.sender(), id, relay_parent).await? { - Some(core) => core, - None => { - gum::warn!( - target: LOG_TARGET, - para_id = %id, - ?relay_parent, - "looks like no core is assigned to {} at {}", id, relay_parent, - ); + let (our_core, num_cores) = + match determine_core(ctx.sender(), id, candidate_relay_parent, relay_parent_mode).await? { + Some(core) => core, + None => { + gum::warn!( + target: LOG_TARGET, + para_id = %id, + "looks like no core is assigned to {} at {}", id, candidate_relay_parent, + ); - return Ok(()) - }, - }; + return Ok(()) + }, + }; // Determine the group on that core. + // + // When prospective parachains are disabled, candidate relay parent here is + // guaranteed to be an active leaf. let GroupValidators { validators, session_index, group_index } = - determine_our_validators(ctx, runtime, our_core, num_cores, relay_parent).await?; + determine_our_validators(ctx, runtime, our_core, num_cores, candidate_relay_parent).await?; if validators.is_empty() { gum::warn!( @@ -365,13 +413,13 @@ async fn distribute_collation( return Ok(()) } - // It's important to insert new collation bits **before** + // It's important to insert new collation interests **before** // issuing a connection request. // // If a validator managed to fetch all the relevant collations // but still assigned to our core, we keep the connection alive. state.validator_groups_buf.note_collation_advertised( - relay_parent, + candidate_hash, session_index, group_index, &validators, @@ -380,7 +428,8 @@ async fn distribute_collation( gum::debug!( target: LOG_TARGET, para_id = %id, - relay_parent = %relay_parent, + candidate_relay_parent = %candidate_relay_parent, + relay_parent_mode = ?relay_parent_mode, ?candidate_hash, pov_hash = ?pov.hash(), core = ?our_core, @@ -388,23 +437,56 @@ async fn distribute_collation( "Accepted collation, connecting to validators." ); - // Update a set of connected validators if necessary. - state.last_connected_at = connect_to_validators(ctx, &state.validator_groups_buf).await; + let validators_at_relay_parent = &mut per_relay_parent.validator_group.validators; + if validators_at_relay_parent.is_empty() { + *validators_at_relay_parent = validators; + } - state.our_validators_groups.insert(relay_parent, ValidatorGroup::new()); + // Update a set of connected validators if necessary. + state.reconnect_timeout = connect_to_validators(ctx, &state.validator_groups_buf).await; if let Some(result_sender) = result_sender { state.collation_result_senders.insert(candidate_hash, result_sender); } - state - .collations - .insert(relay_parent, Collation { receipt, pov, status: CollationStatus::Created }); + per_relay_parent.collations.insert( + candidate_hash, + Collation { receipt, parent_head_data_hash, pov, status: CollationStatus::Created }, + ); + + // If prospective parachains are disabled, a leaf should be known to peer. + // Otherwise, it should be present in allowed ancestry of some leaf. + // + // It's collation-producer responsibility to verify that there exists + // a hypothetical membership in a fragment tree for candidate. + let interested = + state + .peer_data + .iter() + .filter(|(_, PeerData { view: v, .. })| match relay_parent_mode { + ProspectiveParachainsMode::Disabled => v.contains(&candidate_relay_parent), + ProspectiveParachainsMode::Enabled { .. } => v.iter().any(|block_hash| { + state + .implicit_view + .known_allowed_relay_parents_under(block_hash, Some(id)) + .unwrap_or_default() + .contains(&candidate_relay_parent) + }), + }); - let interested = state.peers_interested_in_leaf(&relay_parent); // Make sure already connected peers get collations: - for peer_id in interested { - advertise_collation(ctx, state, relay_parent, peer_id).await; + for (peer_id, peer_data) in interested { + advertise_collation( + ctx, + candidate_relay_parent, + per_relay_parent, + peer_id, + peer_data.version, + &state.peer_ids, + &mut state.advertisement_timeouts, + &state.metrics, + ) + .await; } Ok(()) @@ -416,14 +498,26 @@ async fn determine_core( sender: &mut impl overseer::SubsystemSender, para_id: ParaId, relay_parent: Hash, + relay_parent_mode: ProspectiveParachainsMode, ) -> Result> { let cores = get_availability_cores(sender, relay_parent).await?; for (idx, core) in cores.iter().enumerate() { - if let CoreState::Scheduled(occupied) = core { - if occupied.para_id == para_id { - return Ok(Some(((idx as u32).into(), cores.len()))) - } + let core_para_id = match core { + CoreState::Scheduled(scheduled) => Some(scheduled.para_id), + CoreState::Occupied(occupied) => + if relay_parent_mode.is_enabled() { + // With async backing we don't care about the core state, + // it is only needed for figuring our validators group. + Some(occupied.candidate_descriptor.para_id) + } else { + None + }, + CoreState::Free => None, + }; + + if core_para_id == Some(para_id) { + return Ok(Some(((idx as u32).into(), cores.len()))) } } @@ -478,36 +572,62 @@ async fn determine_our_validators( Ok(current_validators) } -/// Issue a `Declare` collation message to the given `peer`. -#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] -async fn declare(ctx: &mut Context, state: &mut State, peer: PeerId) { - let declare_signature_payload = protocol_v1::declare_signature_payload(&state.local_peer_id); - - if let Some(para_id) = state.collating_on { - let wire_message = protocol_v1::CollatorProtocolMessage::Declare( - state.collator_pair.public(), - para_id, - state.collator_pair.sign(&declare_signature_payload), - ); +/// Construct the declare message to be sent to validator depending on its +/// network protocol version. +fn declare_message( + state: &mut State, + version: CollationVersion, +) -> Option> { + let para_id = state.collating_on?; + Some(match version { + CollationVersion::V1 => { + let declare_signature_payload = + protocol_v1::declare_signature_payload(&state.local_peer_id); + let wire_message = protocol_v1::CollatorProtocolMessage::Declare( + state.collator_pair.public(), + para_id, + state.collator_pair.sign(&declare_signature_payload), + ); + Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)) + }, + CollationVersion::VStaging => { + let declare_signature_payload = + protocol_vstaging::declare_signature_payload(&state.local_peer_id); + let wire_message = protocol_vstaging::CollatorProtocolMessage::Declare( + state.collator_pair.public(), + para_id, + state.collator_pair.sign(&declare_signature_payload), + ); + Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + wire_message, + )) + }, + }) +} - ctx.send_message(NetworkBridgeTxMessage::SendCollationMessage( - vec![peer], - Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)), - )) - .await; +/// Issue versioned `Declare` collation message to the given `peer`. +#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] +async fn declare( + ctx: &mut Context, + state: &mut State, + peer: &PeerId, + version: CollationVersion, +) { + if let Some(wire_message) = declare_message(state, version) { + ctx.send_message(NetworkBridgeTxMessage::SendCollationMessage(vec![*peer], wire_message)) + .await; } } /// Updates a set of connected validators based on their advertisement-bits /// in a validators buffer. /// -/// Returns current timestamp if the connection request was non-empty, `None` -/// otherwise. +/// Should be called again once a returned future resolves. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn connect_to_validators( ctx: &mut Context, validator_groups_buf: &ValidatorGroupsBuffer, -) -> Option { +) -> ReconnectTimeout { let validator_ids = validator_groups_buf.validators_to_connect(); let is_disconnect = validator_ids.is_empty(); @@ -521,69 +641,106 @@ async fn connect_to_validators( }) .await; - (!is_disconnect).then_some(Instant::now()) + if is_disconnect { + gum::trace!(target: LOG_TARGET, "Disconnecting from all peers"); + // Never resolves. + Fuse::terminated() + } else { + futures_timer::Delay::new(RECONNECT_TIMEOUT).fuse() + } } /// Advertise collation to the given `peer`. /// -/// This will only advertise a collation if there exists one for the given `relay_parent` and the -/// given `peer` is set as validator for our para at the given `relay_parent`. +/// This will only advertise a collation if there exists at least one for the given +/// `relay_parent` and the given `peer` is set as validator for our para at the given +/// `relay_parent`. +/// +/// We also make sure not to advertise the same collation multiple times to the same validator. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn advertise_collation( ctx: &mut Context, - state: &mut State, relay_parent: Hash, - peer: PeerId, + per_relay_parent: &mut PerRelayParent, + peer: &PeerId, + protocol_version: CollationVersion, + peer_ids: &HashMap>, + advertisement_timeouts: &mut FuturesUnordered, + metrics: &Metrics, ) { - let should_advertise = state - .our_validators_groups - .get(&relay_parent) - .map(|g| g.should_advertise_to(&state.peer_ids, &peer)) - .unwrap_or(false); + for (candidate_hash, collation) in per_relay_parent.collations.iter_mut() { + // Check that peer will be able to request the collation. + if let CollationVersion::V1 = protocol_version { + if per_relay_parent.prospective_parachains_mode.is_enabled() { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + peer_id = %peer, + "Skipping advertising to validator, incorrect network protocol version", + ); + return + } + } - match (state.collations.get_mut(&relay_parent), should_advertise) { - (None, _) => { - gum::trace!( - target: LOG_TARGET, - ?relay_parent, - peer_id = %peer, - "No collation to advertise.", - ); - return - }, - (_, false) => { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - peer_id = %peer, - "Not advertising collation as we already advertised it to this validator.", - ); - return - }, - (Some(collation), true) => { + let should_advertise = + per_relay_parent + .validator_group + .should_advertise_to(candidate_hash, peer_ids, &peer); + + if !should_advertise { gum::debug!( target: LOG_TARGET, ?relay_parent, peer_id = %peer, - "Advertising collation.", + "Not advertising collation since validator is not interested", ); - collation.status.advance_to_advertised() - }, - } + continue + } - let wire_message = protocol_v1::CollatorProtocolMessage::AdvertiseCollation(relay_parent); + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + peer_id = %peer, + "Advertising collation.", + ); + collation.status.advance_to_advertised(); + + let collation_message = match protocol_version { + CollationVersion::VStaging => { + let wire_message = protocol_vstaging::CollatorProtocolMessage::AdvertiseCollation { + relay_parent, + candidate_hash: *candidate_hash, + parent_head_data_hash: collation.parent_head_data_hash, + }; + Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + wire_message, + )) + }, + CollationVersion::V1 => { + let wire_message = + protocol_v1::CollatorProtocolMessage::AdvertiseCollation(relay_parent); + Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)) + }, + }; - ctx.send_message(NetworkBridgeTxMessage::SendCollationMessage( - vec![peer], - Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)), - )) - .await; + ctx.send_message(NetworkBridgeTxMessage::SendCollationMessage( + vec![*peer], + collation_message, + )) + .await; - if let Some(validators) = state.our_validators_groups.get_mut(&relay_parent) { - validators.advertised_to_peer(&state.peer_ids, &peer); - } + per_relay_parent + .validator_group + .advertised_to_peer(candidate_hash, &peer_ids, peer); - state.metrics.on_advertisment_made(); + advertisement_timeouts.push(ResetInterestTimeout::new( + *candidate_hash, + *peer, + RESET_INTEREST_TIMEOUT, + )); + + metrics.on_advertisement_made(); + } } /// The main incoming message dispatching switch. @@ -600,12 +757,13 @@ async fn process_msg( CollateOn(id) => { state.collating_on = Some(id); }, - DistributeCollation(receipt, pov, result_sender) => { + DistributeCollation(receipt, parent_head_data_hash, pov, result_sender) => { let _span1 = state .span_per_relay_parent .get(&receipt.descriptor.relay_parent) .map(|s| s.child("distributing-collation")); let _span2 = jaeger::Span::new(&pov, "distributing-collation"); + match state.collating_on { Some(id) if receipt.descriptor.para_id != id => { // If the ParaId of a collation requested to be distributed does not match @@ -619,8 +777,17 @@ async fn process_msg( }, Some(id) => { let _ = state.metrics.time_collation_distribution("distribute"); - distribute_collation(ctx, runtime, state, id, receipt, pov, result_sender) - .await?; + distribute_collation( + ctx, + runtime, + state, + id, + receipt, + parent_head_data_hash, + pov, + result_sender, + ) + .await?; }, None => { gum::warn!( @@ -631,12 +798,6 @@ async fn process_msg( }, } }, - ReportCollator(_) => { - gum::warn!( - target: LOG_TARGET, - "ReportCollator message is not expected on the collator side of the protocol", - ); - }, NetworkBridgeUpdate(event) => { // We should count only this shoulder in the histogram, as other shoulders are just // introducing noise @@ -650,7 +811,13 @@ async fn process_msg( ); } }, - _ => {}, + msg @ (ReportCollator(..) | Invalid(..) | Seconded(..) | Backed { .. }) => { + gum::warn!( + target: LOG_TARGET, + "{:?} message is not expected on the collator side of the protocol", + msg, + ); + }, } Ok(()) @@ -659,17 +826,20 @@ async fn process_msg( /// Issue a response to a previously requested collation. async fn send_collation( state: &mut State, - request: IncomingRequest, + request: VersionedCollationRequest, receipt: CandidateReceipt, pov: PoV, ) { let (tx, rx) = oneshot::channel(); - let relay_parent = request.payload.relay_parent; - let peer_id = request.peer; + let relay_parent = request.relay_parent(); + let peer_id = request.peer_id(); + let candidate_hash = receipt.hash(); + // The response payload is the same for both versions of protocol + // and doesn't have vstaging alias for simplicity. let response = OutgoingResponse { - result: Ok(CollationFetchingResponse::Collation(receipt, pov)), + result: Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)), reputation_changes: Vec::new(), sent_feedback: Some(tx), }; @@ -683,7 +853,7 @@ async fn send_collation( let r = rx.timeout(MAX_UNSHARED_UPLOAD_TIME).await; let timed_out = r.is_none(); - CollationSendResult { relay_parent, peer_id, timed_out } + CollationSendResult { relay_parent, candidate_hash, peer_id, timed_out } } .boxed(), ); @@ -698,12 +868,16 @@ async fn handle_incoming_peer_message( runtime: &mut RuntimeInfo, state: &mut State, origin: PeerId, - msg: protocol_v1::CollatorProtocolMessage, + msg: Versioned< + protocol_v1::CollatorProtocolMessage, + protocol_vstaging::CollatorProtocolMessage, + >, ) -> Result<()> { - use protocol_v1::CollatorProtocolMessage::*; + use protocol_v1::CollatorProtocolMessage as V1; + use protocol_vstaging::CollatorProtocolMessage as VStaging; match msg { - Declare(_, _, _) => { + Versioned::V1(V1::Declare(..)) | Versioned::VStaging(VStaging::Declare(..)) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -714,7 +888,8 @@ async fn handle_incoming_peer_message( ctx.send_message(NetworkBridgeTxMessage::DisconnectPeer(origin, PeerSet::Collation)) .await; }, - AdvertiseCollation(_) => { + Versioned::V1(V1::AdvertiseCollation(_)) | + Versioned::VStaging(VStaging::AdvertiseCollation { .. }) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -728,7 +903,8 @@ async fn handle_incoming_peer_message( ctx.send_message(NetworkBridgeTxMessage::DisconnectPeer(origin, PeerSet::Collation)) .await; }, - CollationSeconded(relay_parent, statement) => { + Versioned::V1(V1::CollationSeconded(relay_parent, statement)) | + Versioned::VStaging(VStaging::CollationSeconded(relay_parent, statement)) => { if !matches!(statement.unchecked_payload(), Statement::Seconded(_)) { gum::warn!( target: LOG_TARGET, @@ -773,37 +949,72 @@ async fn handle_incoming_peer_message( async fn handle_incoming_request( ctx: &mut Context, state: &mut State, - req: IncomingRequest, + req: std::result::Result, ) -> Result<()> { + let req = req?; + let relay_parent = req.relay_parent(); + let peer_id = req.peer_id(); + let para_id = req.para_id(); + let _span = state .span_per_relay_parent - .get(&req.payload.relay_parent) + .get(&relay_parent) .map(|s| s.child("request-collation")); match state.collating_on { - Some(our_para_id) if our_para_id == req.payload.para_id => { - let (receipt, pov) = - if let Some(collation) = state.collations.get_mut(&req.payload.relay_parent) { - collation.status.advance_to_requested(); - (collation.receipt.clone(), collation.pov.clone()) - } else { + Some(our_para_id) if our_para_id == para_id => { + let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { + Some(per_relay_parent) => per_relay_parent, + None => { + gum::debug!( + target: LOG_TARGET, + relay_parent = %relay_parent, + "received a `RequestCollation` for a relay parent out of our view", + ); + + return Ok(()) + }, + }; + let mode = per_relay_parent.prospective_parachains_mode; + + let collation = match &req { + VersionedCollationRequest::V1(_) if !mode.is_enabled() => + per_relay_parent.collations.values_mut().next(), + VersionedCollationRequest::VStaging(req) => + per_relay_parent.collations.get_mut(&req.payload.candidate_hash), + _ => { gum::warn!( target: LOG_TARGET, - relay_parent = %req.payload.relay_parent, - "received a `RequestCollation` for a relay parent we don't have collation stored.", + relay_parent = %relay_parent, + prospective_parachains_mode = ?mode, + ?peer_id, + "Collation request version is invalid", ); return Ok(()) - }; + }, + }; + let (receipt, pov) = if let Some(collation) = collation { + collation.status.advance_to_requested(); + (collation.receipt.clone(), collation.pov.clone()) + } else { + gum::warn!( + target: LOG_TARGET, + relay_parent = %relay_parent, + "received a `RequestCollation` for a relay parent we don't have collation stored.", + ); + + return Ok(()) + }; state.metrics.on_collation_sent_requested(); let _span = _span.as_ref().map(|s| s.child("sending")); - let waiting = - state.waiting_collation_fetches.entry(req.payload.relay_parent).or_default(); + let waiting = state.waiting_collation_fetches.entry(relay_parent).or_default(); + let candidate_hash = receipt.hash(); - if !waiting.waiting_peers.insert(req.peer) { + if !waiting.waiting_peers.insert((peer_id, candidate_hash)) { gum::debug!( target: LOG_TARGET, "Dropping incoming request as peer has a request in flight already." @@ -811,7 +1022,7 @@ async fn handle_incoming_request( modify_reputation( &mut state.reputation, ctx.sender(), - req.peer, + peer_id, COST_APPARENT_FLOOD.into(), ) .await; @@ -819,7 +1030,7 @@ async fn handle_incoming_request( } if waiting.collation_fetch_active { - waiting.waiting.push_back(req); + waiting.req_queue.push_back(req); } else { waiting.collation_fetch_active = true; // Obtain a timer for sending collation @@ -830,7 +1041,7 @@ async fn handle_incoming_request( Some(our_para_id) => { gum::warn!( target: LOG_TARGET, - for_para_id = %req.payload.para_id, + for_para_id = %para_id, our_para_id = %our_para_id, "received a `CollationFetchingRequest` for unexpected para_id", ); @@ -838,7 +1049,7 @@ async fn handle_incoming_request( None => { gum::warn!( target: LOG_TARGET, - for_para_id = %req.payload.para_id, + for_para_id = %para_id, "received a `RequestCollation` while not collating on any para", ); }, @@ -846,7 +1057,8 @@ async fn handle_incoming_request( Ok(()) } -/// Our view has changed. +/// Peer's view has changed. Send advertisements for new relay parents +/// if there're any. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn handle_peer_view_change( ctx: &mut Context, @@ -854,14 +1066,54 @@ async fn handle_peer_view_change( peer_id: PeerId, view: View, ) { - let current = state.peer_views.entry(peer_id).or_default(); + let PeerData { view: current, version } = match state.peer_data.get_mut(&peer_id) { + Some(peer_data) => peer_data, + None => return, + }; let added: Vec = view.difference(&*current).cloned().collect(); *current = view; for added in added.into_iter() { - advertise_collation(ctx, state, added, peer_id).await; + let block_hashes = match state + .per_relay_parent + .get(&added) + .map(|per_relay_parent| per_relay_parent.prospective_parachains_mode) + { + Some(ProspectiveParachainsMode::Disabled) => std::slice::from_ref(&added), + Some(ProspectiveParachainsMode::Enabled { .. }) => state + .implicit_view + .known_allowed_relay_parents_under(&added, state.collating_on) + .unwrap_or_default(), + None => { + gum::trace!( + target: LOG_TARGET, + ?peer_id, + new_leaf = ?added, + "New leaf in peer's view is unknown", + ); + continue + }, + }; + + for block_hash in block_hashes { + let per_relay_parent = match state.per_relay_parent.get_mut(block_hash) { + Some(per_relay_parent) => per_relay_parent, + None => continue, + }; + advertise_collation( + ctx, + *block_hash, + per_relay_parent, + &peer_id, + *version, + &state.peer_ids, + &mut state.advertisement_timeouts, + &state.metrics, + ) + .await; + } } } @@ -876,10 +1128,30 @@ async fn handle_network_msg( use NetworkBridgeEvent::*; match bridge_message { - PeerConnected(peer_id, observed_role, _, maybe_authority) => { + PeerConnected(peer_id, observed_role, protocol_version, maybe_authority) => { // If it is possible that a disconnected validator would attempt a reconnect // it should be handled here. gum::trace!(target: LOG_TARGET, ?peer_id, ?observed_role, "Peer connected"); + + let version = match protocol_version.try_into() { + Ok(version) => version, + Err(err) => { + // Network bridge is expected to handle this. + gum::error!( + target: LOG_TARGET, + ?peer_id, + ?observed_role, + ?err, + "Unsupported protocol version" + ); + return Ok(()) + }, + }; + state + .peer_data + .entry(peer_id) + .or_insert_with(|| PeerData { view: View::default(), version }); + if let Some(authority_ids) = maybe_authority { gum::trace!( target: LOG_TARGET, @@ -889,7 +1161,7 @@ async fn handle_network_msg( ); state.peer_ids.insert(peer_id, authority_ids); - declare(ctx, state, peer_id).await; + declare(ctx, state, &peer_id, version).await; } }, PeerViewChange(peer_id, view) => { @@ -898,14 +1170,14 @@ async fn handle_network_msg( }, PeerDisconnected(peer_id) => { gum::trace!(target: LOG_TARGET, ?peer_id, "Peer disconnected"); - state.peer_views.remove(&peer_id); + state.peer_data.remove(&peer_id); state.peer_ids.remove(&peer_id); }, OurViewChange(view) => { gum::trace!(target: LOG_TARGET, ?view, "Own view change"); - handle_our_view_change(state, view).await?; + handle_our_view_change(ctx.sender(), state, view).await?; }, - PeerMessage(remote, Versioned::V1(msg)) => { + PeerMessage(remote, msg) => { handle_incoming_peer_message(ctx, runtime, state, remote, msg).await?; }, UpdatedAuthorityIds(peer_id, authority_ids) => { @@ -921,42 +1193,99 @@ async fn handle_network_msg( } /// Handles our view changes. -async fn handle_our_view_change(state: &mut State, view: OurView) -> Result<()> { - for removed in state.view.difference(&view) { - gum::debug!(target: LOG_TARGET, relay_parent = ?removed, "Removing relay parent because our view changed."); +async fn handle_our_view_change( + sender: &mut Sender, + state: &mut State, + view: OurView, +) -> Result<()> +where + Sender: CollatorProtocolSenderTrait, +{ + let current_leaves = state.active_leaves.clone(); - if let Some(collation) = state.collations.remove(removed) { - state.collation_result_senders.remove(&collation.receipt.hash()); + let removed = current_leaves.iter().filter(|(h, _)| !view.contains(h)); + let added = view.iter().filter(|h| !current_leaves.contains_key(h)); - match collation.status { - CollationStatus::Created => gum::warn!( - target: LOG_TARGET, - candidate_hash = ?collation.receipt.hash(), - pov_hash = ?collation.pov.hash(), - "Collation wasn't advertised to any validator.", - ), - CollationStatus::Advertised => gum::debug!( - target: LOG_TARGET, - candidate_hash = ?collation.receipt.hash(), - pov_hash = ?collation.pov.hash(), - "Collation was advertised but not requested by any validator.", - ), - CollationStatus::Requested => gum::debug!( - target: LOG_TARGET, - candidate_hash = ?collation.receipt.hash(), - pov_hash = ?collation.pov.hash(), - "Collation was requested.", - ), + for leaf in added { + let mode = prospective_parachains_mode(sender, *leaf).await?; + + if let Some(span) = view.span_per_head().get(leaf).cloned() { + let per_leaf_span = PerLeafSpan::new(span, "collator-side"); + state.span_per_relay_parent.insert(*leaf, per_leaf_span); + } + + state.active_leaves.insert(*leaf, mode); + state.per_relay_parent.insert(*leaf, PerRelayParent::new(mode)); + + if mode.is_enabled() { + state + .implicit_view + .activate_leaf(sender, *leaf) + .await + .map_err(Error::ImplicitViewFetchError)?; + + let allowed_ancestry = state + .implicit_view + .known_allowed_relay_parents_under(leaf, state.collating_on) + .unwrap_or_default(); + for block_hash in allowed_ancestry { + state + .per_relay_parent + .entry(*block_hash) + .or_insert_with(|| PerRelayParent::new(mode)); } } - state.our_validators_groups.remove(removed); - state.span_per_relay_parent.remove(removed); - state.waiting_collation_fetches.remove(removed); - state.validator_groups_buf.remove_relay_parent(removed); } - state.view = view; - + for (leaf, mode) in removed { + state.active_leaves.remove(leaf); + // If the leaf is deactivated it still may stay in the view as a part + // of implicit ancestry. Only update the state after the hash is actually + // pruned from the block info storage. + let pruned = if mode.is_enabled() { + state.implicit_view.deactivate_leaf(*leaf) + } else { + vec![*leaf] + }; + + for removed in &pruned { + gum::debug!(target: LOG_TARGET, relay_parent = ?removed, "Removing relay parent because our view changed."); + + let collations = state + .per_relay_parent + .remove(removed) + .map(|per_relay_parent| per_relay_parent.collations) + .unwrap_or_default(); + for collation in collations.into_values() { + let candidate_hash = collation.receipt.hash(); + state.collation_result_senders.remove(&candidate_hash); + state.validator_groups_buf.remove_candidate(&candidate_hash); + + match collation.status { + CollationStatus::Created => gum::warn!( + target: LOG_TARGET, + candidate_hash = ?collation.receipt.hash(), + pov_hash = ?collation.pov.hash(), + "Collation wasn't advertised to any validator.", + ), + CollationStatus::Advertised => gum::debug!( + target: LOG_TARGET, + candidate_hash = ?collation.receipt.hash(), + pov_hash = ?collation.pov.hash(), + "Collation was advertised but not requested by any validator.", + ), + CollationStatus::Requested => gum::debug!( + target: LOG_TARGET, + candidate_hash = ?collation.receipt.hash(), + pov_hash = ?collation.pov.hash(), + "Collation was requested.", + ), + } + } + state.span_per_relay_parent.remove(removed); + state.waiting_collation_fetches.remove(removed); + } + } Ok(()) } @@ -966,14 +1295,16 @@ pub(crate) async fn run( ctx: Context, local_peer_id: PeerId, collator_pair: CollatorPair, - req_receiver: IncomingRequestReceiver, + req_v1_receiver: IncomingRequestReceiver, + req_v2_receiver: IncomingRequestReceiver, metrics: Metrics, ) -> std::result::Result<(), FatalError> { run_inner( ctx, local_peer_id, collator_pair, - req_receiver, + req_v1_receiver, + req_v2_receiver, metrics, ReputationAggregator::default(), REPUTATION_CHANGE_INTERVAL, @@ -986,7 +1317,8 @@ async fn run_inner( mut ctx: Context, local_peer_id: PeerId, collator_pair: CollatorPair, - mut req_receiver: IncomingRequestReceiver, + mut req_v1_receiver: IncomingRequestReceiver, + mut req_v2_receiver: IncomingRequestReceiver, metrics: Metrics, reputation: ReputationAggregator, reputation_interval: Duration, @@ -999,12 +1331,14 @@ async fn run_inner( let mut state = State::new(local_peer_id, collator_pair, metrics, reputation); let mut runtime = RuntimeInfo::new(None); - let reconnect_stream = super::tick_stream(RECONNECT_POLL); - pin_mut!(reconnect_stream); - loop { - let recv_req = req_receiver.recv(|| vec![COST_INVALID_REQUEST]).fuse(); - pin_mut!(recv_req); + let reputation_changes = || vec![COST_INVALID_REQUEST]; + let recv_req_v1 = req_v1_receiver.recv(reputation_changes).fuse(); + let recv_req_v2 = req_v2_receiver.recv(reputation_changes).fuse(); + pin_mut!(recv_req_v1); + pin_mut!(recv_req_v2); + + let mut reconnect_timeout = &mut state.reconnect_timeout; select! { _ = reputation_delay => { state.reputation.send(ctx.sender()).await; @@ -1021,28 +1355,30 @@ async fn run_inner( FromOrchestra::Signal(BlockFinalized(..)) => {} FromOrchestra::Signal(Conclude) => return Ok(()), }, - CollationSendResult { - relay_parent, - peer_id, - timed_out, - } = state.active_collation_fetches.select_next_some() => { - if timed_out { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - ?peer_id, - "Sending collation to validator timed out, carrying on with next validator", - ); - } else { - for authority_id in state.peer_ids.get(&peer_id).into_iter().flatten() { - // Timeout not hit, this peer is no longer interested in this relay parent. - state.validator_groups_buf.reset_validator_interest(relay_parent, authority_id); + CollationSendResult { relay_parent, candidate_hash, peer_id, timed_out } = + state.active_collation_fetches.select_next_some() => { + let next = if let Some(waiting) = state.waiting_collation_fetches.get_mut(&relay_parent) { + if timed_out { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?peer_id, + ?candidate_hash, + "Sending collation to validator timed out, carrying on with next validator." + ); + // We try to throttle requests per relay parent to give validators + // more bandwidth, but if the collation is not received within the + // timeout, we simply start processing next request. + // The request it still alive, it should be kept in a waiting queue. + } else { + for authority_id in state.peer_ids.get(&peer_id).into_iter().flatten() { + // Timeout not hit, this peer is no longer interested in this relay parent. + state.validator_groups_buf.reset_validator_interest(candidate_hash, authority_id); + } + waiting.waiting_peers.remove(&(peer_id, candidate_hash)); } - } - let next = if let Some(waiting) = state.waiting_collation_fetches.get_mut(&relay_parent) { - waiting.waiting_peers.remove(&peer_id); - if let Some(next) = waiting.waiting.pop_front() { + if let Some(next) = waiting.req_queue.pop_front() { next } else { waiting.collation_fetch_active = false; @@ -1053,53 +1389,69 @@ async fn run_inner( continue }; - if let Some(collation) = state.collations.get(&relay_parent) { + let next_collation = { + let per_relay_parent = match state.per_relay_parent.get(&relay_parent) { + Some(per_relay_parent) => per_relay_parent, + None => continue, + }; + + match (per_relay_parent.prospective_parachains_mode, &next) { + (ProspectiveParachainsMode::Disabled, VersionedCollationRequest::V1(_)) => { + per_relay_parent.collations.values().next() + }, + (ProspectiveParachainsMode::Enabled { .. }, VersionedCollationRequest::VStaging(req)) => { + per_relay_parent.collations.get(&req.payload.candidate_hash) + }, + _ => { + // Request version is checked in `handle_incoming_request`. + continue + }, + } + }; + + if let Some(collation) = next_collation { let receipt = collation.receipt.clone(); let pov = collation.pov.clone(); send_collation(&mut state, next, receipt, pov).await; } }, - _ = reconnect_stream.next() => { - let now = Instant::now(); - if state - .last_connected_at - .map_or(false, |timestamp| now - timestamp > RECONNECT_TIMEOUT) - { - // Remove all advertisements from the buffer if the timeout was hit. - // Usually, it shouldn't be necessary as leaves get deactivated, rather - // serves as a safeguard against finality lags. - state.validator_groups_buf.clear_advertisements(); - // Returns `None` if connection request is empty. - state.last_connected_at = - connect_to_validators(&mut ctx, &state.validator_groups_buf).await; - - gum::debug!( - target: LOG_TARGET, - timeout = ?RECONNECT_TIMEOUT, - "Timeout hit, sent a connection request. Disconnected from all validators = {}", - state.last_connected_at.is_none(), - ); + (candidate_hash, peer_id) = state.advertisement_timeouts.select_next_some() => { + // NOTE: it doesn't necessarily mean that a validator gets disconnected, + // it only will if there're no other advertisements we want to send. + // + // No-op if the collation was already fetched or went out of view. + for authority_id in state.peer_ids.get(&peer_id).into_iter().flatten() { + state + .validator_groups_buf + .reset_validator_interest(candidate_hash, &authority_id); } + } + _ = reconnect_timeout => { + state.reconnect_timeout = + connect_to_validators(&mut ctx, &state.validator_groups_buf).await; + + gum::trace!( + target: LOG_TARGET, + timeout = ?RECONNECT_TIMEOUT, + "Peer-set updated due to a timeout" + ); }, - in_req = recv_req => { - match in_req { - Ok(req) => { - log_error( - handle_incoming_request(&mut ctx, &mut state, req).await, - "Handling incoming request" - )?; - } - Err(error) => { - let jfyi = error.split().map_err(incoming::Error::from)?; - gum::debug!( - target: LOG_TARGET, - error = ?jfyi, - "Decoding incoming request failed" - ); - continue - } - } + in_req = recv_req_v1 => { + let request = in_req.map(VersionedCollationRequest::from); + + log_error( + handle_incoming_request(&mut ctx, &mut state, request).await, + "Handling incoming collation fetch request V1" + )?; + } + in_req = recv_req_v2 => { + let request = in_req.map(VersionedCollationRequest::from); + + log_error( + handle_incoming_request(&mut ctx, &mut state, request).await, + "Handling incoming collation fetch request VStaging" + )?; } } } diff --git a/node/network/collator-protocol/src/collator_side/tests.rs b/node/network/collator-protocol/src/collator_side/tests/mod.rs similarity index 75% rename from node/network/collator-protocol/src/collator_side/tests.rs rename to node/network/collator-protocol/src/collator_side/tests/mod.rs index ad1096196574..fae719b2b4a1 100644 --- a/node/network/collator-protocol/src/collator_side/tests.rs +++ b/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -37,6 +37,7 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::BlockData; use polkadot_node_subsystem::{ + errors::RuntimeApiError, jaeger, messages::{AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest}, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, @@ -49,8 +50,13 @@ use polkadot_primitives::{ }; use polkadot_primitives_test_helpers::TestCandidateBuilder; +mod prospective_parachains; + const REPUTATION_CHANGE_TEST_INTERVAL: Duration = Duration::from_millis(10); +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; + #[derive(Clone)] struct TestState { para_id: ParaId, @@ -186,6 +192,17 @@ impl TestState { )), ) .await; + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::StagingAsyncBackingParams(tx) + )) => { + assert_eq!(relay_parent, self.relay_parent); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + } + ); } } @@ -193,7 +210,8 @@ type VirtualOverseer = test_helpers::TestSubsystemContextHandle>( @@ -215,7 +233,9 @@ fn test_harness>( let genesis_hash = Hash::repeat_byte(0xff); let req_protocol_names = ReqProtocolNames::new(&genesis_hash, None); - let (collation_req_receiver, req_cfg) = + let (collation_req_receiver, req_v1_cfg) = + IncomingRequest::get_config_receiver(&req_protocol_names); + let (collation_req_vstaging_receiver, req_vstaging_cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); let subsystem = async { run_inner( @@ -223,6 +243,7 @@ fn test_harness>( local_peer_id, collator_pair, collation_req_receiver, + collation_req_vstaging_receiver, Default::default(), reputation, REPUTATION_CHANGE_TEST_INTERVAL, @@ -231,7 +252,7 @@ fn test_harness>( .unwrap(); }; - let test_fut = test(TestHarness { virtual_overseer, req_cfg }); + let test_fut = test(TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg }); futures::pin_mut!(test_fut); futures::pin_mut!(subsystem); @@ -305,6 +326,17 @@ async fn setup_system(virtual_overseer: &mut VirtualOverseer, test_state: &TestS ])), ) .await; + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::StagingAsyncBackingParams(tx) + )) => { + assert_eq!(relay_parent, test_state.relay_parent); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + } + ); } /// Result of [`distribute_collation`] @@ -313,29 +345,23 @@ struct DistributeCollation { pov_block: PoV, } -/// Create some PoV and distribute it. -async fn distribute_collation( +async fn distribute_collation_with_receipt( virtual_overseer: &mut VirtualOverseer, test_state: &TestState, - // whether or not we expect a connection request or not. + relay_parent: Hash, should_connect: bool, + candidate: CandidateReceipt, + pov: PoV, + parent_head_data_hash: Hash, ) -> DistributeCollation { - // Now we want to distribute a `PoVBlock` - let pov_block = PoV { block_data: BlockData(vec![42, 43, 44]) }; - - let pov_hash = pov_block.hash(); - - let candidate = TestCandidateBuilder { - para_id: test_state.para_id, - relay_parent: test_state.relay_parent, - pov_hash, - ..Default::default() - } - .build(); - overseer_send( virtual_overseer, - CollatorProtocolMessage::DistributeCollation(candidate.clone(), pov_block.clone(), None), + CollatorProtocolMessage::DistributeCollation( + candidate.clone(), + parent_head_data_hash, + pov.clone(), + None, + ), ) .await; @@ -343,10 +369,10 @@ async fn distribute_collation( assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, + _relay_parent, RuntimeApiRequest::AvailabilityCores(tx) )) => { - assert_eq!(relay_parent, test_state.relay_parent); + assert_eq!(relay_parent, _relay_parent); tx.send(Ok(test_state.availability_cores.clone())).unwrap(); } ); @@ -358,7 +384,7 @@ async fn distribute_collation( relay_parent, RuntimeApiRequest::SessionIndexForChild(tx), )) => { - assert_eq!(relay_parent, test_state.relay_parent); + assert_eq!(relay_parent, relay_parent); tx.send(Ok(test_state.current_session_index())).unwrap(); }, @@ -366,17 +392,17 @@ async fn distribute_collation( relay_parent, RuntimeApiRequest::SessionInfo(index, tx), )) => { - assert_eq!(relay_parent, test_state.relay_parent); + assert_eq!(relay_parent, relay_parent); assert_eq!(index, test_state.current_session_index()); tx.send(Ok(Some(test_state.session_info.clone()))).unwrap(); }, AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, + _relay_parent, RuntimeApiRequest::ValidatorGroups(tx), )) => { - assert_eq!(relay_parent, test_state.relay_parent); + assert_eq!(_relay_parent, relay_parent); tx.send(Ok(( test_state.session_info.validator_groups.to_vec(), test_state.group_rotation_info.clone(), @@ -400,13 +426,48 @@ async fn distribute_collation( ); } - DistributeCollation { candidate, pov_block } + DistributeCollation { candidate, pov_block: pov } +} + +/// Create some PoV and distribute it. +async fn distribute_collation( + virtual_overseer: &mut VirtualOverseer, + test_state: &TestState, + relay_parent: Hash, + // whether or not we expect a connection request or not. + should_connect: bool, +) -> DistributeCollation { + // Now we want to distribute a `PoVBlock` + let pov_block = PoV { block_data: BlockData(vec![42, 43, 44]) }; + + let pov_hash = pov_block.hash(); + let parent_head_data_hash = Hash::zero(); + + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent, + pov_hash, + ..Default::default() + } + .build(); + + distribute_collation_with_receipt( + virtual_overseer, + test_state, + relay_parent, + should_connect, + candidate, + pov_block, + parent_head_data_hash, + ) + .await } /// Connect a peer async fn connect_peer( virtual_overseer: &mut VirtualOverseer, peer: PeerId, + version: CollationVersion, authority_id: Option, ) { overseer_send( @@ -414,7 +475,7 @@ async fn connect_peer( CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( peer, polkadot_node_network_protocol::ObservedRole::Authority, - CollationVersion::V1.into(), + version.into(), authority_id.map(|v| HashSet::from([v])), )), ) @@ -474,30 +535,65 @@ async fn expect_declare_msg( } /// Check that the next received message is a collation advertisement message. +/// +/// Expects vstaging message if `expected_candidate_hashes` is `Some`, v1 otherwise. async fn expect_advertise_collation_msg( virtual_overseer: &mut VirtualOverseer, peer: &PeerId, expected_relay_parent: Hash, + expected_candidate_hashes: Option>, ) { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::NetworkBridgeTx( - NetworkBridgeTxMessage::SendCollationMessage( - to, - Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)), - ) - ) => { - assert_eq!(to[0], *peer); - assert_matches!( - wire_message, - protocol_v1::CollatorProtocolMessage::AdvertiseCollation( - relay_parent, - ) => { - assert_eq!(relay_parent, expected_relay_parent); + let mut candidate_hashes: Option> = + expected_candidate_hashes.map(|hashes| hashes.into_iter().collect()); + let iter_num = candidate_hashes.as_ref().map(|hashes| hashes.len()).unwrap_or(1); + + for _ in 0..iter_num { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::SendCollationMessage( + to, + wire_message, + ) + ) => { + assert_eq!(to[0], *peer); + match (candidate_hashes.as_mut(), wire_message) { + (None, Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message))) => { + assert_matches!( + wire_message, + protocol_v1::CollatorProtocolMessage::AdvertiseCollation( + relay_parent, + ) => { + assert_eq!(relay_parent, expected_relay_parent); + } + ); + }, + ( + Some(candidate_hashes), + Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + wire_message, + )), + ) => { + assert_matches!( + wire_message, + protocol_vstaging::CollatorProtocolMessage::AdvertiseCollation { + relay_parent, + candidate_hash, + .. + } => { + assert_eq!(relay_parent, expected_relay_parent); + assert!(candidate_hashes.contains(&candidate_hash)); + + // Drop the hash we've already seen. + candidate_hashes.remove(&candidate_hash); + } + ); + }, + _ => panic!("Invalid advertisement"), } - ); - } - ); + } + ); + } } /// Send a message that the given peer's view changed. @@ -528,19 +624,26 @@ fn advertise_and_send_collation() { ReputationAggregator::new(|_| true), |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; - let mut req_cfg = test_harness.req_cfg; + let mut req_v1_cfg = test_harness.req_v1_cfg; + let req_vstaging_cfg = test_harness.req_vstaging_cfg; setup_system(&mut virtual_overseer, &test_state).await; - let DistributeCollation { candidate, pov_block } = - distribute_collation(&mut virtual_overseer, &test_state, true).await; + let DistributeCollation { candidate, pov_block } = distribute_collation( + &mut virtual_overseer, + &test_state, + test_state.relay_parent, + true, + ) + .await; for (val, peer) in test_state .current_group_validator_authority_ids() .into_iter() .zip(test_state.current_group_validator_peer_ids()) { - connect_peer(&mut virtual_overseer, peer, Some(val.clone())).await; + connect_peer(&mut virtual_overseer, peer, CollationVersion::V1, Some(val.clone())) + .await; } // We declare to the connected validators that we are a collator. @@ -558,18 +661,23 @@ fn advertise_and_send_collation() { // The peer is interested in a leaf that we have a collation for; // advertise it. - expect_advertise_collation_msg(&mut virtual_overseer, &peer, test_state.relay_parent) - .await; + expect_advertise_collation_msg( + &mut virtual_overseer, + &peer, + test_state.relay_parent, + None, + ) + .await; // Request a collation. let (pending_response, rx) = oneshot::channel(); - req_cfg + req_v1_cfg .inbound_queue .as_mut() .unwrap() .send(RawIncomingRequest { peer, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: test_state.relay_parent, para_id: test_state.para_id, } @@ -582,13 +690,13 @@ fn advertise_and_send_collation() { { let (pending_response, rx) = oneshot::channel(); - req_cfg + req_v1_cfg .inbound_queue .as_mut() .unwrap() .send(RawIncomingRequest { peer, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: test_state.relay_parent, para_id: test_state.para_id, } @@ -613,8 +721,8 @@ fn advertise_and_send_collation() { assert_matches!( rx.await, Ok(full_response) => { - let CollationFetchingResponse::Collation(receipt, pov): CollationFetchingResponse - = CollationFetchingResponse::decode( + let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse + = request_v1::CollationFetchingResponse::decode( &mut full_response.result .expect("We should have a proper answer").as_ref() ) @@ -632,13 +740,13 @@ fn advertise_and_send_collation() { // Re-request a collation. let (pending_response, rx) = oneshot::channel(); - req_cfg + req_v1_cfg .inbound_queue .as_mut() .unwrap() .send(RawIncomingRequest { peer, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: old_relay_parent, para_id: test_state.para_id, } @@ -652,7 +760,8 @@ fn advertise_and_send_collation() { assert!(overseer_recv_with_timeout(&mut virtual_overseer, TIMEOUT).await.is_none()); - distribute_collation(&mut virtual_overseer, &test_state, true).await; + distribute_collation(&mut virtual_overseer, &test_state, test_state.relay_parent, true) + .await; // Send info about peer's view. overseer_send( @@ -664,9 +773,14 @@ fn advertise_and_send_collation() { ) .await; - expect_advertise_collation_msg(&mut virtual_overseer, &peer, test_state.relay_parent) - .await; - TestHarness { virtual_overseer, req_cfg } + expect_advertise_collation_msg( + &mut virtual_overseer, + &peer, + test_state.relay_parent, + None, + ) + .await; + TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg } }, ); } @@ -683,18 +797,26 @@ fn delay_reputation_change() { ReputationAggregator::new(|_| false), |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; - let mut req_cfg = test_harness.req_cfg; + let mut req_v1_cfg = test_harness.req_v1_cfg; + let req_vstaging_cfg = test_harness.req_vstaging_cfg; setup_system(&mut virtual_overseer, &test_state).await; - let _ = distribute_collation(&mut virtual_overseer, &test_state, true).await; + let _ = distribute_collation( + &mut virtual_overseer, + &test_state, + test_state.relay_parent, + true, + ) + .await; for (val, peer) in test_state .current_group_validator_authority_ids() .into_iter() .zip(test_state.current_group_validator_peer_ids()) { - connect_peer(&mut virtual_overseer, peer, Some(val.clone())).await; + connect_peer(&mut virtual_overseer, peer, CollationVersion::V1, Some(val.clone())) + .await; } // We declare to the connected validators that we are a collator. @@ -712,18 +834,23 @@ fn delay_reputation_change() { // The peer is interested in a leaf that we have a collation for; // advertise it. - expect_advertise_collation_msg(&mut virtual_overseer, &peer, test_state.relay_parent) - .await; + expect_advertise_collation_msg( + &mut virtual_overseer, + &peer, + test_state.relay_parent, + None, + ) + .await; // Request a collation. let (pending_response, _rx) = oneshot::channel(); - req_cfg + req_v1_cfg .inbound_queue .as_mut() .unwrap() .send(RawIncomingRequest { peer, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: test_state.relay_parent, para_id: test_state.para_id, } @@ -736,13 +863,13 @@ fn delay_reputation_change() { { let (pending_response, _rx) = oneshot::channel(); - req_cfg + req_v1_cfg .inbound_queue .as_mut() .unwrap() .send(RawIncomingRequest { peer, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: test_state.relay_parent, para_id: test_state.para_id, } @@ -767,7 +894,90 @@ fn delay_reputation_change() { ); } - TestHarness { virtual_overseer, req_cfg } + TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg } + }, + ); +} + +/// Tests that collator side works with vstaging network protocol +/// before async backing is enabled. +#[test] +fn advertise_collation_vstaging_protocol() { + let test_state = TestState::default(); + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |mut test_harness| async move { + let virtual_overseer = &mut test_harness.virtual_overseer; + + setup_system(virtual_overseer, &test_state).await; + + let DistributeCollation { candidate, .. } = + distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) + .await; + + let validators = test_state.current_group_validator_authority_ids(); + assert!(validators.len() >= 2); + let peer_ids = test_state.current_group_validator_peer_ids(); + + // Connect first peer with v1. + connect_peer( + virtual_overseer, + peer_ids[0], + CollationVersion::V1, + Some(validators[0].clone()), + ) + .await; + // The rest with vstaging. + for (val, peer) in validators.iter().zip(peer_ids.iter()).skip(1) { + connect_peer( + virtual_overseer, + *peer, + CollationVersion::VStaging, + Some(val.clone()), + ) + .await; + } + + // Declare messages. + expect_declare_msg(virtual_overseer, &test_state, &peer_ids[0]).await; + for peer_id in peer_ids.iter().skip(1) { + prospective_parachains::expect_declare_msg_vstaging( + virtual_overseer, + &test_state, + &peer_id, + ) + .await; + } + + // Send info about peers view. + for peer in peer_ids.iter() { + send_peer_view_change(virtual_overseer, peer, vec![test_state.relay_parent]).await; + } + + // Versioned advertisements work. + expect_advertise_collation_msg( + virtual_overseer, + &peer_ids[0], + test_state.relay_parent, + None, + ) + .await; + for peer_id in peer_ids.iter().skip(1) { + expect_advertise_collation_msg( + virtual_overseer, + peer_id, + test_state.relay_parent, + Some(vec![candidate.hash()]), // This is `Some`, advertisement is vstaging. + ) + .await; + } + + test_harness }, ); } @@ -814,7 +1024,13 @@ fn collators_declare_to_connected_peers() { setup_system(&mut test_harness.virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(&mut test_harness.virtual_overseer, peer, Some(validator_id)).await; + connect_peer( + &mut test_harness.virtual_overseer, + peer, + CollationVersion::V1, + Some(validator_id), + ) + .await; expect_declare_msg(&mut test_harness.virtual_overseer, &test_state, &peer).await; test_harness }, @@ -843,10 +1059,10 @@ fn collations_are_only_advertised_to_validators_with_correct_view() { setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer, Some(validator_id)).await; + connect_peer(virtual_overseer, peer, CollationVersion::V1, Some(validator_id)).await; // Connect the second validator - connect_peer(virtual_overseer, peer2, Some(validator_id2)).await; + connect_peer(virtual_overseer, peer2, CollationVersion::V1, Some(validator_id2)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; expect_declare_msg(virtual_overseer, &test_state, &peer2).await; @@ -854,15 +1070,18 @@ fn collations_are_only_advertised_to_validators_with_correct_view() { // And let it tell us that it is has the same view. send_peer_view_change(virtual_overseer, &peer2, vec![test_state.relay_parent]).await; - distribute_collation(virtual_overseer, &test_state, true).await; + distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) + .await; - expect_advertise_collation_msg(virtual_overseer, &peer2, test_state.relay_parent).await; + expect_advertise_collation_msg(virtual_overseer, &peer2, test_state.relay_parent, None) + .await; // The other validator announces that it changed its view. send_peer_view_change(virtual_overseer, &peer, vec![test_state.relay_parent]).await; // After changing the view we should receive the advertisement - expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent).await; + expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent, None) + .await; test_harness }, ) @@ -890,15 +1109,16 @@ fn collate_on_two_different_relay_chain_blocks() { setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer, Some(validator_id)).await; + connect_peer(virtual_overseer, peer, CollationVersion::V1, Some(validator_id)).await; // Connect the second validator - connect_peer(virtual_overseer, peer2, Some(validator_id2)).await; + connect_peer(virtual_overseer, peer2, CollationVersion::V1, Some(validator_id2)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; expect_declare_msg(virtual_overseer, &test_state, &peer2).await; - distribute_collation(virtual_overseer, &test_state, true).await; + distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) + .await; let old_relay_parent = test_state.relay_parent; @@ -906,14 +1126,16 @@ fn collate_on_two_different_relay_chain_blocks() { // parent are active. test_state.advance_to_new_round(virtual_overseer, true).await; - distribute_collation(virtual_overseer, &test_state, true).await; + distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) + .await; send_peer_view_change(virtual_overseer, &peer, vec![old_relay_parent]).await; - expect_advertise_collation_msg(virtual_overseer, &peer, old_relay_parent).await; + expect_advertise_collation_msg(virtual_overseer, &peer, old_relay_parent, None).await; send_peer_view_change(virtual_overseer, &peer2, vec![test_state.relay_parent]).await; - expect_advertise_collation_msg(virtual_overseer, &peer2, test_state.relay_parent).await; + expect_advertise_collation_msg(virtual_overseer, &peer2, test_state.relay_parent, None) + .await; test_harness }, ) @@ -938,17 +1160,20 @@ fn validator_reconnect_does_not_advertise_a_second_time() { setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer, Some(validator_id.clone())).await; + connect_peer(virtual_overseer, peer, CollationVersion::V1, Some(validator_id.clone())) + .await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; - distribute_collation(virtual_overseer, &test_state, true).await; + distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) + .await; send_peer_view_change(virtual_overseer, &peer, vec![test_state.relay_parent]).await; - expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent).await; + expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent, None) + .await; // Disconnect and reconnect directly disconnect_peer(virtual_overseer, peer).await; - connect_peer(virtual_overseer, peer, Some(validator_id)).await; + connect_peer(virtual_overseer, peer, CollationVersion::V1, Some(validator_id)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; send_peer_view_change(virtual_overseer, &peer, vec![test_state.relay_parent]).await; @@ -979,7 +1204,7 @@ fn collators_reject_declare_messages() { setup_system(virtual_overseer, &test_state).await; // A validator connected to us - connect_peer(virtual_overseer, peer, Some(validator_id)).await; + connect_peer(virtual_overseer, peer, CollationVersion::V1, Some(validator_id)).await; expect_declare_msg(virtual_overseer, &test_state, &peer).await; overseer_send( @@ -1031,19 +1256,20 @@ where ReputationAggregator::new(|_| true), |mut test_harness| async move { let virtual_overseer = &mut test_harness.virtual_overseer; - let req_cfg = &mut test_harness.req_cfg; + let req_cfg = &mut test_harness.req_v1_cfg; setup_system(virtual_overseer, &test_state).await; let DistributeCollation { candidate, pov_block } = - distribute_collation(virtual_overseer, &test_state, true).await; + distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) + .await; for (val, peer) in test_state .current_group_validator_authority_ids() .into_iter() .zip(test_state.current_group_validator_peer_ids()) { - connect_peer(virtual_overseer, peer, Some(val.clone())).await; + connect_peer(virtual_overseer, peer, CollationVersion::V1, Some(val.clone())).await; } // We declare to the connected validators that we are a collator. @@ -1064,10 +1290,20 @@ where // The peer is interested in a leaf that we have a collation for; // advertise it. - expect_advertise_collation_msg(virtual_overseer, &validator_0, test_state.relay_parent) - .await; - expect_advertise_collation_msg(virtual_overseer, &validator_1, test_state.relay_parent) - .await; + expect_advertise_collation_msg( + virtual_overseer, + &validator_0, + test_state.relay_parent, + None, + ) + .await; + expect_advertise_collation_msg( + virtual_overseer, + &validator_1, + test_state.relay_parent, + None, + ) + .await; // Request a collation. let (pending_response, rx) = oneshot::channel(); @@ -1077,7 +1313,7 @@ where .unwrap() .send(RawIncomingRequest { peer: validator_0, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: test_state.relay_parent, para_id: test_state.para_id, } @@ -1092,8 +1328,8 @@ where let feedback_tx = assert_matches!( rx.await, Ok(full_response) => { - let CollationFetchingResponse::Collation(receipt, pov): CollationFetchingResponse - = CollationFetchingResponse::decode( + let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse + = request_v1::CollationFetchingResponse::decode( &mut full_response.result .expect("We should have a proper answer").as_ref() ) @@ -1113,7 +1349,7 @@ where .unwrap() .send(RawIncomingRequest { peer: validator_1, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: test_state.relay_parent, para_id: test_state.para_id, } @@ -1129,8 +1365,8 @@ where assert_matches!( rx.await, Ok(full_response) => { - let CollationFetchingResponse::Collation(receipt, pov): CollationFetchingResponse - = CollationFetchingResponse::decode( + let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse + = request_v1::CollationFetchingResponse::decode( &mut full_response.result .expect("We should have a proper answer").as_ref() ) @@ -1159,7 +1395,8 @@ fn connect_to_buffered_groups() { ReputationAggregator::new(|_| true), |test_harness| async move { let mut virtual_overseer = test_harness.virtual_overseer; - let mut req_cfg = test_harness.req_cfg; + let mut req_cfg = test_harness.req_v1_cfg; + let req_vstaging_cfg = test_harness.req_vstaging_cfg; setup_system(&mut virtual_overseer, &test_state).await; @@ -1167,7 +1404,13 @@ fn connect_to_buffered_groups() { let peers_a = test_state.current_group_validator_peer_ids(); assert!(group_a.len() > 1); - distribute_collation(&mut virtual_overseer, &test_state, false).await; + distribute_collation( + &mut virtual_overseer, + &test_state, + test_state.relay_parent, + false, + ) + .await; assert_matches!( overseer_recv(&mut virtual_overseer).await, @@ -1181,7 +1424,8 @@ fn connect_to_buffered_groups() { let head_a = test_state.relay_parent; for (val, peer) in group_a.iter().zip(&peers_a) { - connect_peer(&mut virtual_overseer, *peer, Some(val.clone())).await; + connect_peer(&mut virtual_overseer, *peer, CollationVersion::V1, Some(val.clone())) + .await; } for peer_id in &peers_a { @@ -1191,7 +1435,7 @@ fn connect_to_buffered_groups() { // Update views. for peed_id in &peers_a { send_peer_view_change(&mut virtual_overseer, peed_id, vec![head_a]).await; - expect_advertise_collation_msg(&mut virtual_overseer, peed_id, head_a).await; + expect_advertise_collation_msg(&mut virtual_overseer, peed_id, head_a, None).await; } let peer = peers_a[0]; @@ -1203,7 +1447,7 @@ fn connect_to_buffered_groups() { .unwrap() .send(RawIncomingRequest { peer, - payload: CollationFetchingRequest { + payload: request_v1::CollationFetchingRequest { relay_parent: head_a, para_id: test_state.para_id, } @@ -1215,14 +1459,17 @@ fn connect_to_buffered_groups() { assert_matches!( rx.await, Ok(full_response) => { - let CollationFetchingResponse::Collation(..): CollationFetchingResponse = - CollationFetchingResponse::decode( + let request_v1::CollationFetchingResponse::Collation(..) = + request_v1::CollationFetchingResponse::decode( &mut full_response.result.expect("We should have a proper answer").as_ref(), ) .expect("Decoding should work"); } ); + // Let the subsystem process process the collation event. + test_helpers::Yield::new().await; + test_state.advance_to_new_round(&mut virtual_overseer, true).await; test_state.group_rotation_info = test_state.group_rotation_info.bump_rotation(); @@ -1231,7 +1478,13 @@ fn connect_to_buffered_groups() { assert_ne!(head_a, head_b); assert_ne!(group_a, group_b); - distribute_collation(&mut virtual_overseer, &test_state, false).await; + distribute_collation( + &mut virtual_overseer, + &test_state, + test_state.relay_parent, + false, + ) + .await; // Should be connected to both groups except for the validator that fetched advertised // collation. @@ -1248,7 +1501,7 @@ fn connect_to_buffered_groups() { } ); - TestHarness { virtual_overseer, req_cfg } + TestHarness { virtual_overseer, req_v1_cfg: req_cfg, req_vstaging_cfg } }, ); } diff --git a/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs new file mode 100644 index 000000000000..02e8d0a7a81d --- /dev/null +++ b/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -0,0 +1,575 @@ +// Copyright 2022 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 . + +//! Tests for the collator side with enabled prospective parachains. + +use super::*; + +use polkadot_node_subsystem::messages::{ChainApiMessage, ProspectiveParachainsMessage}; +use polkadot_primitives::{vstaging as vstaging_primitives, Header, OccupiedCore}; + +const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParams = + vstaging_primitives::AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; + +fn get_parent_hash(hash: Hash) -> Hash { + Hash::from_low_u64_be(hash.to_low_u64_be() + 1) +} + +/// Handle a view update. +async fn update_view( + virtual_overseer: &mut VirtualOverseer, + test_state: &TestState, + new_view: Vec<(Hash, u32)>, // Hash and block number. + activated: u8, // How many new heads does this update contain? +) { + let new_view: HashMap = HashMap::from_iter(new_view); + + let our_view = + OurView::new(new_view.keys().map(|hash| (*hash, Arc::new(jaeger::Span::Disabled))), 0); + + overseer_send( + virtual_overseer, + CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange(our_view)), + ) + .await; + + let mut next_overseer_message = None; + for _ in 0..activated { + let (leaf_hash, leaf_number) = assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::StagingAsyncBackingParams(tx), + )) => { + tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); + (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) + } + ); + + let min_number = leaf_number.saturating_sub(ASYNC_BACKING_PARAMETERS.allowed_ancestry_len); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetMinimumRelayParents(parent, tx), + ) if parent == leaf_hash => { + tx.send(vec![(test_state.para_id, min_number)]).unwrap(); + } + ); + + let ancestry_len = leaf_number + 1 - min_number; + let ancestry_hashes = std::iter::successors(Some(leaf_hash), |h| Some(get_parent_hash(*h))) + .take(ancestry_len as usize); + let ancestry_numbers = (min_number..=leaf_number).rev(); + let mut ancestry_iter = ancestry_hashes.clone().zip(ancestry_numbers).peekable(); + + while let Some((hash, number)) = ancestry_iter.next() { + // May be `None` for the last element. + let parent_hash = + ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); + + let msg = match next_overseer_message.take() { + Some(msg) => Some(msg), + None => + overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(50)).await, + }; + + let msg = match msg { + Some(msg) => msg, + None => { + // We're done. + return + }, + }; + + if !matches!( + &msg, + AllMessages::ChainApi(ChainApiMessage::BlockHeader(_hash, ..)) + if *_hash == hash + ) { + // Ancestry has already been cached for this leaf. + next_overseer_message.replace(msg); + break + } + + assert_matches!( + msg, + AllMessages::ChainApi(ChainApiMessage::BlockHeader(.., tx)) => { + let header = Header { + parent_hash, + number, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + }; + + tx.send(Ok(Some(header))).unwrap(); + } + ); + } + } +} + +/// Check that the next received message is a `Declare` message. +pub(super) async fn expect_declare_msg_vstaging( + virtual_overseer: &mut VirtualOverseer, + test_state: &TestState, + peer: &PeerId, +) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( + to, + Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + wire_message, + )), + )) => { + assert_eq!(to[0], *peer); + assert_matches!( + wire_message, + protocol_vstaging::CollatorProtocolMessage::Declare( + collator_id, + para_id, + signature, + ) => { + assert!(signature.verify( + &*protocol_vstaging::declare_signature_payload(&test_state.local_peer_id), + &collator_id), + ); + assert_eq!(collator_id, test_state.collator_pair.public()); + assert_eq!(para_id, test_state.para_id); + } + ); + } + ); +} + +/// Test that a collator distributes a collation from the allowed ancestry +/// to correct validators group. +#[test] +fn distribute_collation_from_implicit_view() { + let head_a = Hash::from_low_u64_be(126); + let head_a_num: u32 = 66; + + // Grandparent of head `a`. + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 64; + + // Grandparent of head `b`. + let head_c = Hash::from_low_u64_be(130); + let head_c_num = 62; + + let group_rotation_info = GroupRotationInfo { + session_start_block: head_c_num - 2, + group_rotation_frequency: 3, + now: head_c_num, + }; + + let mut test_state = TestState::default(); + test_state.group_rotation_info = group_rotation_info; + + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |mut test_harness| async move { + let virtual_overseer = &mut test_harness.virtual_overseer; + + // Set collating para id. + overseer_send(virtual_overseer, CollatorProtocolMessage::CollateOn(test_state.para_id)) + .await; + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let validator_peer_ids = test_state.current_group_validator_peer_ids(); + for (val, peer) in test_state + .current_group_validator_authority_ids() + .into_iter() + .zip(validator_peer_ids.clone()) + { + connect_peer(virtual_overseer, peer, CollationVersion::VStaging, Some(val.clone())) + .await; + } + + // Collator declared itself to each peer. + for peer_id in &validator_peer_ids { + expect_declare_msg_vstaging(virtual_overseer, &test_state, peer_id).await; + } + + let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let parent_head_data_hash = Hash::repeat_byte(0xAA); + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_c, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + let DistributeCollation { candidate, pov_block: _ } = + distribute_collation_with_receipt( + virtual_overseer, + &test_state, + head_c, + false, // Check the group manually. + candidate, + pov, + parent_head_data_hash, + ) + .await; + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ConnectToValidators { validator_ids, .. } + ) => { + let expected_validators = test_state.current_group_validator_authority_ids(); + + assert_eq!(expected_validators, validator_ids); + } + ); + + let candidate_hash = candidate.hash(); + + // Update peer views. + for peed_id in &validator_peer_ids { + send_peer_view_change(virtual_overseer, peed_id, vec![head_b]).await; + expect_advertise_collation_msg( + virtual_overseer, + peed_id, + head_c, + Some(vec![candidate_hash]), + ) + .await; + } + + // Head `c` goes out of view. + // Build a different candidate for this relay parent and attempt to distribute it. + update_view(virtual_overseer, &test_state, vec![(head_a, head_a_num)], 1).await; + + let pov = PoV { block_data: BlockData(vec![4, 5, 6]) }; + let parent_head_data_hash = Hash::repeat_byte(0xBB); + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_c, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + overseer_send( + virtual_overseer, + CollatorProtocolMessage::DistributeCollation( + candidate.clone(), + parent_head_data_hash, + pov.clone(), + None, + ), + ) + .await; + + // Parent out of view, nothing happens. + assert!(overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(100)) + .await + .is_none()); + + test_harness + }, + ) +} + +/// Tests that collator can distribute up to `MAX_CANDIDATE_DEPTH + 1` candidates +/// per relay parent. +#[test] +fn distribute_collation_up_to_limit() { + let test_state = TestState::default(); + + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |mut test_harness| async move { + let virtual_overseer = &mut test_harness.virtual_overseer; + + let head_a = Hash::from_low_u64_be(128); + let head_a_num: u32 = 64; + + // Grandparent of head `a`. + let head_b = Hash::from_low_u64_be(130); + + // Set collating para id. + overseer_send(virtual_overseer, CollatorProtocolMessage::CollateOn(test_state.para_id)) + .await; + // Activated leaf is `a`, but the collation will be based on `b`. + update_view(virtual_overseer, &test_state, vec![(head_a, head_a_num)], 1).await; + + for i in 0..(ASYNC_BACKING_PARAMETERS.max_candidate_depth + 1) { + let pov = PoV { block_data: BlockData(vec![i as u8]) }; + let parent_head_data_hash = Hash::repeat_byte(0xAA); + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_b, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + distribute_collation_with_receipt( + virtual_overseer, + &test_state, + head_b, + true, + candidate, + pov, + parent_head_data_hash, + ) + .await; + } + + let pov = PoV { block_data: BlockData(vec![10, 12, 6]) }; + let parent_head_data_hash = Hash::repeat_byte(0xBB); + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_b, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + overseer_send( + virtual_overseer, + CollatorProtocolMessage::DistributeCollation( + candidate.clone(), + parent_head_data_hash, + pov.clone(), + None, + ), + ) + .await; + + // Limit has been reached. + assert!(overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(100)) + .await + .is_none()); + + test_harness + }, + ) +} + +/// Tests that collator correctly handles peer V2 requests. +#[test] +fn advertise_and_send_collation_by_hash() { + let test_state = TestState::default(); + + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |test_harness| async move { + let mut virtual_overseer = test_harness.virtual_overseer; + let req_v1_cfg = test_harness.req_v1_cfg; + let mut req_vstaging_cfg = test_harness.req_vstaging_cfg; + + let head_a = Hash::from_low_u64_be(128); + let head_a_num: u32 = 64; + + // Parent of head `a`. + let head_b = Hash::from_low_u64_be(129); + let head_b_num: u32 = 63; + + // Set collating para id. + overseer_send( + &mut virtual_overseer, + CollatorProtocolMessage::CollateOn(test_state.para_id), + ) + .await; + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &test_state, vec![(head_a, head_a_num)], 1).await; + + let candidates: Vec<_> = (0..2) + .map(|i| { + let pov = PoV { block_data: BlockData(vec![i as u8]) }; + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_b, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + (candidate, pov) + }) + .collect(); + for (candidate, pov) in &candidates { + distribute_collation_with_receipt( + &mut virtual_overseer, + &test_state, + head_b, + true, + candidate.clone(), + pov.clone(), + Hash::zero(), + ) + .await; + } + + let peer = test_state.validator_peer_id[0]; + let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); + connect_peer( + &mut virtual_overseer, + peer, + CollationVersion::VStaging, + Some(validator_id.clone()), + ) + .await; + expect_declare_msg_vstaging(&mut virtual_overseer, &test_state, &peer).await; + + // Head `b` is not a leaf, but both advertisements are still relevant. + send_peer_view_change(&mut virtual_overseer, &peer, vec![head_b]).await; + let hashes: Vec<_> = candidates.iter().map(|(candidate, _)| candidate.hash()).collect(); + expect_advertise_collation_msg(&mut virtual_overseer, &peer, head_b, Some(hashes)) + .await; + + for (candidate, pov_block) in candidates { + let (pending_response, rx) = oneshot::channel(); + req_vstaging_cfg + .inbound_queue + .as_mut() + .unwrap() + .send(RawIncomingRequest { + peer, + payload: request_vstaging::CollationFetchingRequest { + relay_parent: head_b, + para_id: test_state.para_id, + candidate_hash: candidate.hash(), + } + .encode(), + pending_response, + }) + .await + .unwrap(); + + assert_matches!( + rx.await, + Ok(full_response) => { + // Response is the same for vstaging. + let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse + = request_v1::CollationFetchingResponse::decode( + &mut full_response.result + .expect("We should have a proper answer").as_ref() + ) + .expect("Decoding should work"); + assert_eq!(receipt, candidate); + assert_eq!(pov, pov_block); + } + ); + } + + TestHarness { virtual_overseer, req_v1_cfg, req_vstaging_cfg } + }, + ) +} + +/// Tests that collator distributes collation built on top of occupied core. +#[test] +fn advertise_core_occupied() { + let mut test_state = TestState::default(); + let candidate = + TestCandidateBuilder { para_id: test_state.para_id, ..Default::default() }.build(); + test_state.availability_cores[0] = CoreState::Occupied(OccupiedCore { + next_up_on_available: None, + occupied_since: 0, + time_out_at: 0, + next_up_on_time_out: None, + availability: BitVec::default(), + group_responsible: GroupIndex(0), + candidate_hash: candidate.hash(), + candidate_descriptor: candidate.descriptor, + }); + + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |mut test_harness| async move { + let virtual_overseer = &mut test_harness.virtual_overseer; + + let head_a = Hash::from_low_u64_be(128); + let head_a_num: u32 = 64; + + // Grandparent of head `a`. + let head_b = Hash::from_low_u64_be(130); + + // Set collating para id. + overseer_send(virtual_overseer, CollatorProtocolMessage::CollateOn(test_state.para_id)) + .await; + // Activated leaf is `a`, but the collation will be based on `b`. + update_view(virtual_overseer, &test_state, vec![(head_a, head_a_num)], 1).await; + + let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_b, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + let candidate_hash = candidate.hash(); + distribute_collation_with_receipt( + virtual_overseer, + &test_state, + head_b, + true, + candidate, + pov, + Hash::zero(), + ) + .await; + + let validators = test_state.current_group_validator_authority_ids(); + let peer_ids = test_state.current_group_validator_peer_ids(); + + connect_peer( + virtual_overseer, + peer_ids[0], + CollationVersion::VStaging, + Some(validators[0].clone()), + ) + .await; + expect_declare_msg_vstaging(virtual_overseer, &test_state, &peer_ids[0]).await; + // Peer is aware of the leaf. + send_peer_view_change(virtual_overseer, &peer_ids[0], vec![head_a]).await; + + // Collation is advertised. + expect_advertise_collation_msg( + virtual_overseer, + &peer_ids[0], + head_b, + Some(vec![candidate_hash]), + ) + .await; + + test_harness + }, + ) +} diff --git a/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/node/network/collator-protocol/src/collator_side/validators_buffer.rs index 13ed3f66e0f1..cfa762703848 100644 --- a/node/network/collator-protocol/src/collator_side/validators_buffer.rs +++ b/node/network/collator-protocol/src/collator_side/validators_buffer.rs @@ -31,13 +31,19 @@ use std::{ collections::{HashMap, VecDeque}, + future::Future, num::NonZeroUsize, ops::Range, + pin::Pin, + task::{Context, Poll}, + time::Duration, }; use bitvec::{bitvec, vec::BitVec}; +use futures::FutureExt; -use polkadot_primitives::{AuthorityDiscoveryId, GroupIndex, Hash, SessionIndex}; +use polkadot_node_network_protocol::PeerId; +use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, GroupIndex, SessionIndex}; /// The ring buffer stores at most this many unique validator groups. /// @@ -66,9 +72,9 @@ pub struct ValidatorGroupsBuffer { group_infos: VecDeque, /// Continuous buffer of validators discovery keys. validators: VecDeque, - /// Mapping from relay-parent to bit-vectors with bits for all `validators`. + /// Mapping from candidate hashes to bit-vectors with bits for all `validators`. /// Invariants kept: All bit-vectors are guaranteed to have the same size. - should_be_connected: HashMap, + should_be_connected: HashMap, /// Buffer capacity, limits the number of **groups** tracked. cap: NonZeroUsize, } @@ -107,7 +113,7 @@ impl ValidatorGroupsBuffer { /// of the buffer. pub fn note_collation_advertised( &mut self, - relay_parent: Hash, + candidate_hash: CandidateHash, session_index: SessionIndex, group_index: GroupIndex, validators: &[AuthorityDiscoveryId], @@ -121,19 +127,19 @@ impl ValidatorGroupsBuffer { }) { Some((idx, group)) => { let group_start_idx = self.group_lengths_iter().take(idx).sum(); - self.set_bits(relay_parent, group_start_idx..(group_start_idx + group.len)); + self.set_bits(candidate_hash, group_start_idx..(group_start_idx + group.len)); }, - None => self.push(relay_parent, session_index, group_index, validators), + None => self.push(candidate_hash, session_index, group_index, validators), } } /// Note that a validator is no longer interested in a given relay parent. pub fn reset_validator_interest( &mut self, - relay_parent: Hash, + candidate_hash: CandidateHash, authority_id: &AuthorityDiscoveryId, ) { - let bits = match self.should_be_connected.get_mut(&relay_parent) { + let bits = match self.should_be_connected.get_mut(&candidate_hash) { Some(bits) => bits, None => return, }; @@ -145,17 +151,12 @@ impl ValidatorGroupsBuffer { } } - /// Remove relay parent from the buffer. + /// Remove advertised candidate from the buffer. /// /// The buffer will no longer track which validators are interested in a corresponding /// advertisement. - pub fn remove_relay_parent(&mut self, relay_parent: &Hash) { - self.should_be_connected.remove(relay_parent); - } - - /// Removes all advertisements from the buffer. - pub fn clear_advertisements(&mut self) { - self.should_be_connected.clear(); + pub fn remove_candidate(&mut self, candidate_hash: &CandidateHash) { + self.should_be_connected.remove(candidate_hash); } /// Pushes a new group to the buffer along with advertisement, setting all validators @@ -164,7 +165,7 @@ impl ValidatorGroupsBuffer { /// If the buffer is full, drops group from the tail. fn push( &mut self, - relay_parent: Hash, + candidate_hash: CandidateHash, session_index: SessionIndex, group_index: GroupIndex, validators: &[AuthorityDiscoveryId], @@ -193,17 +194,17 @@ impl ValidatorGroupsBuffer { self.should_be_connected .values_mut() .for_each(|bits| bits.resize(new_len, false)); - self.set_bits(relay_parent, group_start_idx..(group_start_idx + validators.len())); + self.set_bits(candidate_hash, group_start_idx..(group_start_idx + validators.len())); } /// Sets advertisement bits to 1 in a given range (usually corresponding to some group). /// If the relay parent is unknown, inserts 0-initialized bitvec first. /// /// The range must be ensured to be within bounds. - fn set_bits(&mut self, relay_parent: Hash, range: Range) { + fn set_bits(&mut self, candidate_hash: CandidateHash, range: Range) { let bits = self .should_be_connected - .entry(relay_parent) + .entry(candidate_hash) .or_insert_with(|| bitvec![0; self.validators.len()]); bits[range].fill(true); @@ -217,9 +218,40 @@ impl ValidatorGroupsBuffer { } } +/// A timeout for resetting validators' interests in collations. +pub const RESET_INTEREST_TIMEOUT: Duration = Duration::from_secs(6); + +/// A future that returns a candidate hash along with validator discovery +/// keys once a timeout hit. +/// +/// If a validator doesn't manage to fetch a collation within this timeout +/// we should reset its interest in this advertisement in a buffer. For example, +/// when the PoV was already requested from another peer. +pub struct ResetInterestTimeout { + fut: futures_timer::Delay, + candidate_hash: CandidateHash, + peer_id: PeerId, +} + +impl ResetInterestTimeout { + /// Returns new `ResetInterestTimeout` that resolves after given timeout. + pub fn new(candidate_hash: CandidateHash, peer_id: PeerId, delay: Duration) -> Self { + Self { fut: futures_timer::Delay::new(delay), candidate_hash, peer_id } + } +} + +impl Future for ResetInterestTimeout { + type Output = (CandidateHash, PeerId); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.fut.poll_unpin(cx).map(|_| (self.candidate_hash, self.peer_id)) + } +} + #[cfg(test)] mod tests { use super::*; + use polkadot_primitives::Hash; use sp_keyring::Sr25519Keyring; #[test] @@ -227,8 +259,8 @@ mod tests { let cap = NonZeroUsize::new(1).unwrap(); let mut buf = ValidatorGroupsBuffer::with_capacity(cap); - let hash_a = Hash::repeat_byte(0x1); - let hash_b = Hash::repeat_byte(0x2); + let hash_a = CandidateHash(Hash::repeat_byte(0x1)); + let hash_b = CandidateHash(Hash::repeat_byte(0x2)); let validators: Vec<_> = [ Sr25519Keyring::Alice, @@ -263,7 +295,7 @@ mod tests { let cap = NonZeroUsize::new(3).unwrap(); let mut buf = ValidatorGroupsBuffer::with_capacity(cap); - let hashes: Vec<_> = (0..5).map(Hash::repeat_byte).collect(); + let hashes: Vec<_> = (0..5).map(|i| CandidateHash(Hash::repeat_byte(i))).collect(); let validators: Vec<_> = [ Sr25519Keyring::Alice, diff --git a/node/network/collator-protocol/src/error.rs b/node/network/collator-protocol/src/error.rs index 1b6a512b5dea..9348198e7085 100644 --- a/node/network/collator-protocol/src/error.rs +++ b/node/network/collator-protocol/src/error.rs @@ -17,10 +17,12 @@ //! Error handling related code and Error/Result definitions. +use futures::channel::oneshot; + use polkadot_node_network_protocol::request_response::incoming; use polkadot_node_primitives::UncheckedSignedFullStatement; -use polkadot_node_subsystem::errors::SubsystemError; -use polkadot_node_subsystem_util::runtime; +use polkadot_node_subsystem::{errors::SubsystemError, RuntimeApiError}; +use polkadot_node_subsystem_util::{backing_implicit_view, runtime}; use crate::LOG_TARGET; @@ -44,10 +46,78 @@ pub enum Error { #[error("Error while accessing runtime information")] Runtime(#[from] runtime::Error), + #[error("Error while accessing Runtime API")] + RuntimeApi(#[from] RuntimeApiError), + + #[error(transparent)] + ImplicitViewFetchError(backing_implicit_view::FetchError), + + #[error("Response receiver for active validators request cancelled")] + CancelledActiveValidators(oneshot::Canceled), + + #[error("Response receiver for validator groups request cancelled")] + CancelledValidatorGroups(oneshot::Canceled), + + #[error("Response receiver for availability cores request cancelled")] + CancelledAvailabilityCores(oneshot::Canceled), + #[error("CollationSeconded contained statement with invalid signature")] InvalidStatementSignature(UncheckedSignedFullStatement), } +/// An error happened on the validator side of the protocol when attempting +/// to start seconding a candidate. +#[derive(Debug, thiserror::Error)] +pub enum SecondingError { + #[error("Error while accessing Runtime API")] + RuntimeApi(#[from] RuntimeApiError), + + #[error("Response receiver for persisted validation data request cancelled")] + CancelledRuntimePersistedValidationData(oneshot::Canceled), + + #[error("Response receiver for prospective validation data request cancelled")] + CancelledProspectiveValidationData(oneshot::Canceled), + + #[error("Persisted validation data is not available")] + PersistedValidationDataNotFound, + + #[error("Persisted validation data hash doesn't match one in the candidate receipt.")] + PersistedValidationDataMismatch, + + #[error("Candidate hash doesn't match the advertisement")] + CandidateHashMismatch, + + #[error("Received duplicate collation from the peer")] + Duplicate, +} + +impl SecondingError { + /// Returns true if an error indicates that a peer is malicious. + pub fn is_malicious(&self) -> bool { + use SecondingError::*; + matches!(self, PersistedValidationDataMismatch | CandidateHashMismatch | Duplicate) + } +} + +/// A validator failed to request a collation due to an error. +#[derive(Debug, thiserror::Error)] +pub enum FetchError { + #[error("Collation was not previously advertised")] + NotAdvertised, + + #[error("Peer is unknown")] + UnknownPeer, + + #[error("Collation was already requested")] + AlreadyRequested, + + #[error("Relay parent went out of view")] + RelayParentOutOfView, + + #[error("Peer's protocol doesn't match the advertisement")] + ProtocolMismatch, +} + /// Utility for eating top level errors and log them. /// /// We basically always want to try and continue on error. This utility function is meant to diff --git a/node/network/collator-protocol/src/lib.rs b/node/network/collator-protocol/src/lib.rs index 68d882be6fa1..62c033954f75 100644 --- a/node/network/collator-protocol/src/lib.rs +++ b/node/network/collator-protocol/src/lib.rs @@ -32,7 +32,7 @@ use polkadot_node_subsystem_util::reputation::ReputationAggregator; use sp_keystore::KeystorePtr; use polkadot_node_network_protocol::{ - request_response::{v1 as request_v1, IncomingRequestReceiver}, + request_response::{v1 as request_v1, vstaging as protocol_vstaging, IncomingRequestReceiver}, PeerId, UnifiedReputationChange as Rep, }; use polkadot_primitives::CollatorPair; @@ -76,12 +76,19 @@ pub enum ProtocolSide { metrics: validator_side::Metrics, }, /// Collators operate on a parachain. - Collator( - PeerId, - CollatorPair, - IncomingRequestReceiver, - collator_side::Metrics, - ), + Collator { + /// Local peer id. + peer_id: PeerId, + /// Parachain collator pair. + collator_pair: CollatorPair, + /// Receiver for v1 collation fetching requests. + request_receiver_v1: IncomingRequestReceiver, + /// Receiver for vstaging collation fetching requests. + request_receiver_vstaging: + IncomingRequestReceiver, + /// Metrics. + metrics: collator_side::Metrics, + }, /// No protocol side, just disable it. None, } @@ -110,10 +117,22 @@ impl CollatorProtocolSubsystem { validator_side::run(ctx, keystore, eviction_policy, metrics) .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) .boxed(), - ProtocolSide::Collator(local_peer_id, collator_pair, req_receiver, metrics) => - collator_side::run(ctx, local_peer_id, collator_pair, req_receiver, metrics) - .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) - .boxed(), + ProtocolSide::Collator { + peer_id, + collator_pair, + request_receiver_v1, + request_receiver_vstaging, + metrics, + } => collator_side::run( + ctx, + peer_id, + collator_pair, + request_receiver_v1, + request_receiver_vstaging, + metrics, + ) + .map_err(|e| SubsystemError::with_origin("collator-protocol", e)) + .boxed(), ProtocolSide::None => return DummySubsystem.start(ctx), }; diff --git a/node/network/collator-protocol/src/validator_side/collation.rs b/node/network/collator-protocol/src/validator_side/collation.rs new file mode 100644 index 000000000000..ba59cce56b60 --- /dev/null +++ b/node/network/collator-protocol/src/validator_side/collation.rs @@ -0,0 +1,366 @@ +// Copyright 2017-2022 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 . + +//! Primitives for tracking collations-related data. +//! +//! Usually a path of collations is as follows: +//! 1. First, collation must be advertised by collator. +//! 2. If the advertisement was accepted, it's queued for fetch (per relay parent). +//! 3. Once it's requested, the collation is said to be Pending. +//! 4. Pending collation becomes Fetched once received, we send it to backing for validation. +//! 5. If it turns to be invalid or async backing allows seconding another candidate, carry on +//! with the next advertisement, otherwise we're done with this relay parent. +//! +//! ┌──────────────────────────────────────────┐ +//! └─▶Advertised ─▶ Pending ─▶ Fetched ─▶ Validated + +use std::{collections::VecDeque, future::Future, pin::Pin, task::Poll}; + +use futures::{future::BoxFuture, FutureExt}; +use polkadot_node_network_protocol::{ + request_response::{outgoing::RequestError, v1 as request_v1, OutgoingResult}, + PeerId, +}; +use polkadot_node_primitives::PoV; +use polkadot_node_subsystem::jaeger; +use polkadot_node_subsystem_util::{ + metrics::prometheus::prometheus::HistogramTimer, runtime::ProspectiveParachainsMode, +}; +use polkadot_primitives::{ + CandidateHash, CandidateReceipt, CollatorId, Hash, Id as ParaId, PersistedValidationData, +}; +use tokio_util::sync::CancellationToken; + +use crate::{error::SecondingError, LOG_TARGET}; + +/// Candidate supplied with a para head it's built on top of. +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +pub struct ProspectiveCandidate { + /// Candidate hash. + pub candidate_hash: CandidateHash, + /// Parent head-data hash as supplied in advertisement. + pub parent_head_data_hash: Hash, +} + +impl ProspectiveCandidate { + pub fn candidate_hash(&self) -> CandidateHash { + self.candidate_hash + } +} + +/// Identifier of a fetched collation. +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct FetchedCollation { + /// Candidate's relay parent. + pub relay_parent: Hash, + /// Parachain id. + pub para_id: ParaId, + /// Candidate hash. + pub candidate_hash: CandidateHash, + /// Id of the collator the collation was fetched from. + pub collator_id: CollatorId, +} + +impl From<&CandidateReceipt> for FetchedCollation { + fn from(receipt: &CandidateReceipt) -> Self { + let descriptor = receipt.descriptor(); + Self { + relay_parent: descriptor.relay_parent, + para_id: descriptor.para_id, + candidate_hash: receipt.hash(), + collator_id: descriptor.collator.clone(), + } + } +} + +/// Identifier of a collation being requested. +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +pub struct PendingCollation { + /// Candidate's relay parent. + pub relay_parent: Hash, + /// Parachain id. + pub para_id: ParaId, + /// Peer that advertised this collation. + pub peer_id: PeerId, + /// Optional candidate hash and parent head-data hash if were + /// supplied in advertisement. + pub prospective_candidate: Option, + /// Hash of the candidate's commitments. + pub commitments_hash: Option, +} + +impl PendingCollation { + pub fn new( + relay_parent: Hash, + para_id: ParaId, + peer_id: &PeerId, + prospective_candidate: Option, + ) -> Self { + Self { + relay_parent, + para_id, + peer_id: *peer_id, + prospective_candidate, + commitments_hash: None, + } + } +} + +/// vstaging advertisement that was rejected by the backing +/// subsystem. Validator may fetch it later if its fragment +/// membership gets recognized before relay parent goes out of view. +#[derive(Debug, Clone)] +pub struct BlockedAdvertisement { + /// Peer that advertised the collation. + pub peer_id: PeerId, + /// Collator id. + pub collator_id: CollatorId, + /// The relay-parent of the candidate. + pub candidate_relay_parent: Hash, + /// Hash of the candidate. + pub candidate_hash: CandidateHash, +} + +/// Performs a sanity check between advertised and fetched collations. +/// +/// Since the persisted validation data is constructed using the advertised +/// parent head data hash, the latter doesn't require an additional check. +pub fn fetched_collation_sanity_check( + advertised: &PendingCollation, + fetched: &CandidateReceipt, + persisted_validation_data: &PersistedValidationData, +) -> Result<(), SecondingError> { + if persisted_validation_data.hash() != fetched.descriptor().persisted_validation_data_hash { + Err(SecondingError::PersistedValidationDataMismatch) + } else if advertised + .prospective_candidate + .map_or(false, |pc| pc.candidate_hash() != fetched.hash()) + { + Err(SecondingError::CandidateHashMismatch) + } else { + Ok(()) + } +} + +/// Identifier for a requested collation and the respective collator that advertised it. +#[derive(Debug, Clone)] +pub struct CollationEvent { + /// Collator id. + pub collator_id: CollatorId, + /// The requested collation data. + pub pending_collation: PendingCollation, +} + +/// Fetched collation data. +#[derive(Debug, Clone)] +pub struct PendingCollationFetch { + /// Collation identifier. + pub collation_event: CollationEvent, + /// Candidate receipt. + pub candidate_receipt: CandidateReceipt, + /// Proof of validity. + pub pov: PoV, +} + +/// The status of the collations in [`CollationsPerRelayParent`]. +#[derive(Debug, Clone, Copy)] +pub enum CollationStatus { + /// We are waiting for a collation to be advertised to us. + Waiting, + /// We are currently fetching a collation. + Fetching, + /// We are waiting that a collation is being validated. + WaitingOnValidation, + /// We have seconded a collation. + Seconded, +} + +impl Default for CollationStatus { + fn default() -> Self { + Self::Waiting + } +} + +impl CollationStatus { + /// Downgrades to `Waiting`, but only if `self != Seconded`. + fn back_to_waiting(&mut self, relay_parent_mode: ProspectiveParachainsMode) { + match self { + Self::Seconded => + if relay_parent_mode.is_enabled() { + // With async backing enabled it's allowed to + // second more candidates. + *self = Self::Waiting + }, + _ => *self = Self::Waiting, + } + } +} + +/// Information about collations per relay parent. +#[derive(Default)] +pub struct Collations { + /// What is the current status in regards to a collation for this relay parent? + pub status: CollationStatus, + /// Collator we're fetching from, optionally which candidate was requested. + /// + /// This is the currently last started fetch, which did not exceed `MAX_UNSHARED_DOWNLOAD_TIME` + /// yet. + pub fetching_from: Option<(CollatorId, Option)>, + /// Collation that were advertised to us, but we did not yet fetch. + pub waiting_queue: VecDeque<(PendingCollation, CollatorId)>, + /// How many collations have been seconded. + pub seconded_count: usize, +} + +impl Collations { + /// Note a seconded collation for a given para. + pub(super) fn note_seconded(&mut self) { + self.seconded_count += 1 + } + + /// Returns the next collation to fetch from the `waiting_queue`. + /// + /// This will reset the status back to `Waiting` using [`CollationStatus::back_to_waiting`]. + /// + /// Returns `Some(_)` if there is any collation to fetch, the `status` is not `Seconded` and + /// the passed in `finished_one` is the currently `waiting_collation`. + pub(super) fn get_next_collation_to_fetch( + &mut self, + finished_one: &(CollatorId, Option), + relay_parent_mode: ProspectiveParachainsMode, + ) -> Option<(PendingCollation, CollatorId)> { + // If finished one does not match waiting_collation, then we already dequeued another fetch + // to replace it. + if let Some((collator_id, maybe_candidate_hash)) = self.fetching_from.as_ref() { + // If a candidate hash was saved previously, `finished_one` must include this too. + if collator_id != &finished_one.0 && + maybe_candidate_hash.map_or(true, |hash| Some(&hash) != finished_one.1.as_ref()) + { + gum::trace!( + target: LOG_TARGET, + waiting_collation = ?self.fetching_from, + ?finished_one, + "Not proceeding to the next collation - has already been done." + ); + return None + } + } + self.status.back_to_waiting(relay_parent_mode); + + match self.status { + // We don't need to fetch any other collation when we already have seconded one. + CollationStatus::Seconded => None, + CollationStatus::Waiting => + if !self.is_seconded_limit_reached(relay_parent_mode) { + None + } else { + self.waiting_queue.pop_front() + }, + CollationStatus::WaitingOnValidation | CollationStatus::Fetching => + unreachable!("We have reset the status above!"), + } + } + + /// Checks the limit of seconded candidates for a given para. + pub(super) fn is_seconded_limit_reached( + &self, + relay_parent_mode: ProspectiveParachainsMode, + ) -> bool { + let seconded_limit = + if let ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } = + relay_parent_mode + { + max_candidate_depth + 1 + } else { + 1 + }; + self.seconded_count < seconded_limit + } +} + +// Any error that can occur when awaiting a collation fetch response. +#[derive(Debug, thiserror::Error)] +pub(super) enum CollationFetchError { + #[error("Future was cancelled.")] + Cancelled, + #[error("{0}")] + Request(#[from] RequestError), +} + +/// Future that concludes when the collator has responded to our collation fetch request +/// or the request was cancelled by the validator. +pub(super) struct CollationFetchRequest { + /// Info about the requested collation. + pub pending_collation: PendingCollation, + /// Collator id. + pub collator_id: CollatorId, + /// Responses from collator. + pub from_collator: BoxFuture<'static, OutgoingResult>, + /// Handle used for checking if this request was cancelled. + pub cancellation_token: CancellationToken, + /// A jaeger span corresponding to the lifetime of the request. + pub span: Option, + /// A metric histogram for the lifetime of the request + pub _lifetime_timer: Option, +} + +impl Future for CollationFetchRequest { + type Output = ( + CollationEvent, + std::result::Result, + ); + + fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { + // First check if this fetch request was cancelled. + let cancelled = match std::pin::pin!(self.cancellation_token.cancelled()).poll(cx) { + Poll::Ready(()) => true, + Poll::Pending => false, + }; + + if cancelled { + self.span.as_mut().map(|s| s.add_string_tag("success", "false")); + return Poll::Ready(( + CollationEvent { + collator_id: self.collator_id.clone(), + pending_collation: self.pending_collation, + }, + Err(CollationFetchError::Cancelled), + )) + } + + let res = self.from_collator.poll_unpin(cx).map(|res| { + ( + CollationEvent { + collator_id: self.collator_id.clone(), + pending_collation: self.pending_collation, + }, + res.map_err(CollationFetchError::Request), + ) + }); + + match &res { + Poll::Ready((_, Ok(request_v1::CollationFetchingResponse::Collation(..)))) => { + self.span.as_mut().map(|s| s.add_string_tag("success", "true")); + }, + Poll::Ready((_, Err(_))) => { + self.span.as_mut().map(|s| s.add_string_tag("success", "false")); + }, + _ => {}, + }; + + res + } +} diff --git a/node/network/collator-protocol/src/validator_side/metrics.rs b/node/network/collator-protocol/src/validator_side/metrics.rs new file mode 100644 index 000000000000..d898a5e7cefd --- /dev/null +++ b/node/network/collator-protocol/src/validator_side/metrics.rs @@ -0,0 +1,142 @@ +// Copyright 2017-2023 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 polkadot_node_subsystem_util::metrics::{self, prometheus}; + +#[derive(Clone, Default)] +pub struct Metrics(Option); + +impl Metrics { + pub fn on_request(&self, succeeded: std::result::Result<(), ()>) { + if let Some(metrics) = &self.0 { + match succeeded { + Ok(()) => metrics.collation_requests.with_label_values(&["succeeded"]).inc(), + Err(()) => metrics.collation_requests.with_label_values(&["failed"]).inc(), + } + } + } + + /// Provide a timer for `process_msg` which observes on drop. + pub fn time_process_msg(&self) -> Option { + self.0.as_ref().map(|metrics| metrics.process_msg.start_timer()) + } + + /// Provide a timer for `handle_collation_request_result` which observes on drop. + pub fn time_handle_collation_request_result( + &self, + ) -> Option { + self.0 + .as_ref() + .map(|metrics| metrics.handle_collation_request_result.start_timer()) + } + + /// Note the current number of collator peers. + pub fn note_collator_peer_count(&self, collator_peers: usize) { + self.0 + .as_ref() + .map(|metrics| metrics.collator_peer_count.set(collator_peers as u64)); + } + + /// Provide a timer for `CollationFetchRequest` structure which observes on drop. + pub fn time_collation_request_duration( + &self, + ) -> Option { + self.0.as_ref().map(|metrics| metrics.collation_request_duration.start_timer()) + } + + /// Provide a timer for `request_unblocked_collations` which observes on drop. + pub fn time_request_unblocked_collations( + &self, + ) -> Option { + self.0 + .as_ref() + .map(|metrics| metrics.request_unblocked_collations.start_timer()) + } +} + +#[derive(Clone)] +struct MetricsInner { + collation_requests: prometheus::CounterVec, + process_msg: prometheus::Histogram, + handle_collation_request_result: prometheus::Histogram, + collator_peer_count: prometheus::Gauge, + collation_request_duration: prometheus::Histogram, + request_unblocked_collations: prometheus::Histogram, +} + +impl metrics::Metrics for Metrics { + fn try_register( + registry: &prometheus::Registry, + ) -> std::result::Result { + let metrics = MetricsInner { + collation_requests: prometheus::register( + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_parachain_collation_requests_total", + "Number of collations requested from Collators.", + ), + &["success"], + )?, + registry, + )?, + process_msg: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_collator_protocol_validator_process_msg", + "Time spent within `collator_protocol_validator::process_msg`", + ) + )?, + registry, + )?, + handle_collation_request_result: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_collator_protocol_validator_handle_collation_request_result", + "Time spent within `collator_protocol_validator::handle_collation_request_result`", + ) + )?, + registry, + )?, + collator_peer_count: prometheus::register( + prometheus::Gauge::new( + "polkadot_parachain_collator_peer_count", + "Amount of collator peers connected", + )?, + registry, + )?, + collation_request_duration: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_collator_protocol_validator_collation_request_duration", + "Lifetime of the `CollationFetchRequest` structure", + ).buckets(vec![0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.75, 0.9, 1.0, 1.2, 1.5, 1.75]), + )?, + registry, + )?, + request_unblocked_collations: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_collator_protocol_validator_request_unblocked_collations", + "Time spent within `collator_protocol_validator::request_unblocked_collations`", + ) + )?, + registry, + )?, + }; + + Ok(Metrics(Some(metrics))) + } +} diff --git a/node/network/collator-protocol/src/validator_side/mod.rs b/node/network/collator-protocol/src/validator_side/mod.rs index f87a14971e8a..e8cf769d2e5f 100644 --- a/node/network/collator-protocol/src/validator_side/mod.rs +++ b/node/network/collator-protocol/src/validator_side/mod.rs @@ -14,57 +14,69 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use always_assert::never; use futures::{ - channel::oneshot, - future::{BoxFuture, Fuse, FusedFuture}, - select, - stream::FuturesUnordered, - FutureExt, StreamExt, + channel::oneshot, future::BoxFuture, select, stream::FuturesUnordered, FutureExt, StreamExt, }; use futures_timer::Delay; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, - sync::Arc, - task::Poll, + convert::TryInto, + future::Future, + iter::FromIterator, time::{Duration, Instant}, }; +use tokio_util::sync::CancellationToken; use sp_keystore::KeystorePtr; use polkadot_node_network_protocol::{ self as net_protocol, - peer_set::PeerSet, - request_response as req_res, + peer_set::{CollationVersion, PeerSet}, request_response::{ outgoing::{Recipient, RequestError}, - v1::{CollationFetchingRequest, CollationFetchingResponse}, - OutgoingRequest, Requests, + v1 as request_v1, vstaging as request_vstaging, OutgoingRequest, Requests, }, - v1 as protocol_v1, OurView, PeerId, UnifiedReputationChange as Rep, Versioned, View, + v1 as protocol_v1, vstaging as protocol_vstaging, OurView, PeerId, + UnifiedReputationChange as Rep, Versioned, View, }; -use polkadot_node_primitives::{PoV, SignedFullStatement}; +use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_node_subsystem::{ jaeger, messages::{ - CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected, NetworkBridgeEvent, - NetworkBridgeTxMessage, RuntimeApiMessage, + CanSecondRequest, CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected, + NetworkBridgeEvent, NetworkBridgeTxMessage, ProspectiveParachainsMessage, + ProspectiveValidationDataRequest, }, - overseer, FromOrchestra, OverseerSignal, PerLeafSpan, SubsystemSender, + overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, PerLeafSpan, }; use polkadot_node_subsystem_util::{ - metrics::{self, prometheus}, + backing_implicit_view::View as ImplicitView, reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, + runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, +}; +use polkadot_primitives::{ + CandidateHash, CollatorId, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, + PersistedValidationData, }; -use polkadot_primitives::{CandidateReceipt, CollatorId, Hash, Id as ParaId}; -use crate::error::Result; +use crate::error::{Error, FetchError, Result, SecondingError}; use super::{modify_reputation, tick_stream, LOG_TARGET}; +mod collation; +mod metrics; + +use collation::{ + fetched_collation_sanity_check, BlockedAdvertisement, CollationEvent, CollationFetchError, + CollationFetchRequest, CollationStatus, Collations, FetchedCollation, PendingCollation, + PendingCollationFetch, ProspectiveCandidate, +}; + #[cfg(test)] mod tests; +pub use metrics::Metrics; + const COST_UNEXPECTED_MESSAGE: Rep = Rep::CostMinor("An unexpected message"); /// Message could not be decoded properly. const COST_CORRUPTED_MESSAGE: Rep = Rep::CostMinor("Message was corrupt"); @@ -101,134 +113,16 @@ const MAX_UNSHARED_DOWNLOAD_TIME: Duration = Duration::from_millis(100); #[cfg(test)] const ACTIVITY_POLL: Duration = Duration::from_millis(10); -// How often to poll collation responses. -// This is a hack that should be removed in a refactoring. -// See https://github.com/paritytech/polkadot/issues/4182 -const CHECK_COLLATIONS_POLL: Duration = Duration::from_millis(50); - -#[derive(Clone, Default)] -pub struct Metrics(Option); - -impl Metrics { - fn on_request(&self, succeeded: std::result::Result<(), ()>) { - if let Some(metrics) = &self.0 { - match succeeded { - Ok(()) => metrics.collation_requests.with_label_values(&["succeeded"]).inc(), - Err(()) => metrics.collation_requests.with_label_values(&["failed"]).inc(), - } - } - } - - /// Provide a timer for `process_msg` which observes on drop. - fn time_process_msg(&self) -> Option { - self.0.as_ref().map(|metrics| metrics.process_msg.start_timer()) - } - - /// Provide a timer for `handle_collation_request_result` which observes on drop. - fn time_handle_collation_request_result( - &self, - ) -> Option { - self.0 - .as_ref() - .map(|metrics| metrics.handle_collation_request_result.start_timer()) - } - - /// Note the current number of collator peers. - fn note_collator_peer_count(&self, collator_peers: usize) { - self.0 - .as_ref() - .map(|metrics| metrics.collator_peer_count.set(collator_peers as u64)); - } - - /// Provide a timer for `PerRequest` structure which observes on drop. - fn time_collation_request_duration( - &self, - ) -> Option { - self.0.as_ref().map(|metrics| metrics.collation_request_duration.start_timer()) - } -} - -#[derive(Clone)] -struct MetricsInner { - collation_requests: prometheus::CounterVec, - process_msg: prometheus::Histogram, - handle_collation_request_result: prometheus::Histogram, - collator_peer_count: prometheus::Gauge, - collation_request_duration: prometheus::Histogram, -} - -impl metrics::Metrics for Metrics { - fn try_register( - registry: &prometheus::Registry, - ) -> std::result::Result { - let metrics = MetricsInner { - collation_requests: prometheus::register( - prometheus::CounterVec::new( - prometheus::Opts::new( - "polkadot_parachain_collation_requests_total", - "Number of collations requested from Collators.", - ), - &["success"], - )?, - registry, - )?, - process_msg: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collator_protocol_validator_process_msg", - "Time spent within `collator_protocol_validator::process_msg`", - ) - )?, - registry, - )?, - handle_collation_request_result: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collator_protocol_validator_handle_collation_request_result", - "Time spent within `collator_protocol_validator::handle_collation_request_result`", - ) - )?, - registry, - )?, - collator_peer_count: prometheus::register( - prometheus::Gauge::new( - "polkadot_parachain_collator_peer_count", - "Amount of collator peers connected", - )?, - registry, - )?, - collation_request_duration: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collator_protocol_validator_collation_request_duration", - "Lifetime of the `PerRequest` structure", - ).buckets(vec![0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.75, 0.9, 1.0, 1.2, 1.5, 1.75]), - )?, - registry, - )?, - }; - - Ok(Metrics(Some(metrics))) - } -} - -struct PerRequest { - /// Responses from collator. - from_collator: Fuse>>, - /// Sender to forward to initial requester. - to_requester: oneshot::Sender<(CandidateReceipt, PoV)>, - /// A jaeger span corresponding to the lifetime of the request. - span: Option, - /// A metric histogram for the lifetime of the request - _lifetime_timer: Option, -} - #[derive(Debug)] struct CollatingPeerState { collator_id: CollatorId, para_id: ParaId, - // Advertised relay parents. - advertisements: HashSet, + /// Collations advertised by peer per relay parent. + /// + /// V1 network protocol doesn't include candidate hash in + /// advertisements, we store an empty set in this case to occupy + /// a slot in map. + advertisements: HashMap>, last_active: Instant, } @@ -241,38 +135,85 @@ enum PeerState { } #[derive(Debug)] -enum AdvertisementError { +enum InsertAdvertisementError { + /// Advertisement is already known. Duplicate, + /// Collation relay parent is out of our view. OutOfOurView, + /// No prior declare message received. UndeclaredCollator, + /// A limit for announcements per peer is reached. + PeerLimitReached, + /// Mismatch of relay parent mode and advertisement arguments. + /// An internal error that should not happen. + ProtocolMismatch, } #[derive(Debug)] struct PeerData { view: View, state: PeerState, + version: CollationVersion, } impl PeerData { - fn new(view: View) -> Self { - PeerData { view, state: PeerState::Connected(Instant::now()) } - } - /// Update the view, clearing all advertisements that are no longer in the /// current view. - fn update_view(&mut self, new_view: View) { + fn update_view( + &mut self, + implicit_view: &ImplicitView, + active_leaves: &HashMap, + per_relay_parent: &HashMap, + new_view: View, + ) { let old_view = std::mem::replace(&mut self.view, new_view); if let PeerState::Collating(ref mut peer_state) = self.state { for removed in old_view.difference(&self.view) { - let _ = peer_state.advertisements.remove(&removed); + // Remove relay parent advertisements if it went out + // of our (implicit) view. + let keep = per_relay_parent + .get(removed) + .map(|s| { + is_relay_parent_in_implicit_view( + removed, + s.prospective_parachains_mode, + implicit_view, + active_leaves, + peer_state.para_id, + ) + }) + .unwrap_or(false); + + if !keep { + peer_state.advertisements.remove(&removed); + } } } } /// Prune old advertisements relative to our view. - fn prune_old_advertisements(&mut self, our_view: &View) { + fn prune_old_advertisements( + &mut self, + implicit_view: &ImplicitView, + active_leaves: &HashMap, + per_relay_parent: &HashMap, + ) { if let PeerState::Collating(ref mut peer_state) = self.state { - peer_state.advertisements.retain(|a| our_view.contains(a)); + peer_state.advertisements.retain(|hash, _| { + // Either + // - Relay parent is an active leaf + // - It belongs to allowed ancestry under some leaf + // Discard otherwise. + per_relay_parent.get(hash).map_or(false, |s| { + is_relay_parent_in_implicit_view( + hash, + s.prospective_parachains_mode, + implicit_view, + active_leaves, + peer_state.para_id, + ) + }) + }); } } @@ -282,18 +223,57 @@ impl PeerData { fn insert_advertisement( &mut self, on_relay_parent: Hash, - our_view: &View, - ) -> std::result::Result<(CollatorId, ParaId), AdvertisementError> { + relay_parent_mode: ProspectiveParachainsMode, + candidate_hash: Option, + implicit_view: &ImplicitView, + active_leaves: &HashMap, + ) -> std::result::Result<(CollatorId, ParaId), InsertAdvertisementError> { match self.state { - PeerState::Connected(_) => Err(AdvertisementError::UndeclaredCollator), - _ if !our_view.contains(&on_relay_parent) => Err(AdvertisementError::OutOfOurView), - PeerState::Collating(ref mut state) => - if state.advertisements.insert(on_relay_parent) { - state.last_active = Instant::now(); - Ok((state.collator_id.clone(), state.para_id)) - } else { - Err(AdvertisementError::Duplicate) - }, + PeerState::Connected(_) => Err(InsertAdvertisementError::UndeclaredCollator), + PeerState::Collating(ref mut state) => { + if !is_relay_parent_in_implicit_view( + &on_relay_parent, + relay_parent_mode, + implicit_view, + active_leaves, + state.para_id, + ) { + return Err(InsertAdvertisementError::OutOfOurView) + } + + match (relay_parent_mode, candidate_hash) { + (ProspectiveParachainsMode::Disabled, candidate_hash) => { + if state.advertisements.contains_key(&on_relay_parent) { + return Err(InsertAdvertisementError::Duplicate) + } + state + .advertisements + .insert(on_relay_parent, HashSet::from_iter(candidate_hash)); + }, + ( + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. }, + Some(candidate_hash), + ) => { + if state + .advertisements + .get(&on_relay_parent) + .map_or(false, |candidates| candidates.contains(&candidate_hash)) + { + return Err(InsertAdvertisementError::Duplicate) + } + let candidates = state.advertisements.entry(on_relay_parent).or_default(); + + if candidates.len() > max_candidate_depth { + return Err(InsertAdvertisementError::PeerLimitReached) + } + candidates.insert(candidate_hash); + }, + _ => return Err(InsertAdvertisementError::ProtocolMismatch), + } + + state.last_active = Instant::now(); + Ok((state.collator_id.clone(), state.para_id)) + }, } } @@ -305,7 +285,7 @@ impl PeerData { } } - /// Note that a peer is now collating with the given collator and para ids. + /// Note that a peer is now collating with the given collator and para id. /// /// This will overwrite any previous call to `set_collating` and should only be called /// if `is_collating` is false. @@ -313,7 +293,7 @@ impl PeerData { self.state = PeerState::Collating(CollatingPeerState { collator_id, para_id, - advertisements: HashSet::new(), + advertisements: HashMap::new(), last_active: Instant::now(), }); } @@ -333,10 +313,23 @@ impl PeerData { } /// Whether the peer has advertised the given collation. - fn has_advertised(&self, relay_parent: &Hash) -> bool { - match self.state { - PeerState::Connected(_) => false, - PeerState::Collating(ref state) => state.advertisements.contains(relay_parent), + fn has_advertised( + &self, + relay_parent: &Hash, + maybe_candidate_hash: Option, + ) -> bool { + let collating_state = match self.state { + PeerState::Connected(_) => return false, + PeerState::Collating(ref state) => state, + }; + + if let Some(ref candidate_hash) = maybe_candidate_hash { + collating_state + .advertisements + .get(relay_parent) + .map_or(false, |candidates| candidates.contains(candidate_hash)) + } else { + collating_state.advertisements.contains_key(relay_parent) } } @@ -350,227 +343,24 @@ impl PeerData { } } -impl Default for PeerData { - fn default() -> Self { - PeerData::new(Default::default()) - } -} - +#[derive(Debug)] struct GroupAssignments { + /// Current assignment. current: Option, } -#[derive(Default)] -struct ActiveParas { - relay_parent_assignments: HashMap, - current_assignments: HashMap, -} - -impl ActiveParas { - async fn assign_incoming( - &mut self, - sender: &mut impl SubsystemSender, - keystore: &KeystorePtr, - new_relay_parents: impl IntoIterator, - ) { - for relay_parent in new_relay_parents { - let mv = polkadot_node_subsystem_util::request_validators(relay_parent, sender) - .await - .await - .ok() - .and_then(|x| x.ok()); - - let mg = polkadot_node_subsystem_util::request_validator_groups(relay_parent, sender) - .await - .await - .ok() - .and_then(|x| x.ok()); - - let mc = polkadot_node_subsystem_util::request_availability_cores(relay_parent, sender) - .await - .await - .ok() - .and_then(|x| x.ok()); - - let (validators, groups, rotation_info, cores) = match (mv, mg, mc) { - (Some(v), Some((g, r)), Some(c)) => (v, g, r, c), - _ => { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - "Failed to query runtime API for relay-parent", - ); - - continue - }, - }; - - let para_now = - match polkadot_node_subsystem_util::signing_key_and_index(&validators, keystore) - .and_then(|(_, index)| { - polkadot_node_subsystem_util::find_validator_group(&groups, index) - }) { - Some(group) => { - let core_now = rotation_info.core_for_group(group, cores.len()); - - cores.get(core_now.0 as usize).and_then(|c| c.para_id()) - }, - None => { - gum::trace!(target: LOG_TARGET, ?relay_parent, "Not a validator"); - - continue - }, - }; - - // This code won't work well, if at all for parathreads. For parathreads we'll - // have to be aware of which core the parathread claim is going to be multiplexed - // onto. The parathread claim will also have a known collator, and we should always - // allow an incoming connection from that collator. If not even connecting to them - // directly. - // - // However, this'll work fine for parachains, as each parachain gets a dedicated - // core. - if let Some(para_now) = para_now { - let entry = self.current_assignments.entry(para_now).or_default(); - *entry += 1; - if *entry == 1 { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - para_id = ?para_now, - "Assigned to a parachain", - ); - } - } - - self.relay_parent_assignments - .insert(relay_parent, GroupAssignments { current: para_now }); - } - } - - fn remove_outgoing(&mut self, old_relay_parents: impl IntoIterator) { - for old_relay_parent in old_relay_parents { - if let Some(assignments) = self.relay_parent_assignments.remove(&old_relay_parent) { - let GroupAssignments { current } = assignments; - - if let Some(cur) = current { - if let Entry::Occupied(mut occupied) = self.current_assignments.entry(cur) { - *occupied.get_mut() -= 1; - if *occupied.get() == 0 { - occupied.remove_entry(); - gum::debug!( - target: LOG_TARGET, - para_id = ?cur, - "Unassigned from a parachain", - ); - } - } - } - } - } - } - - fn is_current(&self, id: &ParaId) -> bool { - self.current_assignments.contains_key(id) - } -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -struct PendingCollation { - relay_parent: Hash, - para_id: ParaId, - peer_id: PeerId, - commitments_hash: Option, -} - -impl PendingCollation { - fn new(relay_parent: Hash, para_id: &ParaId, peer_id: &PeerId) -> Self { - Self { relay_parent, para_id: *para_id, peer_id: *peer_id, commitments_hash: None } - } -} - -type CollationEvent = (CollatorId, PendingCollation); - -type PendingCollationFetch = - (CollationEvent, std::result::Result<(CandidateReceipt, PoV), oneshot::Canceled>); - -/// The status of the collations in [`CollationsPerRelayParent`]. -#[derive(Debug, Clone, Copy)] -enum CollationStatus { - /// We are waiting for a collation to be advertised to us. - Waiting, - /// We are currently fetching a collation. - Fetching, - /// We are waiting that a collation is being validated. - WaitingOnValidation, - /// We have seconded a collation. - Seconded, -} - -impl Default for CollationStatus { - fn default() -> Self { - Self::Waiting - } -} - -impl CollationStatus { - /// Downgrades to `Waiting`, but only if `self != Seconded`. - fn back_to_waiting(&mut self) { - match self { - Self::Seconded => {}, - _ => *self = Self::Waiting, - } - } -} - -/// Information about collations per relay parent. -#[derive(Default)] -struct CollationsPerRelayParent { - /// What is the current status in regards to a collation for this relay parent? - status: CollationStatus, - /// Collation currently being fetched. - /// - /// This is the currently last started fetch, which did not exceed `MAX_UNSHARED_DOWNLOAD_TIME` - /// yet. - waiting_collation: Option, - /// Collation that were advertised to us, but we did not yet fetch. - unfetched_collations: Vec<(PendingCollation, CollatorId)>, +struct PerRelayParent { + prospective_parachains_mode: ProspectiveParachainsMode, + assignment: GroupAssignments, + collations: Collations, } -impl CollationsPerRelayParent { - /// Returns the next collation to fetch from the `unfetched_collations`. - /// - /// This will reset the status back to `Waiting` using [`CollationStatus::back_to_waiting`]. - /// - /// Returns `Some(_)` if there is any collation to fetch, the `status` is not `Seconded` and - /// the passed in `finished_one` is the currently `waiting_collation`. - pub fn get_next_collation_to_fetch( - &mut self, - finished_one: Option<&CollatorId>, - ) -> Option<(PendingCollation, CollatorId)> { - // If finished one does not match waiting_collation, then we already dequeued another fetch - // to replace it. - if self.waiting_collation.as_ref() != finished_one { - gum::trace!( - target: LOG_TARGET, - waiting_collation = ?self.waiting_collation, - ?finished_one, - "Not proceeding to the next collation - has already been done." - ); - return None - } - self.status.back_to_waiting(); - - match self.status { - // We don't need to fetch any other collation when we already have seconded one. - CollationStatus::Seconded => None, - CollationStatus::Waiting => { - let next = self.unfetched_collations.pop(); - self.waiting_collation = next.as_ref().map(|(_, collator_id)| collator_id.clone()); - next - }, - CollationStatus::WaitingOnValidation | CollationStatus::Fetching => - unreachable!("We have reset the status above!"), +impl PerRelayParent { + fn new(mode: ProspectiveParachainsMode) -> Self { + Self { + prospective_parachains_mode: mode, + assignment: GroupAssignments { current: None }, + collations: Collations::default(), } } } @@ -578,21 +368,37 @@ impl CollationsPerRelayParent { /// All state relevant for the validator side of the protocol lives here. #[derive(Default)] struct State { - /// Our own view. - view: OurView, + /// Leaves that do support asynchronous backing along with + /// implicit ancestry. Leaves from the implicit view are present in + /// `active_leaves`, the opposite doesn't hold true. + /// + /// Relay-chain blocks which don't support prospective parachains are + /// never included in the fragment trees of active leaves which do. In + /// particular, this means that if a given relay parent belongs to implicit + /// ancestry of some active leaf, then it does support prospective parachains. + implicit_view: ImplicitView, - /// Active paras based on our view. We only accept collators from these paras. - active_paras: ActiveParas, + /// All active leaves observed by us, including both that do and do not + /// support prospective parachains. This mapping works as a replacement for + /// [`polkadot_node_network_protocol::View`] and can be dropped once the transition + /// to asynchronous backing is done. + active_leaves: HashMap, + + /// State tracked per relay parent. + per_relay_parent: HashMap, /// Track all active collators and their data. peer_data: HashMap, - /// The collations we have requested by relay parent and para id. - /// - /// For each relay parent and para id we may be connected to a number - /// of collators each of those may have advertised a different collation. - /// So we group such cases here. - requested_collations: HashMap, + /// Parachains we're currently assigned to. With async backing enabled + /// this includes assignments from the implicit view. + current_assignments: HashMap, + + /// The collations we have requested from collators. + collation_requests: FuturesUnordered, + + /// Cancellation handles for the collation fetch requests. + collation_requests_cancel_handles: HashMap, /// Metrics. metrics: Metrics, @@ -600,26 +406,142 @@ struct State { /// Span per relay parent. span_per_relay_parent: HashMap, - /// Keep track of all fetch collation requests - collation_fetches: FuturesUnordered>, + /// Advertisements that were accepted as valid by collator protocol but rejected by backing. + /// + /// It's only legal to fetch collations that are either built on top of the root + /// of some fragment tree or have a parent node which represents backed candidate. + /// Otherwise, a validator will keep such advertisement in the memory and re-trigger + /// requests to backing on new backed candidates and activations. + blocked_advertisements: HashMap<(ParaId, Hash), Vec>, /// When a timer in this `FuturesUnordered` triggers, we should dequeue the next request /// attempt in the corresponding `collations_per_relay_parent`. /// /// A triggering timer means that the fetching took too long for our taste and we should give /// another collator the chance to be faster (dequeue next fetch request as well). - collation_fetch_timeouts: FuturesUnordered>, + collation_fetch_timeouts: + FuturesUnordered, Hash)>>, - /// Information about the collations per relay parent. - collations_per_relay_parent: HashMap, - - /// Keep track of all pending candidate collations - pending_candidates: HashMap, + /// Collations that we have successfully requested from peers and waiting + /// on validation. + fetched_candidates: HashMap, /// Aggregated reputation change reputation: ReputationAggregator, } +fn is_relay_parent_in_implicit_view( + relay_parent: &Hash, + relay_parent_mode: ProspectiveParachainsMode, + implicit_view: &ImplicitView, + active_leaves: &HashMap, + para_id: ParaId, +) -> bool { + match relay_parent_mode { + ProspectiveParachainsMode::Disabled => active_leaves.contains_key(relay_parent), + ProspectiveParachainsMode::Enabled { .. } => active_leaves.iter().any(|(hash, mode)| { + mode.is_enabled() && + implicit_view + .known_allowed_relay_parents_under(hash, Some(para_id)) + .unwrap_or_default() + .contains(relay_parent) + }), + } +} + +async fn assign_incoming( + sender: &mut Sender, + group_assignment: &mut GroupAssignments, + current_assignments: &mut HashMap, + keystore: &KeystorePtr, + relay_parent: Hash, + relay_parent_mode: ProspectiveParachainsMode, +) -> Result<()> +where + Sender: CollatorProtocolSenderTrait, +{ + let validators = polkadot_node_subsystem_util::request_validators(relay_parent, sender) + .await + .await + .map_err(Error::CancelledActiveValidators)??; + + let (groups, rotation_info) = + polkadot_node_subsystem_util::request_validator_groups(relay_parent, sender) + .await + .await + .map_err(Error::CancelledValidatorGroups)??; + + let cores = polkadot_node_subsystem_util::request_availability_cores(relay_parent, sender) + .await + .await + .map_err(Error::CancelledAvailabilityCores)??; + + let para_now = match polkadot_node_subsystem_util::signing_key_and_index(&validators, keystore) + .and_then(|(_, index)| polkadot_node_subsystem_util::find_validator_group(&groups, index)) + { + Some(group) => { + let core_now = rotation_info.core_for_group(group, cores.len()); + + cores.get(core_now.0 as usize).and_then(|c| match c { + CoreState::Occupied(core) if relay_parent_mode.is_enabled() => Some(core.para_id()), + CoreState::Scheduled(core) => Some(core.para_id), + CoreState::Occupied(_) | CoreState::Free => None, + }) + }, + None => { + gum::trace!(target: LOG_TARGET, ?relay_parent, "Not a validator"); + + return Ok(()) + }, + }; + + // This code won't work well, if at all for on-demand parachains. For on-demand we'll + // have to be aware of which core the on-demand claim is going to be multiplexed + // onto. The on-demand claim will also have a known collator, and we should always + // allow an incoming connection from that collator. If not even connecting to them + // directly. + // + // However, this'll work fine for parachains, as each parachain gets a dedicated + // core. + if let Some(para_id) = para_now.as_ref() { + let entry = current_assignments.entry(*para_id).or_default(); + *entry += 1; + if *entry == 1 { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para_id, + "Assigned to a parachain", + ); + } + } + + *group_assignment = GroupAssignments { current: para_now }; + + Ok(()) +} + +fn remove_outgoing( + current_assignments: &mut HashMap, + per_relay_parent: PerRelayParent, +) { + let GroupAssignments { current, .. } = per_relay_parent.assignment; + + if let Some(cur) = current { + if let Entry::Occupied(mut occupied) = current_assignments.entry(cur) { + *occupied.get_mut() -= 1; + if *occupied.get() == 0 { + occupied.remove_entry(); + gum::debug!( + target: LOG_TARGET, + para_id = ?cur, + "Unassigned from a parachain", + ); + } + } + } +} + // O(n) search for collator ID by iterating through the peers map. This should be fast enough // unless a large amount of peers is expected. fn collator_peer_id( @@ -643,40 +565,26 @@ async fn fetch_collation( state: &mut State, pc: PendingCollation, id: CollatorId, -) { - let (tx, rx) = oneshot::channel(); +) -> std::result::Result<(), FetchError> { + let PendingCollation { relay_parent, peer_id, prospective_candidate, .. } = pc; + let candidate_hash = prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); - let PendingCollation { relay_parent, para_id, peer_id, .. } = pc; + let peer_data = state.peer_data.get(&peer_id).ok_or(FetchError::UnknownPeer)?; - let timeout = |collator_id, relay_parent| async move { - Delay::new(MAX_UNSHARED_DOWNLOAD_TIME).await; - (collator_id, relay_parent) - }; - state.collation_fetch_timeouts.push(timeout(id.clone(), relay_parent).boxed()); + if peer_data.has_advertised(&relay_parent, candidate_hash) { + request_collation(sender, state, pc, id.clone(), peer_data.version).await?; + let timeout = |collator_id, candidate_hash, relay_parent| async move { + Delay::new(MAX_UNSHARED_DOWNLOAD_TIME).await; + (collator_id, candidate_hash, relay_parent) + }; + state + .collation_fetch_timeouts + .push(timeout(id.clone(), candidate_hash, relay_parent).boxed()); - if let Some(peer_data) = state.peer_data.get(&peer_id) { - if peer_data.has_advertised(&relay_parent) { - request_collation(sender, state, relay_parent, para_id, peer_id, tx).await; - } else { - gum::debug!( - target: LOG_TARGET, - ?peer_id, - ?para_id, - ?relay_parent, - "Collation is not advertised for the relay parent by the peer, do not request it", - ); - } + Ok(()) } else { - gum::warn!( - target: LOG_TARGET, - ?peer_id, - ?para_id, - ?relay_parent, - "Requested to fetch a collation from an unknown peer", - ); + Err(FetchError::NotAdvertised) } - - state.collation_fetches.push(rx.map(|r| ((id, pc), r)).boxed()); } /// Report a collator for some malicious actions. @@ -705,83 +613,108 @@ async fn note_good_collation( /// Notify a collator that its collation got seconded. async fn notify_collation_seconded( - reputation: &mut ReputationAggregator, sender: &mut impl overseer::CollatorProtocolSenderTrait, peer_id: PeerId, + version: CollationVersion, relay_parent: Hash, statement: SignedFullStatement, ) { - let wire_message = - protocol_v1::CollatorProtocolMessage::CollationSeconded(relay_parent, statement.into()); + let statement = statement.into(); + let wire_message = match version { + CollationVersion::V1 => Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol( + protocol_v1::CollatorProtocolMessage::CollationSeconded(relay_parent, statement), + )), + CollationVersion::VStaging => + Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + protocol_vstaging::CollatorProtocolMessage::CollationSeconded( + relay_parent, + statement, + ), + )), + }; sender - .send_message(NetworkBridgeTxMessage::SendCollationMessage( - vec![peer_id], - Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message)), - )) + .send_message(NetworkBridgeTxMessage::SendCollationMessage(vec![peer_id], wire_message)) .await; - - modify_reputation(reputation, sender, peer_id, BENEFIT_NOTIFY_GOOD).await; } /// A peer's view has changed. A number of things should be done: /// - Ongoing collation requests have to be canceled. /// - Advertisements by this peer that are no longer relevant have to be removed. -async fn handle_peer_view_change(state: &mut State, peer_id: PeerId, view: View) -> Result<()> { - let peer_data = state.peer_data.entry(peer_id).or_default(); - - peer_data.update_view(view); - state - .requested_collations - .retain(|pc, _| pc.peer_id != peer_id || peer_data.has_advertised(&pc.relay_parent)); +fn handle_peer_view_change(state: &mut State, peer_id: PeerId, view: View) { + let peer_data = match state.peer_data.get_mut(&peer_id) { + Some(peer_data) => peer_data, + None => return, + }; - Ok(()) + peer_data.update_view( + &state.implicit_view, + &state.active_leaves, + &state.per_relay_parent, + view, + ); + state.collation_requests_cancel_handles.retain(|pc, handle| { + let keep = pc.peer_id != peer_id || peer_data.has_advertised(&pc.relay_parent, None); + if !keep { + handle.cancel(); + } + keep + }); } /// Request a collation from the network. /// This function will /// - Check for duplicate requests. /// - Check if the requested collation is in our view. -/// - Update `PerRequest` records with the `result` field if necessary. /// And as such invocations of this function may rely on that. async fn request_collation( sender: &mut impl overseer::CollatorProtocolSenderTrait, state: &mut State, - relay_parent: Hash, - para_id: ParaId, - peer_id: PeerId, - result: oneshot::Sender<(CandidateReceipt, PoV)>, -) { - if !state.view.contains(&relay_parent) { - gum::debug!( - target: LOG_TARGET, - peer_id = %peer_id, - para_id = %para_id, - relay_parent = %relay_parent, - "collation is no longer in view", - ); - return - } - let pending_collation = PendingCollation::new(relay_parent, ¶_id, &peer_id); - if state.requested_collations.contains_key(&pending_collation) { - gum::warn!( - target: LOG_TARGET, - peer_id = %pending_collation.peer_id, - %pending_collation.para_id, - ?pending_collation.relay_parent, - "collation has already been requested", - ); - return + pending_collation: PendingCollation, + collator_id: CollatorId, + peer_protocol_version: CollationVersion, +) -> std::result::Result<(), FetchError> { + if state.collation_requests_cancel_handles.contains_key(&pending_collation) { + return Err(FetchError::AlreadyRequested) } - let (full_request, response_recv) = OutgoingRequest::new( - Recipient::Peer(peer_id), - CollationFetchingRequest { relay_parent, para_id }, - ); - let requests = Requests::CollationFetchingV1(full_request); + let PendingCollation { relay_parent, para_id, peer_id, prospective_candidate, .. } = + pending_collation; + let per_relay_parent = state + .per_relay_parent + .get_mut(&relay_parent) + .ok_or(FetchError::RelayParentOutOfView)?; + + // Relay parent mode is checked in `handle_advertisement`. + let (requests, response_recv) = match (peer_protocol_version, prospective_candidate) { + (CollationVersion::V1, _) => { + let (req, response_recv) = OutgoingRequest::new( + Recipient::Peer(peer_id), + request_v1::CollationFetchingRequest { relay_parent, para_id }, + ); + let requests = Requests::CollationFetchingV1(req); + (requests, response_recv.boxed()) + }, + (CollationVersion::VStaging, Some(ProspectiveCandidate { candidate_hash, .. })) => { + let (req, response_recv) = OutgoingRequest::new( + Recipient::Peer(peer_id), + request_vstaging::CollationFetchingRequest { + relay_parent, + para_id, + candidate_hash, + }, + ); + let requests = Requests::CollationFetchingVStaging(req); + (requests, response_recv.boxed()) + }, + _ => return Err(FetchError::ProtocolMismatch), + }; - let per_request = PerRequest { - from_collator: response_recv.boxed().fuse(), - to_requester: result, + let cancellation_token = CancellationToken::new(); + let collation_request = CollationFetchRequest { + pending_collation, + collator_id: collator_id.clone(), + from_collator: response_recv.boxed(), + cancellation_token: cancellation_token.clone(), span: state .span_per_relay_parent .get(&relay_parent) @@ -789,9 +722,10 @@ async fn request_collation( _lifetime_timer: state.metrics.time_collation_request_duration(), }; + state.collation_requests.push(collation_request); state - .requested_collations - .insert(PendingCollation::new(relay_parent, ¶_id, &peer_id), per_request); + .collation_requests_cancel_handles + .insert(pending_collation, cancellation_token); gum::debug!( target: LOG_TARGET, @@ -801,12 +735,21 @@ async fn request_collation( "Requesting collation", ); + let maybe_candidate_hash = + prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); + per_relay_parent.collations.status = CollationStatus::Fetching; + per_relay_parent + .collations + .fetching_from + .replace((collator_id, maybe_candidate_hash)); + sender .send_message(NetworkBridgeTxMessage::SendRequests( vec![requests], IfDisconnected::ImmediateError, )) .await; + Ok(()) } /// Networking message has been received. @@ -815,12 +758,18 @@ async fn process_incoming_peer_message( ctx: &mut Context, state: &mut State, origin: PeerId, - msg: protocol_v1::CollatorProtocolMessage, + msg: Versioned< + protocol_v1::CollatorProtocolMessage, + protocol_vstaging::CollatorProtocolMessage, + >, ) { - use protocol_v1::CollatorProtocolMessage::*; + use protocol_v1::CollatorProtocolMessage as V1; + use protocol_vstaging::CollatorProtocolMessage as VStaging; use sp_runtime::traits::AppVerify; + match msg { - Declare(collator_id, para_id, signature) => { + Versioned::V1(V1::Declare(collator_id, para_id, signature)) | + Versioned::VStaging(VStaging::Declare(collator_id, para_id, signature)) => { if collator_peer_id(&state.peer_data, &collator_id).is_some() { modify_reputation( &mut state.reputation, @@ -857,7 +806,7 @@ async fn process_incoming_peer_message( target: LOG_TARGET, peer_id = ?origin, ?para_id, - "Peer is not in the collating state", + "Peer is already in the collating state", ); modify_reputation( &mut state.reputation, @@ -886,7 +835,7 @@ async fn process_incoming_peer_message( return } - if state.active_paras.is_current(¶_id) { + if state.current_assignments.contains_key(¶_id) { gum::debug!( target: LOG_TARGET, peer_id = ?origin, @@ -916,184 +865,514 @@ async fn process_incoming_peer_message( disconnect_peer(ctx.sender(), origin).await; } }, - AdvertiseCollation(relay_parent) => { - let _span = state - .span_per_relay_parent - .get(&relay_parent) - .map(|s| s.child("advertise-collation")); + Versioned::V1(V1::AdvertiseCollation(relay_parent)) => + if let Err(err) = + handle_advertisement(ctx.sender(), state, relay_parent, origin, None).await + { + gum::debug!( + target: LOG_TARGET, + peer_id = ?origin, + ?relay_parent, + error = ?err, + "Rejected v1 advertisement", + ); - if !state.view.contains(&relay_parent) { + if let Some(rep) = err.reputation_changes() { + modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; + } + }, + Versioned::VStaging(VStaging::AdvertiseCollation { + relay_parent, + candidate_hash, + parent_head_data_hash, + }) => + if let Err(err) = handle_advertisement( + ctx.sender(), + state, + relay_parent, + origin, + Some((candidate_hash, parent_head_data_hash)), + ) + .await + { gum::debug!( target: LOG_TARGET, peer_id = ?origin, ?relay_parent, - "Advertise collation out of view", + ?candidate_hash, + error = ?err, + "Rejected vstaging advertisement", ); - modify_reputation( - &mut state.reputation, - ctx.sender(), - origin, - COST_UNEXPECTED_MESSAGE, - ) + if let Some(rep) = err.reputation_changes() { + modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; + } + }, + Versioned::V1(V1::CollationSeconded(..)) | + Versioned::VStaging(VStaging::CollationSeconded(..)) => { + gum::warn!( + target: LOG_TARGET, + peer_id = ?origin, + "Unexpected `CollationSeconded` message, decreasing reputation", + ); + + modify_reputation(&mut state.reputation, ctx.sender(), origin, COST_UNEXPECTED_MESSAGE) .await; - return - } + }, + } +} - let peer_data = match state.peer_data.get_mut(&origin) { - None => { - gum::debug!( - target: LOG_TARGET, - peer_id = ?origin, - ?relay_parent, - "Advertise collation message has been received from an unknown peer", - ); - modify_reputation( - &mut state.reputation, - ctx.sender(), - origin, - COST_UNEXPECTED_MESSAGE, - ) - .await; - return - }, - Some(p) => p, - }; +#[derive(Debug)] +enum AdvertisementError { + /// Relay parent is unknown. + RelayParentUnknown, + /// Peer is not present in the subsystem state. + UnknownPeer, + /// Peer has not declared its para id. + UndeclaredCollator, + /// We're assigned to a different para at the given relay parent. + InvalidAssignment, + /// An advertisement format doesn't match the relay parent. + ProtocolMismatch, + /// Para reached a limit of seconded candidates for this relay parent. + SecondedLimitReached, + /// Advertisement is invalid. + Invalid(InsertAdvertisementError), +} - match peer_data.insert_advertisement(relay_parent, &state.view) { - Ok((id, para_id)) => { - gum::debug!( - target: LOG_TARGET, - peer_id = ?origin, - %para_id, - ?relay_parent, - "Received advertise collation", - ); +impl AdvertisementError { + fn reputation_changes(&self) -> Option { + use AdvertisementError::*; + match self { + InvalidAssignment => Some(COST_WRONG_PARA), + RelayParentUnknown | UndeclaredCollator | Invalid(_) => Some(COST_UNEXPECTED_MESSAGE), + UnknownPeer | ProtocolMismatch | SecondedLimitReached => None, + } + } +} - let pending_collation = PendingCollation::new(relay_parent, ¶_id, &origin); - - let collations = - state.collations_per_relay_parent.entry(relay_parent).or_default(); - - match collations.status { - CollationStatus::Fetching | CollationStatus::WaitingOnValidation => { - gum::trace!( - target: LOG_TARGET, - peer_id = ?origin, - %para_id, - ?relay_parent, - "Added collation to the pending list" - ); - collations.unfetched_collations.push((pending_collation, id)); - }, - CollationStatus::Waiting => { - collations.status = CollationStatus::Fetching; - collations.waiting_collation = Some(id.clone()); - - fetch_collation(ctx.sender(), state, pending_collation.clone(), id) - .await; - }, - CollationStatus::Seconded => { - gum::trace!( - target: LOG_TARGET, - peer_id = ?origin, - %para_id, - ?relay_parent, - "Valid seconded collation" - ); - }, - } - }, - Err(error) => { +// Requests backing to sanity check the advertisement. +async fn can_second( + sender: &mut Sender, + candidate_para_id: ParaId, + candidate_relay_parent: Hash, + candidate_hash: CandidateHash, + parent_head_data_hash: Hash, +) -> bool +where + Sender: CollatorProtocolSenderTrait, +{ + let request = CanSecondRequest { + candidate_para_id, + candidate_relay_parent, + candidate_hash, + parent_head_data_hash, + }; + let (tx, rx) = oneshot::channel(); + sender.send_message(CandidateBackingMessage::CanSecond(request, tx)).await; + + rx.await.unwrap_or_else(|err| { + gum::warn!( + target: LOG_TARGET, + ?err, + ?candidate_relay_parent, + ?candidate_para_id, + ?candidate_hash, + "CanSecond-request responder was dropped", + ); + + false + }) +} + +/// Checks whether any of the advertisements are unblocked and attempts to fetch them. +async fn request_unblocked_collations(sender: &mut Sender, state: &mut State, blocked: I) +where + Sender: CollatorProtocolSenderTrait, + I: IntoIterator)>, +{ + let _timer = state.metrics.time_request_unblocked_collations(); + + for (key, mut value) in blocked { + let (para_id, para_head) = key; + let blocked = std::mem::take(&mut value); + for blocked in blocked { + let is_seconding_allowed = can_second( + sender, + para_id, + blocked.candidate_relay_parent, + blocked.candidate_hash, + para_head, + ) + .await; + + if is_seconding_allowed { + let result = enqueue_collation( + sender, + state, + blocked.candidate_relay_parent, + para_id, + blocked.peer_id, + blocked.collator_id, + Some((blocked.candidate_hash, para_head)), + ) + .await; + if let Err(fetch_error) = result { gum::debug!( target: LOG_TARGET, - peer_id = ?origin, - ?relay_parent, - ?error, - "Invalid advertisement", + relay_parent = ?blocked.candidate_relay_parent, + para_id = ?para_id, + peer_id = ?blocked.peer_id, + error = %fetch_error, + "Failed to request unblocked collation", ); - - modify_reputation( - &mut state.reputation, - ctx.sender(), - origin, - COST_UNEXPECTED_MESSAGE, - ) - .await; - }, + } + } else { + // Keep the advertisement. + value.push(blocked); } + } + + if !value.is_empty() { + state.blocked_advertisements.insert(key, value); + } + } +} + +async fn handle_advertisement( + sender: &mut Sender, + state: &mut State, + relay_parent: Hash, + peer_id: PeerId, + prospective_candidate: Option<(CandidateHash, Hash)>, +) -> std::result::Result<(), AdvertisementError> +where + Sender: CollatorProtocolSenderTrait, +{ + let _span = state + .span_per_relay_parent + .get(&relay_parent) + .map(|s| s.child("advertise-collation")); + + let per_relay_parent = state + .per_relay_parent + .get(&relay_parent) + .ok_or(AdvertisementError::RelayParentUnknown)?; + + let relay_parent_mode = per_relay_parent.prospective_parachains_mode; + let assignment = &per_relay_parent.assignment; + + let peer_data = state.peer_data.get_mut(&peer_id).ok_or(AdvertisementError::UnknownPeer)?; + let collator_para_id = + peer_data.collating_para().ok_or(AdvertisementError::UndeclaredCollator)?; + + match assignment.current { + Some(id) if id == collator_para_id => { + // Our assignment. }, - CollationSeconded(_, _) => { - gum::warn!( + _ => return Err(AdvertisementError::InvalidAssignment), + }; + + if relay_parent_mode.is_enabled() && prospective_candidate.is_none() { + // Expected vstaging advertisement. + return Err(AdvertisementError::ProtocolMismatch) + } + + // Always insert advertisements that pass all the checks for spam protection. + let candidate_hash = prospective_candidate.map(|(hash, ..)| hash); + let (collator_id, para_id) = peer_data + .insert_advertisement( + relay_parent, + relay_parent_mode, + candidate_hash, + &state.implicit_view, + &state.active_leaves, + ) + .map_err(AdvertisementError::Invalid)?; + if !per_relay_parent.collations.is_seconded_limit_reached(relay_parent_mode) { + return Err(AdvertisementError::SecondedLimitReached) + } + + if let Some((candidate_hash, parent_head_data_hash)) = prospective_candidate { + let is_seconding_allowed = !relay_parent_mode.is_enabled() || + can_second( + sender, + collator_para_id, + relay_parent, + candidate_hash, + parent_head_data_hash, + ) + .await; + + if !is_seconding_allowed { + gum::debug!( target: LOG_TARGET, - peer_id = ?origin, - "Unexpected `CollationSeconded` message, decreasing reputation", + relay_parent = ?relay_parent, + para_id = ?para_id, + ?candidate_hash, + "Seconding is not allowed by backing, queueing advertisement", ); - }, + state + .blocked_advertisements + .entry((collator_para_id, parent_head_data_hash)) + .or_default() + .push(BlockedAdvertisement { + peer_id, + collator_id: collator_id.clone(), + candidate_relay_parent: relay_parent, + candidate_hash, + }); + + return Ok(()) + } } + + let result = enqueue_collation( + sender, + state, + relay_parent, + para_id, + peer_id, + collator_id, + prospective_candidate, + ) + .await; + if let Err(fetch_error) = result { + gum::debug!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + para_id = ?para_id, + peer_id = ?peer_id, + error = %fetch_error, + "Failed to request advertised collation", + ); + } + + Ok(()) } -/// A leaf has become inactive so we want to -/// - Cancel all ongoing collation requests that are on top of that leaf. -/// - Remove all stored collations relevant to that leaf. -async fn remove_relay_parent(state: &mut State, relay_parent: Hash) -> Result<()> { - state.requested_collations.retain(|k, _| k.relay_parent != relay_parent); +/// Enqueue collation for fetching. The advertisement is expected to be +/// validated. +async fn enqueue_collation( + sender: &mut Sender, + state: &mut State, + relay_parent: Hash, + para_id: ParaId, + peer_id: PeerId, + collator_id: CollatorId, + prospective_candidate: Option<(CandidateHash, Hash)>, +) -> std::result::Result<(), FetchError> +where + Sender: CollatorProtocolSenderTrait, +{ + gum::debug!( + target: LOG_TARGET, + peer_id = ?peer_id, + %para_id, + ?relay_parent, + "Received advertise collation", + ); + let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { + Some(rp_state) => rp_state, + None => { + // Race happened, not an error. + gum::trace!( + target: LOG_TARGET, + peer_id = ?peer_id, + %para_id, + ?relay_parent, + ?prospective_candidate, + "Candidate relay parent went out of view for valid advertisement", + ); + return Ok(()) + }, + }; + let relay_parent_mode = per_relay_parent.prospective_parachains_mode; + let prospective_candidate = + prospective_candidate.map(|(candidate_hash, parent_head_data_hash)| ProspectiveCandidate { + candidate_hash, + parent_head_data_hash, + }); + + let collations = &mut per_relay_parent.collations; + if !collations.is_seconded_limit_reached(relay_parent_mode) { + gum::trace!( + target: LOG_TARGET, + peer_id = ?peer_id, + %para_id, + ?relay_parent, + "Limit of seconded collations reached for valid advertisement", + ); + return Ok(()) + } - state.pending_candidates.retain(|k, _| k != &relay_parent); + let pending_collation = + PendingCollation::new(relay_parent, para_id, &peer_id, prospective_candidate); + + match collations.status { + CollationStatus::Fetching | CollationStatus::WaitingOnValidation => { + gum::trace!( + target: LOG_TARGET, + peer_id = ?peer_id, + %para_id, + ?relay_parent, + "Added collation to the pending list" + ); + collations.waiting_queue.push_back((pending_collation, collator_id)); + }, + CollationStatus::Waiting => { + fetch_collation(sender, state, pending_collation, collator_id).await?; + }, + CollationStatus::Seconded if relay_parent_mode.is_enabled() => { + // Limit is not reached, it's allowed to second another + // collation. + fetch_collation(sender, state, pending_collation, collator_id).await?; + }, + CollationStatus::Seconded => { + gum::trace!( + target: LOG_TARGET, + peer_id = ?peer_id, + %para_id, + ?relay_parent, + ?relay_parent_mode, + "A collation has already been seconded", + ); + }, + } - state.collations_per_relay_parent.remove(&relay_parent); Ok(()) } /// Our view has changed. -#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] -async fn handle_our_view_change( - ctx: &mut Context, +async fn handle_our_view_change( + sender: &mut Sender, state: &mut State, keystore: &KeystorePtr, view: OurView, -) -> Result<()> { - let old_view = std::mem::replace(&mut state.view, view); +) -> Result<()> +where + Sender: CollatorProtocolSenderTrait, +{ + let current_leaves = state.active_leaves.clone(); - let added: HashMap> = state - .view - .span_per_head() - .iter() - .filter(|v| !old_view.contains(&v.0)) - .map(|v| (*v.0, v.1.clone())) - .collect(); + let removed = current_leaves.iter().filter(|(h, _)| !view.contains(h)); + let added = view.iter().filter(|h| !current_leaves.contains_key(h)); - added.into_iter().for_each(|(h, s)| { - state.span_per_relay_parent.insert(h, PerLeafSpan::new(s, "validator-side")); - }); + for leaf in added { + let mode = prospective_parachains_mode(sender, *leaf).await?; + + if let Some(span) = view.span_per_head().get(leaf).cloned() { + let per_leaf_span = PerLeafSpan::new(span, "validator-side"); + state.span_per_relay_parent.insert(*leaf, per_leaf_span); + } + + let mut per_relay_parent = PerRelayParent::new(mode); + assign_incoming( + sender, + &mut per_relay_parent.assignment, + &mut state.current_assignments, + keystore, + *leaf, + mode, + ) + .await?; + + state.active_leaves.insert(*leaf, mode); + state.per_relay_parent.insert(*leaf, per_relay_parent); + + if mode.is_enabled() { + state + .implicit_view + .activate_leaf(sender, *leaf) + .await + .map_err(Error::ImplicitViewFetchError)?; + + // Order is always descending. + let allowed_ancestry = state + .implicit_view + .known_allowed_relay_parents_under(leaf, None) + .unwrap_or_default(); + for block_hash in allowed_ancestry { + if let Entry::Vacant(entry) = state.per_relay_parent.entry(*block_hash) { + let mut per_relay_parent = PerRelayParent::new(mode); + assign_incoming( + sender, + &mut per_relay_parent.assignment, + &mut state.current_assignments, + keystore, + *block_hash, + mode, + ) + .await?; + + entry.insert(per_relay_parent); + } + } + } + } - let added = state.view.difference(&old_view).cloned().collect::>(); - let removed = old_view.difference(&state.view).cloned().collect::>(); + for (removed, mode) in removed { + state.active_leaves.remove(removed); + // If the leaf is deactivated it still may stay in the view as a part + // of implicit ancestry. Only update the state after the hash is actually + // pruned from the block info storage. + let pruned = if mode.is_enabled() { + state.implicit_view.deactivate_leaf(*removed) + } else { + vec![*removed] + }; - for removed in removed.iter().cloned() { - remove_relay_parent(state, removed).await?; - state.span_per_relay_parent.remove(&removed); + for removed in pruned { + if let Some(per_relay_parent) = state.per_relay_parent.remove(&removed) { + remove_outgoing(&mut state.current_assignments, per_relay_parent); + } + + state.collation_requests_cancel_handles.retain(|pc, handle| { + let keep = pc.relay_parent != removed; + if !keep { + handle.cancel(); + } + keep + }); + state.fetched_candidates.retain(|k, _| k.relay_parent != removed); + state.span_per_relay_parent.remove(&removed); + } } + // Remove blocked advertisements that left the view. + state.blocked_advertisements.retain(|_, ads| { + ads.retain(|ad| state.per_relay_parent.contains_key(&ad.candidate_relay_parent)); - state.active_paras.assign_incoming(ctx.sender(), keystore, added).await; - state.active_paras.remove_outgoing(removed); + !ads.is_empty() + }); + // Re-trigger previously failed requests again. + // + // This makes sense for several reasons, one simple example: if a hypothetical depth + // for an advertisement initially exceeded the limit and the candidate was included + // in a new leaf. + let maybe_unblocked = std::mem::take(&mut state.blocked_advertisements); + // Could be optimized to only sanity check new leaves. + request_unblocked_collations(sender, state, maybe_unblocked).await; for (peer_id, peer_data) in state.peer_data.iter_mut() { - peer_data.prune_old_advertisements(&state.view); + peer_data.prune_old_advertisements( + &state.implicit_view, + &state.active_leaves, + &state.per_relay_parent, + ); // Disconnect peers who are not relevant to our current or next para. // // If the peer hasn't declared yet, they will be disconnected if they do not // declare. if let Some(para_id) = peer_data.collating_para() { - if !state.active_paras.is_current(¶_id) { + if !state.current_assignments.contains_key(¶_id) { gum::trace!( target: LOG_TARGET, ?peer_id, ?para_id, "Disconnecting peer on view change (not current parachain id)" ); - disconnect_peer(ctx.sender(), *peer_id).await; + disconnect_peer(sender, *peer_id).await; } } } @@ -1112,8 +1391,26 @@ async fn handle_network_msg( use NetworkBridgeEvent::*; match bridge_message { - PeerConnected(peer_id, _role, _version, _) => { - state.peer_data.entry(peer_id).or_default(); + PeerConnected(peer_id, observed_role, protocol_version, _) => { + let version = match protocol_version.try_into() { + Ok(version) => version, + Err(err) => { + // Network bridge is expected to handle this. + gum::error!( + target: LOG_TARGET, + ?peer_id, + ?observed_role, + ?err, + "Unsupported protocol version" + ); + return Ok(()) + }, + }; + state.peer_data.entry(peer_id).or_insert_with(|| PeerData { + view: View::default(), + state: PeerState::Connected(Instant::now()), + version, + }); state.metrics.note_collator_peer_count(state.peer_data.len()); }, PeerDisconnected(peer_id) => { @@ -1124,12 +1421,12 @@ async fn handle_network_msg( // impossible! }, PeerViewChange(peer_id, view) => { - handle_peer_view_change(state, peer_id, view).await?; + handle_peer_view_change(state, peer_id, view); }, OurViewChange(view) => { - handle_our_view_change(ctx, state, keystore, view).await?; + handle_our_view_change(ctx.sender(), state, keystore, view).await?; }, - PeerMessage(remote, Versioned::V1(msg)) => { + PeerMessage(remote, msg) => { process_incoming_peer_message(ctx, state, remote, msg).await; }, UpdatedAuthorityIds { .. } => { @@ -1160,7 +1457,7 @@ async fn process_msg( "CollateOn message is not expected on the validator side of the protocol", ); }, - DistributeCollation(_, _, _) => { + DistributeCollation(..) => { gum::warn!( target: LOG_TARGET, "DistributeCollation message is not expected on the validator side of the protocol", @@ -1179,28 +1476,56 @@ async fn process_msg( } }, Seconded(parent, stmt) => { - if let Some(collation_event) = state.pending_candidates.remove(&parent) { - let (collator_id, pending_collation) = collation_event; - let PendingCollation { relay_parent, peer_id, .. } = pending_collation; + let receipt = match stmt.payload() { + Statement::Seconded(receipt) => receipt, + Statement::Valid(_) => { + gum::warn!( + target: LOG_TARGET, + ?stmt, + relay_parent = %parent, + "Seconded message received with a `Valid` statement", + ); + return + }, + }; + let fetched_collation = FetchedCollation::from(&receipt.to_plain()); + if let Some(CollationEvent { collator_id, pending_collation }) = + state.fetched_candidates.remove(&fetched_collation) + { + let PendingCollation { relay_parent, peer_id, prospective_candidate, .. } = + pending_collation; note_good_collation( &mut state.reputation, ctx.sender(), &state.peer_data, - collator_id, - ) - .await; - notify_collation_seconded( - &mut state.reputation, - ctx.sender(), - peer_id, - relay_parent, - stmt, + collator_id.clone(), ) .await; + if let Some(peer_data) = state.peer_data.get(&peer_id) { + notify_collation_seconded( + ctx.sender(), + peer_id, + peer_data.version, + relay_parent, + stmt, + ) + .await; + } - if let Some(collations) = state.collations_per_relay_parent.get_mut(&parent) { - collations.status = CollationStatus::Seconded; + if let Some(rp_state) = state.per_relay_parent.get_mut(&parent) { + rp_state.collations.status = CollationStatus::Seconded; + rp_state.collations.note_seconded(); } + // If async backing is enabled, make an attempt to fetch next collation. + let maybe_candidate_hash = + prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); + dequeue_next_collation_and_fetch( + ctx, + state, + parent, + (collator_id, maybe_candidate_hash), + ) + .await; } else { gum::debug!( target: LOG_TARGET, @@ -1209,12 +1534,18 @@ async fn process_msg( ); } }, + Backed { para_id, para_head } => { + let maybe_unblocked = state.blocked_advertisements.remove_entry(&(para_id, para_head)); + request_unblocked_collations(ctx.sender(), state, maybe_unblocked).await; + }, Invalid(parent, candidate_receipt) => { - let id = match state.pending_candidates.entry(parent) { + let fetched_collation = FetchedCollation::from(&candidate_receipt); + let candidate_hash = fetched_collation.candidate_hash; + let id = match state.fetched_candidates.entry(fetched_collation) { Entry::Occupied(entry) - if entry.get().1.commitments_hash == + if entry.get().pending_collation.commitments_hash == Some(candidate_receipt.commitments_hash) => - entry.remove().0, + entry.remove().collator_id, Entry::Occupied(_) => { gum::error!( target: LOG_TARGET, @@ -1230,7 +1561,7 @@ async fn process_msg( report_collator(&mut state.reputation, ctx.sender(), &state.peer_data, id.clone()) .await; - dequeue_next_collation_and_fetch(ctx, state, parent, id).await; + dequeue_next_collation_and_fetch(ctx, state, parent, (id, Some(candidate_hash))).await; }, } } @@ -1271,9 +1602,6 @@ async fn run_inner( let next_inactivity_stream = tick_stream(ACTIVITY_POLL); futures::pin_mut!(next_inactivity_stream); - let check_collations_stream = tick_stream(CHECK_COLLATIONS_POLL); - futures::pin_mut!(check_collations_stream); - let mut network_error_freq = gum::Freq::new(); let mut canceled_freq = gum::Freq::new(); @@ -1301,157 +1629,227 @@ async fn run_inner( _ = next_inactivity_stream.next() => { disconnect_inactive_peers(ctx.sender(), &eviction_policy, &state.peer_data).await; } - res = state.collation_fetches.select_next_some() => { - handle_collation_fetched_result(&mut ctx, &mut state, res).await; + + resp = state.collation_requests.select_next_some() => { + let res = match handle_collation_fetch_response( + &mut state, + resp, + &mut network_error_freq, + &mut canceled_freq, + ).await { + Err(Some((peer_id, rep))) => { + modify_reputation(&mut state.reputation, ctx.sender(), peer_id, rep).await; + continue + }, + Err(None) => { + continue + }, + Ok(res) => res + }; + + let CollationEvent {collator_id, pending_collation} = res.collation_event.clone(); + if let Err(err) = kick_off_seconding(&mut ctx, &mut state, res).await { + gum::warn!( + target: LOG_TARGET, + relay_parent = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + error = %err, + "Seconding aborted due to an error", + ); + + if err.is_malicious() { + // Report malicious peer. + modify_reputation(&mut state.reputation, ctx.sender(), pending_collation.peer_id, COST_REPORT_BAD).await; + } + let maybe_candidate_hash = + pending_collation.prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); + dequeue_next_collation_and_fetch( + &mut ctx, + &mut state, + pending_collation.relay_parent, + (collator_id, maybe_candidate_hash), + ) + .await; + } } res = state.collation_fetch_timeouts.select_next_some() => { - let (collator_id, relay_parent) = res; + let (collator_id, maybe_candidate_hash, relay_parent) = res; gum::debug!( target: LOG_TARGET, ?relay_parent, ?collator_id, "Timeout hit - already seconded?" ); - dequeue_next_collation_and_fetch(&mut ctx, &mut state, relay_parent, collator_id).await; + dequeue_next_collation_and_fetch( + &mut ctx, + &mut state, + relay_parent, + (collator_id, maybe_candidate_hash), + ) + .await; } - _ = check_collations_stream.next() => { - let reputation_changes = poll_requests( - &mut state.requested_collations, - &state.metrics, - &state.span_per_relay_parent, - &mut network_error_freq, - &mut canceled_freq, - ).await; - - for (peer_id, rep) in reputation_changes { - modify_reputation(&mut state.reputation,ctx.sender(), peer_id, rep).await; - } - }, } } Ok(()) } -async fn poll_requests( - requested_collations: &mut HashMap, - metrics: &Metrics, - span_per_relay_parent: &HashMap, - network_error_freq: &mut gum::Freq, - canceled_freq: &mut gum::Freq, -) -> Vec<(PeerId, Rep)> { - let mut retained_requested = HashSet::new(); - let mut reputation_changes = Vec::new(); - for (pending_collation, per_req) in requested_collations.iter_mut() { - // Despite the await, this won't block on the response itself. - let result = poll_collation_response( - metrics, - span_per_relay_parent, - pending_collation, - per_req, - network_error_freq, - canceled_freq, - ) - .await; - - if !result.is_ready() { - retained_requested.insert(pending_collation.clone()); - } - if let CollationFetchResult::Error(Some(rep)) = result { - reputation_changes.push((pending_collation.peer_id, rep)); - } - } - requested_collations.retain(|k, _| retained_requested.contains(k)); - reputation_changes -} - /// Dequeue another collation and fetch. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn dequeue_next_collation_and_fetch( ctx: &mut Context, state: &mut State, relay_parent: Hash, - // The collator we tried to fetch from last. - previous_fetch: CollatorId, + // The collator we tried to fetch from last, optionally which candidate. + previous_fetch: (CollatorId, Option), ) { - if let Some((next, id)) = state - .collations_per_relay_parent - .get_mut(&relay_parent) - .and_then(|c| c.get_next_collation_to_fetch(Some(&previous_fetch))) - { + while let Some((next, id)) = state.per_relay_parent.get_mut(&relay_parent).and_then(|state| { + state + .collations + .get_next_collation_to_fetch(&previous_fetch, state.prospective_parachains_mode) + }) { gum::debug!( target: LOG_TARGET, ?relay_parent, ?id, "Successfully dequeued next advertisement - fetching ..." ); - fetch_collation(ctx.sender(), state, next, id).await; - } else { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - previous_collator = ?previous_fetch, - "No collations are available to fetch" - ); + if let Err(err) = fetch_collation(ctx.sender(), state, next, id).await { + gum::debug!( + target: LOG_TARGET, + relay_parent = ?next.relay_parent, + para_id = ?next.para_id, + peer_id = ?next.peer_id, + error = %err, + "Failed to request a collation, dequeueing next one", + ); + } else { + break + } } } +async fn request_persisted_validation_data( + sender: &mut Sender, + relay_parent: Hash, + para_id: ParaId, +) -> std::result::Result, SecondingError> +where + Sender: CollatorProtocolSenderTrait, +{ + // The core is guaranteed to be scheduled since we accepted the advertisement. + polkadot_node_subsystem_util::request_persisted_validation_data( + relay_parent, + para_id, + OccupiedCoreAssumption::Free, + sender, + ) + .await + .await + .map_err(SecondingError::CancelledRuntimePersistedValidationData)? + .map_err(SecondingError::RuntimeApi) +} + +async fn request_prospective_validation_data( + sender: &mut Sender, + candidate_relay_parent: Hash, + parent_head_data_hash: Hash, + para_id: ParaId, +) -> std::result::Result, SecondingError> +where + Sender: CollatorProtocolSenderTrait, +{ + let (tx, rx) = oneshot::channel(); + + let request = + ProspectiveValidationDataRequest { para_id, candidate_relay_parent, parent_head_data_hash }; + + sender + .send_message(ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx)) + .await; + + rx.await.map_err(SecondingError::CancelledProspectiveValidationData) +} + /// Handle a fetched collation result. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] -async fn handle_collation_fetched_result( +async fn kick_off_seconding( ctx: &mut Context, state: &mut State, - (mut collation_event, res): PendingCollationFetch, -) { - // If no prior collation for this relay parent has been seconded, then - // memorize the `collation_event` for that `relay_parent`, such that we may - // notify the collator of their successful second backing - let relay_parent = collation_event.1.relay_parent; - - let (candidate_receipt, pov) = match res { - Ok(res) => res, - Err(e) => { - gum::debug!( + PendingCollationFetch { mut collation_event, candidate_receipt, pov }: PendingCollationFetch, +) -> std::result::Result<(), SecondingError> { + let pending_collation = collation_event.pending_collation; + let relay_parent = pending_collation.relay_parent; + + let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { + Some(state) => state, + None => { + // Relay parent went out of view, not an error. + gum::trace!( target: LOG_TARGET, - relay_parent = ?collation_event.1.relay_parent, - para_id = ?collation_event.1.para_id, - peer_id = ?collation_event.1.peer_id, - collator_id = ?collation_event.0, - error = ?e, - "Failed to fetch collation.", + relay_parent = ?relay_parent, + "Fetched collation for a parent out of view", ); - - dequeue_next_collation_and_fetch(ctx, state, relay_parent, collation_event.0).await; - return + return Ok(()) }, }; - - if let Some(collations) = state.collations_per_relay_parent.get_mut(&relay_parent) { - if let CollationStatus::Seconded = collations.status { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - "Already seconded - no longer interested in collation fetch result." - ); - return - } + let collations = &mut per_relay_parent.collations; + let relay_parent_mode = per_relay_parent.prospective_parachains_mode; + + let fetched_collation = FetchedCollation::from(&candidate_receipt); + if let Entry::Vacant(entry) = state.fetched_candidates.entry(fetched_collation) { + collation_event.pending_collation.commitments_hash = + Some(candidate_receipt.commitments_hash); + + let pvd = + match (relay_parent_mode, collation_event.pending_collation.prospective_candidate) { + ( + ProspectiveParachainsMode::Enabled { .. }, + Some(ProspectiveCandidate { parent_head_data_hash, .. }), + ) => + request_prospective_validation_data( + ctx.sender(), + relay_parent, + parent_head_data_hash, + pending_collation.para_id, + ) + .await?, + (ProspectiveParachainsMode::Disabled, _) => + request_persisted_validation_data( + ctx.sender(), + candidate_receipt.descriptor().relay_parent, + candidate_receipt.descriptor().para_id, + ) + .await?, + _ => { + // `handle_advertisement` checks for protocol mismatch. + return Ok(()) + }, + } + .ok_or(SecondingError::PersistedValidationDataNotFound)?; + + fetched_collation_sanity_check( + &collation_event.pending_collation, + &candidate_receipt, + &pvd, + )?; + + ctx.send_message(CandidateBackingMessage::Second( + relay_parent, + candidate_receipt, + pvd, + pov, + )) + .await; + // There's always a single collation being fetched at any moment of time. + // In case of a failure, we reset the status back to waiting. collations.status = CollationStatus::WaitingOnValidation; - } - - if let Entry::Vacant(entry) = state.pending_candidates.entry(relay_parent) { - collation_event.1.commitments_hash = Some(candidate_receipt.commitments_hash); - ctx.sender() - .send_message(CandidateBackingMessage::Second(relay_parent, candidate_receipt, pov)) - .await; entry.insert(collation_event); + Ok(()) } else { - gum::trace!( - target: LOG_TARGET, - ?relay_parent, - candidate = ?candidate_receipt.hash(), - "Trying to insert a pending candidate failed, because there is already one.", - ) + Err(SecondingError::Duplicate) } } @@ -1471,153 +1869,125 @@ async fn disconnect_inactive_peers( } } -enum CollationFetchResult { - /// The collation is still being fetched. - Pending, - /// The collation was fetched successfully. - Success, - /// An error occurred when fetching a collation or it was invalid. - /// A given reputation change should be applied to the peer. - Error(Option), -} - -impl CollationFetchResult { - fn is_ready(&self) -> bool { - !matches!(self, Self::Pending) - } -} - -/// Poll collation response, return immediately if there is none. -/// -/// Ready responses are handled, by logging and by -/// forwarding proper responses to the requester. -async fn poll_collation_response( - metrics: &Metrics, - spans: &HashMap, - pending_collation: &PendingCollation, - per_req: &mut PerRequest, +/// Handle a collation fetch response. +async fn handle_collation_fetch_response( + state: &mut State, + response: ::Output, network_error_freq: &mut gum::Freq, canceled_freq: &mut gum::Freq, -) -> CollationFetchResult { - if never!(per_req.from_collator.is_terminated()) { - gum::error!( - target: LOG_TARGET, - "We remove pending responses once received, this should not happen." - ); - return CollationFetchResult::Success - } - - if let Poll::Ready(response) = futures::poll!(&mut per_req.from_collator) { - let _span = spans - .get(&pending_collation.relay_parent) - .map(|s| s.child("received-collation")); - let _timer = metrics.time_handle_collation_request_result(); - - let mut metrics_result = Err(()); - let mut success = "false"; +) -> std::result::Result> { + let (CollationEvent { collator_id, pending_collation }, response) = response; + // Remove the cancellation handle, as the future already completed. + state.collation_requests_cancel_handles.remove(&pending_collation); - let result = match response { - Err(RequestError::InvalidResponse(err)) => { - gum::warn!( - target: LOG_TARGET, - hash = ?pending_collation.relay_parent, - para_id = ?pending_collation.para_id, - peer_id = ?pending_collation.peer_id, - err = ?err, - "Collator provided response that could not be decoded" - ); - CollationFetchResult::Error(Some(COST_CORRUPTED_MESSAGE)) - }, - Err(err) if err.is_timed_out() => { - gum::debug!( - target: LOG_TARGET, - hash = ?pending_collation.relay_parent, - para_id = ?pending_collation.para_id, - peer_id = ?pending_collation.peer_id, - "Request timed out" - ); - // For now we don't want to change reputation on timeout, to mitigate issues like - // this: https://github.com/paritytech/polkadot/issues/4617 - CollationFetchResult::Error(None) - }, - Err(RequestError::NetworkError(err)) => { - gum::warn_if_frequent!( - freq: network_error_freq, - max_rate: gum::Times::PerHour(100), - target: LOG_TARGET, - hash = ?pending_collation.relay_parent, - para_id = ?pending_collation.para_id, - peer_id = ?pending_collation.peer_id, - err = ?err, - "Fetching collation failed due to network error" - ); - // A minor decrease in reputation for any network failure seems - // sensible. In theory this could be exploited, by DoSing this node, - // which would result in reduced reputation for proper nodes, but the - // same can happen for penalties on timeouts, which we also have. - CollationFetchResult::Error(Some(COST_NETWORK_ERROR)) - }, - Err(RequestError::Canceled(err)) => { - gum::warn_if_frequent!( - freq: canceled_freq, - max_rate: gum::Times::PerHour(100), - target: LOG_TARGET, - hash = ?pending_collation.relay_parent, - para_id = ?pending_collation.para_id, - peer_id = ?pending_collation.peer_id, - err = ?err, - "Canceled should be handled by `is_timed_out` above - this is a bug!" - ); - CollationFetchResult::Error(None) - }, - Ok(CollationFetchingResponse::Collation(receipt, _)) - if receipt.descriptor().para_id != pending_collation.para_id => - { - gum::debug!( - target: LOG_TARGET, - expected_para_id = ?pending_collation.para_id, - got_para_id = ?receipt.descriptor().para_id, - peer_id = ?pending_collation.peer_id, - "Got wrong para ID for requested collation." - ); + let response = match response { + Err(CollationFetchError::Cancelled) => { + gum::debug!( + target: LOG_TARGET, + hash = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + "Request was cancelled from the validator side" + ); + return Err(None) + }, + Err(CollationFetchError::Request(req_error)) => Err(req_error), + Ok(resp) => Ok(resp), + }; - CollationFetchResult::Error(Some(COST_WRONG_PARA)) - }, - Ok(CollationFetchingResponse::Collation(receipt, pov)) => { - gum::debug!( - target: LOG_TARGET, - para_id = %pending_collation.para_id, - hash = ?pending_collation.relay_parent, - candidate_hash = ?receipt.hash(), - "Received collation", - ); - // Actual sending: - let _span = jaeger::Span::new(&pov, "received-collation"); - let (mut tx, _) = oneshot::channel(); - std::mem::swap(&mut tx, &mut (per_req.to_requester)); - let result = tx.send((receipt, pov)); + let _span = state + .span_per_relay_parent + .get(&pending_collation.relay_parent) + .map(|s| s.child("received-collation")); + let _timer = state.metrics.time_handle_collation_request_result(); - if let Err(_) = result { - gum::warn!( - target: LOG_TARGET, - hash = ?pending_collation.relay_parent, - para_id = ?pending_collation.para_id, - peer_id = ?pending_collation.peer_id, - "Sending response back to requester failed (receiving side closed)" - ); - } else { - metrics_result = Ok(()); - success = "true"; - } + let mut metrics_result = Err(()); - CollationFetchResult::Success - }, - }; - metrics.on_request(metrics_result); - per_req.span.as_mut().map(|s| s.add_string_tag("success", success)); + let result = match response { + Err(RequestError::InvalidResponse(err)) => { + gum::warn!( + target: LOG_TARGET, + hash = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + err = ?err, + "Collator provided response that could not be decoded" + ); + Err(Some((pending_collation.peer_id, COST_CORRUPTED_MESSAGE))) + }, + Err(err) if err.is_timed_out() => { + gum::debug!( + target: LOG_TARGET, + hash = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + "Request timed out" + ); + // For now we don't want to change reputation on timeout, to mitigate issues like + // this: https://github.com/paritytech/polkadot/issues/4617 + Err(None) + }, + Err(RequestError::NetworkError(err)) => { + gum::warn_if_frequent!( + freq: network_error_freq, + max_rate: gum::Times::PerHour(100), + target: LOG_TARGET, + hash = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + err = ?err, + "Fetching collation failed due to network error" + ); + // A minor decrease in reputation for any network failure seems + // sensible. In theory this could be exploited, by DoSing this node, + // which would result in reduced reputation for proper nodes, but the + // same can happen for penalties on timeouts, which we also have. + Err(Some((pending_collation.peer_id, COST_NETWORK_ERROR))) + }, + Err(RequestError::Canceled(err)) => { + gum::warn_if_frequent!( + freq: canceled_freq, + max_rate: gum::Times::PerHour(100), + target: LOG_TARGET, + hash = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + err = ?err, + "Canceled should be handled by `is_timed_out` above - this is a bug!" + ); + Err(None) + }, + Ok(request_v1::CollationFetchingResponse::Collation(receipt, _)) + if receipt.descriptor().para_id != pending_collation.para_id => + { + gum::debug!( + target: LOG_TARGET, + expected_para_id = ?pending_collation.para_id, + got_para_id = ?receipt.descriptor().para_id, + peer_id = ?pending_collation.peer_id, + "Got wrong para ID for requested collation." + ); - result - } else { - CollationFetchResult::Pending - } + Err(Some((pending_collation.peer_id, COST_WRONG_PARA))) + }, + Ok(request_v1::CollationFetchingResponse::Collation(candidate_receipt, pov)) => { + gum::debug!( + target: LOG_TARGET, + para_id = %pending_collation.para_id, + hash = ?pending_collation.relay_parent, + candidate_hash = ?candidate_receipt.hash(), + "Received collation", + ); + let _span = jaeger::Span::new(&pov, "received-collation"); + + metrics_result = Ok(()); + Ok(PendingCollationFetch { + collation_event: CollationEvent { collator_id, pending_collation }, + candidate_receipt, + pov, + }) + }, + }; + state.metrics.on_request(metrics_result); + result } diff --git a/node/network/collator-protocol/src/validator_side/tests.rs b/node/network/collator-protocol/src/validator_side/tests/mod.rs similarity index 70% rename from node/network/collator-protocol/src/validator_side/tests.rs rename to node/network/collator-protocol/src/validator_side/tests/mod.rs index e921e6c38c3e..1cb656e325d3 100644 --- a/node/network/collator-protocol/src/validator_side/tests.rs +++ b/node/network/collator-protocol/src/validator_side/tests/mod.rs @@ -19,8 +19,8 @@ use assert_matches::assert_matches; use futures::{executor, future, Future}; use sp_core::{crypto::Pair, Encode}; use sp_keyring::Sr25519Keyring; -use sp_keystore::{testing::MemoryKeystore, Keystore}; -use std::{iter, sync::Arc, task::Poll, time::Duration}; +use sp_keystore::Keystore; +use std::{iter, sync::Arc, time::Duration}; use polkadot_node_network_protocol::{ our_view, @@ -28,24 +28,39 @@ use polkadot_node_network_protocol::{ request_response::{Requests, ResponseSender}, ObservedRole, }; -use polkadot_node_primitives::BlockData; -use polkadot_node_subsystem::messages::{ - AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest, +use polkadot_node_primitives::{BlockData, PoV}; +use polkadot_node_subsystem::{ + errors::RuntimeApiError, + messages::{AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest}, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - CollatorPair, CoreState, GroupIndex, GroupRotationInfo, OccupiedCore, ScheduledCore, - ValidatorId, ValidatorIndex, + CandidateReceipt, CollatorPair, CoreState, GroupIndex, GroupRotationInfo, HeadData, + OccupiedCore, PersistedValidationData, ScheduledCore, ValidatorId, ValidatorIndex, }; use polkadot_primitives_test_helpers::{ dummy_candidate_descriptor, dummy_candidate_receipt_bad_sig, dummy_hash, }; +mod prospective_parachains; + const ACTIVITY_TIMEOUT: Duration = Duration::from_millis(500); const DECLARE_TIMEOUT: Duration = Duration::from_millis(25); const REPUTATION_CHANGE_TEST_INTERVAL: Duration = Duration::from_millis(10); +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; + +fn dummy_pvd() -> PersistedValidationData { + PersistedValidationData { + parent_head: HeadData(vec![7, 8, 9]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + } +} + #[derive(Clone)] struct TestState { chain_ids: Vec, @@ -120,6 +135,7 @@ type VirtualOverseer = test_helpers::TestSubsystemContextHandle>( @@ -136,17 +152,17 @@ fn test_harness>( let (context, virtual_overseer) = test_helpers::make_subsystem_context(pool.clone()); - let keystore = MemoryKeystore::new(); - keystore - .sr25519_generate_new( - polkadot_primitives::PARACHAIN_KEY_TYPE_ID, - Some(&Sr25519Keyring::Alice.to_seed()), - ) - .unwrap(); + let keystore = Arc::new(sc_keystore::LocalKeystore::in_memory()); + Keystore::sr25519_generate_new( + &*keystore, + polkadot_primitives::PARACHAIN_KEY_TYPE_ID, + Some(&Sr25519Keyring::Alice.to_seed()), + ) + .expect("Insert key into keystore"); let subsystem = run_inner( context, - Arc::new(keystore), + keystore.clone(), crate::CollatorEvictionPolicy { inactive_collator: ACTIVITY_TIMEOUT, undeclared: DECLARE_TIMEOUT, @@ -156,7 +172,7 @@ fn test_harness>( REPUTATION_CHANGE_TEST_INTERVAL, ); - let test_fut = test(TestHarness { virtual_overseer }); + let test_fut = test(TestHarness { virtual_overseer, keystore }); futures::pin_mut!(test_fut); futures::pin_mut!(subsystem); @@ -253,16 +269,53 @@ async fn assert_candidate_backing_second( expected_relay_parent: Hash, expected_para_id: ParaId, expected_pov: &PoV, + mode: ProspectiveParachainsMode, ) -> CandidateReceipt { + let pvd = dummy_pvd(); + + // Depending on relay parent mode pvd will be either requested + // from the Runtime API or Prospective Parachains. + let msg = overseer_recv(virtual_overseer).await; + match mode { + ProspectiveParachainsMode::Disabled => assert_matches!( + msg, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::PersistedValidationData(para_id, assumption, tx), + )) => { + assert_eq!(expected_relay_parent, hash); + assert_eq!(expected_para_id, para_id); + assert_eq!(OccupiedCoreAssumption::Free, assumption); + tx.send(Ok(Some(pvd.clone()))).unwrap(); + } + ), + ProspectiveParachainsMode::Enabled { .. } => assert_matches!( + msg, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), + ) => { + assert_eq!(expected_relay_parent, request.candidate_relay_parent); + assert_eq!(expected_para_id, request.para_id); + tx.send(Some(pvd.clone())).unwrap(); + } + ), + } + assert_matches!( overseer_recv(virtual_overseer).await, - AllMessages::CandidateBacking(CandidateBackingMessage::Second(relay_parent, candidate_receipt, incoming_pov) - ) => { - assert_eq!(expected_relay_parent, relay_parent); - assert_eq!(expected_para_id, candidate_receipt.descriptor.para_id); - assert_eq!(*expected_pov, incoming_pov); - candidate_receipt - }) + AllMessages::CandidateBacking(CandidateBackingMessage::Second( + relay_parent, + candidate_receipt, + received_pvd, + incoming_pov, + )) => { + assert_eq!(expected_relay_parent, relay_parent); + assert_eq!(expected_para_id, candidate_receipt.descriptor.para_id); + assert_eq!(*expected_pov, incoming_pov); + assert_eq!(pvd, received_pvd); + candidate_receipt + } + ) } /// Assert that a collator got disconnected. @@ -284,6 +337,7 @@ async fn assert_fetch_collation_request( virtual_overseer: &mut VirtualOverseer, relay_parent: Hash, para_id: ParaId, + candidate_hash: Option, ) -> ResponseSender { assert_matches!( overseer_recv(virtual_overseer).await, @@ -291,14 +345,26 @@ async fn assert_fetch_collation_request( ) => { let req = reqs.into_iter().next() .expect("There should be exactly one request"); - match req { - Requests::CollationFetchingV1(req) => { - let payload = req.payload; - assert_eq!(payload.relay_parent, relay_parent); - assert_eq!(payload.para_id, para_id); - req.pending_response - } - _ => panic!("Unexpected request"), + match candidate_hash { + None => assert_matches!( + req, + Requests::CollationFetchingV1(req) => { + let payload = req.payload; + assert_eq!(payload.relay_parent, relay_parent); + assert_eq!(payload.para_id, para_id); + req.pending_response + } + ), + Some(candidate_hash) => assert_matches!( + req, + Requests::CollationFetchingVStaging(req) => { + let payload = req.payload; + assert_eq!(payload.relay_parent, relay_parent); + assert_eq!(payload.para_id, para_id); + assert_eq!(payload.candidate_hash, candidate_hash); + req.pending_response + } + ), } }) } @@ -309,27 +375,38 @@ async fn connect_and_declare_collator( peer: PeerId, collator: CollatorPair, para_id: ParaId, + version: CollationVersion, ) { overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( peer, ObservedRole::Full, - CollationVersion::V1.into(), + version.into(), None, )), ) .await; - overseer_send( - virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( - peer, - Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( + let wire_message = match version { + CollationVersion::V1 => Versioned::V1(protocol_v1::CollatorProtocolMessage::Declare( + collator.public(), + para_id, + collator.sign(&protocol_v1::declare_signature_payload(&peer)), + )), + CollationVersion::VStaging => + Versioned::VStaging(protocol_vstaging::CollatorProtocolMessage::Declare( collator.public(), para_id, collator.sign(&protocol_v1::declare_signature_payload(&peer)), )), + }; + + overseer_send( + virtual_overseer, + CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( + peer, + wire_message, )), ) .await; @@ -340,24 +417,48 @@ async fn advertise_collation( virtual_overseer: &mut VirtualOverseer, peer: PeerId, relay_parent: Hash, + candidate: Option<(CandidateHash, Hash)>, // Candidate hash + parent head data hash. ) { + let wire_message = match candidate { + Some((candidate_hash, parent_head_data_hash)) => + Versioned::VStaging(protocol_vstaging::CollatorProtocolMessage::AdvertiseCollation { + relay_parent, + candidate_hash, + parent_head_data_hash, + }), + None => + Versioned::V1(protocol_v1::CollatorProtocolMessage::AdvertiseCollation(relay_parent)), + }; overseer_send( virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( peer, - Versioned::V1(protocol_v1::CollatorProtocolMessage::AdvertiseCollation(relay_parent)), + wire_message, )), ) .await; } +async fn assert_async_backing_params_request(virtual_overseer: &mut VirtualOverseer, hash: Hash) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::StagingAsyncBackingParams(tx) + )) => { + assert_eq!(relay_parent, hash); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + } + ); +} + // As we receive a relevant advertisement act on it and issue a collation request. #[test] fn act_on_advertisement() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; gum::trace!("activating"); @@ -370,6 +471,7 @@ fn act_on_advertisement() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -379,15 +481,74 @@ fn act_on_advertisement() { peer_b, pair.clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; assert_fetch_collation_request( &mut virtual_overseer, test_state.relay_parent, test_state.chain_ids[0], + None, + ) + .await; + + virtual_overseer + }); +} + +/// Tests that validator side works with vstaging network protocol +/// before async backing is enabled. +#[test] +fn act_on_advertisement_vstaging() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair = CollatorPair::generate().0; + gum::trace!("activating"); + + overseer_send( + &mut virtual_overseer, + CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( + our_view![test_state.relay_parent], + )), + ) + .await; + + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; + respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + + let peer_b = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_b, + pair.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + + let candidate_hash = CandidateHash::default(); + let parent_head_data_hash = Hash::zero(); + // vstaging advertisement. + advertise_collation( + &mut virtual_overseer, + peer_b, + test_state.relay_parent, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + + assert_fetch_collation_request( + &mut virtual_overseer, + test_state.relay_parent, + test_state.chain_ids[0], + Some(candidate_hash), ) .await; @@ -401,7 +562,7 @@ fn collator_reporting_works() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; overseer_send( &mut virtual_overseer, @@ -411,6 +572,8 @@ fn collator_reporting_works() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; + respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -421,6 +584,7 @@ fn collator_reporting_works() { peer_b, test_state.collators[0].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -429,6 +593,7 @@ fn collator_reporting_works() { peer_c, test_state.collators[1].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -458,7 +623,7 @@ fn collator_authentication_verification_works() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let peer_b = PeerId::random(); @@ -509,20 +674,24 @@ fn fetch_one_collation_at_a_time() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; - + let TestHarness { mut virtual_overseer, .. } = test_harness; let second = Hash::random(); + let our_view = our_view![test_state.relay_parent, second]; + overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent, second], + our_view.clone(), )), ) .await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + // Iter over view since the order may change due to sorted invariant. + for hash in our_view.iter() { + assert_async_backing_params_request(&mut virtual_overseer, *hash).await; + respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + } let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -532,6 +701,7 @@ fn fetch_one_collation_at_a_time() { peer_b, test_state.collators[0].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -540,16 +710,18 @@ fn fetch_one_collation_at_a_time() { peer_c, test_state.collators[1].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; - advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent, None).await; let response_channel = assert_fetch_collation_request( &mut virtual_overseer, test_state.relay_parent, test_state.chain_ids[0], + None, ) .await; @@ -563,10 +735,13 @@ fn fetch_one_collation_at_a_time() { dummy_candidate_receipt_bad_sig(dummy_hash(), Some(Default::default())); candidate_a.descriptor.para_id = test_state.chain_ids[0]; candidate_a.descriptor.relay_parent = test_state.relay_parent; + candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); response_channel - .send(Ok( - CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()).encode() - )) + .send(Ok(request_v1::CollationFetchingResponse::Collation( + candidate_a.clone(), + pov.clone(), + ) + .encode())) .expect("Sending response should succeed"); assert_candidate_backing_second( @@ -574,6 +749,7 @@ fn fetch_one_collation_at_a_time() { test_state.relay_parent, test_state.chain_ids[0], &pov, + ProspectiveParachainsMode::Disabled, ) .await; @@ -581,7 +757,7 @@ fn fetch_one_collation_at_a_time() { test_helpers::Yield::new().await; // Second collation is not requested since there's already seconded one. - assert_matches!(futures::poll!(virtual_overseer.recv().boxed()), Poll::Pending); + assert_matches!(virtual_overseer.recv().now_or_never(), None); virtual_overseer }) @@ -594,20 +770,24 @@ fn fetches_next_collation() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let second = Hash::random(); + let our_view = our_view![test_state.relay_parent, second]; + overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent, second], + our_view.clone(), )), ) .await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + for hash in our_view.iter() { + assert_async_backing_params_request(&mut virtual_overseer, *hash).await; + respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + } let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -618,6 +798,7 @@ fn fetches_next_collation() { peer_b, test_state.collators[2].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -626,6 +807,7 @@ fn fetches_next_collation() { peer_c, test_state.collators[3].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -634,45 +816,64 @@ fn fetches_next_collation() { peer_d, test_state.collators[4].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; - advertise_collation(&mut virtual_overseer, peer_b, second).await; - advertise_collation(&mut virtual_overseer, peer_c, second).await; - advertise_collation(&mut virtual_overseer, peer_d, second).await; + advertise_collation(&mut virtual_overseer, peer_b, second, None).await; + advertise_collation(&mut virtual_overseer, peer_c, second, None).await; + advertise_collation(&mut virtual_overseer, peer_d, second, None).await; // Dropping the response channel should lead to fetching the second collation. - assert_fetch_collation_request(&mut virtual_overseer, second, test_state.chain_ids[0]) - .await; + assert_fetch_collation_request( + &mut virtual_overseer, + second, + test_state.chain_ids[0], + None, + ) + .await; - let response_channel_non_exclusive = - assert_fetch_collation_request(&mut virtual_overseer, second, test_state.chain_ids[0]) - .await; + let response_channel_non_exclusive = assert_fetch_collation_request( + &mut virtual_overseer, + second, + test_state.chain_ids[0], + None, + ) + .await; // Third collator should receive response after that timeout: Delay::new(MAX_UNSHARED_DOWNLOAD_TIME + Duration::from_millis(50)).await; - let response_channel = - assert_fetch_collation_request(&mut virtual_overseer, second, test_state.chain_ids[0]) - .await; + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + second, + test_state.chain_ids[0], + None, + ) + .await; let pov = PoV { block_data: BlockData(vec![1]) }; let mut candidate_a = dummy_candidate_receipt_bad_sig(dummy_hash(), Some(Default::default())); candidate_a.descriptor.para_id = test_state.chain_ids[0]; candidate_a.descriptor.relay_parent = second; + candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); // First request finishes now: response_channel_non_exclusive - .send(Ok( - CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()).encode() - )) + .send(Ok(request_v1::CollationFetchingResponse::Collation( + candidate_a.clone(), + pov.clone(), + ) + .encode())) .expect("Sending response should succeed"); response_channel - .send(Ok( - CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()).encode() - )) + .send(Ok(request_v1::CollationFetchingResponse::Collation( + candidate_a.clone(), + pov.clone(), + ) + .encode())) .expect("Sending response should succeed"); assert_candidate_backing_second( @@ -680,6 +881,7 @@ fn fetches_next_collation() { second, test_state.chain_ids[0], &pov, + ProspectiveParachainsMode::Disabled, ) .await; @@ -692,7 +894,7 @@ fn reject_connection_to_next_group() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; overseer_send( &mut virtual_overseer, @@ -702,6 +904,7 @@ fn reject_connection_to_next_group() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -711,6 +914,7 @@ fn reject_connection_to_next_group() { peer_b, test_state.collators[0].clone(), test_state.chain_ids[1], // next, not current `para_id` + CollationVersion::V1, ) .await; @@ -737,20 +941,24 @@ fn fetch_next_collation_on_invalid_collation() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let second = Hash::random(); + let our_view = our_view![test_state.relay_parent, second]; + overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent, second], + our_view.clone(), )), ) .await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + for hash in our_view.iter() { + assert_async_backing_params_request(&mut virtual_overseer, *hash).await; + respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + } let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -760,6 +968,7 @@ fn fetch_next_collation_on_invalid_collation() { peer_b, test_state.collators[0].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -768,16 +977,18 @@ fn fetch_next_collation_on_invalid_collation() { peer_c, test_state.collators[1].clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; - advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent, None).await; let response_channel = assert_fetch_collation_request( &mut virtual_overseer, test_state.relay_parent, test_state.chain_ids[0], + None, ) .await; @@ -786,10 +997,13 @@ fn fetch_next_collation_on_invalid_collation() { dummy_candidate_receipt_bad_sig(dummy_hash(), Some(Default::default())); candidate_a.descriptor.para_id = test_state.chain_ids[0]; candidate_a.descriptor.relay_parent = test_state.relay_parent; + candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); response_channel - .send(Ok( - CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()).encode() - )) + .send(Ok(request_v1::CollationFetchingResponse::Collation( + candidate_a.clone(), + pov.clone(), + ) + .encode())) .expect("Sending response should succeed"); let receipt = assert_candidate_backing_second( @@ -797,6 +1011,7 @@ fn fetch_next_collation_on_invalid_collation() { test_state.relay_parent, test_state.chain_ids[0], &pov, + ProspectiveParachainsMode::Disabled, ) .await; @@ -822,6 +1037,7 @@ fn fetch_next_collation_on_invalid_collation() { &mut virtual_overseer, test_state.relay_parent, test_state.chain_ids[0], + None, ) .await; @@ -834,7 +1050,7 @@ fn inactive_disconnected() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; @@ -848,6 +1064,7 @@ fn inactive_disconnected() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, hash_a).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -857,14 +1074,16 @@ fn inactive_disconnected() { peer_b, pair.clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent).await; + advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; assert_fetch_collation_request( &mut virtual_overseer, test_state.relay_parent, test_state.chain_ids[0], + None, ) .await; @@ -880,7 +1099,7 @@ fn activity_extends_life() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; @@ -888,18 +1107,20 @@ fn activity_extends_life() { let hash_b = Hash::repeat_byte(1); let hash_c = Hash::repeat_byte(2); + let our_view = our_view![hash_a, hash_b, hash_c]; + overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![hash_a, hash_b, hash_c], + our_view.clone(), )), ) .await; - // 3 heads, 3 times. - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + for hash in our_view.iter() { + assert_async_backing_params_request(&mut virtual_overseer, *hash).await; + respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + } let peer_b = PeerId::random(); @@ -908,29 +1129,45 @@ fn activity_extends_life() { peer_b, pair.clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; Delay::new(ACTIVITY_TIMEOUT * 2 / 3).await; - advertise_collation(&mut virtual_overseer, peer_b, hash_a).await; + advertise_collation(&mut virtual_overseer, peer_b, hash_a, None).await; - assert_fetch_collation_request(&mut virtual_overseer, hash_a, test_state.chain_ids[0]) - .await; + assert_fetch_collation_request( + &mut virtual_overseer, + hash_a, + test_state.chain_ids[0], + None, + ) + .await; Delay::new(ACTIVITY_TIMEOUT * 2 / 3).await; - advertise_collation(&mut virtual_overseer, peer_b, hash_b).await; + advertise_collation(&mut virtual_overseer, peer_b, hash_b, None).await; - assert_fetch_collation_request(&mut virtual_overseer, hash_b, test_state.chain_ids[0]) - .await; + assert_fetch_collation_request( + &mut virtual_overseer, + hash_b, + test_state.chain_ids[0], + None, + ) + .await; Delay::new(ACTIVITY_TIMEOUT * 2 / 3).await; - advertise_collation(&mut virtual_overseer, peer_b, hash_c).await; + advertise_collation(&mut virtual_overseer, peer_b, hash_c, None).await; - assert_fetch_collation_request(&mut virtual_overseer, hash_c, test_state.chain_ids[0]) - .await; + assert_fetch_collation_request( + &mut virtual_overseer, + hash_c, + test_state.chain_ids[0], + None, + ) + .await; Delay::new(ACTIVITY_TIMEOUT * 3 / 2).await; @@ -945,7 +1182,7 @@ fn disconnect_if_no_declare() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; overseer_send( &mut virtual_overseer, @@ -955,6 +1192,7 @@ fn disconnect_if_no_declare() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -981,7 +1219,7 @@ fn disconnect_if_wrong_declare() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; @@ -993,6 +1231,7 @@ fn disconnect_if_wrong_declare() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1042,7 +1281,7 @@ fn delay_reputation_change() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| false), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; @@ -1054,6 +1293,7 @@ fn delay_reputation_change() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1127,7 +1367,7 @@ fn view_change_clears_old_collators() { let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer } = test_harness; + let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; @@ -1139,6 +1379,7 @@ fn view_change_clears_old_collators() { ) .await; + assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1148,6 +1389,7 @@ fn view_change_clears_old_collators() { peer_b, pair.clone(), test_state.chain_ids[0], + CollationVersion::V1, ) .await; @@ -1162,6 +1404,7 @@ fn view_change_clears_old_collators() { .await; test_state.group_rotation_info = test_state.group_rotation_info.bump_rotation(); + assert_async_backing_params_request(&mut virtual_overseer, hash_b).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; assert_collator_disconnect(&mut virtual_overseer, peer_b).await; diff --git a/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs new file mode 100644 index 000000000000..a803827792d8 --- /dev/null +++ b/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -0,0 +1,988 @@ +// Copyright 2022 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 . + +//! Tests for the validator side with enabled prospective parachains. + +use super::*; + +use polkadot_node_subsystem::messages::ChainApiMessage; +use polkadot_primitives::{ + vstaging as vstaging_primitives, BlockNumber, CandidateCommitments, CommittedCandidateReceipt, + Header, SigningContext, ValidatorId, +}; + +const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParams = + vstaging_primitives::AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; + +fn get_parent_hash(hash: Hash) -> Hash { + Hash::from_low_u64_be(hash.to_low_u64_be() + 1) +} + +async fn assert_assign_incoming( + virtual_overseer: &mut VirtualOverseer, + test_state: &TestState, + hash: Hash, + number: BlockNumber, + next_msg: &mut Option, +) { + let msg = match next_msg.take() { + Some(msg) => msg, + None => overseer_recv(virtual_overseer).await, + }; + assert_matches!( + msg, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.validator_public.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx)) + ) if parent == hash => { + let validator_groups = test_state.validator_groups.clone(); + let mut group_rotation_info = test_state.group_rotation_info.clone(); + group_rotation_info.now = number; + tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.cores.clone())).unwrap(); + } + ); +} + +/// Handle a view update. +async fn update_view( + virtual_overseer: &mut VirtualOverseer, + test_state: &TestState, + new_view: Vec<(Hash, u32)>, // Hash and block number. + activated: u8, // How many new heads does this update contain? +) -> Option { + let new_view: HashMap = HashMap::from_iter(new_view); + + let our_view = + OurView::new(new_view.keys().map(|hash| (*hash, Arc::new(jaeger::Span::Disabled))), 0); + + overseer_send( + virtual_overseer, + CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange(our_view)), + ) + .await; + + let mut next_overseer_message = None; + for _ in 0..activated { + let (leaf_hash, leaf_number) = assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::StagingAsyncBackingParams(tx), + )) => { + tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); + (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) + } + ); + + assert_assign_incoming( + virtual_overseer, + test_state, + leaf_hash, + leaf_number, + &mut next_overseer_message, + ) + .await; + + let min_number = leaf_number.saturating_sub(ASYNC_BACKING_PARAMETERS.allowed_ancestry_len); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetMinimumRelayParents(parent, tx), + ) if parent == leaf_hash => { + tx.send(test_state.chain_ids.iter().map(|para_id| (*para_id, min_number)).collect()).unwrap(); + } + ); + + let ancestry_len = leaf_number + 1 - min_number; + let ancestry_hashes = std::iter::successors(Some(leaf_hash), |h| Some(get_parent_hash(*h))) + .take(ancestry_len as usize); + let ancestry_numbers = (min_number..=leaf_number).rev(); + let ancestry_iter = ancestry_hashes.clone().zip(ancestry_numbers).peekable(); + + // How many blocks were actually requested. + let mut requested_len: usize = 0; + { + let mut ancestry_iter = ancestry_iter.clone(); + while let Some((hash, number)) = ancestry_iter.next() { + // May be `None` for the last element. + let parent_hash = + ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); + + let msg = match next_overseer_message.take() { + Some(msg) => msg, + None => overseer_recv(virtual_overseer).await, + }; + + if !matches!(&msg, AllMessages::ChainApi(ChainApiMessage::BlockHeader(..))) { + // Ancestry has already been cached for this leaf. + next_overseer_message.replace(msg); + break + } + + assert_matches!( + msg, + AllMessages::ChainApi(ChainApiMessage::BlockHeader(.., tx)) => { + let header = Header { + parent_hash, + number, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + }; + + tx.send(Ok(Some(header))).unwrap(); + } + ); + + requested_len += 1; + } + } + + // Skip the leaf. + for (hash, number) in ancestry_iter.skip(1).take(requested_len.saturating_sub(1)) { + assert_assign_incoming( + virtual_overseer, + test_state, + hash, + number, + &mut next_overseer_message, + ) + .await; + } + } + next_overseer_message +} + +async fn send_seconded_statement( + virtual_overseer: &mut VirtualOverseer, + keystore: KeystorePtr, + candidate: &CommittedCandidateReceipt, +) { + let signing_context = SigningContext { session_index: 0, parent_hash: Hash::zero() }; + let stmt = SignedFullStatement::sign( + &keystore, + Statement::Seconded(candidate.clone()), + &signing_context, + ValidatorIndex(0), + &ValidatorId::from(Sr25519Keyring::Alice.public()), + ) + .ok() + .flatten() + .expect("should be signed"); + + overseer_send( + virtual_overseer, + CollatorProtocolMessage::Seconded(candidate.descriptor.relay_parent, stmt), + ) + .await; +} + +async fn assert_collation_seconded( + virtual_overseer: &mut VirtualOverseer, + relay_parent: Hash, + peer_id: PeerId, +) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer( + ReportPeerMessage::Single(peer, rep) + )) => { + assert_eq!(peer_id, peer); + assert_eq!(rep.value, BENEFIT_NOTIFY_GOOD.cost_or_benefit()); + } + ); + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendCollationMessage( + peers, + Versioned::VStaging(protocol_vstaging::CollationProtocol::CollatorProtocol( + protocol_vstaging::CollatorProtocolMessage::CollationSeconded( + _relay_parent, + .., + ), + )), + )) => { + assert_eq!(peers, vec![peer_id]); + assert_eq!(relay_parent, _relay_parent); + } + ); +} + +#[test] +fn v1_advertisement_rejected() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair_a = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 0; + + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + + // Accept both collators from the implicit view. + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::V1, + ) + .await; + + advertise_collation(&mut virtual_overseer, peer_a, head_b, None).await; + + // Not reported. + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + +#[test] +fn accept_advertisements_from_implicit_view() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair_a = CollatorPair::generate().0; + let pair_b = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 2; + + let head_c = get_parent_hash(head_b); + // Grandparent of head `b`. + // Group rotation frequency is 1 by default, at `d` we're assigned + // to the first para. + let head_d = get_parent_hash(head_c); + + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + + // Accept both collators from the implicit view. + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + connect_and_declare_collator( + &mut virtual_overseer, + peer_b, + pair_b.clone(), + test_state.chain_ids[1], + CollationVersion::VStaging, + ) + .await; + + let candidate_hash = CandidateHash::default(); + let parent_head_data_hash = Hash::zero(); + advertise_collation( + &mut virtual_overseer, + peer_b, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[1]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + assert_fetch_collation_request( + &mut virtual_overseer, + head_c, + test_state.chain_ids[1], + Some(candidate_hash), + ) + .await; + // Advertise with different para. + advertise_collation( + &mut virtual_overseer, + peer_a, + head_d, // Note different relay parent. + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + assert_fetch_collation_request( + &mut virtual_overseer, + head_d, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + + virtual_overseer + }); +} + +#[test] +fn second_multiple_candidates_per_relay_parent() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let pair = CollatorPair::generate().0; + + // Grandparent of head `a`. + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 2; + + // Grandparent of head `b`. + // Group rotation frequency is 1 by default, at `c` we're assigned + // to the first para. + let head_c = Hash::from_low_u64_be(130); + + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + + for i in 0..(ASYNC_BACKING_PARAMETERS.max_candidate_depth + 1) { + let mut candidate = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); + candidate.descriptor.para_id = test_state.chain_ids[0]; + candidate.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); + let commitments = CandidateCommitments { + head_data: HeadData(vec![i as u8]), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate.commitments_hash = commitments.hash(); + + let candidate_hash = candidate.hash(); + let parent_head_data_hash = Hash::zero(); + + advertise_collation( + &mut virtual_overseer, + peer_a, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + head_c, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + + let pov = PoV { block_data: BlockData(vec![1]) }; + + response_channel + .send(Ok(request_vstaging::CollationFetchingResponse::Collation( + candidate.clone(), + pov.clone(), + ) + .encode())) + .expect("Sending response should succeed"); + + assert_candidate_backing_second( + &mut virtual_overseer, + head_c, + test_state.chain_ids[0], + &pov, + ProspectiveParachainsMode::Enabled { + max_candidate_depth: ASYNC_BACKING_PARAMETERS.max_candidate_depth as _, + allowed_ancestry_len: ASYNC_BACKING_PARAMETERS.allowed_ancestry_len as _, + }, + ) + .await; + + let candidate = + CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments }; + + send_seconded_statement(&mut virtual_overseer, keystore.clone(), &candidate).await; + + assert_collation_seconded(&mut virtual_overseer, head_c, peer_a).await; + } + + // No more advertisements can be made for this relay parent. + let candidate_hash = CandidateHash(Hash::repeat_byte(0xAA)); + advertise_collation( + &mut virtual_overseer, + peer_a, + head_c, + Some((candidate_hash, Hash::zero())), + ) + .await; + + // Reported because reached the limit of advertisements per relay parent. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), + ) => { + assert_eq!(peer_a, peer_id); + assert_eq!(rep.value, COST_UNEXPECTED_MESSAGE.cost_or_benefit()); + } + ); + + // By different peer too (not reported). + let pair_b = CollatorPair::generate().0; + let peer_b = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_b, + pair_b.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + + let candidate_hash = CandidateHash(Hash::repeat_byte(0xFF)); + advertise_collation( + &mut virtual_overseer, + peer_b, + head_c, + Some((candidate_hash, Hash::zero())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + +#[test] +fn fetched_collation_sanity_check() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair = CollatorPair::generate().0; + + // Grandparent of head `a`. + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 2; + + // Grandparent of head `b`. + // Group rotation frequency is 1 by default, at `c` we're assigned + // to the first para. + let head_c = Hash::from_low_u64_be(130); + + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + + let mut candidate = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); + candidate.descriptor.para_id = test_state.chain_ids[0]; + let commitments = CandidateCommitments { + head_data: HeadData(vec![1, 2, 3]), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate.commitments_hash = commitments.hash(); + + let candidate_hash = CandidateHash(Hash::zero()); + let parent_head_data_hash = Hash::zero(); + + advertise_collation( + &mut virtual_overseer, + peer_a, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + head_c, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + + let pov = PoV { block_data: BlockData(vec![1]) }; + + response_channel + .send(Ok(request_vstaging::CollationFetchingResponse::Collation( + candidate.clone(), + pov.clone(), + ) + .encode())) + .expect("Sending response should succeed"); + + // PVD request. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), + ) => { + assert_eq!(head_c, request.candidate_relay_parent); + assert_eq!(test_state.chain_ids[0], request.para_id); + tx.send(Some(dummy_pvd())).unwrap(); + } + ); + + // Reported malicious. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), + ) => { + assert_eq!(peer_a, peer_id); + assert_eq!(rep.value, COST_REPORT_BAD.cost_or_benefit()); + } + ); + + virtual_overseer + }); +} + +#[test] +fn advertisement_spam_protection() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair_a = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 2; + + let head_c = get_parent_hash(head_b); + + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[1], + CollationVersion::VStaging, + ) + .await; + + let candidate_hash = CandidateHash::default(); + let parent_head_data_hash = Hash::zero(); + advertise_collation( + &mut virtual_overseer, + peer_a, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[1]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + // Reject it. + tx.send(false).expect("receiving side should be alive"); + } + ); + + // Send the same advertisement again. + advertise_collation( + &mut virtual_overseer, + peer_a, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + // Reported. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), + ) => { + assert_eq!(peer_a, peer_id); + assert_eq!(rep.value, COST_UNEXPECTED_MESSAGE.cost_or_benefit()); + } + ); + + virtual_overseer + }); +} + +#[test] +fn backed_candidate_unblocks_advertisements() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair_a = CollatorPair::generate().0; + let pair_b = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 2; + + let head_c = get_parent_hash(head_b); + // Grandparent of head `b`. + // Group rotation frequency is 1 by default, at `d` we're assigned + // to the first para. + let head_d = get_parent_hash(head_c); + + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + + // Accept both collators from the implicit view. + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + connect_and_declare_collator( + &mut virtual_overseer, + peer_b, + pair_b.clone(), + test_state.chain_ids[1], + CollationVersion::VStaging, + ) + .await; + + let candidate_hash = CandidateHash::default(); + let parent_head_data_hash = Hash::zero(); + advertise_collation( + &mut virtual_overseer, + peer_b, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[1]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + // Reject it. + tx.send(false).expect("receiving side should be alive"); + } + ); + + // Advertise with different para. + advertise_collation( + &mut virtual_overseer, + peer_a, + head_d, // Note different relay parent. + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(false).expect("receiving side should be alive"); + } + ); + + overseer_send( + &mut virtual_overseer, + CollatorProtocolMessage::Backed { + para_id: test_state.chain_ids[0], + para_head: parent_head_data_hash, + }, + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + assert_fetch_collation_request( + &mut virtual_overseer, + head_d, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + virtual_overseer + }); +} + +#[test] +fn active_leave_unblocks_advertisements() { + let mut test_state = TestState::default(); + test_state.group_rotation_info.group_rotation_frequency = 100; + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 0; + + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let peers: Vec = (0..3).map(|_| CollatorPair::generate().0).collect(); + let peer_ids: Vec = (0..3).map(|_| PeerId::random()).collect(); + let candidates: Vec = + (0u8..3).map(|i| CandidateHash(Hash::repeat_byte(i))).collect(); + + for (peer, peer_id) in peers.iter().zip(&peer_ids) { + connect_and_declare_collator( + &mut virtual_overseer, + *peer_id, + peer.clone(), + test_state.chain_ids[0], + CollationVersion::VStaging, + ) + .await; + } + + let parent_head_data_hash = Hash::zero(); + for (peer, candidate) in peer_ids.iter().zip(&candidates).take(2) { + advertise_collation( + &mut virtual_overseer, + *peer, + head_b, + Some((*candidate, parent_head_data_hash)), + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, *candidate); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + // Send false. + tx.send(false).expect("receiving side should be alive"); + } + ); + } + + let head_c = Hash::from_low_u64_be(127); + let head_c_num: u32 = 1; + + let next_overseer_message = + update_view(&mut virtual_overseer, &test_state, vec![(head_c, head_c_num)], 1) + .await + .expect("should've sent request to backing"); + + // Unblock first request. + assert_matches!( + next_overseer_message, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidates[0]); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + assert_fetch_collation_request( + &mut virtual_overseer, + head_b, + test_state.chain_ids[0], + Some(candidates[0]), + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidates[1]); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(false).expect("receiving side should be alive"); + } + ); + + // Collation request was discarded. + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + advertise_collation( + &mut virtual_overseer, + peer_ids[2], + head_c, + Some((candidates[2], parent_head_data_hash)), + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidates[2]); + tx.send(false).expect("receiving side should be alive"); + } + ); + + let head_d = Hash::from_low_u64_be(126); + let head_d_num: u32 = 2; + + let next_overseer_message = + update_view(&mut virtual_overseer, &test_state, vec![(head_d, head_d_num)], 1) + .await + .expect("should've sent request to backing"); + + // Reject 2, accept 3. + assert_matches!( + next_overseer_message, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidates[1]); + tx.send(false).expect("receiving side should be alive"); + } + ); + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidates[2]); + tx.send(true).expect("receiving side should be alive"); + } + ); + assert_fetch_collation_request( + &mut virtual_overseer, + head_c, + test_state.chain_ids[0], + Some(candidates[2]), + ) + .await; + + virtual_overseer + }); +} diff --git a/node/network/gossip-support/src/lib.rs b/node/network/gossip-support/src/lib.rs index b92aa4e9fe39..c5dc1ba14bd3 100644 --- a/node/network/gossip-support/src/lib.rs +++ b/node/network/gossip-support/src/lib.rs @@ -448,8 +448,12 @@ where NetworkBridgeEvent::OurViewChange(_) => {}, NetworkBridgeEvent::PeerViewChange(_, _) => {}, NetworkBridgeEvent::NewGossipTopology { .. } => {}, - NetworkBridgeEvent::PeerMessage(_, Versioned::V1(v)) => { - match v {}; + NetworkBridgeEvent::PeerMessage(_, message) => { + // match void -> LLVM unreachable + match message { + Versioned::V1(m) => match m {}, + Versioned::VStaging(m) => match m {}, + } }, } } diff --git a/node/network/protocol/Cargo.toml b/node/network/protocol/Cargo.toml index cfb7a5c2d0f0..207d740f32e5 100644 --- a/node/network/protocol/Cargo.toml +++ b/node/network/protocol/Cargo.toml @@ -23,6 +23,10 @@ fatality = "0.0.6" rand = "0.8" derive_more = "0.99" gum = { package = "tracing-gum", path = "../../gum" } +bitvec = "1" [dev-dependencies] rand_chacha = "0.3.1" + +[features] +network-protocol-staging = [] diff --git a/node/network/protocol/src/lib.rs b/node/network/protocol/src/lib.rs index 2df926ac55d8..1bed2c12fe20 100644 --- a/node/network/protocol/src/lib.rs +++ b/node/network/protocol/src/lib.rs @@ -253,22 +253,26 @@ impl View { /// A protocol-versioned type. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Versioned { +pub enum Versioned { /// V1 type. V1(V1), + /// VStaging type. + VStaging(VStaging), } -impl Versioned<&'_ V1> { +impl Versioned<&'_ V1, &'_ VStaging> { /// Convert to a fully-owned version of the message. - pub fn clone_inner(&self) -> Versioned { + pub fn clone_inner(&self) -> Versioned { match *self { Versioned::V1(inner) => Versioned::V1(inner.clone()), + Versioned::VStaging(inner) => Versioned::VStaging(inner.clone()), } } } /// All supported versions of the validation protocol message. -pub type VersionedValidationProtocol = Versioned; +pub type VersionedValidationProtocol = + Versioned; impl From for VersionedValidationProtocol { fn from(v1: v1::ValidationProtocol) -> Self { @@ -276,8 +280,14 @@ impl From for VersionedValidationProtocol { } } +impl From for VersionedValidationProtocol { + fn from(vstaging: vstaging::ValidationProtocol) -> Self { + VersionedValidationProtocol::VStaging(vstaging) + } +} + /// All supported versions of the collation protocol message. -pub type VersionedCollationProtocol = Versioned; +pub type VersionedCollationProtocol = Versioned; impl From for VersionedCollationProtocol { fn from(v1: v1::CollationProtocol) -> Self { @@ -285,12 +295,19 @@ impl From for VersionedCollationProtocol { } } +impl From for VersionedCollationProtocol { + fn from(vstaging: vstaging::CollationProtocol) -> Self { + VersionedCollationProtocol::VStaging(vstaging) + } +} + macro_rules! impl_versioned_full_protocol_from { ($from:ty, $out:ty, $variant:ident) => { impl From<$from> for $out { fn from(versioned_from: $from) -> $out { match versioned_from { Versioned::V1(x) => Versioned::V1(x.into()), + Versioned::VStaging(x) => Versioned::VStaging(x.into()), } } } @@ -300,7 +317,12 @@ macro_rules! impl_versioned_full_protocol_from { /// Implement `TryFrom` for one versioned enum variant into the inner type. /// `$m_ty::$variant(inner) -> Ok(inner)` macro_rules! impl_versioned_try_from { - ($from:ty, $out:ty, $v1_pat:pat => $v1_out:expr) => { + ( + $from:ty, + $out:ty, + $v1_pat:pat => $v1_out:expr, + $vstaging_pat:pat => $vstaging_out:expr + ) => { impl TryFrom<$from> for $out { type Error = crate::WrongVariant; @@ -308,6 +330,7 @@ macro_rules! impl_versioned_try_from { #[allow(unreachable_patterns)] // when there is only one variant match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)), + Versioned::VStaging($vstaging_pat) => Ok(Versioned::VStaging($vstaging_out)), _ => Err(crate::WrongVariant), } } @@ -320,6 +343,8 @@ macro_rules! impl_versioned_try_from { #[allow(unreachable_patterns)] // when there is only one variant match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())), + Versioned::VStaging($vstaging_pat) => + Ok(Versioned::VStaging($vstaging_out.clone())), _ => Err(crate::WrongVariant), } } @@ -328,7 +353,8 @@ macro_rules! impl_versioned_try_from { } /// Version-annotated messages used by the bitfield distribution subsystem. -pub type BitfieldDistributionMessage = Versioned; +pub type BitfieldDistributionMessage = + Versioned; impl_versioned_full_protocol_from!( BitfieldDistributionMessage, VersionedValidationProtocol, @@ -337,11 +363,13 @@ impl_versioned_full_protocol_from!( impl_versioned_try_from!( VersionedValidationProtocol, BitfieldDistributionMessage, - v1::ValidationProtocol::BitfieldDistribution(x) => x + v1::ValidationProtocol::BitfieldDistribution(x) => x, + vstaging::ValidationProtocol::BitfieldDistribution(x) => x ); /// Version-annotated messages used by the statement distribution subsystem. -pub type StatementDistributionMessage = Versioned; +pub type StatementDistributionMessage = + Versioned; impl_versioned_full_protocol_from!( StatementDistributionMessage, VersionedValidationProtocol, @@ -350,11 +378,13 @@ impl_versioned_full_protocol_from!( impl_versioned_try_from!( VersionedValidationProtocol, StatementDistributionMessage, - v1::ValidationProtocol::StatementDistribution(x) => x + v1::ValidationProtocol::StatementDistribution(x) => x, + vstaging::ValidationProtocol::StatementDistribution(x) => x ); /// Version-annotated messages used by the approval distribution subsystem. -pub type ApprovalDistributionMessage = Versioned; +pub type ApprovalDistributionMessage = + Versioned; impl_versioned_full_protocol_from!( ApprovalDistributionMessage, VersionedValidationProtocol, @@ -363,11 +393,14 @@ impl_versioned_full_protocol_from!( impl_versioned_try_from!( VersionedValidationProtocol, ApprovalDistributionMessage, - v1::ValidationProtocol::ApprovalDistribution(x) => x + v1::ValidationProtocol::ApprovalDistribution(x) => x, + vstaging::ValidationProtocol::ApprovalDistribution(x) => x + ); /// Version-annotated messages used by the gossip-support subsystem (this is void). -pub type GossipSupportNetworkMessage = Versioned; +pub type GossipSupportNetworkMessage = + Versioned; // This is a void enum placeholder, so never gets sent over the wire. impl TryFrom for GossipSupportNetworkMessage { type Error = WrongVariant; @@ -384,7 +417,8 @@ impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessag } /// Version-annotated messages used by the bitfield distribution subsystem. -pub type CollatorProtocolMessage = Versioned; +pub type CollatorProtocolMessage = + Versioned; impl_versioned_full_protocol_from!( CollatorProtocolMessage, VersionedCollationProtocol, @@ -393,7 +427,8 @@ impl_versioned_full_protocol_from!( impl_versioned_try_from!( VersionedCollationProtocol, CollatorProtocolMessage, - v1::CollationProtocol::CollatorProtocol(x) => x + v1::CollationProtocol::CollatorProtocol(x) => x, + vstaging::CollationProtocol::CollatorProtocol(x) => x ); /// v1 notification protocol types. @@ -553,3 +588,256 @@ pub mod v1 { payload } } + +/// vstaging network protocol types. +pub mod vstaging { + use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec}; + use parity_scale_codec::{Decode, Encode}; + + use polkadot_primitives::vstaging::{ + CandidateHash, CandidateIndex, CollatorId, CollatorSignature, GroupIndex, Hash, + Id as ParaId, UncheckedSignedAvailabilityBitfield, UncheckedSignedStatement, + }; + + use polkadot_node_primitives::{ + approval::{IndirectAssignmentCert, IndirectSignedApprovalVote}, + UncheckedSignedFullStatement, + }; + + /// Network messages used by the bitfield distribution subsystem. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum BitfieldDistributionMessage { + /// A signed availability bitfield for a given relay-parent hash. + #[codec(index = 0)] + Bitfield(Hash, UncheckedSignedAvailabilityBitfield), + } + + /// Bitfields indicating the statements that are known or undesired + /// about a candidate. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct StatementFilter { + /// Seconded statements. '1' is known or undesired. + pub seconded_in_group: BitVec, + /// Valid statements. '1' is known or undesired. + pub validated_in_group: BitVec, + } + + impl StatementFilter { + /// Create a new blank filter with the given group size. + pub fn blank(group_size: usize) -> Self { + StatementFilter { + seconded_in_group: BitVec::repeat(false, group_size), + validated_in_group: BitVec::repeat(false, group_size), + } + } + + /// Create a new full filter with the given group size. + pub fn full(group_size: usize) -> Self { + StatementFilter { + seconded_in_group: BitVec::repeat(true, group_size), + validated_in_group: BitVec::repeat(true, group_size), + } + } + + /// Whether the filter has a specific expected length, consistent across both + /// bitfields. + pub fn has_len(&self, len: usize) -> bool { + self.seconded_in_group.len() == len && self.validated_in_group.len() == len + } + + /// Determine the number of backing validators in the statement filter. + pub fn backing_validators(&self) -> usize { + self.seconded_in_group + .iter() + .by_vals() + .zip(self.validated_in_group.iter().by_vals()) + .filter(|&(s, v)| s || v) // no double-counting + .count() + } + + /// Whether the statement filter has at least one seconded statement. + pub fn has_seconded(&self) -> bool { + self.seconded_in_group.iter().by_vals().any(|x| x) + } + + /// Mask out `Seconded` statements in `self` according to the provided + /// bitvec. Bits appearing in `mask` will not appear in `self` afterwards. + pub fn mask_seconded(&mut self, mask: &BitSlice) { + for (mut x, mask) in self + .seconded_in_group + .iter_mut() + .zip(mask.iter().by_vals().chain(std::iter::repeat(false))) + { + // (x, mask) => x + // (true, true) => false + // (true, false) => true + // (false, true) => false + // (false, false) => false + *x = *x && !mask; + } + } + + /// Mask out `Valid` statements in `self` according to the provided + /// bitvec. Bits appearing in `mask` will not appear in `self` afterwards. + pub fn mask_valid(&mut self, mask: &BitSlice) { + for (mut x, mask) in self + .validated_in_group + .iter_mut() + .zip(mask.iter().by_vals().chain(std::iter::repeat(false))) + { + // (x, mask) => x + // (true, true) => false + // (true, false) => true + // (false, true) => false + // (false, false) => false + *x = *x && !mask; + } + } + } + + /// A manifest of a known backed candidate, along with a description + /// of the statements backing it. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct BackedCandidateManifest { + /// The relay-parent of the candidate. + pub relay_parent: Hash, + /// The hash of the candidate. + pub candidate_hash: CandidateHash, + /// The group index backing the candidate at the relay-parent. + pub group_index: GroupIndex, + /// The para ID of the candidate. It is illegal for this to + /// be a para ID which is not assigned to the group indicated + /// in this manifest. + pub para_id: ParaId, + /// The head-data corresponding to the candidate. + pub parent_head_data_hash: Hash, + /// A statement filter which indicates which validators in the + /// para's group at the relay-parent have validated this candidate + /// and issued statements about it, to the advertiser's knowledge. + /// + /// This MUST have exactly the minimum amount of bytes + /// necessary to represent the number of validators in the assigned + /// backing group as-of the relay-parent. + pub statement_knowledge: StatementFilter, + } + + /// An acknowledgement of a backed candidate being known. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct BackedCandidateAcknowledgement { + /// The hash of the candidate. + pub candidate_hash: CandidateHash, + /// A statement filter which indicates which validators in the + /// para's group at the relay-parent have validated this candidate + /// and issued statements about it, to the advertiser's knowledge. + /// + /// This MUST have exactly the minimum amount of bytes + /// necessary to represent the number of validators in the assigned + /// backing group as-of the relay-parent. + pub statement_knowledge: StatementFilter, + } + + /// Network messages used by the statement distribution subsystem. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum StatementDistributionMessage { + /// A notification of a signed statement in compact form, for a given relay parent. + #[codec(index = 0)] + Statement(Hash, UncheckedSignedStatement), + + /// A notification of a backed candidate being known by the + /// sending node, for the purpose of being requested by the receiving node + /// if needed. + #[codec(index = 1)] + BackedCandidateManifest(BackedCandidateManifest), + + /// A notification of a backed candidate being known by the sending node, + /// for the purpose of informing a receiving node which already has the candidate. + #[codec(index = 2)] + BackedCandidateKnown(BackedCandidateAcknowledgement), + + /// All messages for V1 for compatibility with the statement distribution + /// protocol, for relay-parents that don't support asynchronous backing. + /// + /// These are illegal to send to V1 peers, and illegal to send concerning relay-parents + /// which support asynchronous backing. This backwards compatibility should be + /// considered immediately deprecated and can be removed once the node software + /// is not required to support logic from before asynchronous backing anymore. + #[codec(index = 255)] + V1Compatibility(crate::v1::StatementDistributionMessage), + } + + /// Network messages used by the approval distribution subsystem. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum ApprovalDistributionMessage { + /// Assignments for candidates in recent, unfinalized blocks. + /// + /// Actually checking the assignment may yield a different result. + #[codec(index = 0)] + Assignments(Vec<(IndirectAssignmentCert, CandidateIndex)>), + /// Approvals for candidates in some recent, unfinalized block. + #[codec(index = 1)] + Approvals(Vec), + } + + /// Dummy network message type, so we will receive connect/disconnect events. + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum GossipSupportNetworkMessage {} + + /// Network messages used by the collator protocol subsystem + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub enum CollatorProtocolMessage { + /// Declare the intent to advertise collations under a collator ID, attaching a + /// signature of the `PeerId` of the node using the given collator ID key. + #[codec(index = 0)] + Declare(CollatorId, ParaId, CollatorSignature), + /// Advertise a collation to a validator. Can only be sent once the peer has + /// declared that they are a collator with given ID. + #[codec(index = 1)] + AdvertiseCollation { + /// Hash of the relay parent advertised collation is based on. + relay_parent: Hash, + /// Candidate hash. + candidate_hash: CandidateHash, + /// Parachain head data hash before candidate execution. + parent_head_data_hash: Hash, + }, + /// A collation sent to a validator was seconded. + #[codec(index = 4)] + CollationSeconded(Hash, UncheckedSignedFullStatement), + } + + /// All network messages on the validation peer-set. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] + pub enum ValidationProtocol { + /// Bitfield distribution messages + #[codec(index = 1)] + #[from] + BitfieldDistribution(BitfieldDistributionMessage), + /// Statement distribution messages + #[codec(index = 3)] + #[from] + StatementDistribution(StatementDistributionMessage), + /// Approval distribution messages + #[codec(index = 4)] + #[from] + ApprovalDistribution(ApprovalDistributionMessage), + } + + /// All network messages on the collation peer-set. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] + pub enum CollationProtocol { + /// Collator protocol messages + #[codec(index = 0)] + #[from] + CollatorProtocol(CollatorProtocolMessage), + } + + /// Get the payload that should be signed and included in a `Declare` message. + /// + /// The payload is the local peer id of the node, which serves to prove that it + /// controls the collator key it is declaring an intention to collate under. + pub fn declare_signature_payload(peer_id: &sc_network::PeerId) -> Vec { + let mut payload = peer_id.to_bytes(); + payload.extend_from_slice(b"COLL"); + payload + } +} diff --git a/node/network/protocol/src/peer_set.rs b/node/network/protocol/src/peer_set.rs index b9fa80d5c4a2..b6f8c9dec231 100644 --- a/node/network/protocol/src/peer_set.rs +++ b/node/network/protocol/src/peer_set.rs @@ -118,10 +118,17 @@ impl PeerSet { /// Networking layer relies on `get_main_version()` being the version /// of the main protocol name reported by [`PeerSetProtocolNames::get_main_name()`]. pub fn get_main_version(self) -> ProtocolVersion { + #[cfg(not(feature = "network-protocol-staging"))] match self { PeerSet::Validation => ValidationVersion::V1.into(), PeerSet::Collation => CollationVersion::V1.into(), } + + #[cfg(feature = "network-protocol-staging")] + match self { + PeerSet::Validation => ValidationVersion::VStaging.into(), + PeerSet::Collation => CollationVersion::VStaging.into(), + } } /// Get the max notification size for this peer set. @@ -145,12 +152,16 @@ impl PeerSet { PeerSet::Validation => if version == ValidationVersion::V1.into() { Some("validation/1") + } else if version == ValidationVersion::VStaging.into() { + Some("validation/2") } else { None }, PeerSet::Collation => if version == CollationVersion::V1.into() { Some("collation/1") + } else if version == CollationVersion::VStaging.into() { + Some("collation/2") } else { None }, @@ -212,6 +223,8 @@ impl From for u32 { pub enum ValidationVersion { /// The first version. V1 = 1, + /// The staging version. + VStaging = 2, } /// Supported collation protocol versions. Only versions defined here must be used in the codebase. @@ -219,6 +232,40 @@ pub enum ValidationVersion { pub enum CollationVersion { /// The first version. V1 = 1, + /// The staging version. + VStaging = 2, +} + +/// Marker indicating the version is unknown. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UnknownVersion; + +impl TryFrom for ValidationVersion { + type Error = UnknownVersion; + + fn try_from(p: ProtocolVersion) -> Result { + for v in Self::iter() { + if v as u32 == p.0 { + return Ok(v) + } + } + + Err(UnknownVersion) + } +} + +impl TryFrom for CollationVersion { + type Error = UnknownVersion; + + fn try_from(p: ProtocolVersion) -> Result { + for v in Self::iter() { + if v as u32 == p.0 { + return Ok(v) + } + } + + Err(UnknownVersion) + } } impl From for ProtocolVersion { diff --git a/node/network/protocol/src/request_response/mod.rs b/node/network/protocol/src/request_response/mod.rs index 912447c0c626..baed4b846316 100644 --- a/node/network/protocol/src/request_response/mod.rs +++ b/node/network/protocol/src/request_response/mod.rs @@ -51,9 +51,12 @@ pub use outgoing::{OutgoingRequest, OutgoingResult, Recipient, Requests, Respons ///// Multiplexer for incoming requests. // pub mod multiplexer; -/// Actual versioned requests and responses, that are sent over the wire. +/// Actual versioned requests and responses that are sent over the wire. pub mod v1; +/// Actual versioned requests and responses that are sent over the wire. +pub mod vstaging; + /// A protocol per subsystem seems to make the most sense, this way we don't need any dispatching /// within protocols. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, EnumIter)] @@ -62,6 +65,8 @@ pub enum Protocol { ChunkFetchingV1, /// Protocol for fetching collations from collators. CollationFetchingV1, + /// Protocol for fetching collations from collators when async backing is enabled. + CollationFetchingVStaging, /// Protocol for fetching seconded PoVs from validators of the same group. PoVFetchingV1, /// Protocol for fetching available data. @@ -70,6 +75,10 @@ pub enum Protocol { StatementFetchingV1, /// Sending of dispute statements with application level confirmations. DisputeSendingV1, + + /// Protocol for requesting candidates with attestations in statement distribution + /// when async backing is enabled. + AttestedCandidateVStaging, } /// Minimum bandwidth we expect for validators - 500Mbit/s is the recommendation, so approximately @@ -101,12 +110,30 @@ const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(1200); /// fit statement distribution within a block of 6 seconds.) const STATEMENTS_TIMEOUT: Duration = Duration::from_secs(1); +/// We want attested candidate requests to time out relatively fast, +/// because slow requests will bottleneck the backing system. Ideally, we'd have +/// an adaptive timeout based on the candidate size, because there will be a lot of variance +/// in candidate sizes: candidates with no code and no messages vs candidates with code +/// and messages. +/// +/// We supply leniency because there are often large candidates and asynchronous +/// backing allows them to be included over a longer window of time. Exponential back-off +/// up to a maximum of 10 seconds would be ideal, but isn't supported by the +/// infrastructure here yet: see https://github.com/paritytech/polkadot/issues/6009 +const ATTESTED_CANDIDATE_TIMEOUT: Duration = Duration::from_millis(2500); + /// We don't want a slow peer to slow down all the others, at the same time we want to get out the /// data quickly in full to at least some peers (as this will reduce load on us as they then can /// start serving the data). So this value is a trade-off. 3 seems to be sensible. So we would need /// to have 3 slow nodes connected, to delay transfer for others by `STATEMENTS_TIMEOUT`. pub const MAX_PARALLEL_STATEMENT_REQUESTS: u32 = 3; +/// We don't want a slow peer to slow down all the others, at the same time we want to get out the +/// data quickly in full to at least some peers (as this will reduce load on us as they then can +/// start serving the data). So this value is a tradeoff. 5 seems to be sensible. So we would need +/// to have 5 slow nodes connected, to delay transfer for others by `ATTESTED_CANDIDATE_TIMEOUT`. +pub const MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS: u32 = 5; + /// Response size limit for responses of POV like data. /// /// This is larger than `MAX_POV_SIZE` to account for protocol overhead and for additional data in @@ -120,6 +147,12 @@ const POV_RESPONSE_SIZE: u64 = MAX_POV_SIZE as u64 + 10_000; /// This is `MAX_CODE_SIZE` plus some additional space for protocol overhead. const STATEMENT_RESPONSE_SIZE: u64 = MAX_CODE_SIZE as u64 + 10_000; +/// Maximum response sizes for `AttestedCandidateVStaging`. +/// +/// This is `MAX_CODE_SIZE` plus some additional space for protocol overhead and +/// additional backing statements. +const ATTESTED_CANDIDATE_RESPONSE_SIZE: u64 = MAX_CODE_SIZE as u64 + 100_000; + /// We can have relative large timeouts here, there is no value of hitting a /// timeout as we want to get statements through to each node in any case. pub const DISPUTE_REQUEST_TIMEOUT: Duration = Duration::from_secs(12); @@ -166,15 +199,16 @@ impl Protocol { request_timeout: CHUNK_REQUEST_TIMEOUT, inbound_queue: tx, }, - Protocol::CollationFetchingV1 => RequestResponseConfig { - name, - fallback_names, - max_request_size: 1_000, - max_response_size: POV_RESPONSE_SIZE, - // Taken from initial implementation in collator protocol: - request_timeout: POV_REQUEST_TIMEOUT_CONNECTED, - inbound_queue: tx, - }, + Protocol::CollationFetchingV1 | Protocol::CollationFetchingVStaging => + RequestResponseConfig { + name, + fallback_names, + max_request_size: 1_000, + max_response_size: POV_RESPONSE_SIZE, + // Taken from initial implementation in collator protocol: + request_timeout: POV_REQUEST_TIMEOUT_CONNECTED, + inbound_queue: tx, + }, Protocol::PoVFetchingV1 => RequestResponseConfig { name, fallback_names, @@ -220,6 +254,14 @@ impl Protocol { request_timeout: DISPUTE_REQUEST_TIMEOUT, inbound_queue: tx, }, + Protocol::AttestedCandidateVStaging => RequestResponseConfig { + name, + fallback_names, + max_request_size: 1_000, + max_response_size: ATTESTED_CANDIDATE_RESPONSE_SIZE, + request_timeout: ATTESTED_CANDIDATE_TIMEOUT, + inbound_queue: tx, + }, } } @@ -233,7 +275,7 @@ impl Protocol { // as well. Protocol::ChunkFetchingV1 => 100, // 10 seems reasonable, considering group sizes of max 10 validators. - Protocol::CollationFetchingV1 => 10, + Protocol::CollationFetchingV1 | Protocol::CollationFetchingVStaging => 10, // 10 seems reasonable, considering group sizes of max 10 validators. Protocol::PoVFetchingV1 => 10, // Validators are constantly self-selecting to request available data which may lead @@ -264,23 +306,46 @@ impl Protocol { // average, so something in the ballpark of 100 should be fine. Nodes will retry on // failure, so having a good value here is mostly about performance tuning. Protocol::DisputeSendingV1 => 100, + + Protocol::AttestedCandidateVStaging => { + // We assume we can utilize up to 70% of the available bandwidth for statements. + // This is just a guess/estimate, with the following considerations: If we are + // faster than that, queue size will stay low anyway, even if not - requesters will + // get an immediate error, but if we are slower, requesters will run in a timeout - + // wasting precious time. + let available_bandwidth = 7 * MIN_BANDWIDTH_BYTES / 10; + let size = u64::saturating_sub( + ATTESTED_CANDIDATE_TIMEOUT.as_millis() as u64 * available_bandwidth / + (1000 * MAX_CODE_SIZE as u64), + MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as u64, + ); + debug_assert!( + size > 0, + "We should have a channel size greater zero, otherwise we won't accept any requests." + ); + size as usize + }, } } /// Fallback protocol names of this protocol, as understood by substrate networking. fn get_fallback_names(self) -> Vec { - std::iter::once(self.get_legacy_name().into()).collect() + self.get_legacy_name().into_iter().map(Into::into).collect() } - /// Legacy protocol name associated with each peer set. - const fn get_legacy_name(self) -> &'static str { + /// Legacy protocol name associated with each peer set, if any. + const fn get_legacy_name(self) -> Option<&'static str> { match self { - Protocol::ChunkFetchingV1 => "/polkadot/req_chunk/1", - Protocol::CollationFetchingV1 => "/polkadot/req_collation/1", - Protocol::PoVFetchingV1 => "/polkadot/req_pov/1", - Protocol::AvailableDataFetchingV1 => "/polkadot/req_available_data/1", - Protocol::StatementFetchingV1 => "/polkadot/req_statement/1", - Protocol::DisputeSendingV1 => "/polkadot/send_dispute/1", + Protocol::ChunkFetchingV1 => Some("/polkadot/req_chunk/1"), + Protocol::CollationFetchingV1 => Some("/polkadot/req_collation/1"), + Protocol::PoVFetchingV1 => Some("/polkadot/req_pov/1"), + Protocol::AvailableDataFetchingV1 => Some("/polkadot/req_available_data/1"), + Protocol::StatementFetchingV1 => Some("/polkadot/req_statement/1"), + Protocol::DisputeSendingV1 => Some("/polkadot/send_dispute/1"), + + // Introduced after legacy names became legacy. + Protocol::AttestedCandidateVStaging => None, + Protocol::CollationFetchingVStaging => None, } } } @@ -336,6 +401,9 @@ impl ReqProtocolNames { Protocol::AvailableDataFetchingV1 => "/req_available_data/1", Protocol::StatementFetchingV1 => "/req_statement/1", Protocol::DisputeSendingV1 => "/send_dispute/1", + + Protocol::CollationFetchingVStaging => "/req_collation/2", + Protocol::AttestedCandidateVStaging => "/req_attested_candidate/2", }; format!("{}{}", prefix, short_name).into() diff --git a/node/network/protocol/src/request_response/outgoing.rs b/node/network/protocol/src/request_response/outgoing.rs index 581a4de63bd9..ddc6b85645bb 100644 --- a/node/network/protocol/src/request_response/outgoing.rs +++ b/node/network/protocol/src/request_response/outgoing.rs @@ -23,7 +23,7 @@ use sc_network::PeerId; use polkadot_primitives::AuthorityDiscoveryId; -use super::{v1, IsRequest, Protocol}; +use super::{v1, vstaging, IsRequest, Protocol}; /// All requests that can be sent to the network bridge via `NetworkBridgeTxMessage::SendRequest`. #[derive(Debug)] @@ -40,6 +40,12 @@ pub enum Requests { StatementFetchingV1(OutgoingRequest), /// Requests for notifying about an ongoing dispute. DisputeSendingV1(OutgoingRequest), + + /// Request a candidate and attestations. + AttestedCandidateVStaging(OutgoingRequest), + /// Fetch a collation from a collator which previously announced it. + /// Compared to V1 it requires specifying which candidate is requested by its hash. + CollationFetchingVStaging(OutgoingRequest), } impl Requests { @@ -48,10 +54,12 @@ impl Requests { match self { Self::ChunkFetchingV1(_) => Protocol::ChunkFetchingV1, Self::CollationFetchingV1(_) => Protocol::CollationFetchingV1, + Self::CollationFetchingVStaging(_) => Protocol::CollationFetchingVStaging, Self::PoVFetchingV1(_) => Protocol::PoVFetchingV1, Self::AvailableDataFetchingV1(_) => Protocol::AvailableDataFetchingV1, Self::StatementFetchingV1(_) => Protocol::StatementFetchingV1, Self::DisputeSendingV1(_) => Protocol::DisputeSendingV1, + Self::AttestedCandidateVStaging(_) => Protocol::AttestedCandidateVStaging, } } @@ -66,10 +74,12 @@ impl Requests { match self { Self::ChunkFetchingV1(r) => r.encode_request(), Self::CollationFetchingV1(r) => r.encode_request(), + Self::CollationFetchingVStaging(r) => r.encode_request(), Self::PoVFetchingV1(r) => r.encode_request(), Self::AvailableDataFetchingV1(r) => r.encode_request(), Self::StatementFetchingV1(r) => r.encode_request(), Self::DisputeSendingV1(r) => r.encode_request(), + Self::AttestedCandidateVStaging(r) => r.encode_request(), } } } diff --git a/node/network/protocol/src/request_response/vstaging.rs b/node/network/protocol/src/request_response/vstaging.rs new file mode 100644 index 000000000000..f84de9505534 --- /dev/null +++ b/node/network/protocol/src/request_response/vstaging.rs @@ -0,0 +1,80 @@ +// Copyright 2022 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 . + +//! Requests and responses as sent over the wire for the individual protocols. + +use parity_scale_codec::{Decode, Encode}; + +use polkadot_primitives::vstaging::{ + CandidateHash, CommittedCandidateReceipt, Hash, Id as ParaId, PersistedValidationData, + UncheckedSignedStatement, +}; + +use super::{IsRequest, Protocol}; +use crate::vstaging::StatementFilter; + +/// Request a candidate with statements. +#[derive(Debug, Clone, Encode, Decode)] +pub struct AttestedCandidateRequest { + /// Hash of the candidate we want to request. + pub candidate_hash: CandidateHash, + /// Statement filter with 'OR' semantics, indicating which validators + /// not to send statements for. + /// + /// The filter must have exactly the minimum size required to + /// fit all validators from the backing group. + /// + /// The response may not contain any statements masked out by this mask. + pub mask: StatementFilter, +} + +/// Response to an `AttestedCandidateRequest`. +#[derive(Debug, Clone, Encode, Decode)] +pub struct AttestedCandidateResponse { + /// The candidate receipt, with commitments. + pub candidate_receipt: CommittedCandidateReceipt, + /// The [`PersistedValidationData`] corresponding to the candidate. + pub persisted_validation_data: PersistedValidationData, + /// All known statements about the candidate, in compact form, + /// omitting `Seconded` statements which were intended to be masked + /// out. + pub statements: Vec, +} + +impl IsRequest for AttestedCandidateRequest { + type Response = AttestedCandidateResponse; + const PROTOCOL: Protocol = Protocol::AttestedCandidateVStaging; +} + +/// Responses as sent by collators. +pub type CollationFetchingResponse = super::v1::CollationFetchingResponse; + +/// Request the advertised collation at that relay-parent. +#[derive(Debug, Clone, Encode, Decode)] +pub struct CollationFetchingRequest { + /// Relay parent collation is built on top of. + pub relay_parent: Hash, + /// The `ParaId` of the collation. + pub para_id: ParaId, + /// Candidate hash. + pub candidate_hash: CandidateHash, +} + +impl IsRequest for CollationFetchingRequest { + // The response is the same as for V1. + type Response = CollationFetchingResponse; + const PROTOCOL: Protocol = Protocol::CollationFetchingVStaging; +} diff --git a/node/network/statement-distribution/Cargo.toml b/node/network/statement-distribution/Cargo.toml index 9d2ee1f621f6..dadd07613713 100644 --- a/node/network/statement-distribution/Cargo.toml +++ b/node/network/statement-distribution/Cargo.toml @@ -22,10 +22,12 @@ indexmap = "1.9.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } thiserror = "1.0.31" fatality = "0.0.6" +bitvec = "1" [dev-dependencies] -polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } +async-channel = "1.8.0" assert_matches = "1.4.0" +polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -36,3 +38,5 @@ sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "maste sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } futures-timer = "3.0.2" polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } +rand_chacha = "0.3" +polkadot-node-subsystem-types = { path = "../../subsystem-types" } diff --git a/node/network/statement-distribution/src/error.rs b/node/network/statement-distribution/src/error.rs index e0895989eeb6..b676e5b6a223 100644 --- a/node/network/statement-distribution/src/error.rs +++ b/node/network/statement-distribution/src/error.rs @@ -18,9 +18,13 @@ //! Error handling related code and Error/Result definitions. use polkadot_node_network_protocol::PeerId; -use polkadot_node_subsystem::SubsystemError; -use polkadot_node_subsystem_util::runtime; -use polkadot_primitives::{CandidateHash, Hash}; +use polkadot_node_subsystem::{RuntimeApiError, SubsystemError}; +use polkadot_node_subsystem_util::{ + backing_implicit_view::FetchError as ImplicitViewFetchError, runtime, +}; +use polkadot_primitives::{CandidateHash, Hash, Id as ParaId}; + +use futures::channel::oneshot; use crate::LOG_TARGET; @@ -56,6 +60,27 @@ pub enum Error { #[error("Error while accessing runtime information")] Runtime(#[from] runtime::Error), + #[error("RuntimeAPISubsystem channel closed before receipt")] + RuntimeApiUnavailable(#[source] oneshot::Canceled), + + #[error("Fetching persisted validation data for para {0:?}, {1:?}")] + FetchPersistedValidationData(ParaId, RuntimeApiError), + + #[error("Fetching session index failed {0:?}")] + FetchSessionIndex(RuntimeApiError), + + #[error("Fetching session info failed {0:?}")] + FetchSessionInfo(RuntimeApiError), + + #[error("Fetching availability cores failed {0:?}")] + FetchAvailabilityCores(RuntimeApiError), + + #[error("Fetching validator groups failed {0:?}")] + FetchValidatorGroups(RuntimeApiError), + + #[error("Attempted to share statement when not a validator or not assigned")] + InvalidShare, + #[error("Relay parent could not be found in active heads")] NoSuchHead(Hash), @@ -76,6 +101,10 @@ pub enum Error { // Responder no longer waits for our data. (Should not happen right now.) #[error("Oneshot `GetData` channel closed")] ResponderGetDataCanceled, + + // Failed to activate leaf due to a fetch error. + #[error("Implicit view failure while activating leaf")] + ActivateLeafFailure(ImplicitViewFetchError), } /// Utility for eating top level errors and log them. diff --git a/node/network/statement-distribution/src/legacy_v1/mod.rs b/node/network/statement-distribution/src/legacy_v1/mod.rs new file mode 100644 index 000000000000..219151daa020 --- /dev/null +++ b/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -0,0 +1,2177 @@ +// Copyright 2022 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 parity_scale_codec::Encode; + +use polkadot_node_network_protocol::{ + self as net_protocol, + grid_topology::{GridNeighbors, RequiredRouting, SessionBoundGridTopologyStorage}, + peer_set::{IsAuthority, PeerSet, ValidationVersion}, + v1::{self as protocol_v1, StatementMetadata}, + vstaging as protocol_vstaging, IfDisconnected, PeerId, UnifiedReputationChange as Rep, + Versioned, View, +}; +use polkadot_node_primitives::{ + SignedFullStatement, Statement, StatementWithPVD, UncheckedSignedFullStatement, +}; +use polkadot_node_subsystem_util::{ + self as util, rand, reputation::ReputationAggregator, MIN_GOSSIP_PEERS, +}; + +use polkadot_node_subsystem::{ + jaeger, + messages::{CandidateBackingMessage, NetworkBridgeEvent, NetworkBridgeTxMessage}, + overseer, ActivatedLeaf, PerLeafSpan, StatementDistributionSenderTrait, +}; +use polkadot_primitives::{ + AuthorityDiscoveryId, CandidateHash, CommittedCandidateReceipt, CompactStatement, Hash, + Id as ParaId, IndexedVec, OccupiedCoreAssumption, PersistedValidationData, SignedStatement, + SigningContext, UncheckedSignedStatement, ValidatorId, ValidatorIndex, ValidatorSignature, +}; + +use futures::{ + channel::{mpsc, oneshot}, + future::RemoteHandle, + prelude::*, +}; +use indexmap::{map::Entry as IEntry, IndexMap}; +use rand::Rng; +use sp_keystore::KeystorePtr; +use util::runtime::RuntimeInfo; + +use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque}; + +use crate::error::{Error, JfyiError, JfyiErrorResult, Result}; + +/// Background task logic for requesting of large statements. +mod requester; +use requester::fetch; + +/// Background task logic for responding for large statements. +mod responder; + +use crate::{metrics::Metrics, LOG_TARGET}; + +pub use requester::RequesterMessage; +pub use responder::{respond, ResponderMessage}; + +#[cfg(test)] +mod tests; + +const COST_UNEXPECTED_STATEMENT: Rep = Rep::CostMinor("Unexpected Statement"); +const COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE: Rep = + Rep::CostMinor("Unexpected Statement, missing knowlege for relay parent"); +const COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE: Rep = + Rep::CostMinor("Unexpected Statement, unknown candidate"); +const COST_UNEXPECTED_STATEMENT_REMOTE: Rep = + Rep::CostMinor("Unexpected Statement, remote not allowed"); + +const COST_FETCH_FAIL: Rep = + Rep::CostMinor("Requesting `CommittedCandidateReceipt` from peer failed"); +const COST_INVALID_SIGNATURE: Rep = Rep::CostMajor("Invalid Statement Signature"); +const COST_WRONG_HASH: Rep = Rep::CostMajor("Received candidate had wrong hash"); +const COST_DUPLICATE_STATEMENT: Rep = + Rep::CostMajorRepeated("Statement sent more than once by peer"); +const COST_APPARENT_FLOOD: Rep = Rep::Malicious("Peer appears to be flooding us with statements"); + +const BENEFIT_VALID_STATEMENT: Rep = Rep::BenefitMajor("Peer provided a valid statement"); +const BENEFIT_VALID_STATEMENT_FIRST: Rep = + Rep::BenefitMajorFirst("Peer was the first to provide a valid statement"); +const BENEFIT_VALID_RESPONSE: Rep = + Rep::BenefitMajor("Peer provided a valid large statement response"); + +/// The maximum amount of candidates each validator is allowed to second at any relay-parent. +/// Short for "Validator Candidate Threshold". +/// +/// This is the amount of candidates we keep per validator at any relay-parent. +/// Typically we will only keep 1, but when a validator equivocates we will need to track 2. +const VC_THRESHOLD: usize = 2; + +/// Large statements should be rare. +const MAX_LARGE_STATEMENTS_PER_SENDER: usize = 20; + +/// Overall state of the legacy-v1 portion of the subsystem. +pub(crate) struct State { + peers: HashMap, + topology_storage: SessionBoundGridTopologyStorage, + authorities: HashMap, + active_heads: HashMap, + recent_outdated_heads: RecentOutdatedHeads, + runtime: RuntimeInfo, +} + +impl State { + /// Create a new state. + pub(crate) fn new(keystore: KeystorePtr) -> Self { + State { + peers: HashMap::new(), + topology_storage: Default::default(), + authorities: HashMap::new(), + active_heads: HashMap::new(), + recent_outdated_heads: RecentOutdatedHeads::default(), + runtime: RuntimeInfo::new(Some(keystore)), + } + } + + /// Query whether the state contains some relay-parent. + pub(crate) fn contains_relay_parent(&self, relay_parent: &Hash) -> bool { + self.active_heads.contains_key(relay_parent) + } +} + +#[derive(Default)] +struct RecentOutdatedHeads { + buf: VecDeque, +} + +impl RecentOutdatedHeads { + fn note_outdated(&mut self, hash: Hash) { + const MAX_BUF_LEN: usize = 10; + + self.buf.push_back(hash); + + while self.buf.len() > MAX_BUF_LEN { + let _ = self.buf.pop_front(); + } + } + + fn is_recent_outdated(&self, hash: &Hash) -> bool { + self.buf.contains(hash) + } +} + +/// Tracks our impression of a single peer's view of the candidates a validator has seconded +/// for a given relay-parent. +/// +/// It is expected to receive at most `VC_THRESHOLD` from us and be aware of at most `VC_THRESHOLD` +/// via other means. +#[derive(Default)] +struct VcPerPeerTracker { + local_observed: arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, + remote_observed: arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, +} + +impl VcPerPeerTracker { + /// Note that the remote should now be aware that a validator has seconded a given candidate (by + /// hash) based on a message that we have sent it from our local pool. + fn note_local(&mut self, h: CandidateHash) { + if !note_hash(&mut self.local_observed, h) { + gum::warn!( + target: LOG_TARGET, + "Statement distribution is erroneously attempting to distribute more \ + than {} candidate(s) per validator index. Ignoring", + VC_THRESHOLD, + ); + } + } + + /// Note that the remote should now be aware that a validator has seconded a given candidate (by + /// hash) based on a message that it has sent us. + /// + /// Returns `true` if the peer was allowed to send us such a message, `false` otherwise. + fn note_remote(&mut self, h: CandidateHash) -> bool { + note_hash(&mut self.remote_observed, h) + } + + /// Returns `true` if the peer is allowed to send us such a message, `false` otherwise. + fn is_wanted_candidate(&self, h: &CandidateHash) -> bool { + !self.remote_observed.contains(h) && !self.remote_observed.is_full() + } +} + +fn note_hash( + observed: &mut arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, + h: CandidateHash, +) -> bool { + if observed.contains(&h) { + return true + } + + observed.try_push(h).is_ok() +} + +/// knowledge that a peer has about goings-on in a relay parent. +#[derive(Default)] +struct PeerRelayParentKnowledge { + /// candidates that the peer is aware of because we sent statements to it. This indicates that + /// we can send other statements pertaining to that candidate. + sent_candidates: HashSet, + /// candidates that peer is aware of, because we received statements from it. + received_candidates: HashSet, + /// fingerprints of all statements a peer should be aware of: those that + /// were sent to the peer by us. + sent_statements: HashSet<(CompactStatement, ValidatorIndex)>, + /// fingerprints of all statements a peer should be aware of: those that + /// were sent to us by the peer. + received_statements: HashSet<(CompactStatement, ValidatorIndex)>, + /// How many candidates this peer is aware of for each given validator index. + seconded_counts: HashMap, + /// How many statements we've received for each candidate that we're aware of. + received_message_count: HashMap, + + /// How many large statements this peer already sent us. + /// + /// Flood protection for large statements is rather hard and as soon as we get + /// `https://github.com/paritytech/polkadot/issues/2979` implemented also no longer necessary. + /// Reason: We keep messages around until we fetched the payload, but if a node makes up + /// statements and never provides the data, we will keep it around for the slot duration. Not + /// even signature checking would help, as the sender, if a validator, can just sign arbitrary + /// invalid statements and will not face any consequences as long as it won't provide the + /// payload. + /// + /// Quick and temporary fix, only accept `MAX_LARGE_STATEMENTS_PER_SENDER` per connected node. + /// + /// Large statements should be rare, if they were not, we would run into problems anyways, as + /// we would not be able to distribute them in a timely manner. Therefore + /// `MAX_LARGE_STATEMENTS_PER_SENDER` can be set to a relatively small number. It is also not + /// per candidate hash, but in total as candidate hashes can be made up, as illustrated above. + /// + /// An attacker could still try to fill up our memory, by repeatedly disconnecting and + /// connecting again with new peer ids, but we assume that the resulting effective bandwidth + /// for such an attack would be too low. + large_statement_count: usize, + + /// We have seen a message that that is unexpected from this peer, so note this fact + /// and stop subsequent logging and peer reputation flood. + unexpected_count: usize, +} + +impl PeerRelayParentKnowledge { + /// Updates our view of the peer's knowledge with this statement's fingerprint based + /// on something that we would like to send to the peer. + /// + /// NOTE: assumes `self.can_send` returned true before this call. + /// + /// Once the knowledge has incorporated a statement, it cannot be incorporated again. + /// + /// This returns `true` if this is the first time the peer has become aware of a + /// candidate with the given hash. + fn send(&mut self, fingerprint: &(CompactStatement, ValidatorIndex)) -> bool { + debug_assert!( + self.can_send(fingerprint), + "send is only called after `can_send` returns true; qed", + ); + + let new_known = match fingerprint.0 { + CompactStatement::Seconded(ref h) => { + self.seconded_counts.entry(fingerprint.1).or_default().note_local(*h); + + let was_known = self.is_known_candidate(h); + self.sent_candidates.insert(*h); + !was_known + }, + CompactStatement::Valid(_) => false, + }; + + self.sent_statements.insert(fingerprint.clone()); + + new_known + } + + /// This returns `true` if the peer cannot accept this statement, without altering internal + /// state, `false` otherwise. + fn can_send(&self, fingerprint: &(CompactStatement, ValidatorIndex)) -> bool { + let already_known = self.sent_statements.contains(fingerprint) || + self.received_statements.contains(fingerprint); + + if already_known { + return false + } + + match fingerprint.0 { + CompactStatement::Valid(ref h) => { + // The peer can only accept Valid statements for which it is aware + // of the corresponding candidate. + self.is_known_candidate(h) + }, + CompactStatement::Seconded(_) => true, + } + } + + /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based + /// on a message we are receiving from the peer. + /// + /// Provide the maximum message count that we can receive per candidate. In practice we should + /// not receive more statements for any one candidate than there are members in the group + /// assigned to that para, but this maximum needs to be lenient to account for equivocations + /// that may be cross-group. As such, a maximum of 2 * `n_validators` is recommended. + /// + /// This returns an error if the peer should not have sent us this message according to protocol + /// rules for flood protection. + /// + /// If this returns `Ok`, the internal state has been altered. After `receive`ing a new + /// candidate, we are then cleared to send the peer further statements about that candidate. + /// + /// This returns `Ok(true)` if this is the first time the peer has become aware of a + /// candidate with given hash. + fn receive( + &mut self, + fingerprint: &(CompactStatement, ValidatorIndex), + max_message_count: usize, + ) -> std::result::Result { + // We don't check `sent_statements` because a statement could be in-flight from both + // sides at the same time. + if self.received_statements.contains(fingerprint) { + return Err(COST_DUPLICATE_STATEMENT) + } + + let (candidate_hash, fresh) = match fingerprint.0 { + CompactStatement::Seconded(ref h) => { + let allowed_remote = self + .seconded_counts + .entry(fingerprint.1) + .or_insert_with(Default::default) + .note_remote(*h); + + if !allowed_remote { + return Err(COST_UNEXPECTED_STATEMENT_REMOTE) + } + + (h, !self.is_known_candidate(h)) + }, + CompactStatement::Valid(ref h) => { + if !self.is_known_candidate(h) { + return Err(COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE) + } + + (h, false) + }, + }; + + { + let received_per_candidate = + self.received_message_count.entry(*candidate_hash).or_insert(0); + + if *received_per_candidate >= max_message_count { + return Err(COST_APPARENT_FLOOD) + } + + *received_per_candidate += 1; + } + + self.received_statements.insert(fingerprint.clone()); + self.received_candidates.insert(*candidate_hash); + Ok(fresh) + } + + /// Note a received large statement metadata. + fn receive_large_statement(&mut self) -> std::result::Result<(), Rep> { + if self.large_statement_count >= MAX_LARGE_STATEMENTS_PER_SENDER { + return Err(COST_APPARENT_FLOOD) + } + self.large_statement_count += 1; + Ok(()) + } + + /// This method does the same checks as `receive` without modifying the internal state. + /// Returns an error if the peer should not have sent us this message according to protocol + /// rules for flood protection. + fn check_can_receive( + &self, + fingerprint: &(CompactStatement, ValidatorIndex), + max_message_count: usize, + ) -> std::result::Result<(), Rep> { + // We don't check `sent_statements` because a statement could be in-flight from both + // sides at the same time. + if self.received_statements.contains(fingerprint) { + return Err(COST_DUPLICATE_STATEMENT) + } + + let candidate_hash = match fingerprint.0 { + CompactStatement::Seconded(ref h) => { + let allowed_remote = self + .seconded_counts + .get(&fingerprint.1) + .map_or(true, |r| r.is_wanted_candidate(h)); + + if !allowed_remote { + return Err(COST_UNEXPECTED_STATEMENT_REMOTE) + } + + h + }, + CompactStatement::Valid(ref h) => { + if !self.is_known_candidate(&h) { + return Err(COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE) + } + + h + }, + }; + + let received_per_candidate = self.received_message_count.get(candidate_hash).unwrap_or(&0); + + if *received_per_candidate >= max_message_count { + Err(COST_APPARENT_FLOOD) + } else { + Ok(()) + } + } + + /// Check for candidates that the peer is aware of. This indicates that we can + /// send other statements pertaining to that candidate. + fn is_known_candidate(&self, candidate: &CandidateHash) -> bool { + self.sent_candidates.contains(candidate) || self.received_candidates.contains(candidate) + } +} + +pub struct PeerData { + view: View, + protocol_version: ValidationVersion, + view_knowledge: HashMap, + /// Peer might be known as authority with the given ids. + maybe_authority: Option>, +} + +impl PeerData { + /// Updates our view of the peer's knowledge with this statement's fingerprint based + /// on something that we would like to send to the peer. + /// + /// NOTE: assumes `self.can_send` returned true before this call. + /// + /// Once the knowledge has incorporated a statement, it cannot be incorporated again. + /// + /// This returns `true` if this is the first time the peer has become aware of a + /// candidate with the given hash. + fn send( + &mut self, + relay_parent: &Hash, + fingerprint: &(CompactStatement, ValidatorIndex), + ) -> bool { + debug_assert!( + self.can_send(relay_parent, fingerprint), + "send is only called after `can_send` returns true; qed", + ); + self.view_knowledge + .get_mut(relay_parent) + .expect("send is only called after `can_send` returns true; qed") + .send(fingerprint) + } + + /// This returns `None` if the peer cannot accept this statement, without altering internal + /// state. + fn can_send( + &self, + relay_parent: &Hash, + fingerprint: &(CompactStatement, ValidatorIndex), + ) -> bool { + self.view_knowledge.get(relay_parent).map_or(false, |k| k.can_send(fingerprint)) + } + + /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based + /// on a message we are receiving from the peer. + /// + /// Provide the maximum message count that we can receive per candidate. In practice we should + /// not receive more statements for any one candidate than there are members in the group + /// assigned to that para, but this maximum needs to be lenient to account for equivocations + /// that may be cross-group. As such, a maximum of 2 * `n_validators` is recommended. + /// + /// This returns an error if the peer should not have sent us this message according to protocol + /// rules for flood protection. + /// + /// If this returns `Ok`, the internal state has been altered. After `receive`ing a new + /// candidate, we are then cleared to send the peer further statements about that candidate. + /// + /// This returns `Ok(true)` if this is the first time the peer has become aware of a + /// candidate with given hash. + fn receive( + &mut self, + relay_parent: &Hash, + fingerprint: &(CompactStatement, ValidatorIndex), + max_message_count: usize, + ) -> std::result::Result { + self.view_knowledge + .get_mut(relay_parent) + .ok_or(COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE)? + .receive(fingerprint, max_message_count) + } + + /// This method does the same checks as `receive` without modifying the internal state. + /// Returns an error if the peer should not have sent us this message according to protocol + /// rules for flood protection. + fn check_can_receive( + &self, + relay_parent: &Hash, + fingerprint: &(CompactStatement, ValidatorIndex), + max_message_count: usize, + ) -> std::result::Result<(), Rep> { + self.view_knowledge + .get(relay_parent) + .ok_or(COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE)? + .check_can_receive(fingerprint, max_message_count) + } + + /// Receive a notice about out of view statement and returns the value of the old flag + fn receive_unexpected(&mut self, relay_parent: &Hash) -> usize { + self.view_knowledge + .get_mut(relay_parent) + .map_or(0_usize, |relay_parent_peer_knowledge| { + let old = relay_parent_peer_knowledge.unexpected_count; + relay_parent_peer_knowledge.unexpected_count += 1_usize; + old + }) + } + + /// Basic flood protection for large statements. + fn receive_large_statement(&mut self, relay_parent: &Hash) -> std::result::Result<(), Rep> { + self.view_knowledge + .get_mut(relay_parent) + .ok_or(COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE)? + .receive_large_statement() + } +} + +// A statement stored while a relay chain head is active. +#[derive(Debug, Copy, Clone)] +struct StoredStatement<'a> { + comparator: &'a StoredStatementComparator, + statement: &'a SignedFullStatement, +} + +// A value used for comparison of stored statements to each other. +// +// The compact version of the statement, the validator index, and the signature of the validator +// is enough to differentiate between all types of equivocations, as long as the signature is +// actually checked to be valid. The same statement with 2 signatures and 2 statements with +// different (or same) signatures wll all be correctly judged to be unequal with this comparator. +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +struct StoredStatementComparator { + compact: CompactStatement, + validator_index: ValidatorIndex, + signature: ValidatorSignature, +} + +impl<'a> From<(&'a StoredStatementComparator, &'a SignedFullStatement)> for StoredStatement<'a> { + fn from( + (comparator, statement): (&'a StoredStatementComparator, &'a SignedFullStatement), + ) -> Self { + Self { comparator, statement } + } +} + +impl<'a> StoredStatement<'a> { + fn compact(&self) -> &'a CompactStatement { + &self.comparator.compact + } + + fn fingerprint(&self) -> (CompactStatement, ValidatorIndex) { + (self.comparator.compact.clone(), self.statement.validator_index()) + } +} + +#[derive(Debug)] +enum NotedStatement<'a> { + NotUseful, + Fresh(StoredStatement<'a>), + UsefulButKnown, +} + +/// Large statement fetching status. +enum LargeStatementStatus { + /// We are currently fetching the statement data from a remote peer. We keep a list of other + /// nodes claiming to have that data and will fallback on them. + Fetching(FetchingInfo), + /// Statement data is fetched or we got it locally via `StatementDistributionMessage::Share`. + FetchedOrShared(CommittedCandidateReceipt), +} + +/// Info about a fetch in progress. +struct FetchingInfo { + /// All peers that send us a `LargeStatement` or a `Valid` statement for the given + /// `CandidateHash`, together with their originally sent messages. + /// + /// We use an `IndexMap` here to preserve the ordering of peers sending us messages. This is + /// desirable because we reward first sending peers with reputation. + available_peers: IndexMap>, + /// Peers left to try in case the background task needs it. + peers_to_try: Vec, + /// Sender for sending fresh peers to the fetching task in case of failure. + peer_sender: Option>>, + /// Task taking care of the request. + /// + /// Will be killed once dropped. + #[allow(dead_code)] + fetching_task: RemoteHandle<()>, +} + +#[derive(Debug, PartialEq, Eq)] +enum DeniedStatement { + NotUseful, + UsefulButKnown, +} + +pub(crate) struct ActiveHeadData { + /// All candidates we are aware of for this head, keyed by hash. + candidates: HashSet, + /// Persisted validation data cache. + cached_validation_data: HashMap, + /// Stored statements for circulation to peers. + /// + /// These are iterable in insertion order, and `Seconded` statements are always + /// accepted before dependent statements. + statements: IndexMap, + /// Large statements we are waiting for with associated meta data. + waiting_large_statements: HashMap, + /// The parachain validators at the head's child session index. + validators: IndexedVec, + /// The current session index of this fork. + session_index: sp_staking::SessionIndex, + /// How many `Seconded` statements we've seen per validator. + seconded_counts: HashMap, + /// A Jaeger span for this head, so we can attach data to it. + span: PerLeafSpan, +} + +impl ActiveHeadData { + fn new( + validators: IndexedVec, + session_index: sp_staking::SessionIndex, + span: PerLeafSpan, + ) -> Self { + ActiveHeadData { + candidates: Default::default(), + cached_validation_data: Default::default(), + statements: Default::default(), + waiting_large_statements: Default::default(), + validators, + session_index, + seconded_counts: Default::default(), + span, + } + } + + /// Fetches the `PersistedValidationData` from the runtime, assuming + /// that the core is free. The relay parent must match that of the active + /// head. + async fn fetch_persisted_validation_data( + &mut self, + sender: &mut Sender, + relay_parent: Hash, + para_id: ParaId, + ) -> Result> + where + Sender: StatementDistributionSenderTrait, + { + if let Entry::Vacant(entry) = self.cached_validation_data.entry(para_id) { + let persisted_validation_data = + polkadot_node_subsystem_util::request_persisted_validation_data( + relay_parent, + para_id, + OccupiedCoreAssumption::Free, + sender, + ) + .await + .await + .map_err(Error::RuntimeApiUnavailable)? + .map_err(|err| Error::FetchPersistedValidationData(para_id, err))?; + + match persisted_validation_data { + Some(pvd) => entry.insert(pvd), + None => return Ok(None), + }; + } + + Ok(self.cached_validation_data.get(¶_id)) + } + + /// Note the given statement. + /// + /// If it was not already known and can be accepted, returns `NotedStatement::Fresh`, + /// with a handle to the statement. + /// + /// If it can be accepted, but we already know it, returns `NotedStatement::UsefulButKnown`. + /// + /// We accept up to `VC_THRESHOLD` (2 at time of writing) `Seconded` statements + /// per validator. These will be the first ones we see. The statement is assumed + /// to have been checked, including that the validator index is not out-of-bounds and + /// the signature is valid. + /// + /// Any other statements or those that reference a candidate we are not aware of cannot be + /// accepted and will return `NotedStatement::NotUseful`. + fn note_statement(&mut self, statement: SignedFullStatement) -> NotedStatement { + let validator_index = statement.validator_index(); + let comparator = StoredStatementComparator { + compact: statement.payload().to_compact(), + validator_index, + signature: statement.signature().clone(), + }; + + match comparator.compact { + CompactStatement::Seconded(h) => { + let seconded_so_far = self.seconded_counts.entry(validator_index).or_insert(0); + if *seconded_so_far >= VC_THRESHOLD { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + ?statement, + "Extra statement is ignored" + ); + return NotedStatement::NotUseful + } + + self.candidates.insert(h); + if let Some(old) = self.statements.insert(comparator.clone(), statement) { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + statement = ?old, + "Known statement" + ); + NotedStatement::UsefulButKnown + } else { + *seconded_so_far += 1; + + gum::trace!( + target: LOG_TARGET, + ?validator_index, + statement = ?self.statements.last().expect("Just inserted").1, + "Noted new statement" + ); + // This will always return `Some` because it was just inserted. + let key_value = self + .statements + .get_key_value(&comparator) + .expect("Statement was just inserted; qed"); + + NotedStatement::Fresh(key_value.into()) + } + }, + CompactStatement::Valid(h) => { + if !self.candidates.contains(&h) { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + ?statement, + "Statement for unknown candidate" + ); + return NotedStatement::NotUseful + } + + if let Some(old) = self.statements.insert(comparator.clone(), statement) { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + statement = ?old, + "Known statement" + ); + NotedStatement::UsefulButKnown + } else { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + statement = ?self.statements.last().expect("Just inserted").1, + "Noted new statement" + ); + // This will always return `Some` because it was just inserted. + NotedStatement::Fresh( + self.statements + .get_key_value(&comparator) + .expect("Statement was just inserted; qed") + .into(), + ) + } + }, + } + } + + /// Returns an error if the statement is already known or not useful + /// without modifying the internal state. + fn check_useful_or_unknown( + &self, + statement: &UncheckedSignedStatement, + ) -> std::result::Result<(), DeniedStatement> { + let validator_index = statement.unchecked_validator_index(); + let compact = statement.unchecked_payload(); + let comparator = StoredStatementComparator { + compact: compact.clone(), + validator_index, + signature: statement.unchecked_signature().clone(), + }; + + match compact { + CompactStatement::Seconded(_) => { + let seconded_so_far = self.seconded_counts.get(&validator_index).unwrap_or(&0); + if *seconded_so_far >= VC_THRESHOLD { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + ?statement, + "Extra statement is ignored", + ); + return Err(DeniedStatement::NotUseful) + } + + if self.statements.contains_key(&comparator) { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + ?statement, + "Known statement", + ); + return Err(DeniedStatement::UsefulButKnown) + } + }, + CompactStatement::Valid(h) => { + if !self.candidates.contains(&h) { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + ?statement, + "Statement for unknown candidate", + ); + return Err(DeniedStatement::NotUseful) + } + + if self.statements.contains_key(&comparator) { + gum::trace!( + target: LOG_TARGET, + ?validator_index, + ?statement, + "Known statement", + ); + return Err(DeniedStatement::UsefulButKnown) + } + }, + } + Ok(()) + } + + /// Get an iterator over all statements for the active head. Seconded statements come first. + fn statements(&self) -> impl Iterator> + '_ { + self.statements.iter().map(Into::into) + } + + /// Get an iterator over all statements for the active head that are for a particular candidate. + fn statements_about( + &self, + candidate_hash: CandidateHash, + ) -> impl Iterator> + '_ { + self.statements() + .filter(move |s| s.compact().candidate_hash() == &candidate_hash) + } +} + +/// Check a statement signature under this parent hash. +fn check_statement_signature( + head: &ActiveHeadData, + relay_parent: Hash, + statement: UncheckedSignedStatement, +) -> std::result::Result { + let signing_context = + SigningContext { session_index: head.session_index, parent_hash: relay_parent }; + + head.validators + .get(statement.unchecked_validator_index()) + .ok_or_else(|| statement.clone()) + .and_then(|v| statement.try_into_checked(&signing_context, v)) +} + +/// Places the statement in storage if it is new, and then +/// circulates the statement to all peers who have not seen it yet, and +/// sends all statements dependent on that statement to peers who could previously not receive +/// them but now can. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn circulate_statement_and_dependents( + topology_store: &SessionBoundGridTopologyStorage, + peers: &mut HashMap, + active_heads: &mut HashMap, + ctx: &mut Context, + relay_parent: Hash, + statement: SignedFullStatement, + priority_peers: Vec, + metrics: &Metrics, + rng: &mut impl rand::Rng, +) { + let active_head = match active_heads.get_mut(&relay_parent) { + Some(res) => res, + None => return, + }; + + let _span = active_head + .span + .child("circulate-statement") + .with_candidate(statement.payload().candidate_hash()) + .with_stage(jaeger::Stage::StatementDistribution); + + let topology = topology_store + .get_topology_or_fallback(active_head.session_index) + .local_grid_neighbors(); + // First circulate the statement directly to all peers needing it. + // The borrow of `active_head` needs to encompass only this (Rust) statement. + let outputs: Option<(CandidateHash, Vec)> = { + match active_head.note_statement(statement) { + NotedStatement::Fresh(stored) => Some(( + *stored.compact().candidate_hash(), + circulate_statement( + RequiredRouting::GridXY, + topology, + peers, + ctx, + relay_parent, + stored, + priority_peers, + metrics, + rng, + ) + .await, + )), + _ => None, + } + }; + + let _span = _span.child("send-to-peers"); + // Now send dependent statements to all peers needing them, if any. + if let Some((candidate_hash, peers_needing_dependents)) = outputs { + for peer in peers_needing_dependents { + if let Some(peer_data) = peers.get_mut(&peer) { + let _span_loop = _span.child("to-peer").with_peer_id(&peer); + // defensive: the peer data should always be some because the iterator + // of peers is derived from the set of peers. + send_statements_about( + peer, + peer_data, + ctx, + relay_parent, + candidate_hash, + &*active_head, + metrics, + ) + .await; + } + } + } +} + +/// Create a network message from a given statement. +fn v1_statement_message( + relay_parent: Hash, + statement: SignedFullStatement, + metrics: &Metrics, +) -> protocol_v1::StatementDistributionMessage { + let (is_large, size) = is_statement_large(&statement); + if let Some(size) = size { + metrics.on_created_message(size); + } + + if is_large { + protocol_v1::StatementDistributionMessage::LargeStatement(StatementMetadata { + relay_parent, + candidate_hash: statement.payload().candidate_hash(), + signed_by: statement.validator_index(), + signature: statement.signature().clone(), + }) + } else { + protocol_v1::StatementDistributionMessage::Statement(relay_parent, statement.into()) + } +} + +/// Check whether a statement should be treated as large statement. +/// +/// Also report size of statement - if it is a `Seconded` statement, otherwise `None`. +fn is_statement_large(statement: &SignedFullStatement) -> (bool, Option) { + match &statement.payload() { + Statement::Seconded(committed) => { + let size = statement.as_unchecked().encoded_size(); + // Runtime upgrades will always be large and even if not - no harm done. + if committed.commitments.new_validation_code.is_some() { + return (true, Some(size)) + } + + // Half max size seems to be a good threshold to start not using notifications: + let threshold = + PeerSet::Validation.get_max_notification_size(IsAuthority::Yes) as usize / 2; + + (size >= threshold, Some(size)) + }, + Statement::Valid(_) => (false, None), + } +} + +/// Circulates a statement to all peers who have not seen it yet, and returns +/// an iterator over peers who need to have dependent statements sent. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn circulate_statement<'a, Context>( + required_routing: RequiredRouting, + topology: &GridNeighbors, + peers: &mut HashMap, + ctx: &mut Context, + relay_parent: Hash, + stored: StoredStatement<'a>, + mut priority_peers: Vec, + metrics: &Metrics, + rng: &mut impl rand::Rng, +) -> Vec { + let fingerprint = stored.fingerprint(); + + let mut peers_to_send: Vec = peers + .iter() + .filter_map( + |(peer, data)| { + if data.can_send(&relay_parent, &fingerprint) { + Some(*peer) + } else { + None + } + }, + ) + .collect(); + + let good_peers: HashSet<&PeerId> = peers_to_send.iter().collect(); + // Only take priority peers we can send data to: + priority_peers.retain(|p| good_peers.contains(p)); + + // Avoid duplicates: + let priority_set: HashSet<&PeerId> = priority_peers.iter().collect(); + peers_to_send.retain(|p| !priority_set.contains(p)); + + util::choose_random_subset_with_rng( + |e| topology.route_to_peer(required_routing, e), + &mut peers_to_send, + rng, + MIN_GOSSIP_PEERS, + ); + + // We don't want to use less peers, than we would without any priority peers: + let min_size = std::cmp::max(peers_to_send.len(), MIN_GOSSIP_PEERS); + // Make set full: + let needed_peers = min_size as i64 - priority_peers.len() as i64; + if needed_peers > 0 { + peers_to_send.truncate(needed_peers as usize); + // Order important here - priority peers are placed first, so will be sent first. + // This gives backers a chance to be among the first in requesting any large statement + // data. + priority_peers.append(&mut peers_to_send); + } + peers_to_send = priority_peers; + // We must not have duplicates: + debug_assert!( + peers_to_send.len() == peers_to_send.clone().into_iter().collect::>().len(), + "We filter out duplicates above. qed.", + ); + + let (v1_peers_to_send, vstaging_peers_to_send) = peers_to_send + .into_iter() + .map(|peer_id| { + let peer_data = + peers.get_mut(&peer_id).expect("a subset is taken above, so it exists; qed"); + + let new = peer_data.send(&relay_parent, &fingerprint); + + (peer_id, new, peer_data.protocol_version) + }) + .partition::, _>(|(_, _, version)| match version { + ValidationVersion::V1 => true, + ValidationVersion::VStaging => false, + }); // partition is handy here but not if we add more protocol versions + + let payload = v1_statement_message(relay_parent, stored.statement.clone(), metrics); + + // Send all these peers the initial statement. + if !v1_peers_to_send.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?v1_peers_to_send, + ?relay_parent, + statement = ?stored.statement, + "Sending statement to v1 peers", + ); + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + v1_peers_to_send.iter().map(|(p, _, _)| *p).collect(), + compatible_v1_message(ValidationVersion::V1, payload.clone()).into(), + )) + .await; + } + if !vstaging_peers_to_send.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?vstaging_peers_to_send, + ?relay_parent, + statement = ?stored.statement, + "Sending statement to vstaging peers", + ); + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vstaging_peers_to_send.iter().map(|(p, _, _)| *p).collect(), + compatible_v1_message(ValidationVersion::VStaging, payload.clone()).into(), + )) + .await; + } + + v1_peers_to_send + .into_iter() + .chain(vstaging_peers_to_send) + .filter_map(|(peer, needs_dependent, _)| if needs_dependent { Some(peer) } else { None }) + .collect() +} + +/// Send all statements about a given candidate hash to a peer. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_statements_about( + peer: PeerId, + peer_data: &mut PeerData, + ctx: &mut Context, + relay_parent: Hash, + candidate_hash: CandidateHash, + active_head: &ActiveHeadData, + metrics: &Metrics, +) { + for statement in active_head.statements_about(candidate_hash) { + let fingerprint = statement.fingerprint(); + if !peer_data.can_send(&relay_parent, &fingerprint) { + continue + } + peer_data.send(&relay_parent, &fingerprint); + let payload = v1_statement_message(relay_parent, statement.statement.clone(), metrics); + + gum::trace!( + target: LOG_TARGET, + ?peer, + ?relay_parent, + ?candidate_hash, + statement = ?statement.statement, + "Sending statement", + ); + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vec![peer], + compatible_v1_message(peer_data.protocol_version, payload).into(), + )) + .await; + + metrics.on_statement_distributed(); + } +} + +/// Send all statements at a given relay-parent to a peer. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_statements( + peer: PeerId, + peer_data: &mut PeerData, + ctx: &mut Context, + relay_parent: Hash, + active_head: &ActiveHeadData, + metrics: &Metrics, +) { + for statement in active_head.statements() { + let fingerprint = statement.fingerprint(); + if !peer_data.can_send(&relay_parent, &fingerprint) { + continue + } + peer_data.send(&relay_parent, &fingerprint); + let payload = v1_statement_message(relay_parent, statement.statement.clone(), metrics); + + gum::trace!( + target: LOG_TARGET, + ?peer, + ?relay_parent, + statement = ?statement.statement, + "Sending statement" + ); + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + vec![peer], + compatible_v1_message(peer_data.protocol_version, payload).into(), + )) + .await; + + metrics.on_statement_distributed(); + } +} + +/// Modify the reputation of a peer based on its behavior. +async fn modify_reputation( + reputation: &mut ReputationAggregator, + sender: &mut impl overseer::StatementDistributionSenderTrait, + peer: PeerId, + rep: Rep, +) { + reputation.modify(sender, peer, rep).await; +} + +/// If message contains a statement, then retrieve it, otherwise fork task to fetch it. +/// +/// This function will also return `None` if the message did not pass some basic checks, in that +/// case no statement will be requested, on the flipside you get `ActiveHeadData` in addition to +/// your statement. +/// +/// If the message was large, but the result has been fetched already that one is returned. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn retrieve_statement_from_message<'a, Context>( + peer: PeerId, + peer_version: ValidationVersion, + message: protocol_v1::StatementDistributionMessage, + active_head: &'a mut ActiveHeadData, + ctx: &mut Context, + req_sender: &mpsc::Sender, + metrics: &Metrics, +) -> Option { + let fingerprint = message.get_fingerprint(); + let candidate_hash = *fingerprint.0.candidate_hash(); + + // Immediately return any Seconded statement: + let message = if let protocol_v1::StatementDistributionMessage::Statement(h, s) = message { + if let Statement::Seconded(_) = s.unchecked_payload() { + return Some(s) + } + protocol_v1::StatementDistributionMessage::Statement(h, s) + } else { + message + }; + + match active_head.waiting_large_statements.entry(candidate_hash) { + Entry::Occupied(mut occupied) => { + match occupied.get_mut() { + LargeStatementStatus::Fetching(info) => { + let is_large_statement = message.is_large_statement(); + + let is_new_peer = match info.available_peers.entry(peer) { + IEntry::Occupied(mut occupied) => { + occupied.get_mut().push(compatible_v1_message(peer_version, message)); + false + }, + IEntry::Vacant(vacant) => { + vacant.insert(vec![compatible_v1_message(peer_version, message)]); + true + }, + }; + + if is_new_peer & is_large_statement { + info.peers_to_try.push(peer); + // Answer any pending request for more peers: + if let Some(sender) = info.peer_sender.take() { + let to_send = std::mem::take(&mut info.peers_to_try); + if let Err(peers) = sender.send(to_send) { + // Requester no longer interested for now, might want them + // later: + info.peers_to_try = peers; + } + } + } + }, + LargeStatementStatus::FetchedOrShared(committed) => { + match message { + protocol_v1::StatementDistributionMessage::Statement(_, s) => { + // We can now immediately return any statements (should only be + // `Statement::Valid` ones, but we don't care at this point.) + return Some(s) + }, + protocol_v1::StatementDistributionMessage::LargeStatement(metadata) => + return Some(UncheckedSignedFullStatement::new( + Statement::Seconded(committed.clone()), + metadata.signed_by, + metadata.signature.clone(), + )), + } + }, + } + }, + Entry::Vacant(vacant) => { + match message { + protocol_v1::StatementDistributionMessage::LargeStatement(metadata) => { + if let Some(new_status) = launch_request( + metadata, + peer, + peer_version, + req_sender.clone(), + ctx, + metrics, + ) + .await + { + vacant.insert(new_status); + } + }, + protocol_v1::StatementDistributionMessage::Statement(_, s) => { + // No fetch in progress, safe to return any statement immediately (we don't + // bother about normal network jitter which might cause `Valid` statements to + // arrive early for now.). + return Some(s) + }, + } + }, + } + None +} + +/// Launch request for a large statement and get tracking status. +/// +/// Returns `None` if spawning task failed. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn launch_request( + meta: StatementMetadata, + peer: PeerId, + peer_version: ValidationVersion, + req_sender: mpsc::Sender, + ctx: &mut Context, + metrics: &Metrics, +) -> Option { + let (task, handle) = + fetch(meta.relay_parent, meta.candidate_hash, vec![peer], req_sender, metrics.clone()) + .remote_handle(); + + let result = ctx.spawn("large-statement-fetcher", task.boxed()); + if let Err(err) = result { + gum::error!(target: LOG_TARGET, ?err, "Spawning task failed."); + return None + } + let available_peers = { + let mut m = IndexMap::new(); + m.insert( + peer, + vec![compatible_v1_message( + peer_version, + protocol_v1::StatementDistributionMessage::LargeStatement(meta), + )], + ); + m + }; + Some(LargeStatementStatus::Fetching(FetchingInfo { + available_peers, + peers_to_try: Vec::new(), + peer_sender: None, + fetching_task: handle, + })) +} + +/// Handle incoming message and circulate it to peers, if we did not know it already. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_incoming_message_and_circulate<'a, Context, R>( + peer: PeerId, + topology_storage: &SessionBoundGridTopologyStorage, + peers: &mut HashMap, + active_heads: &'a mut HashMap, + recent_outdated_heads: &RecentOutdatedHeads, + ctx: &mut Context, + message: net_protocol::StatementDistributionMessage, + req_sender: &mpsc::Sender, + metrics: &Metrics, + runtime: &mut RuntimeInfo, + rng: &mut R, + reputation: &mut ReputationAggregator, +) where + R: rand::Rng, +{ + let handled_incoming = match peers.get_mut(&peer) { + Some(data) => + handle_incoming_message( + peer, + data, + active_heads, + recent_outdated_heads, + ctx, + message, + req_sender, + metrics, + reputation, + ) + .await, + None => None, + }; + + // if we got a fresh message, we need to circulate it to all peers. + if let Some((relay_parent, statement)) = handled_incoming { + // we can ignore the set of peers who this function returns as now expecting + // dependent statements. + // + // we have the invariant in this subsystem that we never store a `Valid` or `Invalid` + // statement before a `Seconded` statement. `Seconded` statements are the only ones + // that require dependents. Thus, if this is a `Seconded` statement for a candidate we + // were not aware of before, we cannot have any dependent statements from the candidate. + let _ = metrics.time_network_bridge_update("circulate_statement"); + + let session_index = runtime.get_session_index_for_child(ctx.sender(), relay_parent).await; + let topology = match session_index { + Ok(session_index) => + topology_storage.get_topology_or_fallback(session_index).local_grid_neighbors(), + Err(e) => { + gum::debug!( + target: LOG_TARGET, + %relay_parent, + "cannot get session index for the specific relay parent: {:?}", + e + ); + + topology_storage.get_current_topology().local_grid_neighbors() + }, + }; + let required_routing = + topology.required_routing_by_index(statement.statement.validator_index(), false); + + let _ = circulate_statement( + required_routing, + topology, + peers, + ctx, + relay_parent, + statement, + Vec::new(), + metrics, + rng, + ) + .await; + } +} + +// Handle a statement. Returns a reference to a newly-stored statement +// if we were not already aware of it, along with the corresponding relay-parent. +// +// This function checks the signature and ensures the statement is compatible with our +// view. It also notifies candidate backing if the statement was previously unknown. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_incoming_message<'a, Context>( + peer: PeerId, + peer_data: &mut PeerData, + active_heads: &'a mut HashMap, + recent_outdated_heads: &RecentOutdatedHeads, + ctx: &mut Context, + message: net_protocol::StatementDistributionMessage, + req_sender: &mpsc::Sender, + metrics: &Metrics, + reputation: &mut ReputationAggregator, +) -> Option<(Hash, StoredStatement<'a>)> { + let _ = metrics.time_network_bridge_update("handle_incoming_message"); + + let message = match message { + Versioned::V1(m) => m, + Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::V1Compatibility( + m, + )) => m, + Versioned::VStaging(_) => { + // The higher-level subsystem code is supposed to filter out + // all non v1 messages. + gum::debug!( + target: LOG_TARGET, + "Legacy statement-distribution code received unintended v2 message" + ); + + return None + }, + }; + + let relay_parent = message.get_relay_parent(); + + let active_head = match active_heads.get_mut(&relay_parent) { + Some(h) => h, + None => { + gum::debug!( + target: LOG_TARGET, + %relay_parent, + "our view out-of-sync with active heads; head not found", + ); + + if !recent_outdated_heads.is_recent_outdated(&relay_parent) { + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + } + + return None + }, + }; + + if let protocol_v1::StatementDistributionMessage::LargeStatement(_) = message { + if let Err(rep) = peer_data.receive_large_statement(&relay_parent) { + gum::debug!(target: LOG_TARGET, ?peer, ?message, ?rep, "Unexpected large statement.",); + modify_reputation(reputation, ctx.sender(), peer, rep).await; + return None + } + } + + let fingerprint = message.get_fingerprint(); + let candidate_hash = *fingerprint.0.candidate_hash(); + let handle_incoming_span = active_head + .span + .child("handle-incoming") + .with_candidate(candidate_hash) + .with_peer_id(&peer); + + let max_message_count = active_head.validators.len() * 2; + + // perform only basic checks before verifying the signature + // as it's more computationally heavy + if let Err(rep) = peer_data.check_can_receive(&relay_parent, &fingerprint, max_message_count) { + // This situation can happen when a peer's Seconded message was lost + // but we have received the Valid statement. + // So we check it once and then ignore repeated violation to avoid + // reputation change flood. + let unexpected_count = peer_data.receive_unexpected(&relay_parent); + + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?peer, + ?message, + ?rep, + ?unexpected_count, + "Error inserting received statement" + ); + + match rep { + // This happens when a Valid statement has been received but there is no corresponding + // Seconded + COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE => { + metrics.on_unexpected_statement_valid(); + // Report peer merely if this is not a duplicate out-of-view statement that + // was caused by a missing Seconded statement from this peer + if unexpected_count == 0_usize { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + } + }, + // This happens when we have an unexpected remote peer that announced Seconded + COST_UNEXPECTED_STATEMENT_REMOTE => { + metrics.on_unexpected_statement_seconded(); + modify_reputation(reputation, ctx.sender(), peer, rep).await; + }, + _ => { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + }, + } + + return None + } + + let checked_compact = { + let (compact, validator_index) = message.get_fingerprint(); + let signature = message.get_signature(); + + let unchecked_compact = UncheckedSignedStatement::new(compact, validator_index, signature); + + match active_head.check_useful_or_unknown(&unchecked_compact) { + Ok(()) => {}, + Err(DeniedStatement::NotUseful) => return None, + Err(DeniedStatement::UsefulButKnown) => { + // Note a received statement in the peer data + peer_data + .receive(&relay_parent, &fingerprint, max_message_count) + .expect("checked in `check_can_receive` above; qed"); + modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT).await; + + return None + }, + } + + // check the signature on the statement. + match check_statement_signature(&active_head, relay_parent, unchecked_compact) { + Err(statement) => { + gum::debug!(target: LOG_TARGET, ?peer, ?statement, "Invalid statement signature"); + modify_reputation(reputation, ctx.sender(), peer, COST_INVALID_SIGNATURE).await; + return None + }, + Ok(statement) => statement, + } + }; + + // Fetch from the network only after signature and usefulness checks are completed. + let is_large_statement = message.is_large_statement(); + let statement = retrieve_statement_from_message( + peer, + peer_data.protocol_version, + message, + active_head, + ctx, + req_sender, + metrics, + ) + .await?; + + let payload = statement.unchecked_into_payload(); + + // Upgrade the `Signed` wrapper from the compact payload to the full payload. + // This fails if the payload doesn't encode correctly. + let statement: SignedFullStatement = match checked_compact.convert_to_superpayload(payload) { + Err((compact, _)) => { + gum::debug!( + target: LOG_TARGET, + ?peer, + ?compact, + is_large_statement, + "Full statement had bad payload." + ); + modify_reputation(reputation, ctx.sender(), peer, COST_WRONG_HASH).await; + return None + }, + Ok(statement) => statement, + }; + + // Ensure the statement is stored in the peer data. + // + // Note that if the peer is sending us something that is not within their view, + // it will not be kept within their log. + match peer_data.receive(&relay_parent, &fingerprint, max_message_count) { + Err(_) => { + unreachable!("checked in `check_can_receive` above; qed"); + }, + Ok(true) => { + gum::trace!(target: LOG_TARGET, ?peer, ?statement, "Statement accepted"); + // Send the peer all statements concerning the candidate that we have, + // since it appears to have just learned about the candidate. + send_statements_about( + peer, + peer_data, + ctx, + relay_parent, + candidate_hash, + &*active_head, + metrics, + ) + .await; + }, + Ok(false) => {}, + } + + // For `Seconded` statements `None` or `Err` means we couldn't fetch the PVD, which + // means the statement shouldn't be accepted. + // + // In case of `Valid` we should have it cached prior, therefore this performs + // no Runtime API calls and always returns `Ok(Some(_))`. + let pvd = if let Statement::Seconded(receipt) = statement.payload() { + let para_id = receipt.descriptor.para_id; + // Either call the Runtime API or check that validation data is cached. + let result = active_head + .fetch_persisted_validation_data(ctx.sender(), relay_parent, para_id) + .await; + + match result { + Ok(Some(pvd)) => Some(pvd.clone()), + Ok(None) | Err(_) => return None, + } + } else { + None + }; + + // Extend the payload with persisted validation data required by the backing + // subsystem. + // + // Do it in advance before noting the statement because we don't want to borrow active + // head mutable and use the cache. + let statement_with_pvd = statement + .clone() + .convert_to_superpayload_with(move |statement| match statement { + Statement::Seconded(receipt) => { + let persisted_validation_data = pvd + .expect("PVD is ensured to be `Some` for all `Seconded` messages above; qed"); + StatementWithPVD::Seconded(receipt, persisted_validation_data) + }, + Statement::Valid(candidate_hash) => StatementWithPVD::Valid(candidate_hash), + }) + .expect("payload was checked with conversion from compact; qed"); + + // Note: `peer_data.receive` already ensures that the statement is not an unbounded equivocation + // or unpinned to a seconded candidate. So it is safe to place it into the storage. + match active_head.note_statement(statement) { + NotedStatement::NotUseful | NotedStatement::UsefulButKnown => { + unreachable!("checked in `is_useful_or_unknown` above; qed"); + }, + NotedStatement::Fresh(statement) => { + modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT_FIRST).await; + + let mut _span = handle_incoming_span.child("notify-backing"); + + // When we receive a new message from a peer, we forward it to the + // candidate backing subsystem. + ctx.send_message(CandidateBackingMessage::Statement(relay_parent, statement_with_pvd)) + .await; + + Some((relay_parent, statement)) + }, + } +} + +/// Update a peer's view. Sends all newly unlocked statements based on the previous +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn update_peer_view_and_maybe_send_unlocked( + peer: PeerId, + topology: &GridNeighbors, + peer_data: &mut PeerData, + ctx: &mut Context, + active_heads: &HashMap, + new_view: View, + metrics: &Metrics, + rng: &mut R, +) where + R: rand::Rng, +{ + let old_view = std::mem::replace(&mut peer_data.view, new_view); + + // Remove entries for all relay-parents in the old view but not the new. + for removed in old_view.difference(&peer_data.view) { + let _ = peer_data.view_knowledge.remove(removed); + } + + // Use both grid directions + let is_gossip_peer = topology.route_to_peer(RequiredRouting::GridXY, &peer); + let lucky = is_gossip_peer || + util::gen_ratio_rng( + util::MIN_GOSSIP_PEERS.saturating_sub(topology.len()), + util::MIN_GOSSIP_PEERS, + rng, + ); + + // Add entries for all relay-parents in the new view but not the old. + // Furthermore, send all statements we have for those relay parents. + let new_view = peer_data.view.difference(&old_view).copied().collect::>(); + for new in new_view.iter().copied() { + peer_data.view_knowledge.insert(new, Default::default()); + if !lucky { + continue + } + if let Some(active_head) = active_heads.get(&new) { + send_statements(peer, peer_data, ctx, new, active_head, metrics).await; + } + } +} + +/// Handle a local network update. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn handle_network_update( + ctx: &mut Context, + state: &mut State, + req_sender: &mpsc::Sender, + update: NetworkBridgeEvent, + rng: &mut R, + metrics: &Metrics, + reputation: &mut ReputationAggregator, +) where + R: rand::Rng, +{ + let peers = &mut state.peers; + let topology_storage = &mut state.topology_storage; + let authorities = &mut state.authorities; + let active_heads = &mut state.active_heads; + let recent_outdated_heads = &state.recent_outdated_heads; + let runtime = &mut state.runtime; + + match update { + NetworkBridgeEvent::PeerConnected(peer, role, protocol_version, maybe_authority) => { + gum::trace!(target: LOG_TARGET, ?peer, ?role, ?protocol_version, "Peer connected"); + + let protocol_version = match ValidationVersion::try_from(protocol_version).ok() { + Some(v) => v, + None => { + gum::trace!( + target: LOG_TARGET, + ?peer, + ?protocol_version, + "unknown protocol version, ignoring" + ); + return + }, + }; + + peers.insert( + peer, + PeerData { + view: Default::default(), + protocol_version, + view_knowledge: Default::default(), + maybe_authority: maybe_authority.clone(), + }, + ); + if let Some(authority_ids) = maybe_authority { + authority_ids.into_iter().for_each(|a| { + authorities.insert(a, peer); + }); + } + }, + NetworkBridgeEvent::PeerDisconnected(peer) => { + gum::trace!(target: LOG_TARGET, ?peer, "Peer disconnected"); + if let Some(auth_ids) = peers.remove(&peer).and_then(|p| p.maybe_authority) { + auth_ids.into_iter().for_each(|a| { + authorities.remove(&a); + }); + } + }, + NetworkBridgeEvent::NewGossipTopology(topology) => { + let _ = metrics.time_network_bridge_update("new_gossip_topology"); + + let new_session_index = topology.session; + let new_topology = topology.topology; + let old_topology = + topology_storage.get_current_topology().local_grid_neighbors().clone(); + topology_storage.update_topology(new_session_index, new_topology, topology.local_index); + + let newly_added = topology_storage + .get_current_topology() + .local_grid_neighbors() + .peers_diff(&old_topology); + + for peer in newly_added { + if let Some(data) = peers.get_mut(&peer) { + let view = std::mem::take(&mut data.view); + update_peer_view_and_maybe_send_unlocked( + peer, + topology_storage.get_current_topology().local_grid_neighbors(), + data, + ctx, + &*active_heads, + view, + metrics, + rng, + ) + .await + } + } + }, + NetworkBridgeEvent::PeerMessage(peer, message) => { + handle_incoming_message_and_circulate( + peer, + topology_storage, + peers, + active_heads, + recent_outdated_heads, + ctx, + message, + req_sender, + metrics, + runtime, + rng, + reputation, + ) + .await; + }, + NetworkBridgeEvent::PeerViewChange(peer, view) => { + let _ = metrics.time_network_bridge_update("peer_view_change"); + gum::trace!(target: LOG_TARGET, ?peer, ?view, "Peer view change"); + match peers.get_mut(&peer) { + Some(data) => + update_peer_view_and_maybe_send_unlocked( + peer, + topology_storage.get_current_topology().local_grid_neighbors(), + data, + ctx, + &*active_heads, + view, + metrics, + rng, + ) + .await, + None => (), + } + }, + NetworkBridgeEvent::OurViewChange(_view) => { + // handled by `ActiveLeavesUpdate` + }, + NetworkBridgeEvent::UpdatedAuthorityIds(peer, authority_ids) => { + gum::trace!( + target: LOG_TARGET, + ?peer, + ?authority_ids, + "Updated `AuthorityDiscoveryId`s" + ); + + // Remove the authority IDs which were previously mapped to the peer + // but aren't part of the new set. + authorities.retain(|a, p| p != &peer || authority_ids.contains(a)); + + // Map the new authority IDs to the peer. + for a in authority_ids.iter().cloned() { + authorities.insert(a, peer); + } + + if let Some(data) = peers.get_mut(&peer) { + data.maybe_authority = Some(authority_ids); + } + }, + } +} + +/// Handle messages from responder background task. +pub(crate) async fn handle_responder_message( + state: &mut State, + message: ResponderMessage, +) -> JfyiErrorResult<()> { + let peers = &state.peers; + let active_heads = &mut state.active_heads; + + match message { + ResponderMessage::GetData { requesting_peer, relay_parent, candidate_hash, tx } => { + if !requesting_peer_knows_about_candidate( + peers, + &requesting_peer, + &relay_parent, + &candidate_hash, + )? { + return Err(JfyiError::RequestedUnannouncedCandidate( + requesting_peer, + candidate_hash, + )) + } + + let active_head = + active_heads.get(&relay_parent).ok_or(JfyiError::NoSuchHead(relay_parent))?; + + let committed = match active_head.waiting_large_statements.get(&candidate_hash) { + Some(LargeStatementStatus::FetchedOrShared(committed)) => committed.clone(), + _ => + return Err(JfyiError::NoSuchFetchedLargeStatement(relay_parent, candidate_hash)), + }; + + tx.send(committed).map_err(|_| JfyiError::ResponderGetDataCanceled)?; + }, + } + Ok(()) +} + +#[overseer::contextbounds(StatementDistribution, prefix = self::overseer)] +pub(crate) async fn handle_requester_message( + ctx: &mut Context, + state: &mut State, + req_sender: &mpsc::Sender, + rng: &mut R, + message: RequesterMessage, + metrics: &Metrics, + reputation: &mut ReputationAggregator, +) -> JfyiErrorResult<()> { + let topology_storage = &state.topology_storage; + let peers = &mut state.peers; + let active_heads = &mut state.active_heads; + let recent_outdated_heads = &state.recent_outdated_heads; + let runtime = &mut state.runtime; + + match message { + RequesterMessage::Finished { + relay_parent, + candidate_hash, + from_peer, + response, + bad_peers, + } => { + for bad in bad_peers { + modify_reputation(reputation, ctx.sender(), bad, COST_FETCH_FAIL).await; + } + modify_reputation(reputation, ctx.sender(), from_peer, BENEFIT_VALID_RESPONSE).await; + + let active_head = + active_heads.get_mut(&relay_parent).ok_or(JfyiError::NoSuchHead(relay_parent))?; + + let status = active_head.waiting_large_statements.remove(&candidate_hash); + + let info = match status { + Some(LargeStatementStatus::Fetching(info)) => info, + Some(LargeStatementStatus::FetchedOrShared(_)) => { + // We are no longer interested in the data. + return Ok(()) + }, + None => + return Err(JfyiError::NoSuchLargeStatementStatus(relay_parent, candidate_hash)), + }; + + active_head + .waiting_large_statements + .insert(candidate_hash, LargeStatementStatus::FetchedOrShared(response)); + + // Cache is now populated, send all messages: + for (peer, messages) in info.available_peers { + for message in messages { + handle_incoming_message_and_circulate( + peer, + topology_storage, + peers, + active_heads, + recent_outdated_heads, + ctx, + message, + req_sender, + &metrics, + runtime, + rng, + reputation, + ) + .await; + } + } + }, + RequesterMessage::SendRequest(req) => { + ctx.send_message(NetworkBridgeTxMessage::SendRequests( + vec![req], + IfDisconnected::ImmediateError, + )) + .await; + }, + RequesterMessage::GetMorePeers { relay_parent, candidate_hash, tx } => { + let active_head = + active_heads.get_mut(&relay_parent).ok_or(JfyiError::NoSuchHead(relay_parent))?; + + let status = active_head.waiting_large_statements.get_mut(&candidate_hash); + + let info = match status { + Some(LargeStatementStatus::Fetching(info)) => info, + Some(LargeStatementStatus::FetchedOrShared(_)) => { + // This task is going to die soon - no need to send it anything. + gum::debug!(target: LOG_TARGET, "Zombie task wanted more peers."); + return Ok(()) + }, + None => + return Err(JfyiError::NoSuchLargeStatementStatus(relay_parent, candidate_hash)), + }; + + if info.peers_to_try.is_empty() { + info.peer_sender = Some(tx); + } else { + let peers_to_try = std::mem::take(&mut info.peers_to_try); + if let Err(peers) = tx.send(peers_to_try) { + // No longer interested for now - might want them later: + info.peers_to_try = peers; + } + } + }, + RequesterMessage::ReportPeer(peer, rep) => + modify_reputation(reputation, ctx.sender(), peer, rep).await, + } + Ok(()) +} + +/// Handle a deactivated leaf. +pub(crate) fn handle_deactivate_leaf(state: &mut State, deactivated: Hash) { + if state.active_heads.remove(&deactivated).is_some() { + gum::trace!( + target: LOG_TARGET, + hash = ?deactivated, + "Deactivating leaf", + ); + + state.recent_outdated_heads.note_outdated(deactivated); + } +} + +/// Handle a new activated leaf. This assumes that the leaf does not +/// support prospective parachains. +#[overseer::contextbounds(StatementDistribution, prefix = self::overseer)] +pub(crate) async fn handle_activated_leaf( + ctx: &mut Context, + state: &mut State, + activated: ActivatedLeaf, +) -> Result<()> { + let relay_parent = activated.hash; + let span = PerLeafSpan::new(activated.span, "statement-distribution-legacy"); + gum::trace!( + target: LOG_TARGET, + hash = ?relay_parent, + "New active leaf", + ); + + // Retrieve the parachain validators at the child of the head we track. + let session_index = + state.runtime.get_session_index_for_child(ctx.sender(), relay_parent).await?; + let info = state + .runtime + .get_session_info_by_index(ctx.sender(), relay_parent, session_index) + .await?; + let session_info = &info.session_info; + + state.active_heads.entry(relay_parent).or_insert(ActiveHeadData::new( + session_info.validators.clone(), + session_index, + span, + )); + + Ok(()) +} + +/// Share a local statement with the rest of the network. +#[overseer::contextbounds(StatementDistribution, prefix = self::overseer)] +pub(crate) async fn share_local_statement( + ctx: &mut Context, + state: &mut State, + relay_parent: Hash, + statement: SignedFullStatement, + rng: &mut R, + metrics: &Metrics, +) -> Result<()> { + // Make sure we have data in cache: + if is_statement_large(&statement).0 { + if let Statement::Seconded(committed) = &statement.payload() { + let active_head = state + .active_heads + .get_mut(&relay_parent) + // This should never be out-of-sync with our view if the view + // updates correspond to actual `StartWork` messages. + .ok_or(JfyiError::NoSuchHead(relay_parent))?; + active_head.waiting_large_statements.insert( + statement.payload().candidate_hash(), + LargeStatementStatus::FetchedOrShared(committed.clone()), + ); + } + } + + let info = state.runtime.get_session_info(ctx.sender(), relay_parent).await?; + let session_info = &info.session_info; + let validator_info = &info.validator_info; + + // Get peers in our group, so we can make sure they get our statement + // directly: + let group_peers = { + if let Some(our_group) = validator_info.our_group { + let our_group = &session_info + .validator_groups + .get(our_group) + .expect("`our_group` is derived from `validator_groups`; qed"); + + our_group + .into_iter() + .filter_map(|i| { + if Some(*i) == validator_info.our_index { + return None + } + let authority_id = &session_info.discovery_keys[i.0 as usize]; + state.authorities.get(authority_id).map(|p| *p) + }) + .collect() + } else { + Vec::new() + } + }; + circulate_statement_and_dependents( + &mut state.topology_storage, + &mut state.peers, + &mut state.active_heads, + ctx, + relay_parent, + statement, + group_peers, + metrics, + rng, + ) + .await; + + Ok(()) +} + +/// Check whether a peer knows about a candidate from us. +/// +/// If not, it is deemed illegal for it to request corresponding data from us. +fn requesting_peer_knows_about_candidate( + peers: &HashMap, + requesting_peer: &PeerId, + relay_parent: &Hash, + candidate_hash: &CandidateHash, +) -> JfyiErrorResult { + let peer_data = peers + .get(requesting_peer) + .ok_or_else(|| JfyiError::NoSuchPeer(*requesting_peer))?; + let knowledge = peer_data + .view_knowledge + .get(relay_parent) + .ok_or_else(|| JfyiError::NoSuchHead(*relay_parent))?; + Ok(knowledge.sent_candidates.get(&candidate_hash).is_some()) +} + +fn compatible_v1_message( + version: ValidationVersion, + message: protocol_v1::StatementDistributionMessage, +) -> net_protocol::StatementDistributionMessage { + match version { + ValidationVersion::V1 => Versioned::V1(message), + ValidationVersion::VStaging => Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::V1Compatibility(message), + ), + } +} diff --git a/node/network/statement-distribution/src/requester.rs b/node/network/statement-distribution/src/legacy_v1/requester.rs similarity index 98% rename from node/network/statement-distribution/src/requester.rs rename to node/network/statement-distribution/src/legacy_v1/requester.rs index 3b477243becf..8a8a8f3d624a 100644 --- a/node/network/statement-distribution/src/requester.rs +++ b/node/network/statement-distribution/src/legacy_v1/requester.rs @@ -32,7 +32,10 @@ use polkadot_node_subsystem::{Span, Stage}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{CandidateHash, CommittedCandidateReceipt, Hash}; -use crate::{metrics::Metrics, COST_WRONG_HASH, LOG_TARGET}; +use crate::{ + legacy_v1::{COST_WRONG_HASH, LOG_TARGET}, + metrics::Metrics, +}; // In case we failed fetching from our known peers, how long we should wait before attempting a // retry, even though we have not yet discovered any new peers. Or in other words how long to diff --git a/node/network/statement-distribution/src/responder.rs b/node/network/statement-distribution/src/legacy_v1/responder.rs similarity index 97% rename from node/network/statement-distribution/src/responder.rs rename to node/network/statement-distribution/src/legacy_v1/responder.rs index 68976436039d..81e226c4ff89 100644 --- a/node/network/statement-distribution/src/responder.rs +++ b/node/network/statement-distribution/src/legacy_v1/responder.rs @@ -48,8 +48,8 @@ pub enum ResponderMessage { /// A fetching task, taking care of fetching large statements via request/response. /// -/// A fetch task does not know about a particular `Statement` instead it just tries fetching a -/// `CommittedCandidateReceipt` from peers, whether this can be used to re-assemble one ore +/// A fetch task does not know about a particular `Statement`, instead it just tries fetching a +/// `CommittedCandidateReceipt` from peers, whether this can be used to re-assemble one or /// many `SignedFullStatement`s needs to be verified by the caller. pub async fn respond( mut receiver: IncomingRequestReceiver, diff --git a/node/network/statement-distribution/src/tests.rs b/node/network/statement-distribution/src/legacy_v1/tests.rs similarity index 91% rename from node/network/statement-distribution/src/tests.rs rename to node/network/statement-distribution/src/legacy_v1/tests.rs index affed80fce30..a8ce65f29861 100644 --- a/node/network/statement-distribution/src/tests.rs +++ b/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -14,7 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use super::{metrics::Metrics, *}; +#![allow(clippy::clone_on_copy)] + +use super::*; +use crate::{metrics::Metrics, *}; + use assert_matches::assert_matches; use futures::executor; use futures_timer::Delay; @@ -26,19 +30,21 @@ use polkadot_node_network_protocol::{ v1::{StatementFetchingRequest, StatementFetchingResponse}, IncomingRequest, Recipient, ReqProtocolNames, Requests, }, - view, ObservedRole, + view, ObservedRole, VersionedValidationProtocol, +}; +use polkadot_node_primitives::{ + SignedFullStatementWithPVD, Statement, UncheckedSignedFullStatement, }; -use polkadot_node_primitives::{Statement, UncheckedSignedFullStatement}; use polkadot_node_subsystem::{ jaeger, messages::{ network_bridge_event, AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest, }, - ActivatedLeaf, LeafStatus, + ActivatedLeaf, LeafStatus, RuntimeApiError, }; use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore; use polkadot_primitives::{ - GroupIndex, Hash, Id as ParaId, IndexedVec, SessionInfo, ValidationCode, ValidatorId, + GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo, ValidationCode, }; use polkadot_primitives_test_helpers::{ dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng, @@ -54,6 +60,30 @@ use util::reputation::add_reputation; // Some deterministic genesis hash for protocol names const GENESIS_HASH: Hash = Hash::repeat_byte(0xff); +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; + +fn dummy_pvd() -> PersistedValidationData { + PersistedValidationData { + parent_head: HeadData(vec![7, 8, 9]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + } +} + +fn extend_statement_with_pvd( + statement: SignedFullStatement, + pvd: PersistedValidationData, +) -> SignedFullStatementWithPVD { + statement + .convert_to_superpayload_with(|statement| match statement { + Statement::Seconded(receipt) => StatementWithPVD::Seconded(receipt, pvd), + Statement::Valid(candidate_hash) => StatementWithPVD::Valid(candidate_hash), + }) + .unwrap() +} + #[test] fn active_head_accepts_only_2_seconded_per_validator() { let validators = vec![ @@ -496,6 +526,7 @@ fn peer_view_update_sends_messages() { let mut peer_data = PeerData { view: old_view, + protocol_version: ValidationVersion::V1, view_knowledge: { let mut k = HashMap::new(); @@ -554,8 +585,9 @@ fn peer_view_update_sends_messages() { for statement in active_head.statements_about(candidate_hash) { let message = handle.recv().await; let expected_to = vec![peer]; - let expected_payload = - statement_message(hash_c, statement.statement.clone(), &Metrics::default()); + let expected_payload = VersionedValidationProtocol::from(Versioned::V1( + v1_statement_message(hash_c, statement.statement.clone(), &Metrics::default()), + )); assert_matches!( message, @@ -596,6 +628,7 @@ fn circulated_statement_goes_to_all_peers_with_view() { let peer_data_from_view = |view: View| PeerData { view: view.clone(), + protocol_version: ValidationVersion::V1, view_knowledge: view.iter().map(|v| (*v, Default::default())).collect(), maybe_authority: None, }; @@ -697,7 +730,7 @@ fn circulated_statement_goes_to_all_peers_with_view() { assert_eq!( payload, - statement_message(hash_b, statement.statement.clone(), &Metrics::default()), + VersionedValidationProtocol::from(Versioned::V1(v1_statement_message(hash_b, statement.statement.clone(), &Metrics::default()))), ); } ) @@ -706,12 +739,14 @@ fn circulated_statement_goes_to_all_peers_with_view() { #[test] fn receiving_from_one_sends_to_another_and_to_candidate_backing() { + const PARA_ID: ParaId = ParaId::new(1); let hash_a = Hash::repeat_byte(1); + let pvd = dummy_pvd(); let candidate = { let mut c = dummy_committed_candidate_receipt(dummy_hash()); c.descriptor.relay_parent = hash_a; - c.descriptor.para_id = 1.into(); + c.descriptor.para_id = PARA_ID; c }; @@ -733,11 +768,13 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); let (statement_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); let bg = async move { let s = StatementDistributionSubsystem { keystore: Arc::new(LocalKeystore::in_memory()), - req_receiver: Some(statement_req_receiver), + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), metrics: Default::default(), rng: AlwaysZeroRng, reputation: ReputationAggregator::new(|_| true), @@ -758,6 +795,17 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { ))) .await; + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) + if r == hash_a + => { + let _ = tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)); + } + ); + assert_matches!( handle.recv().await, AllMessages::RuntimeApi( @@ -862,18 +910,32 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { }) .await; + let statement_with_pvd = extend_statement_with_pvd(statement.clone(), pvd.clone()); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::PersistedValidationData(para_id, assumption, tx), + )) if para_id == PARA_ID && + assumption == OccupiedCoreAssumption::Free && + hash == hash_a => + { + tx.send(Ok(Some(pvd))).unwrap(); + } + ); + assert_matches!( handle.recv().await, AllMessages::NetworkBridgeTx( NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)) ) if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => {} ); - assert_matches!( handle.recv().await, AllMessages::CandidateBacking( CandidateBackingMessage::Statement(r, s) - ) if r == hash_a && s == statement => {} + ) if r == hash_a && s == statement_with_pvd => {} ); assert_matches!( @@ -902,6 +964,9 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { #[test] fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing() { + const PARA_ID: ParaId = ParaId::new(1); + let pvd = dummy_pvd(); + sp_tracing::try_init_simple(); let hash_a = Hash::repeat_byte(1); let hash_b = Hash::repeat_byte(2); @@ -909,7 +974,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( let candidate = { let mut c = dummy_committed_candidate_receipt(dummy_hash()); c.descriptor.relay_parent = hash_a; - c.descriptor.para_id = 1.into(); + c.descriptor.para_id = PARA_ID; c.commitments.new_validation_code = Some(ValidationCode(vec![1, 2, 3])); c }; @@ -937,11 +1002,13 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); let (statement_req_receiver, mut req_cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); let bg = async move { let s = StatementDistributionSubsystem { keystore: make_ferdie_keystore(), - req_receiver: Some(statement_req_receiver), + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), metrics: Default::default(), rng: AlwaysZeroRng, reputation: ReputationAggregator::new(|_| true), @@ -962,6 +1029,17 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( ))) .await; + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) + if r == hash_a + => { + let _ = tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)); + } + ); + assert_matches!( handle.recv().await, AllMessages::RuntimeApi( @@ -1292,6 +1370,20 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( ) if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() => {} ); + let statement_with_pvd = extend_statement_with_pvd(statement.clone(), pvd.clone()); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::PersistedValidationData(para_id, assumption, tx), + )) if para_id == PARA_ID && + assumption == OccupiedCoreAssumption::Free && + hash == hash_a => + { + tx.send(Ok(Some(pvd))).unwrap(); + } + ); assert_matches!( handle.recv().await, AllMessages::NetworkBridgeTx( @@ -1303,7 +1395,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( handle.recv().await, AllMessages::CandidateBacking( CandidateBackingMessage::Statement(r, s) - ) if r == hash_a && s == statement => {} + ) if r == hash_a && s == statement_with_pvd => {} ); // Now messages should go out: @@ -1400,6 +1492,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( fn delay_reputation_changes() { sp_tracing::try_init_simple(); let hash_a = Hash::repeat_byte(1); + let pvd = dummy_pvd(); let candidate = { let mut c = dummy_committed_candidate_receipt(dummy_hash()); @@ -1431,13 +1524,15 @@ fn delay_reputation_changes() { let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); let (statement_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); let reputation_interval = Duration::from_millis(100); let bg = async move { let s = StatementDistributionSubsystem { keystore: make_ferdie_keystore(), - req_receiver: Some(statement_req_receiver), + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), metrics: Default::default(), rng: AlwaysZeroRng, reputation: ReputationAggregator::new(|_| false), @@ -1458,6 +1553,17 @@ fn delay_reputation_changes() { ))) .await; + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) + if r == hash_a + => { + let _ = tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)); + } + ); + assert_matches!( handle.recv().await, AllMessages::RuntimeApi( @@ -1768,9 +1874,18 @@ fn delay_reputation_changes() { assert_matches!( handle.recv().await, - AllMessages::CandidateBacking( - CandidateBackingMessage::Statement(r, s) - ) if r == hash_a && s == statement => {} + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::PersistedValidationData(_, assumption, tx), + )) if assumption == OccupiedCoreAssumption::Free && hash == hash_a => + { + tx.send(Ok(Some(pvd))).unwrap(); + } + ); + + assert_matches!( + handle.recv().await, + AllMessages::CandidateBacking(CandidateBackingMessage::Statement(..)) ); // Now messages should go out: @@ -1885,11 +2000,13 @@ fn share_prioritizes_backing_group() { let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); let (statement_req_receiver, mut req_cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); let bg = async move { let s = StatementDistributionSubsystem { keystore: make_ferdie_keystore(), - req_receiver: Some(statement_req_receiver), + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), metrics: Default::default(), rng: AlwaysZeroRng, reputation: ReputationAggregator::new(|_| true), @@ -1910,6 +2027,17 @@ fn share_prioritizes_backing_group() { ))) .await; + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) + if r == hash_a + => { + let _ = tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)); + } + ); + assert_matches!( handle.recv().await, AllMessages::RuntimeApi( @@ -2069,9 +2197,17 @@ fn share_prioritizes_backing_group() { ) .unwrap(); - SignedFullStatement::sign( + // note: this is ignored by legacy-v1 code. + let pvd = PersistedValidationData { + parent_head: HeadData::from(vec![1, 2, 3]), + relay_parent_number: 0, + relay_parent_storage_root: Hash::repeat_byte(42), + max_pov_size: 100, + }; + + SignedFullStatementWithPVD::sign( &keystore, - Statement::Seconded(candidate.clone()), + Statement::Seconded(candidate.clone()).supply_pvd(pvd), &signing_context, ValidatorIndex(4), &ferdie_public.into(), @@ -2081,14 +2217,15 @@ fn share_prioritizes_backing_group() { .expect("should be signed") }; - let metadata = derive_metadata_assuming_seconded(hash_a, statement.clone().into()); - handle .send(FromOrchestra::Communication { msg: StatementDistributionMessage::Share(hash_a, statement.clone()), }) .await; + let statement = StatementWithPVD::drop_pvd_from_signed(statement); + let metadata = derive_metadata_assuming_seconded(hash_a, statement.clone().into()); + // Messages should go out: assert_matches!( handle.recv().await, @@ -2180,10 +2317,12 @@ fn peer_cant_flood_with_large_statements() { let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); let (statement_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); let bg = async move { let s = StatementDistributionSubsystem { keystore: make_ferdie_keystore(), - req_receiver: Some(statement_req_receiver), + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), metrics: Default::default(), rng: AlwaysZeroRng, reputation: ReputationAggregator::new(|_| true), @@ -2204,6 +2343,17 @@ fn peer_cant_flood_with_large_statements() { ))) .await; + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) + if r == hash_a + => { + let _ = tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)); + } + ); + assert_matches!( handle.recv().await, AllMessages::RuntimeApi( @@ -2341,6 +2491,7 @@ fn peer_cant_flood_with_large_statements() { #[test] fn handle_multiple_seconded_statements() { let relay_parent_hash = Hash::repeat_byte(1); + let pvd = dummy_pvd(); let candidate = dummy_committed_candidate_receipt(relay_parent_hash); let candidate_hash = candidate.hash(); @@ -2384,11 +2535,13 @@ fn handle_multiple_seconded_statements() { let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); let (statement_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); let virtual_overseer_fut = async move { let s = StatementDistributionSubsystem { keystore: Arc::new(LocalKeystore::in_memory()), - req_receiver: Some(statement_req_receiver), + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), metrics: Default::default(), rng: AlwaysZeroRng, reputation: ReputationAggregator::new(|_| true), @@ -2409,6 +2562,17 @@ fn handle_multiple_seconded_statements() { ))) .await; + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(r, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) + if r == relay_parent_hash + => { + let _ = tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)); + } + ); + assert_matches!( handle.recv().await, AllMessages::RuntimeApi( @@ -2575,6 +2739,18 @@ fn handle_multiple_seconded_statements() { }) .await; + let statement_with_pvd = extend_statement_with_pvd(statement.clone(), pvd.clone()); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::PersistedValidationData(_, assumption, tx), + )) if assumption == OccupiedCoreAssumption::Free => { + tx.send(Ok(Some(pvd.clone()))).unwrap(); + } + ); + assert_matches!( handle.recv().await, AllMessages::NetworkBridgeTx( @@ -2592,7 +2768,7 @@ fn handle_multiple_seconded_statements() { CandidateBackingMessage::Statement(r, s) ) => { assert_eq!(r, relay_parent_hash); - assert_eq!(s, statement); + assert_eq!(s, statement_with_pvd); } ); @@ -2676,6 +2852,10 @@ fn handle_multiple_seconded_statements() { }) .await; + let statement_with_pvd = extend_statement_with_pvd(statement.clone(), pvd.clone()); + + // Persisted validation data is cached. + assert_matches!( handle.recv().await, AllMessages::NetworkBridgeTx( @@ -2692,7 +2872,7 @@ fn handle_multiple_seconded_statements() { CandidateBackingMessage::Statement(r, s) ) => { assert_eq!(r, relay_parent_hash); - assert_eq!(s, statement); + assert_eq!(s, statement_with_pvd); } ); @@ -2784,3 +2964,8 @@ fn derive_metadata_assuming_seconded( signature: statement.unchecked_signature().clone(), } } + +// TODO [now]: adapt most tests to v2 messages. +// TODO [now]: test that v2 peers send v1 messages to v1 peers +// TODO [now]: test that v2 peers handle v1 messages from v1 peers. +// TODO [now]: test that v2 peers send v2 messages to v2 peers. diff --git a/node/network/statement-distribution/src/lib.rs b/node/network/statement-distribution/src/lib.rs index 4cdf0d8af467..b2eb9cccced4 100644 --- a/node/network/statement-distribution/src/lib.rs +++ b/node/network/statement-distribution/src/lib.rs @@ -19,116 +19,59 @@ //! This is responsible for distributing signed statements about candidate //! validity among validators. -#![deny(unused_crate_dependencies)] +// #![deny(unused_crate_dependencies)] #![warn(missing_docs)] -use error::{log_error, FatalResult, JfyiErrorResult}; -use parity_scale_codec::Encode; +use error::{log_error, FatalResult}; +use std::time::Duration; use polkadot_node_network_protocol::{ - self as net_protocol, - grid_topology::{GridNeighbors, RequiredRouting, SessionBoundGridTopologyStorage}, - peer_set::{IsAuthority, PeerSet}, - request_response::{v1 as request_v1, IncomingRequestReceiver}, - v1::{self as protocol_v1, StatementMetadata}, - IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, -}; -use polkadot_node_primitives::{SignedFullStatement, Statement, UncheckedSignedFullStatement}; -use polkadot_node_subsystem_util::{self as util, rand, MIN_GOSSIP_PEERS}; - -use polkadot_node_subsystem::{ - jaeger, - messages::{ - CandidateBackingMessage, NetworkBridgeEvent, NetworkBridgeTxMessage, - StatementDistributionMessage, + request_response::{ + v1 as request_v1, vstaging::AttestedCandidateRequest, IncomingRequestReceiver, }, - overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, SpawnedSubsystem, - SubsystemError, -}; -use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateHash, CommittedCandidateReceipt, CompactStatement, Hash, - IndexedVec, SignedStatement, SigningContext, UncheckedSignedStatement, ValidatorId, - ValidatorIndex, ValidatorSignature, + vstaging as protocol_vstaging, Versioned, }; - -use futures::{ - channel::{mpsc, oneshot}, - future::RemoteHandle, - prelude::*, - select, +use polkadot_node_primitives::StatementWithPVD; +use polkadot_node_subsystem::{ + messages::{NetworkBridgeEvent, StatementDistributionMessage}, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; -use indexmap::{map::Entry as IEntry, IndexMap}; -use sp_keystore::KeystorePtr; -use util::{ +use polkadot_node_subsystem_util::{ + rand, reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, - runtime::RuntimeInfo, + runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, }; -use std::{ - collections::{hash_map::Entry, HashMap, HashSet, VecDeque}, - time::Duration, -}; +use futures::{channel::mpsc, prelude::*}; +use sp_keystore::KeystorePtr; use fatality::Nested; mod error; pub use error::{Error, FatalError, JfyiError, Result}; -/// Background task logic for requesting of large statements. -mod requester; -use requester::{fetch, RequesterMessage}; - -/// Background task logic for responding for large statements. -mod responder; -use responder::{respond, ResponderMessage}; - /// Metrics for the statement distribution pub(crate) mod metrics; use metrics::Metrics; -#[cfg(test)] -mod tests; - -const COST_UNEXPECTED_STATEMENT: Rep = Rep::CostMinor("Unexpected Statement"); -const COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE: Rep = - Rep::CostMinor("Unexpected Statement, missing knowlege for relay parent"); -const COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE: Rep = - Rep::CostMinor("Unexpected Statement, unknown candidate"); -const COST_UNEXPECTED_STATEMENT_REMOTE: Rep = - Rep::CostMinor("Unexpected Statement, remote not allowed"); - -const COST_FETCH_FAIL: Rep = - Rep::CostMinor("Requesting `CommittedCandidateReceipt` from peer failed"); -const COST_INVALID_SIGNATURE: Rep = Rep::CostMajor("Invalid Statement Signature"); -const COST_WRONG_HASH: Rep = Rep::CostMajor("Received candidate had wrong hash"); -const COST_DUPLICATE_STATEMENT: Rep = - Rep::CostMajorRepeated("Statement sent more than once by peer"); -const COST_APPARENT_FLOOD: Rep = Rep::Malicious("Peer appears to be flooding us with statements"); - -const BENEFIT_VALID_STATEMENT: Rep = Rep::BenefitMajor("Peer provided a valid statement"); -const BENEFIT_VALID_STATEMENT_FIRST: Rep = - Rep::BenefitMajorFirst("Peer was the first to provide a valid statement"); -const BENEFIT_VALID_RESPONSE: Rep = - Rep::BenefitMajor("Peer provided a valid large statement response"); +mod legacy_v1; +use legacy_v1::{ + respond as v1_respond_task, RequesterMessage as V1RequesterMessage, + ResponderMessage as V1ResponderMessage, +}; -/// The maximum amount of candidates each validator is allowed to second at any relay-parent. -/// Short for "Validator Candidate Threshold". -/// -/// This is the amount of candidates we keep per validator at any relay-parent. -/// Typically we will only keep 1, but when a validator equivocates we will need to track 2. -const VC_THRESHOLD: usize = 2; +mod vstaging; const LOG_TARGET: &str = "parachain::statement-distribution"; -/// Large statements should be rare. -const MAX_LARGE_STATEMENTS_PER_SENDER: usize = 20; - /// The statement distribution subsystem. pub struct StatementDistributionSubsystem { /// Pointer to a keystore, which is required for determining this node's validator index. keystore: KeystorePtr, /// Receiver for incoming large statement requests. - req_receiver: Option>, + v1_req_receiver: Option>, + /// Receiver for incoming candidate requests. + req_receiver: Option>, /// Prometheus metrics metrics: Metrics, /// Pseudo-random generator for peers selection logic @@ -152,1651 +95,73 @@ impl StatementDistributionSubsyst } } -#[derive(Default)] -struct RecentOutdatedHeads { - buf: VecDeque, -} - -impl RecentOutdatedHeads { - fn note_outdated(&mut self, hash: Hash) { - const MAX_BUF_LEN: usize = 10; - - self.buf.push_back(hash); - - while self.buf.len() > MAX_BUF_LEN { - let _ = self.buf.pop_front(); - } - } - - fn is_recent_outdated(&self, hash: &Hash) -> bool { - self.buf.contains(hash) - } -} - -/// Tracks our impression of a single peer's view of the candidates a validator has seconded -/// for a given relay-parent. -/// -/// It is expected to receive at most `VC_THRESHOLD` from us and be aware of at most `VC_THRESHOLD` -/// via other means. -#[derive(Default)] -struct VcPerPeerTracker { - local_observed: arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, - remote_observed: arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, -} - -impl VcPerPeerTracker { - /// Note that the remote should now be aware that a validator has seconded a given candidate (by - /// hash) based on a message that we have sent it from our local pool. - fn note_local(&mut self, h: CandidateHash) { - if !note_hash(&mut self.local_observed, h) { - gum::warn!( - target: LOG_TARGET, - "Statement distribution is erroneously attempting to distribute more \ - than {} candidate(s) per validator index. Ignoring", - VC_THRESHOLD, - ); - } - } - - /// Note that the remote should now be aware that a validator has seconded a given candidate (by - /// hash) based on a message that it has sent us. - /// - /// Returns `true` if the peer was allowed to send us such a message, `false` otherwise. - fn note_remote(&mut self, h: CandidateHash) -> bool { - note_hash(&mut self.remote_observed, h) - } - - /// Returns `true` if the peer is allowed to send us such a message, `false` otherwise. - fn is_wanted_candidate(&self, h: &CandidateHash) -> bool { - !self.remote_observed.contains(h) && !self.remote_observed.is_full() - } -} - -fn note_hash( - observed: &mut arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, - h: CandidateHash, -) -> bool { - if observed.contains(&h) { - return true - } - - observed.try_push(h).is_ok() -} - -/// knowledge that a peer has about goings-on in a relay parent. -#[derive(Default)] -struct PeerRelayParentKnowledge { - /// candidates that the peer is aware of because we sent statements to it. This indicates that - /// we can send other statements pertaining to that candidate. - sent_candidates: HashSet, - /// candidates that peer is aware of, because we received statements from it. - received_candidates: HashSet, - /// fingerprints of all statements a peer should be aware of: those that - /// were sent to the peer by us. - sent_statements: HashSet<(CompactStatement, ValidatorIndex)>, - /// fingerprints of all statements a peer should be aware of: those that - /// were sent to us by the peer. - received_statements: HashSet<(CompactStatement, ValidatorIndex)>, - /// How many candidates this peer is aware of for each given validator index. - seconded_counts: HashMap, - /// How many statements we've received for each candidate that we're aware of. - received_message_count: HashMap, - - /// How many large statements this peer already sent us. - /// - /// Flood protection for large statements is rather hard and as soon as we get - /// `https://github.com/paritytech/polkadot/issues/2979` implemented also no longer necessary. - /// Reason: We keep messages around until we fetched the payload, but if a node makes up - /// statements and never provides the data, we will keep it around for the slot duration. Not - /// even signature checking would help, as the sender, if a validator, can just sign arbitrary - /// invalid statements and will not face any consequences as long as it won't provide the - /// payload. - /// - /// Quick and temporary fix, only accept `MAX_LARGE_STATEMENTS_PER_SENDER` per connected node. - /// - /// Large statements should be rare, if they were not, we would run into problems anyways, as - /// we would not be able to distribute them in a timely manner. Therefore - /// `MAX_LARGE_STATEMENTS_PER_SENDER` can be set to a relatively small number. It is also not - /// per candidate hash, but in total as candidate hashes can be made up, as illustrated above. - /// - /// An attacker could still try to fill up our memory, by repeatedly disconnecting and - /// connecting again with new peer ids, but we assume that the resulting effective bandwidth - /// for such an attack would be too low. - large_statement_count: usize, - - /// We have seen a message that that is unexpected from this peer, so note this fact - /// and stop subsequent logging and peer reputation flood. - unexpected_count: usize, -} - -impl PeerRelayParentKnowledge { - /// Updates our view of the peer's knowledge with this statement's fingerprint based - /// on something that we would like to send to the peer. - /// - /// NOTE: assumes `self.can_send` returned true before this call. - /// - /// Once the knowledge has incorporated a statement, it cannot be incorporated again. - /// - /// This returns `true` if this is the first time the peer has become aware of a - /// candidate with the given hash. - fn send(&mut self, fingerprint: &(CompactStatement, ValidatorIndex)) -> bool { - debug_assert!( - self.can_send(fingerprint), - "send is only called after `can_send` returns true; qed", - ); - - let new_known = match fingerprint.0 { - CompactStatement::Seconded(ref h) => { - self.seconded_counts.entry(fingerprint.1).or_default().note_local(*h); - - let was_known = self.is_known_candidate(h); - self.sent_candidates.insert(*h); - !was_known - }, - CompactStatement::Valid(_) => false, - }; - - self.sent_statements.insert(fingerprint.clone()); - - new_known - } - - /// This returns `true` if the peer cannot accept this statement, without altering internal - /// state, `false` otherwise. - fn can_send(&self, fingerprint: &(CompactStatement, ValidatorIndex)) -> bool { - let already_known = self.sent_statements.contains(fingerprint) || - self.received_statements.contains(fingerprint); - - if already_known { - return false - } - - match fingerprint.0 { - CompactStatement::Valid(ref h) => { - // The peer can only accept Valid statements for which it is aware - // of the corresponding candidate. - self.is_known_candidate(h) - }, - CompactStatement::Seconded(_) => true, - } - } - - /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based - /// on a message we are receiving from the peer. - /// - /// Provide the maximum message count that we can receive per candidate. In practice we should - /// not receive more statements for any one candidate than there are members in the group - /// assigned to that para, but this maximum needs to be lenient to account for equivocations - /// that may be cross-group. As such, a maximum of 2 * `n_validators` is recommended. - /// - /// This returns an error if the peer should not have sent us this message according to protocol - /// rules for flood protection. - /// - /// If this returns `Ok`, the internal state has been altered. After `receive`ing a new - /// candidate, we are then cleared to send the peer further statements about that candidate. - /// - /// This returns `Ok(true)` if this is the first time the peer has become aware of a - /// candidate with given hash. - fn receive( - &mut self, - fingerprint: &(CompactStatement, ValidatorIndex), - max_message_count: usize, - ) -> std::result::Result { - // We don't check `sent_statements` because a statement could be in-flight from both - // sides at the same time. - if self.received_statements.contains(fingerprint) { - return Err(COST_DUPLICATE_STATEMENT) - } - - let (candidate_hash, fresh) = match fingerprint.0 { - CompactStatement::Seconded(ref h) => { - let allowed_remote = self - .seconded_counts - .entry(fingerprint.1) - .or_insert_with(Default::default) - .note_remote(*h); - - if !allowed_remote { - return Err(COST_UNEXPECTED_STATEMENT_REMOTE) - } - - (h, !self.is_known_candidate(h)) - }, - CompactStatement::Valid(ref h) => { - if !self.is_known_candidate(h) { - return Err(COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE) - } - - (h, false) - }, - }; - - { - let received_per_candidate = - self.received_message_count.entry(*candidate_hash).or_insert(0); - - if *received_per_candidate >= max_message_count { - return Err(COST_APPARENT_FLOOD) - } - - *received_per_candidate += 1; - } - - self.received_statements.insert(fingerprint.clone()); - self.received_candidates.insert(*candidate_hash); - Ok(fresh) - } - - /// Note a received large statement metadata. - fn receive_large_statement(&mut self) -> std::result::Result<(), Rep> { - if self.large_statement_count >= MAX_LARGE_STATEMENTS_PER_SENDER { - return Err(COST_APPARENT_FLOOD) - } - self.large_statement_count += 1; - Ok(()) - } - - /// This method does the same checks as `receive` without modifying the internal state. - /// Returns an error if the peer should not have sent us this message according to protocol - /// rules for flood protection. - fn check_can_receive( - &self, - fingerprint: &(CompactStatement, ValidatorIndex), - max_message_count: usize, - ) -> std::result::Result<(), Rep> { - // We don't check `sent_statements` because a statement could be in-flight from both - // sides at the same time. - if self.received_statements.contains(fingerprint) { - return Err(COST_DUPLICATE_STATEMENT) - } - - let candidate_hash = match fingerprint.0 { - CompactStatement::Seconded(ref h) => { - let allowed_remote = self - .seconded_counts - .get(&fingerprint.1) - .map_or(true, |r| r.is_wanted_candidate(h)); - - if !allowed_remote { - return Err(COST_UNEXPECTED_STATEMENT_REMOTE) - } - - h - }, - CompactStatement::Valid(ref h) => { - if !self.is_known_candidate(&h) { - return Err(COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE) - } - - h - }, - }; - - let received_per_candidate = self.received_message_count.get(candidate_hash).unwrap_or(&0); - - if *received_per_candidate >= max_message_count { - Err(COST_APPARENT_FLOOD) - } else { - Ok(()) - } - } - - /// Check for candidates that the peer is aware of. This indicates that we can - /// send other statements pertaining to that candidate. - fn is_known_candidate(&self, candidate: &CandidateHash) -> bool { - self.sent_candidates.contains(candidate) || self.received_candidates.contains(candidate) - } -} - -struct PeerData { - view: View, - view_knowledge: HashMap, - /// Peer might be known as authority with the given ids. - maybe_authority: Option>, -} - -impl PeerData { - /// Updates our view of the peer's knowledge with this statement's fingerprint based - /// on something that we would like to send to the peer. - /// - /// NOTE: assumes `self.can_send` returned true before this call. - /// - /// Once the knowledge has incorporated a statement, it cannot be incorporated again. - /// - /// This returns `true` if this is the first time the peer has become aware of a - /// candidate with the given hash. - fn send( - &mut self, - relay_parent: &Hash, - fingerprint: &(CompactStatement, ValidatorIndex), - ) -> bool { - debug_assert!( - self.can_send(relay_parent, fingerprint), - "send is only called after `can_send` returns true; qed", - ); - self.view_knowledge - .get_mut(relay_parent) - .expect("send is only called after `can_send` returns true; qed") - .send(fingerprint) - } - - /// This returns `None` if the peer cannot accept this statement, without altering internal - /// state. - fn can_send( - &self, - relay_parent: &Hash, - fingerprint: &(CompactStatement, ValidatorIndex), - ) -> bool { - self.view_knowledge.get(relay_parent).map_or(false, |k| k.can_send(fingerprint)) - } - - /// Attempt to update our view of the peer's knowledge with this statement's fingerprint based - /// on a message we are receiving from the peer. - /// - /// Provide the maximum message count that we can receive per candidate. In practice we should - /// not receive more statements for any one candidate than there are members in the group - /// assigned to that para, but this maximum needs to be lenient to account for equivocations - /// that may be cross-group. As such, a maximum of 2 * `n_validators` is recommended. - /// - /// This returns an error if the peer should not have sent us this message according to protocol - /// rules for flood protection. - /// - /// If this returns `Ok`, the internal state has been altered. After `receive`ing a new - /// candidate, we are then cleared to send the peer further statements about that candidate. - /// - /// This returns `Ok(true)` if this is the first time the peer has become aware of a - /// candidate with given hash. - fn receive( - &mut self, - relay_parent: &Hash, - fingerprint: &(CompactStatement, ValidatorIndex), - max_message_count: usize, - ) -> std::result::Result { - self.view_knowledge - .get_mut(relay_parent) - .ok_or(COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE)? - .receive(fingerprint, max_message_count) - } - - /// This method does the same checks as `receive` without modifying the internal state. - /// Returns an error if the peer should not have sent us this message according to protocol - /// rules for flood protection. - fn check_can_receive( - &self, - relay_parent: &Hash, - fingerprint: &(CompactStatement, ValidatorIndex), - max_message_count: usize, - ) -> std::result::Result<(), Rep> { - self.view_knowledge - .get(relay_parent) - .ok_or(COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE)? - .check_can_receive(fingerprint, max_message_count) - } - - /// Receive a notice about out of view statement and returns the value of the old flag - fn receive_unexpected(&mut self, relay_parent: &Hash) -> usize { - self.view_knowledge - .get_mut(relay_parent) - .map_or(0_usize, |relay_parent_peer_knowledge| { - let old = relay_parent_peer_knowledge.unexpected_count; - relay_parent_peer_knowledge.unexpected_count += 1_usize; - old - }) - } - - /// Basic flood protection for large statements. - fn receive_large_statement(&mut self, relay_parent: &Hash) -> std::result::Result<(), Rep> { - self.view_knowledge - .get_mut(relay_parent) - .ok_or(COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE)? - .receive_large_statement() - } -} - -// A statement stored while a relay chain head is active. -#[derive(Debug, Copy, Clone)] -struct StoredStatement<'a> { - comparator: &'a StoredStatementComparator, - statement: &'a SignedFullStatement, -} - -// A value used for comparison of stored statements to each other. -// -// The compact version of the statement, the validator index, and the signature of the validator -// is enough to differentiate between all types of equivocations, as long as the signature is -// actually checked to be valid. The same statement with 2 signatures and 2 statements with -// different (or same) signatures wll all be correctly judged to be unequal with this comparator. -#[derive(PartialEq, Eq, Hash, Clone, Debug)] -struct StoredStatementComparator { - compact: CompactStatement, - validator_index: ValidatorIndex, - signature: ValidatorSignature, -} - -impl<'a> From<(&'a StoredStatementComparator, &'a SignedFullStatement)> for StoredStatement<'a> { - fn from( - (comparator, statement): (&'a StoredStatementComparator, &'a SignedFullStatement), - ) -> Self { - Self { comparator, statement } - } -} - -impl<'a> StoredStatement<'a> { - fn compact(&self) -> &'a CompactStatement { - &self.comparator.compact - } - - fn fingerprint(&self) -> (CompactStatement, ValidatorIndex) { - (self.comparator.compact.clone(), self.statement.validator_index()) - } -} - -#[derive(Debug)] -enum NotedStatement<'a> { - NotUseful, - Fresh(StoredStatement<'a>), - UsefulButKnown, -} - -/// Large statement fetching status. -enum LargeStatementStatus { - /// We are currently fetching the statement data from a remote peer. We keep a list of other - /// nodes claiming to have that data and will fallback on them. - Fetching(FetchingInfo), - /// Statement data is fetched or we got it locally via `StatementDistributionMessage::Share`. - FetchedOrShared(CommittedCandidateReceipt), -} - -/// Info about a fetch in progress. -struct FetchingInfo { - /// All peers that send us a `LargeStatement` or a `Valid` statement for the given - /// `CandidateHash`, together with their originally sent messages. - /// - /// We use an `IndexMap` here to preserve the ordering of peers sending us messages. This is - /// desirable because we reward first sending peers with reputation. - available_peers: IndexMap>, - /// Peers left to try in case the background task needs it. - peers_to_try: Vec, - /// Sender for sending fresh peers to the fetching task in case of failure. - peer_sender: Option>>, - /// Task taking care of the request. - /// - /// Will be killed once dropped. - #[allow(dead_code)] - fetching_task: RemoteHandle<()>, -} - /// Messages to be handled in this subsystem. enum MuxedMessage { /// Messages from other subsystems. Subsystem(FatalResult>), - /// Messages from spawned requester background tasks. - Requester(Option), - /// Messages from spawned responder background task. - Responder(Option), + /// Messages from spawned v1 (legacy) requester background tasks. + V1Requester(Option), + /// Messages from spawned v1 (legacy) responder background task. + V1Responder(Option), + /// Messages from candidate responder background task. + Responder(Option), + /// Messages from answered requests. + Response(vstaging::UnhandledResponse), + /// Message that a request is ready to be retried. This just acts as a signal that we should + /// dispatch all pending requests again. + RetryRequest(()), } #[overseer::contextbounds(StatementDistribution, prefix = self::overseer)] impl MuxedMessage { async fn receive( ctx: &mut Context, - from_requester: &mut mpsc::Receiver, - from_responder: &mut mpsc::Receiver, + state: &mut vstaging::State, + from_v1_requester: &mut mpsc::Receiver, + from_v1_responder: &mut mpsc::Receiver, + from_responder: &mut mpsc::Receiver, ) -> MuxedMessage { + let (request_manager, response_manager) = state.request_and_response_managers(); // We are only fusing here to make `select` happy, in reality we will quit if one of those // streams end: - let from_overseer = ctx.recv().fuse(); - let from_requester = from_requester.next(); + let from_orchestra = ctx.recv().fuse(); + let from_v1_requester = from_v1_requester.next(); + let from_v1_responder = from_v1_responder.next(); let from_responder = from_responder.next(); - futures::pin_mut!(from_overseer, from_requester, from_responder); + let receive_response = vstaging::receive_response(response_manager).fuse(); + let retry_request = vstaging::next_retry(request_manager).fuse(); + futures::pin_mut!( + from_orchestra, + from_v1_requester, + from_v1_responder, + from_responder, + receive_response, + retry_request, + ); futures::select! { - msg = from_overseer => MuxedMessage::Subsystem(msg.map_err(FatalError::SubsystemReceive)), - msg = from_requester => MuxedMessage::Requester(msg), + msg = from_orchestra => MuxedMessage::Subsystem(msg.map_err(FatalError::SubsystemReceive)), + msg = from_v1_requester => MuxedMessage::V1Requester(msg), + msg = from_v1_responder => MuxedMessage::V1Responder(msg), msg = from_responder => MuxedMessage::Responder(msg), + msg = receive_response => MuxedMessage::Response(msg), + msg = retry_request => MuxedMessage::RetryRequest(msg), } } } -#[derive(Debug, PartialEq, Eq)] -enum DeniedStatement { - NotUseful, - UsefulButKnown, -} - -struct ActiveHeadData { - /// All candidates we are aware of for this head, keyed by hash. - candidates: HashSet, - /// Stored statements for circulation to peers. - /// - /// These are iterable in insertion order, and `Seconded` statements are always - /// accepted before dependent statements. - statements: IndexMap, - /// Large statements we are waiting for with associated meta data. - waiting_large_statements: HashMap, - /// The parachain validators at the head's child session index. - validators: IndexedVec, - /// The current session index of this fork. - session_index: sp_staking::SessionIndex, - /// How many `Seconded` statements we've seen per validator. - seconded_counts: HashMap, - /// A Jaeger span for this head, so we can attach data to it. - span: PerLeafSpan, -} - -impl ActiveHeadData { - fn new( - validators: IndexedVec, - session_index: sp_staking::SessionIndex, - span: PerLeafSpan, - ) -> Self { - ActiveHeadData { - candidates: Default::default(), - statements: Default::default(), - waiting_large_statements: Default::default(), - validators, - session_index, - seconded_counts: Default::default(), - span, - } - } - - /// Note the given statement. - /// - /// If it was not already known and can be accepted, returns `NotedStatement::Fresh`, - /// with a handle to the statement. - /// - /// If it can be accepted, but we already know it, returns `NotedStatement::UsefulButKnown`. - /// - /// We accept up to `VC_THRESHOLD` (2 at time of writing) `Seconded` statements - /// per validator. These will be the first ones we see. The statement is assumed - /// to have been checked, including that the validator index is not out-of-bounds and - /// the signature is valid. - /// - /// Any other statements or those that reference a candidate we are not aware of cannot be - /// accepted and will return `NotedStatement::NotUseful`. - fn note_statement(&mut self, statement: SignedFullStatement) -> NotedStatement { - let validator_index = statement.validator_index(); - let comparator = StoredStatementComparator { - compact: statement.payload().to_compact(), - validator_index, - signature: statement.signature().clone(), - }; - - match comparator.compact { - CompactStatement::Seconded(h) => { - let seconded_so_far = self.seconded_counts.entry(validator_index).or_insert(0); - if *seconded_so_far >= VC_THRESHOLD { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - ?statement, - "Extra statement is ignored" - ); - return NotedStatement::NotUseful - } - - self.candidates.insert(h); - if let Some(old) = self.statements.insert(comparator.clone(), statement) { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - statement = ?old, - "Known statement" - ); - NotedStatement::UsefulButKnown - } else { - *seconded_so_far += 1; - - gum::trace!( - target: LOG_TARGET, - ?validator_index, - statement = ?self.statements.last().expect("Just inserted").1, - "Noted new statement" - ); - // This will always return `Some` because it was just inserted. - let key_value = self - .statements - .get_key_value(&comparator) - .expect("Statement was just inserted; qed"); - - NotedStatement::Fresh(key_value.into()) - } - }, - CompactStatement::Valid(h) => { - if !self.candidates.contains(&h) { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - ?statement, - "Statement for unknown candidate" - ); - return NotedStatement::NotUseful - } - - if let Some(old) = self.statements.insert(comparator.clone(), statement) { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - statement = ?old, - "Known statement" - ); - NotedStatement::UsefulButKnown - } else { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - statement = ?self.statements.last().expect("Just inserted").1, - "Noted new statement" - ); - // This will always return `Some` because it was just inserted. - NotedStatement::Fresh( - self.statements - .get_key_value(&comparator) - .expect("Statement was just inserted; qed") - .into(), - ) - } - }, - } - } - - /// Returns an error if the statement is already known or not useful - /// without modifying the internal state. - fn check_useful_or_unknown( - &self, - statement: &UncheckedSignedStatement, - ) -> std::result::Result<(), DeniedStatement> { - let validator_index = statement.unchecked_validator_index(); - let compact = statement.unchecked_payload(); - let comparator = StoredStatementComparator { - compact: compact.clone(), - validator_index, - signature: statement.unchecked_signature().clone(), - }; - - match compact { - CompactStatement::Seconded(_) => { - let seconded_so_far = self.seconded_counts.get(&validator_index).unwrap_or(&0); - if *seconded_so_far >= VC_THRESHOLD { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - ?statement, - "Extra statement is ignored", - ); - return Err(DeniedStatement::NotUseful) - } - - if self.statements.contains_key(&comparator) { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - ?statement, - "Known statement", - ); - return Err(DeniedStatement::UsefulButKnown) - } - }, - CompactStatement::Valid(h) => { - if !self.candidates.contains(&h) { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - ?statement, - "Statement for unknown candidate", - ); - return Err(DeniedStatement::NotUseful) - } - - if self.statements.contains_key(&comparator) { - gum::trace!( - target: LOG_TARGET, - ?validator_index, - ?statement, - "Known statement", - ); - return Err(DeniedStatement::UsefulButKnown) - } - }, - } - Ok(()) - } - - /// Get an iterator over all statements for the active head. Seconded statements come first. - fn statements(&self) -> impl Iterator> + '_ { - self.statements.iter().map(Into::into) - } - - /// Get an iterator over all statements for the active head that are for a particular candidate. - fn statements_about( - &self, - candidate_hash: CandidateHash, - ) -> impl Iterator> + '_ { - self.statements() - .filter(move |s| s.compact().candidate_hash() == &candidate_hash) - } -} - -/// Check a statement signature under this parent hash. -fn check_statement_signature( - head: &ActiveHeadData, - relay_parent: Hash, - statement: UncheckedSignedStatement, -) -> std::result::Result { - let signing_context = - SigningContext { session_index: head.session_index, parent_hash: relay_parent }; - - head.validators - .get(statement.unchecked_validator_index()) - .ok_or_else(|| statement.clone()) - .and_then(|v| statement.try_into_checked(&signing_context, v)) -} - -/// Places the statement in storage if it is new, and then -/// circulates the statement to all peers who have not seen it yet, and -/// sends all statements dependent on that statement to peers who could previously not receive -/// them but now can. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn circulate_statement_and_dependents( - topology_store: &SessionBoundGridTopologyStorage, - peers: &mut HashMap, - active_heads: &mut HashMap, - ctx: &mut Context, - relay_parent: Hash, - statement: SignedFullStatement, - priority_peers: Vec, - metrics: &Metrics, - rng: &mut impl rand::Rng, -) { - let active_head = match active_heads.get_mut(&relay_parent) { - Some(res) => res, - None => return, - }; - - let _span = active_head - .span - .child("circulate-statement") - .with_candidate(statement.payload().candidate_hash()) - .with_stage(jaeger::Stage::StatementDistribution); - - let topology = topology_store - .get_topology_or_fallback(active_head.session_index) - .local_grid_neighbors(); - - // First circulate the statement directly to all peers needing it. - // The borrow of `active_head` needs to encompass only this (Rust) statement. - let outputs: Option<(CandidateHash, Vec)> = { - match active_head.note_statement(statement) { - NotedStatement::Fresh(stored) => Some(( - *stored.compact().candidate_hash(), - circulate_statement( - RequiredRouting::GridXY, - topology, - peers, - ctx, - relay_parent, - stored, - priority_peers, - metrics, - rng, - ) - .await, - )), - _ => None, - } - }; - - let _span = _span.child("send-to-peers"); - // Now send dependent statements to all peers needing them, if any. - if let Some((candidate_hash, peers_needing_dependents)) = outputs { - for peer in peers_needing_dependents { - if let Some(peer_data) = peers.get_mut(&peer) { - let _span_loop = _span.child("to-peer").with_peer_id(&peer); - // defensive: the peer data should always be some because the iterator - // of peers is derived from the set of peers. - send_statements_about( - peer, - peer_data, - ctx, - relay_parent, - candidate_hash, - &*active_head, - metrics, - ) - .await; - } - } - } -} - -/// Create a network message from a given statement. -fn statement_message( - relay_parent: Hash, - statement: SignedFullStatement, - metrics: &Metrics, -) -> net_protocol::VersionedValidationProtocol { - let (is_large, size) = is_statement_large(&statement); - if let Some(size) = size { - metrics.on_created_message(size); - } - - let msg = if is_large { - protocol_v1::StatementDistributionMessage::LargeStatement(StatementMetadata { - relay_parent, - candidate_hash: statement.payload().candidate_hash(), - signed_by: statement.validator_index(), - signature: statement.signature().clone(), - }) - } else { - protocol_v1::StatementDistributionMessage::Statement(relay_parent, statement.into()) - }; - - protocol_v1::ValidationProtocol::StatementDistribution(msg).into() -} - -/// Check whether a statement should be treated as large statement. -/// -/// Also report size of statement - if it is a `Seconded` statement, otherwise `None`. -fn is_statement_large(statement: &SignedFullStatement) -> (bool, Option) { - match &statement.payload() { - Statement::Seconded(committed) => { - let size = statement.as_unchecked().encoded_size(); - // Runtime upgrades will always be large and even if not - no harm done. - if committed.commitments.new_validation_code.is_some() { - return (true, Some(size)) - } - - // Half max size seems to be a good threshold to start not using notifications: - let threshold = - PeerSet::Validation.get_max_notification_size(IsAuthority::Yes) as usize / 2; - - (size >= threshold, Some(size)) - }, - Statement::Valid(_) => (false, None), - } -} - -/// Circulates a statement to all peers who have not seen it yet, and returns -/// an iterator over peers who need to have dependent statements sent. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn circulate_statement<'a, Context>( - required_routing: RequiredRouting, - topology: &GridNeighbors, - peers: &mut HashMap, - ctx: &mut Context, - relay_parent: Hash, - stored: StoredStatement<'a>, - mut priority_peers: Vec, - metrics: &Metrics, - rng: &mut impl rand::Rng, -) -> Vec { - let fingerprint = stored.fingerprint(); - - let mut peers_to_send: Vec = peers - .iter() - .filter_map( - |(peer, data)| { - if data.can_send(&relay_parent, &fingerprint) { - Some(*peer) - } else { - None - } - }, - ) - .collect(); - - let good_peers: HashSet<&PeerId> = peers_to_send.iter().collect(); - // Only take priority peers we can send data to: - priority_peers.retain(|p| good_peers.contains(p)); - - // Avoid duplicates: - let priority_set: HashSet<&PeerId> = priority_peers.iter().collect(); - peers_to_send.retain(|p| !priority_set.contains(p)); - - util::choose_random_subset_with_rng( - |e| topology.route_to_peer(required_routing, e), - &mut peers_to_send, - rng, - MIN_GOSSIP_PEERS, - ); - // We don't want to use less peers, than we would without any priority peers: - let min_size = std::cmp::max(peers_to_send.len(), MIN_GOSSIP_PEERS); - // Make set full: - let needed_peers = min_size as i64 - priority_peers.len() as i64; - if needed_peers > 0 { - peers_to_send.truncate(needed_peers as usize); - // Order important here - priority peers are placed first, so will be sent first. - // This gives backers a chance to be among the first in requesting any large statement - // data. - priority_peers.append(&mut peers_to_send); - } - peers_to_send = priority_peers; - // We must not have duplicates: - debug_assert!( - peers_to_send.len() == peers_to_send.clone().into_iter().collect::>().len(), - "We filter out duplicates above. qed.", - ); - let peers_to_send: Vec<(PeerId, bool)> = peers_to_send - .into_iter() - .map(|peer_id| { - let new = peers - .get_mut(&peer_id) - .expect("a subset is taken above, so it exists; qed") - .send(&relay_parent, &fingerprint); - (peer_id, new) - }) - .collect(); - - // Send all these peers the initial statement. - if !peers_to_send.is_empty() { - let payload = statement_message(relay_parent, stored.statement.clone(), metrics); - gum::trace!( - target: LOG_TARGET, - ?peers_to_send, - ?relay_parent, - statement = ?stored.statement, - "Sending statement", - ); - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - peers_to_send.iter().map(|(p, _)| *p).collect(), - payload, - )) - .await; - } - - peers_to_send - .into_iter() - .filter_map(|(peer, needs_dependent)| if needs_dependent { Some(peer) } else { None }) - .collect() -} - -/// Send all statements about a given candidate hash to a peer. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn send_statements_about( - peer: PeerId, - peer_data: &mut PeerData, - ctx: &mut Context, - relay_parent: Hash, - candidate_hash: CandidateHash, - active_head: &ActiveHeadData, - metrics: &Metrics, -) { - for statement in active_head.statements_about(candidate_hash) { - let fingerprint = statement.fingerprint(); - if !peer_data.can_send(&relay_parent, &fingerprint) { - continue - } - peer_data.send(&relay_parent, &fingerprint); - let payload = statement_message(relay_parent, statement.statement.clone(), metrics); - - gum::trace!( - target: LOG_TARGET, - ?peer, - ?relay_parent, - ?candidate_hash, - statement = ?statement.statement, - "Sending statement", - ); - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(vec![peer], payload)) - .await; - - metrics.on_statement_distributed(); - } -} - -/// Send all statements at a given relay-parent to a peer. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn send_statements( - peer: PeerId, - peer_data: &mut PeerData, - ctx: &mut Context, - relay_parent: Hash, - active_head: &ActiveHeadData, - metrics: &Metrics, -) { - for statement in active_head.statements() { - let fingerprint = statement.fingerprint(); - if !peer_data.can_send(&relay_parent, &fingerprint) { - continue - } - peer_data.send(&relay_parent, &fingerprint); - let payload = statement_message(relay_parent, statement.statement.clone(), metrics); - - gum::trace!( - target: LOG_TARGET, - ?peer, - ?relay_parent, - statement = ?statement.statement, - "Sending statement" - ); - ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(vec![peer], payload)) - .await; - - metrics.on_statement_distributed(); - } -} - -/// Modify the reputation of a peer based on its behavior. -async fn modify_reputation( - reputation: &mut ReputationAggregator, - sender: &mut impl overseer::StatementDistributionSenderTrait, - peer: PeerId, - rep: Rep, -) { - reputation.modify(sender, peer, rep).await; -} - -/// If message contains a statement, then retrieve it, otherwise fork task to fetch it. -/// -/// This function will also return `None` if the message did not pass some basic checks, in that -/// case no statement will be requested, on the flipside you get `ActiveHeadData` in addition to -/// your statement. -/// -/// If the message was large, but the result has been fetched already that one is returned. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn retrieve_statement_from_message<'a, Context>( - peer: PeerId, - message: protocol_v1::StatementDistributionMessage, - active_head: &'a mut ActiveHeadData, - ctx: &mut Context, - req_sender: &mpsc::Sender, - metrics: &Metrics, -) -> Option { - let fingerprint = message.get_fingerprint(); - let candidate_hash = *fingerprint.0.candidate_hash(); - - // Immediately return any Seconded statement: - let message = if let protocol_v1::StatementDistributionMessage::Statement(h, s) = message { - if let Statement::Seconded(_) = s.unchecked_payload() { - return Some(s) - } - protocol_v1::StatementDistributionMessage::Statement(h, s) - } else { - message - }; - - match active_head.waiting_large_statements.entry(candidate_hash) { - Entry::Occupied(mut occupied) => { - match occupied.get_mut() { - LargeStatementStatus::Fetching(info) => { - let is_large_statement = message.is_large_statement(); - - let is_new_peer = match info.available_peers.entry(peer) { - IEntry::Occupied(mut occupied) => { - occupied.get_mut().push(message); - false - }, - IEntry::Vacant(vacant) => { - vacant.insert(vec![message]); - true - }, - }; - - if is_new_peer & is_large_statement { - info.peers_to_try.push(peer); - // Answer any pending request for more peers: - if let Some(sender) = info.peer_sender.take() { - let to_send = std::mem::take(&mut info.peers_to_try); - if let Err(peers) = sender.send(to_send) { - // Requester no longer interested for now, might want them - // later: - info.peers_to_try = peers; - } - } - } - }, - LargeStatementStatus::FetchedOrShared(committed) => { - match message { - protocol_v1::StatementDistributionMessage::Statement(_, s) => { - // We can now immediately return any statements (should only be - // `Statement::Valid` ones, but we don't care at this point.) - return Some(s) - }, - protocol_v1::StatementDistributionMessage::LargeStatement(metadata) => - return Some(UncheckedSignedFullStatement::new( - Statement::Seconded(committed.clone()), - metadata.signed_by, - metadata.signature.clone(), - )), - } - }, - } - }, - Entry::Vacant(vacant) => { - match message { - protocol_v1::StatementDistributionMessage::LargeStatement(metadata) => { - if let Some(new_status) = - launch_request(metadata, peer, req_sender.clone(), ctx, metrics).await - { - vacant.insert(new_status); - } - }, - protocol_v1::StatementDistributionMessage::Statement(_, s) => { - // No fetch in progress, safe to return any statement immediately (we don't - // bother about normal network jitter which might cause `Valid` statements to - // arrive early for now.). - return Some(s) - }, - } - }, - } - None -} - -/// Launch request for a large statement and get tracking status. -/// -/// Returns `None` if spawning task failed. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn launch_request( - meta: StatementMetadata, - peer: PeerId, - req_sender: mpsc::Sender, - ctx: &mut Context, - metrics: &Metrics, -) -> Option { - let (task, handle) = - fetch(meta.relay_parent, meta.candidate_hash, vec![peer], req_sender, metrics.clone()) - .remote_handle(); - - let result = ctx.spawn("large-statement-fetcher", task.boxed()); - if let Err(err) = result { - gum::error!(target: LOG_TARGET, ?err, "Spawning task failed."); - return None - } - let available_peers = { - let mut m = IndexMap::new(); - m.insert(peer, vec![protocol_v1::StatementDistributionMessage::LargeStatement(meta)]); - m - }; - Some(LargeStatementStatus::Fetching(FetchingInfo { - available_peers, - peers_to_try: Vec::new(), - peer_sender: None, - fetching_task: handle, - })) -} - -/// Handle incoming message and circulate it to peers, if we did not know it already. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn handle_incoming_message_and_circulate<'a, Context, R>( - peer: PeerId, - topology_storage: &SessionBoundGridTopologyStorage, - peers: &mut HashMap, - active_heads: &'a mut HashMap, - recent_outdated_heads: &RecentOutdatedHeads, - ctx: &mut Context, - message: protocol_v1::StatementDistributionMessage, - req_sender: &mpsc::Sender, - metrics: &Metrics, - runtime: &mut RuntimeInfo, - rng: &mut R, - reputation: &mut ReputationAggregator, -) where - R: rand::Rng, -{ - let handled_incoming = match peers.get_mut(&peer) { - Some(data) => - handle_incoming_message( - peer, - data, - active_heads, - recent_outdated_heads, - ctx, - message, - req_sender, - metrics, - reputation, - ) - .await, - None => None, - }; - - // if we got a fresh message, we need to circulate it to all peers. - if let Some((relay_parent, statement)) = handled_incoming { - // we can ignore the set of peers who this function returns as now expecting - // dependent statements. - // - // we have the invariant in this subsystem that we never store a `Valid` or `Invalid` - // statement before a `Seconded` statement. `Seconded` statements are the only ones - // that require dependents. Thus, if this is a `Seconded` statement for a candidate we - // were not aware of before, we cannot have any dependent statements from the candidate. - let _ = metrics.time_network_bridge_update_v1("circulate_statement"); - - let session_index = runtime.get_session_index_for_child(ctx.sender(), relay_parent).await; - let topology = match session_index { - Ok(session_index) => - topology_storage.get_topology_or_fallback(session_index).local_grid_neighbors(), - Err(e) => { - gum::debug!( - target: LOG_TARGET, - %relay_parent, - "cannot get session index for the specific relay parent: {:?}", - e - ); - - topology_storage.get_current_topology().local_grid_neighbors() - }, - }; - let required_routing = - topology.required_routing_by_index(statement.statement.validator_index(), false); - - let _ = circulate_statement( - required_routing, - topology, - peers, - ctx, - relay_parent, - statement, - Vec::new(), - metrics, - rng, - ) - .await; - } -} - -// Handle a statement. Returns a reference to a newly-stored statement -// if we were not already aware of it, along with the corresponding relay-parent. -// -// This function checks the signature and ensures the statement is compatible with our -// view. It also notifies candidate backing if the statement was previously unknown. -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn handle_incoming_message<'a, Context>( - peer: PeerId, - peer_data: &mut PeerData, - active_heads: &'a mut HashMap, - recent_outdated_heads: &RecentOutdatedHeads, - ctx: &mut Context, - message: protocol_v1::StatementDistributionMessage, - req_sender: &mpsc::Sender, - metrics: &Metrics, - reputation: &mut ReputationAggregator, -) -> Option<(Hash, StoredStatement<'a>)> { - let relay_parent = message.get_relay_parent(); - let _ = metrics.time_network_bridge_update_v1("handle_incoming_message"); - - let active_head = match active_heads.get_mut(&relay_parent) { - Some(h) => h, - None => { - gum::debug!( - target: LOG_TARGET, - %relay_parent, - "our view out-of-sync with active heads; head not found", - ); - - if !recent_outdated_heads.is_recent_outdated(&relay_parent) { - modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; - } - - return None - }, - }; - - if let protocol_v1::StatementDistributionMessage::LargeStatement(_) = message { - if let Err(rep) = peer_data.receive_large_statement(&relay_parent) { - gum::debug!(target: LOG_TARGET, ?peer, ?message, ?rep, "Unexpected large statement.",); - modify_reputation(reputation, ctx.sender(), peer, rep).await; - return None - } - } - - let fingerprint = message.get_fingerprint(); - let candidate_hash = *fingerprint.0.candidate_hash(); - let handle_incoming_span = active_head - .span - .child("handle-incoming") - .with_candidate(candidate_hash) - .with_peer_id(&peer); - - let max_message_count = active_head.validators.len() * 2; - - // perform only basic checks before verifying the signature - // as it's more computationally heavy - if let Err(rep) = peer_data.check_can_receive(&relay_parent, &fingerprint, max_message_count) { - // This situation can happen when a peer's Seconded message was lost - // but we have received the Valid statement. - // So we check it once and then ignore repeated violation to avoid - // reputation change flood. - let unexpected_count = peer_data.receive_unexpected(&relay_parent); - - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - ?peer, - ?message, - ?rep, - ?unexpected_count, - "Error inserting received statement" - ); - - match rep { - // This happens when a Valid statement has been received but there is no corresponding - // Seconded - COST_UNEXPECTED_STATEMENT_UNKNOWN_CANDIDATE => { - metrics.on_unexpected_statement_valid(); - // Report peer merely if this is not a duplicate out-of-view statement that - // was caused by a missing Seconded statement from this peer - if unexpected_count == 0_usize { - modify_reputation(reputation, ctx.sender(), peer, rep).await; - } - }, - // This happens when we have an unexpected remote peer that announced Seconded - COST_UNEXPECTED_STATEMENT_REMOTE => { - metrics.on_unexpected_statement_seconded(); - modify_reputation(reputation, ctx.sender(), peer, rep).await; - }, - _ => { - modify_reputation(reputation, ctx.sender(), peer, rep).await; - }, - } - - return None - } - - let checked_compact = { - let (compact, validator_index) = message.get_fingerprint(); - let signature = message.get_signature(); - - let unchecked_compact = UncheckedSignedStatement::new(compact, validator_index, signature); - - match active_head.check_useful_or_unknown(&unchecked_compact) { - Ok(()) => {}, - Err(DeniedStatement::NotUseful) => return None, - Err(DeniedStatement::UsefulButKnown) => { - // Note a received statement in the peer data - peer_data - .receive(&relay_parent, &fingerprint, max_message_count) - .expect("checked in `check_can_receive` above; qed"); - modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT).await; - - return None - }, - } - - // check the signature on the statement. - match check_statement_signature(&active_head, relay_parent, unchecked_compact) { - Err(statement) => { - gum::debug!(target: LOG_TARGET, ?peer, ?statement, "Invalid statement signature"); - modify_reputation(reputation, ctx.sender(), peer, COST_INVALID_SIGNATURE).await; - return None - }, - Ok(statement) => statement, - } - }; - - // Fetch from the network only after signature and usefulness checks are completed. - let is_large_statement = message.is_large_statement(); - let statement = - retrieve_statement_from_message(peer, message, active_head, ctx, req_sender, metrics) - .await?; - - let payload = statement.unchecked_into_payload(); - - // Upgrade the `Signed` wrapper from the compact payload to the full payload. - // This fails if the payload doesn't encode correctly. - let statement: SignedFullStatement = match checked_compact.convert_to_superpayload(payload) { - Err((compact, _)) => { - gum::debug!( - target: LOG_TARGET, - ?peer, - ?compact, - is_large_statement, - "Full statement had bad payload." - ); - modify_reputation(reputation, ctx.sender(), peer, COST_WRONG_HASH).await; - return None - }, - Ok(statement) => statement, - }; - - // Ensure the statement is stored in the peer data. - // - // Note that if the peer is sending us something that is not within their view, - // it will not be kept within their log. - match peer_data.receive(&relay_parent, &fingerprint, max_message_count) { - Err(_) => { - unreachable!("checked in `check_can_receive` above; qed"); - }, - Ok(true) => { - gum::trace!(target: LOG_TARGET, ?peer, ?statement, "Statement accepted"); - // Send the peer all statements concerning the candidate that we have, - // since it appears to have just learned about the candidate. - send_statements_about( - peer, - peer_data, - ctx, - relay_parent, - candidate_hash, - &*active_head, - metrics, - ) - .await; - }, - Ok(false) => {}, - } - - // Note: `peer_data.receive` already ensures that the statement is not an unbounded equivocation - // or unpinned to a seconded candidate. So it is safe to place it into the storage. - match active_head.note_statement(statement) { - NotedStatement::NotUseful | NotedStatement::UsefulButKnown => { - unreachable!("checked in `is_useful_or_unknown` above; qed"); - }, - NotedStatement::Fresh(statement) => { - modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT_FIRST).await; - - let mut _span = handle_incoming_span.child("notify-backing"); - - // When we receive a new message from a peer, we forward it to the - // candidate backing subsystem. - ctx.send_message(CandidateBackingMessage::Statement( - relay_parent, - statement.statement.clone(), - )) - .await; - - Some((relay_parent, statement)) - }, - } -} - -/// Update a peer's view. Sends all newly unlocked statements based on the previous -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn update_peer_view_and_maybe_send_unlocked( - peer: PeerId, - topology: &GridNeighbors, - peer_data: &mut PeerData, - ctx: &mut Context, - active_heads: &HashMap, - new_view: View, - metrics: &Metrics, - rng: &mut R, -) where - R: rand::Rng, -{ - let old_view = std::mem::replace(&mut peer_data.view, new_view); - - // Remove entries for all relay-parents in the old view but not the new. - for removed in old_view.difference(&peer_data.view) { - let _ = peer_data.view_knowledge.remove(removed); - } - - // Use both grid directions - let is_gossip_peer = topology.route_to_peer(RequiredRouting::GridXY, &peer); - let lucky = is_gossip_peer || - util::gen_ratio_rng( - util::MIN_GOSSIP_PEERS.saturating_sub(topology.len()), - util::MIN_GOSSIP_PEERS, - rng, - ); - - // Add entries for all relay-parents in the new view but not the old. - // Furthermore, send all statements we have for those relay parents. - let new_view = peer_data.view.difference(&old_view).copied().collect::>(); - for new in new_view.iter().copied() { - peer_data.view_knowledge.insert(new, Default::default()); - if !lucky { - continue - } - if let Some(active_head) = active_heads.get(&new) { - send_statements(peer, peer_data, ctx, new, active_head, metrics).await; - } - } -} - -#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn handle_network_update( - peers: &mut HashMap, - topology_storage: &mut SessionBoundGridTopologyStorage, - authorities: &mut HashMap, - active_heads: &mut HashMap, - recent_outdated_heads: &RecentOutdatedHeads, - ctx: &mut Context, - req_sender: &mpsc::Sender, - update: NetworkBridgeEvent, - metrics: &Metrics, - runtime: &mut RuntimeInfo, - rng: &mut R, - reputation: &mut ReputationAggregator, -) where - R: rand::Rng, -{ - match update { - NetworkBridgeEvent::PeerConnected(peer, role, _, maybe_authority) => { - gum::trace!(target: LOG_TARGET, ?peer, ?role, "Peer connected"); - peers.insert( - peer, - PeerData { - view: Default::default(), - view_knowledge: Default::default(), - maybe_authority: maybe_authority.clone(), - }, - ); - if let Some(authority_ids) = maybe_authority { - authority_ids.into_iter().for_each(|a| { - authorities.insert(a, peer); - }); - } - }, - NetworkBridgeEvent::PeerDisconnected(peer) => { - gum::trace!(target: LOG_TARGET, ?peer, "Peer disconnected"); - if let Some(auth_ids) = peers.remove(&peer).and_then(|p| p.maybe_authority) { - auth_ids.into_iter().for_each(|a| { - authorities.remove(&a); - }); - } - }, - NetworkBridgeEvent::NewGossipTopology(topology) => { - let _ = metrics.time_network_bridge_update_v1("new_gossip_topology"); - - let new_session_index = topology.session; - let new_topology = topology.topology; - let old_topology = - topology_storage.get_current_topology().local_grid_neighbors().clone(); - topology_storage.update_topology(new_session_index, new_topology, topology.local_index); - - let newly_added = topology_storage - .get_current_topology() - .local_grid_neighbors() - .peers_diff(&old_topology); - - for peer in newly_added { - if let Some(data) = peers.get_mut(&peer) { - let view = std::mem::take(&mut data.view); - update_peer_view_and_maybe_send_unlocked( - peer, - topology_storage.get_current_topology().local_grid_neighbors(), - data, - ctx, - &*active_heads, - view, - metrics, - rng, - ) - .await - } - } - }, - NetworkBridgeEvent::PeerMessage(peer, Versioned::V1(message)) => { - handle_incoming_message_and_circulate( - peer, - topology_storage, - peers, - active_heads, - recent_outdated_heads, - ctx, - message, - req_sender, - metrics, - runtime, - rng, - reputation, - ) - .await; - }, - NetworkBridgeEvent::PeerViewChange(peer, view) => { - let _ = metrics.time_network_bridge_update_v1("peer_view_change"); - gum::trace!(target: LOG_TARGET, ?peer, ?view, "Peer view change"); - match peers.get_mut(&peer) { - Some(data) => - update_peer_view_and_maybe_send_unlocked( - peer, - topology_storage.get_current_topology().local_grid_neighbors(), - data, - ctx, - &*active_heads, - view, - metrics, - rng, - ) - .await, - None => (), - } - }, - NetworkBridgeEvent::OurViewChange(_view) => { - // handled by `ActiveLeavesUpdate` - }, - NetworkBridgeEvent::UpdatedAuthorityIds(peer, authority_ids) => { - gum::trace!( - target: LOG_TARGET, - ?peer, - ?authority_ids, - "Updated `AuthorityDiscoveryId`s" - ); - - // get the outdated authority_ids stored for the specific peer_id. - let old_auth_ids: Vec = authorities - .into_iter() - .filter(|(_, p)| **p == peer) - .map(|(auth, _)| auth.clone()) - .collect(); - - // remove all of the outdated authority_ids. - for auth in old_auth_ids { - authorities.remove(&auth); - } - - // update `authorities` with the new updated data. - authority_ids.clone().into_iter().for_each(|a| { - authorities.insert(a, peer); - }); - if let Some(data) = peers.get_mut(&peer) { - data.maybe_authority = Some(authority_ids); - } - }, - } -} - #[overseer::contextbounds(StatementDistribution, prefix = self::overseer)] impl StatementDistributionSubsystem { /// Create a new Statement Distribution Subsystem pub fn new( keystore: KeystorePtr, - req_receiver: IncomingRequestReceiver, + v1_req_receiver: IncomingRequestReceiver, + req_receiver: IncomingRequestReceiver, metrics: Metrics, rng: R, ) -> Self { Self { keystore, + v1_req_receiver: Some(v1_req_receiver), req_receiver: Some(req_receiver), metrics, rng, @@ -1816,22 +181,32 @@ impl StatementDistributionSubsystem { let new_reputation_delay = || futures_timer::Delay::new(reputation_interval).fuse(); let mut reputation_delay = new_reputation_delay(); - let mut peers: HashMap = HashMap::new(); - let mut topology_storage: SessionBoundGridTopologyStorage = Default::default(); - let mut authorities: HashMap = HashMap::new(); - let mut active_heads: HashMap = HashMap::new(); - let mut recent_outdated_heads = RecentOutdatedHeads::default(); - - let mut runtime = RuntimeInfo::new(Some(self.keystore.clone())); + let mut legacy_v1_state = crate::legacy_v1::State::new(self.keystore.clone()); + let mut state = crate::vstaging::State::new(self.keystore.clone()); // Sender/Receiver for getting news from our statement fetching tasks. - let (req_sender, mut req_receiver) = mpsc::channel(1); + let (v1_req_sender, mut v1_req_receiver) = mpsc::channel(1); // Sender/Receiver for getting news from our responder task. - let (res_sender, mut res_receiver) = mpsc::channel(1); + let (v1_res_sender, mut v1_res_receiver) = mpsc::channel(1); + + let mut warn_freq = gum::Freq::new(); ctx.spawn( "large-statement-responder", - respond( + v1_respond_task( + self.v1_req_receiver.take().expect("Mandatory argument to new. qed"), + v1_res_sender.clone(), + ) + .boxed(), + ) + .map_err(FatalError::SpawnTask)?; + + // Sender/receiver for getting news from our candidate responder task. + let (res_sender, mut res_receiver) = mpsc::channel(1); + + ctx.spawn( + "candidate-responder", + vstaging::respond_task( self.req_receiver.take().expect("Mandatory argument to new. qed"), res_sender.clone(), ) @@ -1839,222 +214,89 @@ impl StatementDistributionSubsystem { ) .map_err(FatalError::SpawnTask)?; - let mut warn_freq = gum::Freq::new(); - loop { - select! { + // Wait for the next message. + let message = futures::select! { _ = reputation_delay => { self.reputation.send(ctx.sender()).await; reputation_delay = new_reputation_delay(); + continue }, - message = MuxedMessage::receive(&mut ctx, &mut req_receiver, &mut res_receiver).fuse() => { - match message { - MuxedMessage::Subsystem(result) => { - let result = self - .handle_subsystem_message( - &mut ctx, - &mut runtime, - &mut peers, - &mut topology_storage, - &mut authorities, - &mut active_heads, - &mut recent_outdated_heads, - &req_sender, - result?, - ) - .await; - match result.into_nested()? { - Ok(true) => break, - Ok(false) => {}, - Err(jfyi) => gum::debug!(target: LOG_TARGET, error = ?jfyi), - } - }, - MuxedMessage::Requester(result) => { - let result = self - .handle_requester_message( - &mut ctx, - &topology_storage, - &mut peers, - &mut active_heads, - &recent_outdated_heads, - &req_sender, - &mut runtime, - result.ok_or(FatalError::RequesterReceiverFinished)?, - ) - .await; - log_error(result.map_err(From::from), "handle_requester_message", &mut warn_freq)?; - }, - MuxedMessage::Responder(result) => { - let result = self - .handle_responder_message( - &peers, - &mut active_heads, - result.ok_or(FatalError::ResponderReceiverFinished)?, - ) - .await; - log_error(result.map_err(From::from), "handle_responder_message", &mut warn_freq)?; - }, - }; - } - } - } - Ok(()) - } - - /// Handle messages from responder background task. - async fn handle_responder_message( - &self, - peers: &HashMap, - active_heads: &mut HashMap, - message: ResponderMessage, - ) -> JfyiErrorResult<()> { - match message { - ResponderMessage::GetData { requesting_peer, relay_parent, candidate_hash, tx } => { - if !requesting_peer_knows_about_candidate( - peers, - &requesting_peer, - &relay_parent, - &candidate_hash, - )? { - return Err(JfyiError::RequestedUnannouncedCandidate( - requesting_peer, - candidate_hash, - )) + message = MuxedMessage::receive( + &mut ctx, + &mut state, + &mut v1_req_receiver, + &mut v1_res_receiver, + &mut res_receiver, + ).fuse() => { + message } + }; - let active_head = - active_heads.get(&relay_parent).ok_or(JfyiError::NoSuchHead(relay_parent))?; - - let committed = match active_head.waiting_large_statements.get(&candidate_hash) { - Some(LargeStatementStatus::FetchedOrShared(committed)) => committed.clone(), - _ => - return Err(JfyiError::NoSuchFetchedLargeStatement( - relay_parent, - candidate_hash, - )), - }; - - tx.send(committed).map_err(|_| JfyiError::ResponderGetDataCanceled)?; - }, - } - Ok(()) - } - - async fn handle_requester_message( - &mut self, - ctx: &mut Context, - topology_storage: &SessionBoundGridTopologyStorage, - peers: &mut HashMap, - active_heads: &mut HashMap, - recent_outdated_heads: &RecentOutdatedHeads, - req_sender: &mpsc::Sender, - runtime: &mut RuntimeInfo, - message: RequesterMessage, - ) -> JfyiErrorResult<()> { - match message { - RequesterMessage::Finished { - relay_parent, - candidate_hash, - from_peer, - response, - bad_peers, - } => { - for bad in bad_peers { - modify_reputation(&mut self.reputation, ctx.sender(), bad, COST_FETCH_FAIL) - .await; - } - modify_reputation( - &mut self.reputation, - ctx.sender(), - from_peer, - BENEFIT_VALID_RESPONSE, - ) - .await; - - let active_head = active_heads - .get_mut(&relay_parent) - .ok_or(JfyiError::NoSuchHead(relay_parent))?; - - let status = active_head.waiting_large_statements.remove(&candidate_hash); - - let info = match status { - Some(LargeStatementStatus::Fetching(info)) => info, - Some(LargeStatementStatus::FetchedOrShared(_)) => { - // We are no longer interested in the data. - return Ok(()) - }, - None => - return Err(JfyiError::NoSuchLargeStatementStatus( - relay_parent, - candidate_hash, - )), - }; - - active_head - .waiting_large_statements - .insert(candidate_hash, LargeStatementStatus::FetchedOrShared(response)); - - // Cache is now populated, send all messages: - for (peer, messages) in info.available_peers { - for message in messages { - handle_incoming_message_and_circulate( - peer, - topology_storage, - peers, - active_heads, - recent_outdated_heads, - ctx, - message, - req_sender, - &self.metrics, - runtime, - &mut self.rng, - &mut self.reputation, + match message { + MuxedMessage::Subsystem(result) => { + let result = self + .handle_subsystem_message( + &mut ctx, + &mut state, + &mut legacy_v1_state, + &v1_req_sender, + result?, ) .await; + match result.into_nested()? { + Ok(true) => break, + Ok(false) => {}, + Err(jfyi) => gum::debug!(target: LOG_TARGET, error = ?jfyi), } - } - }, - RequesterMessage::SendRequest(req) => { - ctx.send_message(NetworkBridgeTxMessage::SendRequests( - vec![req], - IfDisconnected::ImmediateError, - )) - .await; - }, - RequesterMessage::GetMorePeers { relay_parent, candidate_hash, tx } => { - let active_head = active_heads - .get_mut(&relay_parent) - .ok_or(JfyiError::NoSuchHead(relay_parent))?; - - let status = active_head.waiting_large_statements.get_mut(&candidate_hash); - - let info = match status { - Some(LargeStatementStatus::Fetching(info)) => info, - Some(LargeStatementStatus::FetchedOrShared(_)) => { - // This task is going to die soon - no need to send it anything. - gum::debug!(target: LOG_TARGET, "Zombie task wanted more peers."); - return Ok(()) - }, - None => - return Err(JfyiError::NoSuchLargeStatementStatus( - relay_parent, - candidate_hash, - )), - }; + }, + MuxedMessage::V1Requester(result) => { + let result = crate::legacy_v1::handle_requester_message( + &mut ctx, + &mut legacy_v1_state, + &v1_req_sender, + &mut self.rng, + result.ok_or(FatalError::RequesterReceiverFinished)?, + &self.metrics, + &mut self.reputation, + ) + .await; + log_error( + result.map_err(From::from), + "handle_requester_message", + &mut warn_freq, + )?; + }, + MuxedMessage::V1Responder(result) => { + let result = crate::legacy_v1::handle_responder_message( + &mut legacy_v1_state, + result.ok_or(FatalError::ResponderReceiverFinished)?, + ) + .await; + log_error( + result.map_err(From::from), + "handle_responder_message", + &mut warn_freq, + )?; + }, + MuxedMessage::Responder(result) => { + vstaging::answer_request( + &mut state, + result.ok_or(FatalError::RequesterReceiverFinished)?, + ); + }, + MuxedMessage::Response(result) => { + vstaging::handle_response(&mut ctx, &mut state, result, &mut self.reputation) + .await; + }, + MuxedMessage::RetryRequest(()) => { + // A pending request is ready to retry. This is only a signal to call + // `dispatch_requests` again. + () + }, + }; - if info.peers_to_try.is_empty() { - info.peer_sender = Some(tx); - } else { - let peers_to_try = std::mem::take(&mut info.peers_to_try); - if let Err(peers) = tx.send(peers_to_try) { - // No longer interested for now - might want them later: - info.peers_to_try = peers; - } - } - }, - RequesterMessage::ReportPeer(peer, rep) => - modify_reputation(&mut self.reputation, ctx.sender(), peer, rep).await, + vstaging::dispatch_requests(&mut ctx, &mut state).await; } Ok(()) } @@ -2062,13 +304,9 @@ impl StatementDistributionSubsystem { async fn handle_subsystem_message( &mut self, ctx: &mut Context, - runtime: &mut RuntimeInfo, - peers: &mut HashMap, - topology_storage: &mut SessionBoundGridTopologyStorage, - authorities: &mut HashMap, - active_heads: &mut HashMap, - recent_outdated_heads: &mut RecentOutdatedHeads, - req_sender: &mpsc::Sender, + state: &mut vstaging::State, + legacy_v1_state: &mut legacy_v1::State, + v1_req_sender: &mpsc::Sender, message: FromOrchestra, ) -> Result { let metrics = &self.metrics; @@ -2080,40 +318,28 @@ impl StatementDistributionSubsystem { })) => { let _timer = metrics.time_active_leaves_update(); - for deactivated in deactivated { - if active_heads.remove(&deactivated).is_some() { - gum::trace!( - target: LOG_TARGET, - hash = ?deactivated, - "Deactivating leaf", - ); - - recent_outdated_heads.note_outdated(deactivated); - } - } - - if let Some(activated) = activated { - let relay_parent = activated.hash; - let span = PerLeafSpan::new(activated.span, "statement-distribution"); - gum::trace!( - target: LOG_TARGET, - hash = ?relay_parent, - "New active leaf", - ); + // vstaging should handle activated first because of implicit view. + if let Some(ref activated) = activated { + let mode = prospective_parachains_mode(ctx.sender(), activated.hash).await?; + if let ProspectiveParachainsMode::Enabled { .. } = mode { + vstaging::handle_active_leaves_update(ctx, state, activated, mode).await?; + } else if let ProspectiveParachainsMode::Disabled = mode { + for deactivated in &deactivated { + crate::legacy_v1::handle_deactivate_leaf(legacy_v1_state, *deactivated); + } - // Retrieve the parachain validators at the child of the head we track. - let session_index = - runtime.get_session_index_for_child(ctx.sender(), relay_parent).await?; - let info = runtime - .get_session_info_by_index(ctx.sender(), relay_parent, session_index) + crate::legacy_v1::handle_activated_leaf( + ctx, + legacy_v1_state, + activated.clone(), + ) .await?; - let session_info = &info.session_info; - - active_heads.entry(relay_parent).or_insert(ActiveHeadData::new( - session_info.validators.clone(), - session_index, - span, - )); + } + } else { + for deactivated in &deactivated { + crate::legacy_v1::handle_deactivate_leaf(legacy_v1_state, *deactivated); + } + vstaging::handle_deactivate_leaves(state, &deactivated); } }, FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => { @@ -2124,99 +350,89 @@ impl StatementDistributionSubsystem { StatementDistributionMessage::Share(relay_parent, statement) => { let _timer = metrics.time_share(); - // Make sure we have data in cache: - if is_statement_large(&statement).0 { - if let Statement::Seconded(committed) = &statement.payload() { - let active_head = active_heads - .get_mut(&relay_parent) - // This should never be out-of-sync with our view if the view - // updates correspond to actual `StartWork` messages. - .ok_or(JfyiError::NoSuchHead(relay_parent))?; - active_head.waiting_large_statements.insert( - statement.payload().candidate_hash(), - LargeStatementStatus::FetchedOrShared(committed.clone()), - ); - } + // pass to legacy if legacy state contains head. + if legacy_v1_state.contains_relay_parent(&relay_parent) { + crate::legacy_v1::share_local_statement( + ctx, + legacy_v1_state, + relay_parent, + StatementWithPVD::drop_pvd_from_signed(statement), + &mut self.rng, + metrics, + ) + .await?; + } else { + vstaging::share_local_statement( + ctx, + state, + relay_parent, + statement, + &mut self.reputation, + ) + .await?; + } + }, + StatementDistributionMessage::NetworkBridgeUpdate(event) => { + // pass all events to both protocols except for messages, + // which are filtered. + enum VersionTarget { + Legacy, + Current, + Both, } - let info = runtime.get_session_info(ctx.sender(), relay_parent).await?; - let session_info = &info.session_info; - let validator_info = &info.validator_info; - - // Get peers in our group, so we can make sure they get our statement - // directly: - let group_peers = { - if let Some(our_group) = validator_info.our_group { - let our_group = &session_info - .validator_groups - .get(our_group) - .expect("`our_group` is derived from `validator_groups`; qed"); + impl VersionTarget { + fn targets_legacy(&self) -> bool { + match self { + &VersionTarget::Legacy | &VersionTarget::Both => true, + _ => false, + } + } - our_group - .into_iter() - .filter_map(|i| { - if Some(*i) == validator_info.our_index { - return None - } - let authority_id = &session_info.discovery_keys[i.0 as usize]; - authorities.get(authority_id).map(|p| *p) - }) - .collect() - } else { - Vec::new() + fn targets_current(&self) -> bool { + match self { + &VersionTarget::Current | &VersionTarget::Both => true, + _ => false, + } } + } + + let target = match &event { + NetworkBridgeEvent::PeerMessage(_, message) => match message { + Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), + ) => VersionTarget::Legacy, + Versioned::V1(_) => VersionTarget::Legacy, + Versioned::VStaging(_) => VersionTarget::Current, + }, + _ => VersionTarget::Both, }; - circulate_statement_and_dependents( - topology_storage, - peers, - active_heads, - ctx, - relay_parent, - statement, - group_peers, - metrics, - &mut self.rng, - ) - .await; + + if target.targets_legacy() { + crate::legacy_v1::handle_network_update( + ctx, + legacy_v1_state, + v1_req_sender, + event.clone(), + &mut self.rng, + metrics, + &mut self.reputation, + ) + .await; + } + + if target.targets_current() { + // pass to vstaging. + vstaging::handle_network_update(ctx, state, event, &mut self.reputation) + .await; + } }, - StatementDistributionMessage::NetworkBridgeUpdate(event) => { - handle_network_update( - peers, - topology_storage, - authorities, - active_heads, - &*recent_outdated_heads, - ctx, - req_sender, - event, - metrics, - runtime, - &mut self.rng, - &mut self.reputation, - ) - .await; + StatementDistributionMessage::Backed(candidate_hash) => { + crate::vstaging::handle_backed_candidate_message(ctx, state, candidate_hash) + .await; }, }, } Ok(false) } } - -/// Check whether a peer knows about a candidate from us. -/// -/// If not, it is deemed illegal for it to request corresponding data from us. -fn requesting_peer_knows_about_candidate( - peers: &HashMap, - requesting_peer: &PeerId, - relay_parent: &Hash, - candidate_hash: &CandidateHash, -) -> JfyiErrorResult { - let peer_data = peers - .get(requesting_peer) - .ok_or_else(|| JfyiError::NoSuchPeer(*requesting_peer))?; - let knowledge = peer_data - .view_knowledge - .get(relay_parent) - .ok_or_else(|| JfyiError::NoSuchHead(*relay_parent))?; - Ok(knowledge.sent_candidates.get(&candidate_hash).is_some()) -} diff --git a/node/network/statement-distribution/src/metrics.rs b/node/network/statement-distribution/src/metrics.rs index 22a43ea7c50a..b9a51dc89d61 100644 --- a/node/network/statement-distribution/src/metrics.rs +++ b/node/network/statement-distribution/src/metrics.rs @@ -29,7 +29,7 @@ struct MetricsInner { received_responses: prometheus::CounterVec, active_leaves_update: prometheus::Histogram, share: prometheus::Histogram, - network_bridge_update_v1: prometheus::HistogramVec, + network_bridge_update: prometheus::HistogramVec, statements_unexpected: prometheus::CounterVec, created_message_size: prometheus::Gauge, } @@ -77,16 +77,13 @@ impl Metrics { self.0.as_ref().map(|metrics| metrics.share.start_timer()) } - /// Provide a timer for `network_bridge_update_v1` which observes on drop. - pub fn time_network_bridge_update_v1( + /// Provide a timer for `network_bridge_update` which observes on drop. + pub fn time_network_bridge_update( &self, message_type: &'static str, ) -> Option { self.0.as_ref().map(|metrics| { - metrics - .network_bridge_update_v1 - .with_label_values(&[message_type]) - .start_timer() + metrics.network_bridge_update.with_label_values(&[message_type]).start_timer() }) } @@ -168,11 +165,11 @@ impl metrics::Metrics for Metrics { )?, registry, )?, - network_bridge_update_v1: prometheus::register( + network_bridge_update: prometheus::register( prometheus::HistogramVec::new( prometheus::HistogramOpts::new( - "polkadot_parachain_statement_distribution_network_bridge_update_v1", - "Time spent within `statement_distribution::network_bridge_update_v1`", + "polkadot_parachain_statement_distribution_network_bridge_update", + "Time spent within `statement_distribution::network_bridge_update`", ) .buckets(HISTOGRAM_LATENCY_BUCKETS.into()), &["message_type"], diff --git a/node/network/statement-distribution/src/vstaging/candidates.rs b/node/network/statement-distribution/src/vstaging/candidates.rs new file mode 100644 index 000000000000..42d243614506 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/candidates.rs @@ -0,0 +1,1298 @@ +// Copyright 2022 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 . + +//! The [`Candidates`] store tracks information about advertised candidates +//! as well as which peers have advertised them. +//! +//! Due to the request-oriented nature of this protocol, we often learn +//! about candidates just as a hash, alongside claimed properties that the +//! receipt would commit to. However, it is only later on that we can +//! confirm those claimed properties. This store lets us keep track of +//! all candidates which are currently 'relevant' after spam-protection, and +//! gives us the ability to detect mis-advertisements after the fact +//! and punish them accordingly. + +use polkadot_node_network_protocol::PeerId; +use polkadot_node_subsystem::messages::HypotheticalCandidate; +use polkadot_primitives::vstaging::{ + CandidateHash, CommittedCandidateReceipt, GroupIndex, Hash, Id as ParaId, + PersistedValidationData, +}; + +use std::{ + collections::{ + hash_map::{Entry, HashMap}, + HashSet, + }, + sync::Arc, +}; + +/// This encapsulates the correct and incorrect advertisers +/// post-confirmation of a candidate. +#[derive(Debug, Default, PartialEq)] +pub struct PostConfirmationReckoning { + /// Peers which advertised correctly. + pub correct: HashSet, + /// Peers which advertised the candidate incorrectly. + pub incorrect: HashSet, +} + +/// Outputs generated by initial confirmation of a candidate. +#[derive(Debug, PartialEq)] +pub struct PostConfirmation { + /// The hypothetical candidate used to determine importability and membership + /// in the hypothetical frontier. + pub hypothetical: HypotheticalCandidate, + /// A "reckoning" of peers who have advertised the candidate previously, + /// either accurately or inaccurately. + pub reckoning: PostConfirmationReckoning, +} + +/// A tracker for all known candidates in the view. +/// +/// See module docs for more info. +#[derive(Default)] +pub struct Candidates { + candidates: HashMap, + by_parent: HashMap<(Hash, ParaId), HashSet>, +} + +impl Candidates { + /// Insert an advertisement. + /// + /// This should be invoked only after performing + /// spam protection and only for advertisements that + /// are valid within the current view. [`Candidates`] never prunes + /// candidate by peer ID, to avoid peers skirting misbehavior + /// reports by disconnecting intermittently. Therefore, this presumes + /// that spam protection limits the peers which can send advertisements + /// about unconfirmed candidates. + /// + /// It returns either `Ok(())` or an immediate error in the + /// case that the candidate is already known and reality conflicts + /// with the advertisement. + pub fn insert_unconfirmed( + &mut self, + peer: PeerId, + candidate_hash: CandidateHash, + claimed_relay_parent: Hash, + claimed_group_index: GroupIndex, + claimed_parent_hash_and_id: Option<(Hash, ParaId)>, + ) -> Result<(), BadAdvertisement> { + let entry = self.candidates.entry(candidate_hash).or_insert_with(|| { + CandidateState::Unconfirmed(UnconfirmedCandidate { + claims: Vec::new(), + parent_claims: HashMap::new(), + unconfirmed_importable_under: HashSet::new(), + }) + }); + + match entry { + CandidateState::Confirmed(ref c) => { + if c.relay_parent() != claimed_relay_parent { + return Err(BadAdvertisement) + } + + if c.group_index() != claimed_group_index { + return Err(BadAdvertisement) + } + + if let Some((claimed_parent_hash, claimed_id)) = claimed_parent_hash_and_id { + if c.parent_head_data_hash() != claimed_parent_hash { + return Err(BadAdvertisement) + } + + if c.para_id() != claimed_id { + return Err(BadAdvertisement) + } + } + }, + CandidateState::Unconfirmed(ref mut c) => { + c.add_claims( + peer, + CandidateClaims { + relay_parent: claimed_relay_parent, + group_index: claimed_group_index, + parent_hash_and_id: claimed_parent_hash_and_id, + }, + ); + + if let Some(parent_claims) = claimed_parent_hash_and_id { + self.by_parent.entry(parent_claims).or_default().insert(candidate_hash); + } + }, + } + + Ok(()) + } + + /// Note that a candidate has been confirmed. If the candidate has just been + /// confirmed (previous state was `Unconfirmed`), then this returns `Some`. Otherwise, `None`. + /// + /// If we are confirming for the first time, then remove any outdated claims, and generate a + /// reckoning of which peers advertised correctly and incorrectly. + /// + /// This does no sanity-checking of input data, and will overwrite already-confirmed candidates. + pub fn confirm_candidate( + &mut self, + candidate_hash: CandidateHash, + candidate_receipt: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + assigned_group: GroupIndex, + ) -> Option { + let parent_hash = persisted_validation_data.parent_head.hash(); + let relay_parent = candidate_receipt.descriptor().relay_parent; + let para_id = candidate_receipt.descriptor().para_id; + + let prev_state = self.candidates.insert( + candidate_hash, + CandidateState::Confirmed(ConfirmedCandidate { + receipt: Arc::new(candidate_receipt), + persisted_validation_data, + assigned_group, + parent_hash, + importable_under: HashSet::new(), + }), + ); + let new_confirmed = + match self.candidates.get_mut(&candidate_hash).expect("just inserted; qed") { + CandidateState::Confirmed(x) => x, + _ => panic!("just inserted as confirmed; qed"), + }; + + self.by_parent.entry((parent_hash, para_id)).or_default().insert(candidate_hash); + + match prev_state { + None => Some(PostConfirmation { + reckoning: Default::default(), + hypothetical: new_confirmed.to_hypothetical(candidate_hash), + }), + Some(CandidateState::Confirmed(_)) => None, + Some(CandidateState::Unconfirmed(u)) => Some({ + let mut reckoning = PostConfirmationReckoning::default(); + + for (leaf_hash, x) in u.unconfirmed_importable_under { + if x.relay_parent == relay_parent && + x.parent_hash == parent_hash && + x.para_id == para_id + { + new_confirmed.importable_under.insert(leaf_hash); + } + } + + for (peer, claims) in u.claims { + // Update the by-parent-hash index not to store any outdated + // claims. + if let Some((claimed_parent_hash, claimed_id)) = claims.parent_hash_and_id { + if claimed_parent_hash != parent_hash || claimed_id != para_id { + if let Entry::Occupied(mut e) = + self.by_parent.entry((claimed_parent_hash, claimed_id)) + { + e.get_mut().remove(&candidate_hash); + if e.get().is_empty() { + e.remove(); + } + } + } + } + + if claims.check(relay_parent, assigned_group, parent_hash, para_id) { + reckoning.correct.insert(peer); + } else { + reckoning.incorrect.insert(peer); + } + } + + PostConfirmation { + reckoning, + hypothetical: new_confirmed.to_hypothetical(candidate_hash), + } + }), + } + } + + /// Whether a candidate is confirmed. + pub fn is_confirmed(&self, candidate_hash: &CandidateHash) -> bool { + match self.candidates.get(candidate_hash) { + Some(CandidateState::Confirmed(_)) => true, + _ => false, + } + } + + /// Get a reference to the candidate, if it's known and confirmed. + pub fn get_confirmed(&self, candidate_hash: &CandidateHash) -> Option<&ConfirmedCandidate> { + match self.candidates.get(candidate_hash) { + Some(CandidateState::Confirmed(ref c)) => Some(c), + _ => None, + } + } + + /// Whether statements from a candidate are importable. + /// + /// This is only true when the candidate is known, confirmed, + /// and is importable in a fragment tree. + pub fn is_importable(&self, candidate_hash: &CandidateHash) -> bool { + self.get_confirmed(candidate_hash).map_or(false, |c| c.is_importable(None)) + } + + /// Note that a candidate is importable in a fragment tree indicated by the given + /// leaf hash. + pub fn note_importable_under(&mut self, candidate: &HypotheticalCandidate, leaf_hash: Hash) { + match candidate { + HypotheticalCandidate::Incomplete { + candidate_hash, + candidate_para, + parent_head_data_hash, + candidate_relay_parent, + } => { + let u = UnconfirmedImportable { + relay_parent: *candidate_relay_parent, + parent_hash: *parent_head_data_hash, + para_id: *candidate_para, + }; + + if let Some(&mut CandidateState::Unconfirmed(ref mut c)) = + self.candidates.get_mut(&candidate_hash) + { + c.note_maybe_importable_under(leaf_hash, u); + } + }, + HypotheticalCandidate::Complete { candidate_hash, .. } => { + if let Some(&mut CandidateState::Confirmed(ref mut c)) = + self.candidates.get_mut(&candidate_hash) + { + c.importable_under.insert(leaf_hash); + } + }, + } + } + + /// Get all hypothetical candidates which should be tested + /// for inclusion in the frontier. + /// + /// Provide optional parent parablock information to filter hypotheticals to only + /// potential children of that parent. + pub fn frontier_hypotheticals( + &self, + parent: Option<(Hash, ParaId)>, + ) -> Vec { + fn extend_hypotheticals<'a>( + v: &mut Vec, + i: impl IntoIterator, + maybe_required_parent: Option<(Hash, ParaId)>, + ) { + for (c_hash, candidate) in i { + match candidate { + CandidateState::Unconfirmed(u) => + u.extend_hypotheticals(*c_hash, v, maybe_required_parent), + CandidateState::Confirmed(c) => v.push(c.to_hypothetical(*c_hash)), + } + } + } + + let mut v = Vec::new(); + if let Some(parent) = parent { + let maybe_children = self.by_parent.get(&parent); + let i = maybe_children + .into_iter() + .flatten() + .filter_map(|c_hash| self.candidates.get_key_value(c_hash)); + + extend_hypotheticals(&mut v, i, Some(parent)); + } else { + extend_hypotheticals(&mut v, self.candidates.iter(), None); + } + v + } + + /// Prune all candidates according to the relay-parent predicate + /// provided. + pub fn on_deactivate_leaves( + &mut self, + leaves: &[Hash], + relay_parent_live: impl Fn(&Hash) -> bool, + ) { + let by_parent = &mut self.by_parent; + let mut remove_parent_claims = |c_hash, parent_hash, id| { + if let Entry::Occupied(mut e) = by_parent.entry((parent_hash, id)) { + e.get_mut().remove(&c_hash); + if e.get().is_empty() { + e.remove(); + } + } + }; + self.candidates.retain(|c_hash, state| match state { + CandidateState::Confirmed(ref mut c) => + if !relay_parent_live(&c.relay_parent()) { + remove_parent_claims(*c_hash, c.parent_head_data_hash(), c.para_id()); + false + } else { + for leaf_hash in leaves { + c.importable_under.remove(leaf_hash); + } + true + }, + CandidateState::Unconfirmed(ref mut c) => { + c.on_deactivate_leaves( + leaves, + |parent_hash, id| remove_parent_claims(*c_hash, parent_hash, id), + &relay_parent_live, + ); + c.has_claims() + }, + }) + } +} + +/// A bad advertisement was recognized. +#[derive(Debug, PartialEq)] +pub struct BadAdvertisement; + +#[derive(Debug, PartialEq)] +enum CandidateState { + Unconfirmed(UnconfirmedCandidate), + Confirmed(ConfirmedCandidate), +} + +/// Claims made alongside the advertisement of a candidate. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct CandidateClaims { + /// The relay-parent committed to by the candidate. + relay_parent: Hash, + /// The group index assigned to this candidate. + group_index: GroupIndex, + /// The hash of the parent head-data and the ParaId. This is optional, + /// as only some types of advertisements include this data. + parent_hash_and_id: Option<(Hash, ParaId)>, +} + +impl CandidateClaims { + fn check( + &self, + relay_parent: Hash, + group_index: GroupIndex, + parent_hash: Hash, + para_id: ParaId, + ) -> bool { + self.relay_parent == relay_parent && + self.group_index == group_index && + self.parent_hash_and_id.map_or(true, |p| p == (parent_hash, para_id)) + } +} + +// properties of an unconfirmed but hypothetically importable candidate. +#[derive(Debug, Hash, PartialEq, Eq)] +struct UnconfirmedImportable { + relay_parent: Hash, + parent_hash: Hash, + para_id: ParaId, +} + +// An unconfirmed candidate may have have been advertised under +// multiple identifiers. We track here, on the basis of unique identifier, +// the peers which advertised each candidate in a specific way. +#[derive(Debug, PartialEq)] +struct UnconfirmedCandidate { + claims: Vec<(PeerId, CandidateClaims)>, + // ref-counted + parent_claims: HashMap<(Hash, ParaId), Vec<(Hash, usize)>>, + unconfirmed_importable_under: HashSet<(Hash, UnconfirmedImportable)>, +} + +impl UnconfirmedCandidate { + fn add_claims(&mut self, peer: PeerId, claims: CandidateClaims) { + // This does no deduplication, but this is only called after + // spam prevention is already done. In practice we expect that + // each peer will be able to announce the same candidate about 1 time per live relay-parent, + // but in doing so it limits the amount of other candidates it can advertise. on balance, + // memory consumption is bounded in the same way. + if let Some(parent_claims) = claims.parent_hash_and_id { + let sub_claims = self.parent_claims.entry(parent_claims).or_default(); + match sub_claims.iter().position(|x| x.0 == claims.relay_parent) { + Some(p) => sub_claims[p].1 += 1, + None => sub_claims.push((claims.relay_parent, 1)), + } + } + self.claims.push((peer, claims)); + } + + fn note_maybe_importable_under( + &mut self, + active_leaf: Hash, + unconfirmed_importable: UnconfirmedImportable, + ) { + self.unconfirmed_importable_under.insert((active_leaf, unconfirmed_importable)); + } + + fn on_deactivate_leaves( + &mut self, + leaves: &[Hash], + mut remove_parent_index: impl FnMut(Hash, ParaId), + relay_parent_live: impl Fn(&Hash) -> bool, + ) { + self.claims.retain(|c| { + if relay_parent_live(&c.1.relay_parent) { + true + } else { + if let Some(parent_claims) = c.1.parent_hash_and_id { + if let Entry::Occupied(mut e) = self.parent_claims.entry(parent_claims) { + if let Some(p) = e.get().iter().position(|x| x.0 == c.1.relay_parent) { + let sub_claims = e.get_mut(); + sub_claims[p].1 -= 1; + if sub_claims[p].1 == 0 { + sub_claims.remove(p); + } + }; + + if e.get().is_empty() { + remove_parent_index(parent_claims.0, parent_claims.1); + e.remove(); + } + } + } + + false + } + }); + + self.unconfirmed_importable_under + .retain(|(l, props)| leaves.contains(l) && relay_parent_live(&props.relay_parent)); + } + + fn extend_hypotheticals( + &self, + candidate_hash: CandidateHash, + v: &mut Vec, + required_parent: Option<(Hash, ParaId)>, + ) { + fn extend_hypotheticals_inner<'a>( + candidate_hash: CandidateHash, + v: &mut Vec, + i: impl IntoIterator)>, + ) { + for ((parent_head_hash, para_id), possible_relay_parents) in i { + for (relay_parent, _rc) in possible_relay_parents { + v.push(HypotheticalCandidate::Incomplete { + candidate_hash, + candidate_para: *para_id, + parent_head_data_hash: *parent_head_hash, + candidate_relay_parent: *relay_parent, + }); + } + } + } + + match required_parent { + Some(parent) => extend_hypotheticals_inner( + candidate_hash, + v, + self.parent_claims.get_key_value(&parent), + ), + None => extend_hypotheticals_inner(candidate_hash, v, self.parent_claims.iter()), + } + } + + fn has_claims(&self) -> bool { + !self.claims.is_empty() + } +} + +/// A confirmed candidate. +#[derive(Debug, PartialEq)] +pub struct ConfirmedCandidate { + receipt: Arc, + persisted_validation_data: PersistedValidationData, + assigned_group: GroupIndex, + parent_hash: Hash, + // active leaves statements about this candidate are importable under. + importable_under: HashSet, +} + +impl ConfirmedCandidate { + /// Get the relay-parent of the candidate. + pub fn relay_parent(&self) -> Hash { + self.receipt.descriptor().relay_parent + } + + /// Get the para-id of the candidate. + pub fn para_id(&self) -> ParaId { + self.receipt.descriptor().para_id + } + + /// Get the underlying candidate receipt. + pub fn candidate_receipt(&self) -> &Arc { + &self.receipt + } + + /// Get the persisted validation data. + pub fn persisted_validation_data(&self) -> &PersistedValidationData { + &self.persisted_validation_data + } + + /// Whether the candidate is importable. + pub fn is_importable<'a>(&self, under_active_leaf: impl Into>) -> bool { + match under_active_leaf.into() { + Some(h) => self.importable_under.contains(h), + None => !self.importable_under.is_empty(), + } + } + + /// Get the parent head data hash. + pub fn parent_head_data_hash(&self) -> Hash { + self.parent_hash + } + + /// Get the group index of the assigned group. Note that this is in the context + /// of the state of the chain at the candidate's relay parent and its para-id. + pub fn group_index(&self) -> GroupIndex { + self.assigned_group + } + + fn to_hypothetical(&self, candidate_hash: CandidateHash) -> HypotheticalCandidate { + HypotheticalCandidate::Complete { + candidate_hash, + receipt: self.receipt.clone(), + persisted_validation_data: self.persisted_validation_data.clone(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use polkadot_primitives::HeadData; + use polkadot_primitives_test_helpers::make_candidate; + + #[test] + fn inserting_unconfirmed_rejects_on_incompatible_claims() { + let relay_head_data_a = HeadData(vec![1, 2, 3]); + let relay_head_data_b = HeadData(vec![4, 5, 6]); + let relay_hash_a = relay_head_data_a.hash(); + let relay_hash_b = relay_head_data_b.hash(); + + let para_id_a = 1.into(); + let para_id_b = 2.into(); + + let (candidate_a, pvd_a) = make_candidate( + relay_hash_a, + 1, + para_id_a, + relay_head_data_a, + HeadData(vec![1]), + Hash::from_low_u64_be(1000).into(), + ); + + let candidate_hash_a = candidate_a.hash(); + + let peer = PeerId::random(); + + let group_index_a = 100.into(); + let group_index_b = 200.into(); + + let mut candidates = Candidates::default(); + + // Confirm a candidate first. + candidates.confirm_candidate(candidate_hash_a, candidate_a, pvd_a, group_index_a); + + // Relay parent does not match. + assert_eq!( + candidates.insert_unconfirmed( + peer, + candidate_hash_a, + relay_hash_b, + group_index_a, + Some((relay_hash_a, para_id_a)), + ), + Err(BadAdvertisement) + ); + + // Group index does not match. + assert_eq!( + candidates.insert_unconfirmed( + peer, + candidate_hash_a, + relay_hash_a, + group_index_b, + Some((relay_hash_a, para_id_a)), + ), + Err(BadAdvertisement) + ); + + // Parent head data does not match. + assert_eq!( + candidates.insert_unconfirmed( + peer, + candidate_hash_a, + relay_hash_a, + group_index_a, + Some((relay_hash_b, para_id_a)), + ), + Err(BadAdvertisement) + ); + + // Para ID does not match. + assert_eq!( + candidates.insert_unconfirmed( + peer, + candidate_hash_a, + relay_hash_a, + group_index_a, + Some((relay_hash_a, para_id_b)), + ), + Err(BadAdvertisement) + ); + + // Everything matches. + assert_eq!( + candidates.insert_unconfirmed( + peer, + candidate_hash_a, + relay_hash_a, + group_index_a, + Some((relay_hash_a, para_id_a)), + ), + Ok(()) + ); + } + + // Tests that: + // + // - When the advertisement matches, confirming does not change the parent hash index. + // - When it doesn't match, confirming updates the index. Specifically, confirming should prune + // unconfirmed claims. + #[test] + fn confirming_maintains_parent_hash_index() { + let relay_head_data = HeadData(vec![1, 2, 3]); + let relay_hash = relay_head_data.hash(); + + let candidate_head_data_a = HeadData(vec![1]); + let candidate_head_data_b = HeadData(vec![2]); + let candidate_head_data_c = HeadData(vec![3]); + let candidate_head_data_d = HeadData(vec![4]); + let candidate_head_data_hash_a = candidate_head_data_a.hash(); + let candidate_head_data_hash_b = candidate_head_data_b.hash(); + let candidate_head_data_hash_c = candidate_head_data_c.hash(); + + let (candidate_a, pvd_a) = make_candidate( + relay_hash, + 1, + 1.into(), + relay_head_data, + candidate_head_data_a.clone(), + Hash::from_low_u64_be(1000).into(), + ); + let (candidate_b, pvd_b) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_a, + candidate_head_data_b.clone(), + Hash::from_low_u64_be(2000).into(), + ); + let (candidate_c, _) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_b.clone(), + candidate_head_data_c.clone(), + Hash::from_low_u64_be(3000).into(), + ); + let (candidate_d, pvd_d) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_c.clone(), + candidate_head_data_d, + Hash::from_low_u64_be(4000).into(), + ); + + let candidate_hash_a = candidate_a.hash(); + let candidate_hash_b = candidate_b.hash(); + let candidate_hash_c = candidate_c.hash(); + let candidate_hash_d = candidate_d.hash(); + + let peer = PeerId::random(); + let group_index = 100.into(); + + let mut candidates = Candidates::default(); + + // Insert some unconfirmed candidates. + + // Advertise A without parent hash. + candidates + .insert_unconfirmed(peer, candidate_hash_a, relay_hash, group_index, None) + .ok() + .unwrap(); + assert_eq!(candidates.by_parent, HashMap::default()); + + // Advertise A with parent hash and ID. + candidates + .insert_unconfirmed( + peer, + candidate_hash_a, + relay_hash, + group_index, + Some((relay_hash, 1.into())), + ) + .ok() + .unwrap(); + assert_eq!( + candidates.by_parent, + HashMap::from([((relay_hash, 1.into()), HashSet::from([candidate_hash_a]))]) + ); + + // Advertise B with parent A. + candidates + .insert_unconfirmed( + peer, + candidate_hash_b, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ((candidate_head_data_hash_a, 1.into()), HashSet::from([candidate_hash_b])) + ]) + ); + + // Advertise C with parent A. + candidates + .insert_unconfirmed( + peer, + candidate_hash_c, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c]) + ) + ]) + ); + + // Advertise D with parent A. + candidates + .insert_unconfirmed( + peer, + candidate_hash_d, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c, candidate_hash_d]) + ) + ]) + ); + + // Insert confirmed candidates and check parent hash index. + + // Confirmation matches advertisement. Index should be unchanged. + candidates.confirm_candidate(candidate_hash_a, candidate_a, pvd_a, group_index); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c, candidate_hash_d]) + ) + ]) + ); + candidates.confirm_candidate(candidate_hash_b, candidate_b, pvd_b, group_index); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c, candidate_hash_d]) + ) + ]) + ); + + // Confirmation does not match advertisement. Index should be updated. + candidates.confirm_candidate(candidate_hash_d, candidate_d, pvd_d, group_index); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c]) + ), + ((candidate_head_data_hash_c, 1.into()), HashSet::from([candidate_hash_d])) + ]) + ); + + // Make a new candidate for C with a different para ID. + let (new_candidate_c, new_pvd_c) = make_candidate( + relay_hash, + 1, + 2.into(), + candidate_head_data_b, + candidate_head_data_c.clone(), + Hash::from_low_u64_be(3000).into(), + ); + candidates.confirm_candidate(candidate_hash_c, new_candidate_c, new_pvd_c, group_index); + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ((candidate_head_data_hash_a, 1.into()), HashSet::from([candidate_hash_b])), + ((candidate_head_data_hash_b, 2.into()), HashSet::from([candidate_hash_c])), + ((candidate_head_data_hash_c, 1.into()), HashSet::from([candidate_hash_d])) + ]) + ); + } + + #[test] + fn test_returned_post_confirmation() { + let relay_head_data = HeadData(vec![1, 2, 3]); + let relay_hash = relay_head_data.hash(); + + let candidate_head_data_a = HeadData(vec![1]); + let candidate_head_data_b = HeadData(vec![2]); + let candidate_head_data_c = HeadData(vec![3]); + let candidate_head_data_d = HeadData(vec![4]); + let candidate_head_data_hash_a = candidate_head_data_a.hash(); + let candidate_head_data_hash_b = candidate_head_data_b.hash(); + + let (candidate_a, pvd_a) = make_candidate( + relay_hash, + 1, + 1.into(), + relay_head_data, + candidate_head_data_a.clone(), + Hash::from_low_u64_be(1000).into(), + ); + let (candidate_b, pvd_b) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_a.clone(), + candidate_head_data_b.clone(), + Hash::from_low_u64_be(2000).into(), + ); + let (candidate_c, _) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_a.clone(), + candidate_head_data_c.clone(), + Hash::from_low_u64_be(3000).into(), + ); + let (candidate_d, pvd_d) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_b.clone(), + candidate_head_data_d, + Hash::from_low_u64_be(4000).into(), + ); + + let candidate_hash_a = candidate_a.hash(); + let candidate_hash_b = candidate_b.hash(); + let candidate_hash_c = candidate_c.hash(); + let candidate_hash_d = candidate_d.hash(); + + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + let group_index = 100.into(); + + let mut candidates = Candidates::default(); + + // Insert some unconfirmed candidates. + + // Advertise A without parent hash. + candidates + .insert_unconfirmed(peer_a, candidate_hash_a, relay_hash, group_index, None) + .ok() + .unwrap(); + + // Advertise A with parent hash and ID. + candidates + .insert_unconfirmed( + peer_a, + candidate_hash_a, + relay_hash, + group_index, + Some((relay_hash, 1.into())), + ) + .ok() + .unwrap(); + + // (Correctly) advertise B with parent A. Do it from a couple of peers. + candidates + .insert_unconfirmed( + peer_a, + candidate_hash_b, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + candidates + .insert_unconfirmed( + peer_b, + candidate_hash_b, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + + // (Wrongly) advertise C with parent A. Do it from a couple peers. + candidates + .insert_unconfirmed( + peer_b, + candidate_hash_c, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + candidates + .insert_unconfirmed( + peer_c, + candidate_hash_c, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + + // Advertise D. Do it correctly from one peer (parent B) and wrongly from another (parent + // A). + candidates + .insert_unconfirmed( + peer_c, + candidate_hash_d, + relay_hash, + group_index, + Some((candidate_head_data_hash_b, 1.into())), + ) + .ok() + .unwrap(); + candidates + .insert_unconfirmed( + peer_d, + candidate_hash_d, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c, candidate_hash_d]) + ), + ((candidate_head_data_hash_b, 1.into()), HashSet::from([candidate_hash_d])) + ]) + ); + + // Insert confirmed candidates and check parent hash index. + + // Confirmation matches advertisement. + let post_confirmation = candidates.confirm_candidate( + candidate_hash_a, + candidate_a.clone(), + pvd_a.clone(), + group_index, + ); + assert_eq!( + post_confirmation, + Some(PostConfirmation { + hypothetical: HypotheticalCandidate::Complete { + candidate_hash: candidate_hash_a, + receipt: Arc::new(candidate_a), + persisted_validation_data: pvd_a, + }, + reckoning: PostConfirmationReckoning { + correct: HashSet::from([peer_a]), + incorrect: HashSet::from([]), + }, + }) + ); + + let post_confirmation = candidates.confirm_candidate( + candidate_hash_b, + candidate_b.clone(), + pvd_b.clone(), + group_index, + ); + assert_eq!( + post_confirmation, + Some(PostConfirmation { + hypothetical: HypotheticalCandidate::Complete { + candidate_hash: candidate_hash_b, + receipt: Arc::new(candidate_b), + persisted_validation_data: pvd_b, + }, + reckoning: PostConfirmationReckoning { + correct: HashSet::from([peer_a, peer_b]), + incorrect: HashSet::from([]), + }, + }) + ); + + // Confirm candidate with two wrong peers (different group index). + let (new_candidate_c, new_pvd_c) = make_candidate( + relay_hash, + 1, + 2.into(), + candidate_head_data_b, + candidate_head_data_c.clone(), + Hash::from_low_u64_be(3000).into(), + ); + let post_confirmation = candidates.confirm_candidate( + candidate_hash_c, + new_candidate_c.clone(), + new_pvd_c.clone(), + group_index, + ); + assert_eq!( + post_confirmation, + Some(PostConfirmation { + hypothetical: HypotheticalCandidate::Complete { + candidate_hash: candidate_hash_c, + receipt: Arc::new(new_candidate_c), + persisted_validation_data: new_pvd_c, + }, + reckoning: PostConfirmationReckoning { + correct: HashSet::from([]), + incorrect: HashSet::from([peer_b, peer_c]), + }, + }) + ); + + // Confirm candidate with one wrong peer (different parent head data). + let post_confirmation = candidates.confirm_candidate( + candidate_hash_d, + candidate_d.clone(), + pvd_d.clone(), + group_index, + ); + assert_eq!( + post_confirmation, + Some(PostConfirmation { + hypothetical: HypotheticalCandidate::Complete { + candidate_hash: candidate_hash_d, + receipt: Arc::new(candidate_d), + persisted_validation_data: pvd_d, + }, + reckoning: PostConfirmationReckoning { + correct: HashSet::from([peer_c]), + incorrect: HashSet::from([peer_d]), + }, + }) + ); + } + + #[test] + fn test_hypothetical_frontiers() { + let relay_head_data = HeadData(vec![1, 2, 3]); + let relay_hash = relay_head_data.hash(); + + let candidate_head_data_a = HeadData(vec![1]); + let candidate_head_data_b = HeadData(vec![2]); + let candidate_head_data_c = HeadData(vec![3]); + let candidate_head_data_d = HeadData(vec![4]); + let candidate_head_data_hash_a = candidate_head_data_a.hash(); + let candidate_head_data_hash_b = candidate_head_data_b.hash(); + let candidate_head_data_hash_d = candidate_head_data_d.hash(); + + let (candidate_a, pvd_a) = make_candidate( + relay_hash, + 1, + 1.into(), + relay_head_data, + candidate_head_data_a.clone(), + Hash::from_low_u64_be(1000).into(), + ); + let (candidate_b, _) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_a.clone(), + candidate_head_data_b.clone(), + Hash::from_low_u64_be(2000).into(), + ); + let (candidate_c, _) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_a.clone(), + candidate_head_data_c.clone(), + Hash::from_low_u64_be(3000).into(), + ); + let (candidate_d, _) = make_candidate( + relay_hash, + 1, + 1.into(), + candidate_head_data_b.clone(), + candidate_head_data_d, + Hash::from_low_u64_be(4000).into(), + ); + + let candidate_hash_a = candidate_a.hash(); + let candidate_hash_b = candidate_b.hash(); + let candidate_hash_c = candidate_c.hash(); + let candidate_hash_d = candidate_d.hash(); + + let peer = PeerId::random(); + let group_index = 100.into(); + + let mut candidates = Candidates::default(); + + // Confirm A. + candidates.confirm_candidate( + candidate_hash_a, + candidate_a.clone(), + pvd_a.clone(), + group_index, + ); + + // Advertise B with parent A. + candidates + .insert_unconfirmed( + peer, + candidate_hash_b, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + + // Advertise C with parent A. + candidates + .insert_unconfirmed( + peer, + candidate_hash_c, + relay_hash, + group_index, + Some((candidate_head_data_hash_a, 1.into())), + ) + .ok() + .unwrap(); + + // Advertise D with parent B. + candidates + .insert_unconfirmed( + peer, + candidate_hash_d, + relay_hash, + group_index, + Some((candidate_head_data_hash_b, 1.into())), + ) + .ok() + .unwrap(); + + assert_eq!( + candidates.by_parent, + HashMap::from([ + ((relay_hash, 1.into()), HashSet::from([candidate_hash_a])), + ( + (candidate_head_data_hash_a, 1.into()), + HashSet::from([candidate_hash_b, candidate_hash_c]) + ), + ((candidate_head_data_hash_b, 1.into()), HashSet::from([candidate_hash_d])) + ]) + ); + + let hypothetical_a = HypotheticalCandidate::Complete { + candidate_hash: candidate_hash_a, + receipt: Arc::new(candidate_a), + persisted_validation_data: pvd_a, + }; + let hypothetical_b = HypotheticalCandidate::Incomplete { + candidate_hash: candidate_hash_b, + candidate_para: 1.into(), + parent_head_data_hash: candidate_head_data_hash_a, + candidate_relay_parent: relay_hash, + }; + let hypothetical_c = HypotheticalCandidate::Incomplete { + candidate_hash: candidate_hash_c, + candidate_para: 1.into(), + parent_head_data_hash: candidate_head_data_hash_a, + candidate_relay_parent: relay_hash, + }; + let hypothetical_d = HypotheticalCandidate::Incomplete { + candidate_hash: candidate_hash_d, + candidate_para: 1.into(), + parent_head_data_hash: candidate_head_data_hash_b, + candidate_relay_parent: relay_hash, + }; + + let hypotheticals = candidates.frontier_hypotheticals(Some((relay_hash, 1.into()))); + assert_eq!(hypotheticals.len(), 1); + assert!(hypotheticals.contains(&hypothetical_a)); + + let hypotheticals = + candidates.frontier_hypotheticals(Some((candidate_head_data_hash_a, 2.into()))); + assert_eq!(hypotheticals.len(), 0); + + let hypotheticals = + candidates.frontier_hypotheticals(Some((candidate_head_data_hash_a, 1.into()))); + assert_eq!(hypotheticals.len(), 2); + assert!(hypotheticals.contains(&hypothetical_b)); + assert!(hypotheticals.contains(&hypothetical_c)); + + let hypotheticals = + candidates.frontier_hypotheticals(Some((candidate_head_data_hash_d, 1.into()))); + assert_eq!(hypotheticals.len(), 0); + + let hypotheticals = candidates.frontier_hypotheticals(None); + assert_eq!(hypotheticals.len(), 4); + assert!(hypotheticals.contains(&hypothetical_a)); + assert!(hypotheticals.contains(&hypothetical_b)); + assert!(hypotheticals.contains(&hypothetical_c)); + assert!(hypotheticals.contains(&hypothetical_d)); + } +} diff --git a/node/network/statement-distribution/src/vstaging/cluster.rs b/node/network/statement-distribution/src/vstaging/cluster.rs new file mode 100644 index 000000000000..3214507407aa --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/cluster.rs @@ -0,0 +1,1203 @@ +// Copyright 2022 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 . + +//! Direct distribution of statements within a cluster, +//! even those concerning candidates which are not yet backed. +//! +//! Members of a validation group assigned to a para at a given relay-parent +//! always distribute statements directly to each other. +//! +//! The main way we limit the amount of candidates that have to be handled by +//! the system is to limit the amount of `Seconded` messages that we allow +//! each validator to issue at each relay-parent. Since the amount of relay-parents +//! that we have to deal with at any time is itself bounded, this lets us bound +//! the memory and work that we have here. Bounding `Seconded` statements is enough +//! because they imply a bounded amount of `Valid` statements about the same candidate +//! which may follow. +//! +//! The motivation for this piece of code is that the statements that each validator +//! sees may differ. i.e. even though a validator is allowed to issue X `Seconded` +//! statements at a relay-parent, they may in fact issue X*2 and issue one set to +//! one partition of the backing group and one set to another. Of course, in practice +//! these types of partitions will not exist, but in the worst case each validator in the +//! group would see an entirely different set of X `Seconded` statements from some validator +//! and each validator is in its own partition. After that partition resolves, we'd have to +//! deal with up to `limit*group_size` `Seconded` statements from that validator. And then +//! if every validator in the group does the same thing, we're dealing with something like +//! `limit*group_size^2` `Seconded` statements in total. +//! +//! Given that both our group sizes and our limits per relay-parent are small, this is +//! quite manageable, and the utility here lets us deal with it in only a few kilobytes +//! of memory. +//! +//! It's also worth noting that any case where a validator issues more than the legal limit +//! of `Seconded` statements at a relay parent is trivially slashable on-chain, which means +//! the 'worst case' adversary that this code defends against is effectively lighting money +//! on fire. Nevertheless, we handle the case here to ensure that the behavior of the +//! system is well-defined even if an adversary is willing to be slashed. +//! +//! More concretely, this module exposes a [`ClusterTracker`] utility which allows us to determine +//! whether to accept or reject messages from other validators in the same group as we +//! are in, based on _the most charitable possible interpretation of our protocol rules_, +//! and to keep track of what we have sent to other validators in the group and what we may +//! continue to send them. + +use polkadot_primitives::vstaging::{CandidateHash, CompactStatement, ValidatorIndex}; + +use std::collections::{HashMap, HashSet}; + +#[derive(Hash, PartialEq, Eq)] +struct ValidStatementManifest { + remote: ValidatorIndex, + originator: ValidatorIndex, + candidate_hash: CandidateHash, +} + +// A piece of knowledge about a candidate +#[derive(Hash, Clone, PartialEq, Eq)] +enum Knowledge { + // General knowledge. + General(CandidateHash), + // Specific knowledge of a given statement (with its originator) + Specific(CompactStatement, ValidatorIndex), +} + +// Knowledge paired with its source. +#[derive(Hash, Clone, PartialEq, Eq)] +enum TaggedKnowledge { + // Knowledge we have received from the validator on the p2p layer. + IncomingP2P(Knowledge), + // Knowledge we have sent to the validator on the p2p layer. + OutgoingP2P(Knowledge), + // Knowledge of candidates the validator has seconded. + // This is limited only to `Seconded` statements we have accepted + // _without prejudice_. + Seconded(CandidateHash), +} + +/// Utility for keeping track of limits on direct statements within a group. +/// +/// See module docs for more details. +pub struct ClusterTracker { + validators: Vec, + seconding_limit: usize, + knowledge: HashMap>, + // Statements known locally which haven't been sent to particular validators. + // maps target validator to (originator, statement) pairs. + pending: HashMap>, +} + +impl ClusterTracker { + /// Instantiate a new `ClusterTracker` tracker. Fails if `cluster_validators` is empty + pub fn new(cluster_validators: Vec, seconding_limit: usize) -> Option { + if cluster_validators.is_empty() { + return None + } + Some(ClusterTracker { + validators: cluster_validators, + seconding_limit, + knowledge: HashMap::new(), + pending: HashMap::new(), + }) + } + + /// Query whether we can receive some statement from the given validator. + /// + /// This does no deduplication of `Valid` statements. + pub fn can_receive( + &self, + sender: ValidatorIndex, + originator: ValidatorIndex, + statement: CompactStatement, + ) -> Result { + if !self.is_in_group(sender) || !self.is_in_group(originator) { + return Err(RejectIncoming::NotInGroup) + } + + if self.they_sent(sender, Knowledge::Specific(statement.clone(), originator)) { + return Err(RejectIncoming::Duplicate) + } + + match statement { + CompactStatement::Seconded(candidate_hash) => { + // check whether the sender has not sent too many seconded statements for the + // originator. we know by the duplicate check above that this iterator doesn't + // include the statement itself. + let other_seconded_for_orig_from_remote = self + .knowledge + .get(&sender) + .into_iter() + .flat_map(|v_knowledge| v_knowledge.iter()) + .filter(|k| match k { + TaggedKnowledge::IncomingP2P(Knowledge::Specific( + CompactStatement::Seconded(_), + orig, + )) if orig == &originator => true, + _ => false, + }) + .count(); + + if other_seconded_for_orig_from_remote == self.seconding_limit { + return Err(RejectIncoming::ExcessiveSeconded) + } + + // at this point, it doesn't seem like the remote has done anything wrong. + if self.seconded_already_or_within_limit(originator, candidate_hash) { + Ok(Accept::Ok) + } else { + Ok(Accept::WithPrejudice) + } + }, + CompactStatement::Valid(candidate_hash) => { + if !self.knows_candidate(sender, candidate_hash) { + return Err(RejectIncoming::CandidateUnknown) + } + + Ok(Accept::Ok) + }, + } + } + + /// Note that we issued a statement. This updates internal structures. + pub fn note_issued(&mut self, originator: ValidatorIndex, statement: CompactStatement) { + for cluster_member in &self.validators { + if !self.they_know_statement(*cluster_member, originator, statement.clone()) { + // add the statement to pending knowledge for all peers + // which don't know the statement. + self.pending + .entry(*cluster_member) + .or_default() + .insert((originator, statement.clone())); + } + } + } + + /// Note that we accepted an incoming statement. This updates internal structures. + /// + /// Should only be called after a successful `can_receive` call. + pub fn note_received( + &mut self, + sender: ValidatorIndex, + originator: ValidatorIndex, + statement: CompactStatement, + ) { + for cluster_member in &self.validators { + if cluster_member == &sender { + if let Some(pending) = self.pending.get_mut(&sender) { + pending.remove(&(originator, statement.clone())); + } + } else if !self.they_know_statement(*cluster_member, originator, statement.clone()) { + // add the statement to pending knowledge for all peers + // which don't know the statement. + self.pending + .entry(*cluster_member) + .or_default() + .insert((originator, statement.clone())); + } + } + + { + let sender_knowledge = self.knowledge.entry(sender).or_default(); + sender_knowledge.insert(TaggedKnowledge::IncomingP2P(Knowledge::Specific( + statement.clone(), + originator, + ))); + + if let CompactStatement::Seconded(candidate_hash) = statement.clone() { + sender_knowledge + .insert(TaggedKnowledge::IncomingP2P(Knowledge::General(candidate_hash))); + } + } + + if let CompactStatement::Seconded(candidate_hash) = statement { + // since we accept additional `Seconded` statements beyond the limits + // 'with prejudice', we must respect the limit here. + if self.seconded_already_or_within_limit(originator, candidate_hash) { + let originator_knowledge = self.knowledge.entry(originator).or_default(); + originator_knowledge.insert(TaggedKnowledge::Seconded(candidate_hash)); + } + } + } + + /// Query whether we can send a statement to a given validator. + pub fn can_send( + &self, + target: ValidatorIndex, + originator: ValidatorIndex, + statement: CompactStatement, + ) -> Result<(), RejectOutgoing> { + if !self.is_in_group(target) || !self.is_in_group(originator) { + return Err(RejectOutgoing::NotInGroup) + } + + if self.they_know_statement(target, originator, statement.clone()) { + return Err(RejectOutgoing::Known) + } + + match statement { + CompactStatement::Seconded(candidate_hash) => { + // we send the same `Seconded` statements to all our peers, and only the first `k` + // from each originator. + if !self.seconded_already_or_within_limit(originator, candidate_hash) { + return Err(RejectOutgoing::ExcessiveSeconded) + } + + Ok(()) + }, + CompactStatement::Valid(candidate_hash) => { + if !self.knows_candidate(target, candidate_hash) { + return Err(RejectOutgoing::CandidateUnknown) + } + + Ok(()) + }, + } + } + + /// Note that we sent an outgoing statement to a peer in the group. + /// This must be preceded by a successful `can_send` call. + pub fn note_sent( + &mut self, + target: ValidatorIndex, + originator: ValidatorIndex, + statement: CompactStatement, + ) { + { + let target_knowledge = self.knowledge.entry(target).or_default(); + target_knowledge.insert(TaggedKnowledge::OutgoingP2P(Knowledge::Specific( + statement.clone(), + originator, + ))); + + if let CompactStatement::Seconded(candidate_hash) = statement.clone() { + target_knowledge + .insert(TaggedKnowledge::OutgoingP2P(Knowledge::General(candidate_hash))); + } + } + + if let CompactStatement::Seconded(candidate_hash) = statement { + let originator_knowledge = self.knowledge.entry(originator).or_default(); + originator_knowledge.insert(TaggedKnowledge::Seconded(candidate_hash)); + } + + if let Some(pending) = self.pending.get_mut(&target) { + pending.remove(&(originator, statement)); + } + } + + /// Get all targets as validator-indices. This doesn't attempt to filter + /// out the local validator index. + pub fn targets(&self) -> &[ValidatorIndex] { + &self.validators + } + + /// Get all possible senders for the given originator. + /// Returns the empty slice in the case that the originator + /// is not part of the cluster. + // note: this API is future-proofing for a case where we may + // extend clusters beyond just the assigned group, for optimization + // purposes. + pub fn senders_for_originator(&self, originator: ValidatorIndex) -> &[ValidatorIndex] { + if self.validators.contains(&originator) { + &self.validators[..] + } else { + &[] + } + } + + /// Whether a validator knows the candidate is `Seconded`. + pub fn knows_candidate( + &self, + validator: ValidatorIndex, + candidate_hash: CandidateHash, + ) -> bool { + // we sent, they sent, or they signed and we received from someone else. + + self.we_sent_seconded(validator, candidate_hash) || + self.they_sent_seconded(validator, candidate_hash) || + self.validator_seconded(validator, candidate_hash) + } + + /// Returns a Vec of pending statements to be sent to a particular validator + /// index. `Seconded` statements are sorted to the front of the vector. + /// + /// Pending statements have the form (originator, compact statement). + pub fn pending_statements_for( + &self, + target: ValidatorIndex, + ) -> Vec<(ValidatorIndex, CompactStatement)> { + let mut v = self + .pending + .get(&target) + .map(|x| x.iter().cloned().collect::>()) + .unwrap_or_default(); + + v.sort_by_key(|(_, s)| match s { + CompactStatement::Seconded(_) => 0u8, + CompactStatement::Valid(_) => 1u8, + }); + + v + } + + // returns true if it's legal to accept a new `Seconded` message from this validator. + // This is either + // 1. because we've already accepted it. + // 2. because there's space for more seconding. + fn seconded_already_or_within_limit( + &self, + validator: ValidatorIndex, + candidate_hash: CandidateHash, + ) -> bool { + let seconded_other_candidates = self + .knowledge + .get(&validator) + .into_iter() + .flat_map(|v_knowledge| v_knowledge.iter()) + .filter(|k| match k { + TaggedKnowledge::Seconded(c) if c != &candidate_hash => true, + _ => false, + }) + .count(); + + // This fulfills both properties by under-counting when the validator is at the limit + // but _has_ seconded the candidate already. + seconded_other_candidates < self.seconding_limit + } + + fn they_know_statement( + &self, + validator: ValidatorIndex, + originator: ValidatorIndex, + statement: CompactStatement, + ) -> bool { + let knowledge = Knowledge::Specific(statement, originator); + self.we_sent(validator, knowledge.clone()) || self.they_sent(validator, knowledge) + } + + fn they_sent(&self, validator: ValidatorIndex, knowledge: Knowledge) -> bool { + self.knowledge + .get(&validator) + .map_or(false, |k| k.contains(&TaggedKnowledge::IncomingP2P(knowledge))) + } + + fn we_sent(&self, validator: ValidatorIndex, knowledge: Knowledge) -> bool { + self.knowledge + .get(&validator) + .map_or(false, |k| k.contains(&TaggedKnowledge::OutgoingP2P(knowledge))) + } + + fn we_sent_seconded(&self, validator: ValidatorIndex, candidate_hash: CandidateHash) -> bool { + self.we_sent(validator, Knowledge::General(candidate_hash)) + } + + fn they_sent_seconded(&self, validator: ValidatorIndex, candidate_hash: CandidateHash) -> bool { + self.they_sent(validator, Knowledge::General(candidate_hash)) + } + + fn validator_seconded(&self, validator: ValidatorIndex, candidate_hash: CandidateHash) -> bool { + self.knowledge + .get(&validator) + .map_or(false, |k| k.contains(&TaggedKnowledge::Seconded(candidate_hash))) + } + + fn is_in_group(&self, validator: ValidatorIndex) -> bool { + self.validators.contains(&validator) + } +} + +/// Incoming statement was accepted. +#[derive(Debug, PartialEq)] +pub enum Accept { + /// Neither the peer nor the originator have apparently exceeded limits. + /// Candidate or statement may already be known. + Ok, + /// Accept the message; the peer hasn't exceeded limits but the originator has. + WithPrejudice, +} + +/// Incoming statement was rejected. +#[derive(Debug, PartialEq)] +pub enum RejectIncoming { + /// Peer sent excessive `Seconded` statements. + ExcessiveSeconded, + /// Sender or originator is not in the group. + NotInGroup, + /// Candidate is unknown to us. Only applies to `Valid` statements. + CandidateUnknown, + /// Statement is duplicate. + Duplicate, +} + +/// Outgoing statement was rejected. +#[derive(Debug, PartialEq)] +pub enum RejectOutgoing { + /// Candidate was unknown. Only applies to `Valid` statements. + CandidateUnknown, + /// We attempted to send excessive `Seconded` statements. + /// indicates a bug on the local node's code. + ExcessiveSeconded, + /// The statement was already known to the peer. + Known, + /// Target or originator not in the group. + NotInGroup, +} + +#[cfg(test)] +mod tests { + use super::*; + use polkadot_primitives::vstaging::Hash; + + #[test] + fn rejects_incoming_outside_of_group() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(100), + ValidatorIndex(5), + CompactStatement::Seconded(CandidateHash(Hash::repeat_byte(1))), + ), + Err(RejectIncoming::NotInGroup), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(100), + CompactStatement::Seconded(CandidateHash(Hash::repeat_byte(1))), + ), + Err(RejectIncoming::NotInGroup), + ); + } + + #[test] + fn begrudgingly_accepts_too_many_seconded_from_multiple_peers() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + let hash_c = CandidateHash(Hash::repeat_byte(3)); + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_c), + ), + Err(RejectIncoming::ExcessiveSeconded), + ); + } + + #[test] + fn rejects_too_many_seconded_from_sender() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + let hash_c = CandidateHash(Hash::repeat_byte(3)); + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_c), + ), + Ok(Accept::WithPrejudice), + ); + } + + #[test] + fn rejects_duplicates() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + let hash_a = CandidateHash(Hash::repeat_byte(1)); + + let mut tracker = ClusterTracker::new(group, seconding_limit).expect("not empty"); + + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Valid(hash_a), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Err(RejectIncoming::Duplicate), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Valid(hash_a), + ), + Err(RejectIncoming::Duplicate), + ); + } + + #[test] + fn rejects_incoming_valid_without_seconded() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let tracker = ClusterTracker::new(group, seconding_limit).expect("not empty"); + + let hash_a = CandidateHash(Hash::repeat_byte(1)); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Valid(hash_a), + ), + Err(RejectIncoming::CandidateUnknown), + ); + } + + #[test] + fn accepts_incoming_valid_after_receiving_seconded() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Valid(hash_a), + ), + Ok(Accept::Ok) + ); + } + + #[test] + fn accepts_incoming_valid_after_outgoing_seconded() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + + tracker.note_sent( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Valid(hash_a), + ), + Ok(Accept::Ok) + ); + } + + #[test] + fn cannot_send_too_many_seconded_even_to_multiple_peers() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + let hash_c = CandidateHash(Hash::repeat_byte(3)); + + tracker.note_sent( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + tracker.note_sent( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ); + + assert_eq!( + tracker.can_send( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_c), + ), + Err(RejectOutgoing::ExcessiveSeconded), + ); + + assert_eq!( + tracker.can_send( + ValidatorIndex(24), + ValidatorIndex(5), + CompactStatement::Seconded(hash_c), + ), + Err(RejectOutgoing::ExcessiveSeconded), + ); + } + + #[test] + fn cannot_send_duplicate() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + + tracker.note_sent( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_send( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Err(RejectOutgoing::Known), + ); + } + + #[test] + fn cannot_send_what_was_received() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 2; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + + tracker.note_received( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_send( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Err(RejectOutgoing::Known), + ); + } + + // Ensure statements received with prejudice don't prevent sending later. + #[test] + fn can_send_statements_received_with_prejudice() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 1; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Ok(Accept::Ok), + ); + + tracker.note_received( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.can_receive( + ValidatorIndex(24), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ), + Ok(Accept::WithPrejudice), + ); + + tracker.note_received( + ValidatorIndex(24), + ValidatorIndex(5), + CompactStatement::Seconded(hash_b), + ); + + assert_eq!( + tracker.can_send( + ValidatorIndex(24), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Ok(()), + ); + } + + // Test that the `pending_statements` are set whenever we receive a fresh statement. + // + // Also test that pending statements are sorted, with `Seconded` statements in the front. + #[test] + fn pending_statements_set_when_receiving_fresh_statements() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 1; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + + // Receive a 'Seconded' statement for candidate A. + { + assert_eq!( + tracker.can_receive( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(5)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!(tracker.pending_statements_for(ValidatorIndex(200)), vec![]); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(24)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(146)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + } + + // Receive a 'Valid' statement for candidate A. + { + // First, send a `Seconded` statement for the candidate. + assert_eq!( + tracker.can_send( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Seconded(hash_a) + ), + Ok(()) + ); + tracker.note_sent( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Seconded(hash_a), + ); + + // We have to see that the candidate is known by the sender, e.g. we sent them + // 'Seconded' above. + assert_eq!( + tracker.can_receive( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Valid(hash_a), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Valid(hash_a), + ); + + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(5)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_a)) + ] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(200)), + vec![(ValidatorIndex(200), CompactStatement::Valid(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(24)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(146)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_a)) + ] + ); + } + + // Receive a 'Seconded' statement for candidate B. + { + assert_eq!( + tracker.can_receive( + ValidatorIndex(5), + ValidatorIndex(146), + CompactStatement::Seconded(hash_b), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(5), + ValidatorIndex(146), + CompactStatement::Seconded(hash_b), + ); + + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(5)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_a)) + ] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(200)), + vec![ + (ValidatorIndex(146), CompactStatement::Seconded(hash_b)), + (ValidatorIndex(200), CompactStatement::Valid(hash_a)), + ] + ); + { + let mut pending_statements = tracker.pending_statements_for(ValidatorIndex(24)); + pending_statements.sort(); + assert_eq!( + pending_statements, + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(146), CompactStatement::Seconded(hash_b)) + ], + ); + } + { + let mut pending_statements = tracker.pending_statements_for(ValidatorIndex(146)); + pending_statements.sort(); + assert_eq!( + pending_statements, + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(146), CompactStatement::Seconded(hash_b)), + (ValidatorIndex(200), CompactStatement::Valid(hash_a)), + ] + ); + } + } + } + + // Test that the `pending_statements` are updated when we send or receive statements from others + // in the cluster. + #[test] + fn pending_statements_updated_when_sending_statements() { + let group = + vec![ValidatorIndex(5), ValidatorIndex(200), ValidatorIndex(24), ValidatorIndex(146)]; + + let seconding_limit = 1; + + let mut tracker = ClusterTracker::new(group.clone(), seconding_limit).expect("not empty"); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + + // Receive a 'Seconded' statement for candidate A. + { + assert_eq!( + tracker.can_receive( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(200), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + // Pending statements should be updated. + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(5)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!(tracker.pending_statements_for(ValidatorIndex(200)), vec![]); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(24)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(146)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + } + + // Receive a 'Valid' statement for candidate B. + { + // First, send a `Seconded` statement for the candidate. + assert_eq!( + tracker.can_send( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Seconded(hash_b) + ), + Ok(()) + ); + tracker.note_sent( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Seconded(hash_b), + ); + + // We have to see the candidate is known by the sender, e.g. we sent them 'Seconded'. + assert_eq!( + tracker.can_receive( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Valid(hash_b), + ), + Ok(Accept::Ok), + ); + tracker.note_received( + ValidatorIndex(24), + ValidatorIndex(200), + CompactStatement::Valid(hash_b), + ); + + // Pending statements should be updated. + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(5)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_b)) + ] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(200)), + vec![(ValidatorIndex(200), CompactStatement::Valid(hash_b))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(24)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(146)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_b)) + ] + ); + } + + // Send a 'Seconded' statement. + { + assert_eq!( + tracker.can_send( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a) + ), + Ok(()) + ); + tracker.note_sent( + ValidatorIndex(5), + ValidatorIndex(5), + CompactStatement::Seconded(hash_a), + ); + + // Pending statements should be updated. + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(5)), + vec![(ValidatorIndex(200), CompactStatement::Valid(hash_b))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(200)), + vec![(ValidatorIndex(200), CompactStatement::Valid(hash_b))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(24)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(146)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_b)) + ] + ); + } + + // Send a 'Valid' statement. + { + // First, send a `Seconded` statement for the candidate. + assert_eq!( + tracker.can_send( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Seconded(hash_b) + ), + Ok(()) + ); + tracker.note_sent( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Seconded(hash_b), + ); + + // We have to see that the candidate is known by the sender, e.g. we sent them + // 'Seconded' above. + assert_eq!( + tracker.can_send( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Valid(hash_b) + ), + Ok(()) + ); + tracker.note_sent( + ValidatorIndex(5), + ValidatorIndex(200), + CompactStatement::Valid(hash_b), + ); + + // Pending statements should be updated. + assert_eq!(tracker.pending_statements_for(ValidatorIndex(5)), vec![]); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(200)), + vec![(ValidatorIndex(200), CompactStatement::Valid(hash_b))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(24)), + vec![(ValidatorIndex(5), CompactStatement::Seconded(hash_a))] + ); + assert_eq!( + tracker.pending_statements_for(ValidatorIndex(146)), + vec![ + (ValidatorIndex(5), CompactStatement::Seconded(hash_a)), + (ValidatorIndex(200), CompactStatement::Valid(hash_b)) + ] + ); + } + } +} diff --git a/node/network/statement-distribution/src/vstaging/grid.rs b/node/network/statement-distribution/src/vstaging/grid.rs new file mode 100644 index 000000000000..c6c73f8bae52 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/grid.rs @@ -0,0 +1,2252 @@ +// Copyright 2022 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 . + +//! Utilities for handling distribution of backed candidates along the grid (outside the group to +//! the rest of the network). +//! +//! The grid uses the gossip topology defined in [`polkadot_node_network_protocol::grid_topology`]. +//! It defines how messages and statements are forwarded between validators. +//! +//! # Protocol +//! +//! - Once the candidate is backed, produce a 'backed candidate packet' `(CommittedCandidateReceipt, +//! Statements)`. +//! - Members of a backing group produce an announcement of a fully-backed candidate (aka "full +//! manifest") when they are finished. +//! - `BackedCandidateManifest` +//! - Manifests are sent along the grid topology to peers who have the relay-parent in their +//! implicit view. +//! - Only sent by 1st-hop nodes after downloading the backed candidate packet. +//! - The grid topology is a 2-dimensional grid that provides either a 1 or 2-hop path from any +//! originator to any recipient - 1st-hop nodes are those which share either a row or column +//! with the originator, and 2nd-hop nodes are those which share a column or row with that +//! 1st-hop node. +//! - Note that for the purposes of statement distribution, we actually take the union of the +//! routing paths from each validator in a group to the local node to determine the sending +//! and receiving paths. +//! - Ignored when received out-of-topology +//! - On every local view change, members of the backing group rebroadcast the manifest for all +//! candidates under every new relay-parent across the grid. +//! - Nodes should send a `BackedCandidateAcknowledgement(CandidateHash, StatementFilter)` +//! notification to any peer which has sent a manifest, and the candidate has been acquired by +//! other means. +//! - Request/response for the candidate + votes. +//! - Ignore if they are inconsistent with the manifest. +//! - A malicious backing group is capable of producing an unbounded number of backed candidates. +//! - We request the candidate only if the candidate has a hypothetical depth in any of our +//! fragment trees, and: +//! - the seconding validators have not seconded any other candidates at that depth in any of +//! those fragment trees +//! - All members of the group attempt to circulate all statements (in compact form) from the rest +//! of the group on candidates that have already been backed. +//! - They do this via the grid topology. +//! - They add the statements to their backed candidate packet for future requestors, and also: +//! - send the statement to any peer, which: +//! - we advertised the backed candidate to (sent manifest), and: +//! - has previously & successfully requested the backed candidate packet, or: +//! - which has sent a `BackedCandidateAcknowledgement` +//! - 1st-hop nodes do the same thing + +use polkadot_node_network_protocol::{ + grid_topology::SessionGridTopology, vstaging::StatementFilter, +}; +use polkadot_primitives::vstaging::{ + CandidateHash, CompactStatement, GroupIndex, Hash, ValidatorIndex, +}; + +use std::collections::{ + hash_map::{Entry, HashMap}, + HashSet, +}; + +use bitvec::{order::Lsb0, slice::BitSlice}; + +use super::{groups::Groups, LOG_TARGET}; + +/// Our local view of a subset of the grid topology organized around a specific validator +/// group. +/// +/// This tracks which authorities we expect to communicate with concerning +/// candidates from the group. This includes both the authorities we are +/// expected to send to as well as the authorities we expect to receive from. +/// +/// In the case that this group is the group that we are locally assigned to, +/// the 'receiving' side will be empty. +#[derive(Debug, PartialEq)] +struct GroupSubView { + // validators we are 'sending' to. + sending: HashSet, + // validators we are 'receiving' from. + receiving: HashSet, +} + +/// Our local view of the topology for a session, as it pertains to backed +/// candidate distribution. +#[derive(Debug)] +pub struct SessionTopologyView { + group_views: HashMap, +} + +impl SessionTopologyView { + /// Returns an iterator over all validator indices from the group who are allowed to + /// send us manifests of the given kind. + pub fn iter_sending_for_group( + &self, + group: GroupIndex, + kind: ManifestKind, + ) -> impl Iterator + '_ { + self.group_views.get(&group).into_iter().flat_map(move |sub| match kind { + ManifestKind::Full => sub.receiving.iter().cloned(), + ManifestKind::Acknowledgement => sub.sending.iter().cloned(), + }) + } +} + +/// Build a view of the topology for the session. +/// For groups that we are part of: we receive from nobody and send to our X/Y peers. +/// For groups that we are not part of: we receive from any validator in the group we share a slice +/// with and send to the corresponding X/Y slice in the other dimension. +/// For any validators we don't share a slice with, we receive from the nodes +/// which share a slice with them. +pub fn build_session_topology<'a>( + groups: impl IntoIterator>, + topology: &SessionGridTopology, + our_index: Option, +) -> SessionTopologyView { + let mut view = SessionTopologyView { group_views: HashMap::new() }; + + let our_index = match our_index { + None => return view, + Some(i) => i, + }; + + let our_neighbors = match topology.compute_grid_neighbors_for(our_index) { + None => { + gum::warn!(target: LOG_TARGET, ?our_index, "our index unrecognized in topology?"); + + return view + }, + Some(n) => n, + }; + + for (i, group) in groups.into_iter().enumerate() { + let mut sub_view = GroupSubView { sending: HashSet::new(), receiving: HashSet::new() }; + + if group.contains(&our_index) { + sub_view.sending.extend(our_neighbors.validator_indices_x.iter().cloned()); + sub_view.sending.extend(our_neighbors.validator_indices_y.iter().cloned()); + + // remove all other same-group validators from this set, they are + // in the cluster. + // TODO [now]: test this behavior. + for v in group { + sub_view.sending.remove(v); + } + } else { + for &group_val in group { + // If the validator shares a slice with us, we expect to + // receive from them and send to our neighbors in the other + // dimension. + + if our_neighbors.validator_indices_x.contains(&group_val) { + sub_view.receiving.insert(group_val); + sub_view.sending.extend( + our_neighbors + .validator_indices_y + .iter() + .filter(|v| !group.contains(v)) + .cloned(), + ); + + continue + } + + if our_neighbors.validator_indices_y.contains(&group_val) { + sub_view.receiving.insert(group_val); + sub_view.sending.extend( + our_neighbors + .validator_indices_x + .iter() + .filter(|v| !group.contains(v)) + .cloned(), + ); + + continue + } + + // If they don't share a slice with us, we don't send to anybody + // but receive from any peers sharing a dimension with both of us + let their_neighbors = match topology.compute_grid_neighbors_for(group_val) { + None => { + gum::warn!( + target: LOG_TARGET, + index = ?group_val, + "validator index unrecognized in topology?" + ); + + continue + }, + Some(n) => n, + }; + + // their X, our Y + for potential_link in &their_neighbors.validator_indices_x { + if our_neighbors.validator_indices_y.contains(potential_link) { + sub_view.receiving.insert(*potential_link); + break // one max + } + } + + // their Y, our X + for potential_link in &their_neighbors.validator_indices_y { + if our_neighbors.validator_indices_x.contains(potential_link) { + sub_view.receiving.insert(*potential_link); + break // one max + } + } + } + } + + view.group_views.insert(GroupIndex(i as _), sub_view); + } + + view +} + +/// The kind of backed candidate manifest we should send to a remote peer. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ManifestKind { + /// Full manifests contain information about the candidate and should be sent + /// to peers which aren't guaranteed to have the candidate already. + Full, + /// Acknowledgement manifests omit information which is implicit in the candidate + /// itself, and should be sent to peers which are guaranteed to have the candidate + /// already. + Acknowledgement, +} + +/// A tracker of knowledge from authorities within the grid for a particular +/// relay-parent. +#[derive(Default)] +pub struct GridTracker { + received: HashMap, + confirmed_backed: HashMap, + unconfirmed: HashMap>, + pending_manifests: HashMap>, + + // maps target to (originator, statement) pairs. + pending_statements: HashMap>, +} + +impl GridTracker { + /// Attempt to import a manifest advertised by a remote peer. + /// + /// This checks whether the peer is allowed to send us manifests + /// about this group at this relay-parent. This also does sanity + /// checks on the format of the manifest and the amount of votes + /// it contains. It has effects on the stored state only when successful. + /// + /// This returns a `bool` on success, which if true indicates that an acknowledgement is + /// to be sent in response to the received manifest. This only occurs when the + /// candidate is already known to be confirmed and backed. + pub fn import_manifest( + &mut self, + session_topology: &SessionTopologyView, + groups: &Groups, + candidate_hash: CandidateHash, + seconding_limit: usize, + manifest: ManifestSummary, + kind: ManifestKind, + sender: ValidatorIndex, + ) -> Result { + let claimed_group_index = manifest.claimed_group_index; + + let group_topology = match session_topology.group_views.get(&manifest.claimed_group_index) { + None => return Err(ManifestImportError::Disallowed), + Some(g) => g, + }; + + let receiving_from = group_topology.receiving.contains(&sender); + let sending_to = group_topology.sending.contains(&sender); + let manifest_allowed = match kind { + // Peers can send manifests _if_: + // * They are in the receiving set for the group AND the manifest is full OR + // * They are in the sending set for the group AND we have sent them a manifest AND + // the received manifest is partial. + ManifestKind::Full => receiving_from, + ManifestKind::Acknowledgement => + sending_to && + self.confirmed_backed + .get(&candidate_hash) + .map_or(false, |c| c.has_sent_manifest_to(sender)), + }; + + if !manifest_allowed { + return Err(ManifestImportError::Disallowed) + } + + let (group_size, backing_threshold) = + match groups.get_size_and_backing_threshold(manifest.claimed_group_index) { + Some(x) => x, + None => return Err(ManifestImportError::Malformed), + }; + + let remote_knowledge = manifest.statement_knowledge.clone(); + + if !remote_knowledge.has_len(group_size) { + return Err(ManifestImportError::Malformed) + } + + if !remote_knowledge.has_seconded() { + return Err(ManifestImportError::Malformed) + } + + // ensure votes are sufficient to back. + let votes = remote_knowledge.backing_validators(); + + if votes < backing_threshold { + return Err(ManifestImportError::Insufficient) + } + + self.received.entry(sender).or_default().import_received( + group_size, + seconding_limit, + candidate_hash, + manifest, + )?; + + let mut ack = false; + if let Some(confirmed) = self.confirmed_backed.get_mut(&candidate_hash) { + if receiving_from && !confirmed.has_sent_manifest_to(sender) { + // due to checks above, the manifest `kind` is guaranteed to be `Full` + self.pending_manifests + .entry(sender) + .or_default() + .insert(candidate_hash, ManifestKind::Acknowledgement); + + ack = true; + } + + // add all statements in local_knowledge & !remote_knowledge + // to `pending_statements` for this validator. + confirmed.manifest_received_from(sender, remote_knowledge); + if let Some(pending_statements) = confirmed.pending_statements(sender) { + self.pending_statements.entry(sender).or_default().extend( + decompose_statement_filter( + groups, + claimed_group_index, + candidate_hash, + &pending_statements, + ), + ); + } + } else { + // `received` prevents conflicting manifests so this is max 1 per validator. + self.unconfirmed + .entry(candidate_hash) + .or_default() + .push((sender, claimed_group_index)) + } + + Ok(ack) + } + + /// Add a new backed candidate to the tracker. This yields + /// a list of validators which we should either advertise to + /// or signal that we know the candidate, along with the corresponding + /// type of manifest we should send. + pub fn add_backed_candidate( + &mut self, + session_topology: &SessionTopologyView, + candidate_hash: CandidateHash, + group_index: GroupIndex, + local_knowledge: StatementFilter, + ) -> Vec<(ValidatorIndex, ManifestKind)> { + let c = match self.confirmed_backed.entry(candidate_hash) { + Entry::Occupied(_) => return Vec::new(), + Entry::Vacant(v) => v.insert(KnownBackedCandidate { + group_index, + mutual_knowledge: HashMap::new(), + local_knowledge, + }), + }; + + // Populate the entry with previously unconfirmed manifests. + for (v, claimed_group_index) in + self.unconfirmed.remove(&candidate_hash).into_iter().flatten() + { + if claimed_group_index != group_index { + // This is misbehavior, but is handled more comprehensively elsewhere + continue + } + + let statement_filter = self + .received + .get(&v) + .and_then(|r| r.candidate_statement_filter(&candidate_hash)) + .expect("unconfirmed is only populated by validators who have sent manifest; qed"); + + // No need to send direct statements, because our local knowledge is `None` + c.manifest_received_from(v, statement_filter); + } + + let group_topology = match session_topology.group_views.get(&group_index) { + None => return Vec::new(), + Some(g) => g, + }; + + // advertise onwards and accept received advertisements + + let sending_group_manifests = + group_topology.sending.iter().map(|v| (*v, ManifestKind::Full)); + + let receiving_group_manifests = group_topology.receiving.iter().filter_map(|v| { + if c.has_received_manifest_from(*v) { + Some((*v, ManifestKind::Acknowledgement)) + } else { + None + } + }); + + // Note that order is important: if a validator is part of both the sending + // and receiving groups, we may overwrite a `Full` manifest with a `Acknowledgement` + // one. + for (v, manifest_mode) in sending_group_manifests.chain(receiving_group_manifests) { + gum::trace!( + target: LOG_TARGET, + validator_index = ?v, + ?manifest_mode, + "Preparing to send manifest/acknowledgement" + ); + + self.pending_manifests + .entry(v) + .or_default() + .insert(candidate_hash, manifest_mode); + } + + self.pending_manifests + .iter() + .filter_map(|(v, x)| x.get(&candidate_hash).map(|k| (*v, *k))) + .collect() + } + + /// Note that a backed candidate has been advertised to a + /// given validator. + pub fn manifest_sent_to( + &mut self, + groups: &Groups, + validator_index: ValidatorIndex, + candidate_hash: CandidateHash, + local_knowledge: StatementFilter, + ) { + if let Some(c) = self.confirmed_backed.get_mut(&candidate_hash) { + c.manifest_sent_to(validator_index, local_knowledge); + + if let Some(pending_statements) = c.pending_statements(validator_index) { + self.pending_statements.entry(validator_index).or_default().extend( + decompose_statement_filter( + groups, + c.group_index, + candidate_hash, + &pending_statements, + ), + ); + } + } + + if let Some(x) = self.pending_manifests.get_mut(&validator_index) { + x.remove(&candidate_hash); + } + } + + /// Returns a vector of all candidates pending manifests for the specific validator, and + /// the type of manifest we should send. + pub fn pending_manifests_for( + &self, + validator_index: ValidatorIndex, + ) -> Vec<(CandidateHash, ManifestKind)> { + self.pending_manifests + .get(&validator_index) + .into_iter() + .flat_map(|pending| pending.iter().map(|(c, m)| (*c, *m))) + .collect() + } + + /// Returns a statement filter indicating statements that a given peer + /// is awaiting concerning the given candidate, constrained by the statements + /// we have ourselves. + pub fn pending_statements_for( + &self, + validator_index: ValidatorIndex, + candidate_hash: CandidateHash, + ) -> Option { + self.confirmed_backed + .get(&candidate_hash) + .and_then(|x| x.pending_statements(validator_index)) + } + + /// Returns a vector of all pending statements to the validator, sorted with + /// `Seconded` statements at the front. + /// + /// Statements are in the form `(Originator, Statement Kind)`. + pub fn all_pending_statements_for( + &self, + validator_index: ValidatorIndex, + ) -> Vec<(ValidatorIndex, CompactStatement)> { + let mut v = self + .pending_statements + .get(&validator_index) + .map(|x| x.iter().cloned().collect()) + .unwrap_or(Vec::new()); + + v.sort_by_key(|(_, s)| match s { + CompactStatement::Seconded(_) => 0u32, + CompactStatement::Valid(_) => 1u32, + }); + + v + } + + /// Whether a validator can request a manifest from us. + pub fn can_request(&self, validator: ValidatorIndex, candidate_hash: CandidateHash) -> bool { + self.confirmed_backed.get(&candidate_hash).map_or(false, |c| { + c.has_sent_manifest_to(validator) && !c.has_received_manifest_from(validator) + }) + } + + /// Determine the validators which can send a statement to us by direct broadcast. + pub fn direct_statement_providers( + &self, + groups: &Groups, + originator: ValidatorIndex, + statement: &CompactStatement, + ) -> Vec { + let (g, c_h, kind, in_group) = + match extract_statement_and_group_info(groups, originator, statement) { + None => return Vec::new(), + Some(x) => x, + }; + + self.confirmed_backed + .get(&c_h) + .map(|k| k.direct_statement_senders(g, in_group, kind)) + .unwrap_or_default() + } + + /// Determine the validators which can receive a statement from us by direct + /// broadcast. + pub fn direct_statement_targets( + &self, + groups: &Groups, + originator: ValidatorIndex, + statement: &CompactStatement, + ) -> Vec { + let (g, c_h, kind, in_group) = + match extract_statement_and_group_info(groups, originator, statement) { + None => return Vec::new(), + Some(x) => x, + }; + + self.confirmed_backed + .get(&c_h) + .map(|k| k.direct_statement_recipients(g, in_group, kind)) + .unwrap_or_default() + } + + /// Note that we have learned about a statement. This will update + /// `pending_statements_for` for any relevant validators if actually + /// fresh. + pub fn learned_fresh_statement( + &mut self, + groups: &Groups, + session_topology: &SessionTopologyView, + originator: ValidatorIndex, + statement: &CompactStatement, + ) { + let (g, c_h, kind, in_group) = + match extract_statement_and_group_info(groups, originator, statement) { + None => return, + Some(x) => x, + }; + + let known = match self.confirmed_backed.get_mut(&c_h) { + None => return, + Some(x) => x, + }; + + if !known.note_fresh_statement(in_group, kind) { + return + } + + // Add to `pending_statements` for all validators we communicate with + // who have exchanged manifests. + let all_group_validators = session_topology + .group_views + .get(&g) + .into_iter() + .flat_map(|g| g.sending.iter().chain(g.receiving.iter())); + + for v in all_group_validators { + if known.is_pending_statement(*v, in_group, kind) { + self.pending_statements + .entry(*v) + .or_default() + .insert((originator, statement.clone())); + } + } + } + + /// Note that a direct statement about a given candidate was sent to or + /// received from the given validator. + pub fn sent_or_received_direct_statement( + &mut self, + groups: &Groups, + originator: ValidatorIndex, + counterparty: ValidatorIndex, + statement: &CompactStatement, + ) { + if let Some((_, c_h, kind, in_group)) = + extract_statement_and_group_info(groups, originator, statement) + { + if let Some(known) = self.confirmed_backed.get_mut(&c_h) { + known.sent_or_received_direct_statement(counterparty, in_group, kind); + + if let Some(pending) = self.pending_statements.get_mut(&counterparty) { + pending.remove(&(originator, statement.clone())); + } + } + } + } + + /// Get the advertised statement filter of a validator for a candidate. + pub fn advertised_statements( + &self, + validator: ValidatorIndex, + candidate_hash: &CandidateHash, + ) -> Option { + self.received.get(&validator)?.candidate_statement_filter(candidate_hash) + } + + #[cfg(test)] + fn is_manifest_pending_for( + &self, + validator: ValidatorIndex, + candidate_hash: &CandidateHash, + ) -> Option { + self.pending_manifests + .get(&validator) + .and_then(|m| m.get(candidate_hash)) + .map(|x| *x) + } +} + +fn extract_statement_and_group_info( + groups: &Groups, + originator: ValidatorIndex, + statement: &CompactStatement, +) -> Option<(GroupIndex, CandidateHash, StatementKind, usize)> { + let (statement_kind, candidate_hash) = match statement { + CompactStatement::Seconded(h) => (StatementKind::Seconded, h), + CompactStatement::Valid(h) => (StatementKind::Valid, h), + }; + + let group = match groups.by_validator_index(originator) { + None => return None, + Some(g) => g, + }; + + let index_in_group = groups.get(group)?.iter().position(|v| v == &originator)?; + + Some((group, *candidate_hash, statement_kind, index_in_group)) +} + +fn decompose_statement_filter<'a>( + groups: &'a Groups, + group_index: GroupIndex, + candidate_hash: CandidateHash, + statement_filter: &'a StatementFilter, +) -> impl Iterator + 'a { + groups.get(group_index).into_iter().flat_map(move |g| { + let s = statement_filter + .seconded_in_group + .iter_ones() + .map(|i| g[i]) + .map(move |i| (i, CompactStatement::Seconded(candidate_hash))); + + let v = statement_filter + .validated_in_group + .iter_ones() + .map(|i| g[i]) + .map(move |i| (i, CompactStatement::Valid(candidate_hash))); + + s.chain(v) + }) +} + +/// A summary of a manifest being sent by a counterparty. +#[derive(Debug, Clone)] +pub struct ManifestSummary { + /// The claimed parent head data hash of the candidate. + pub claimed_parent_hash: Hash, + /// The claimed group index assigned to the candidate. + pub claimed_group_index: GroupIndex, + /// A statement filter sent alongisde the candidate, communicating + /// knowledge. + pub statement_knowledge: StatementFilter, +} + +/// Errors in importing a manifest. +#[derive(Debug, Clone)] +pub enum ManifestImportError { + /// The manifest conflicts with another, previously sent manifest. + Conflicting, + /// The manifest has overflowed beyond the limits of what the + /// counterparty was allowed to send us. + Overflow, + /// The manifest claims insufficient attestations to achieve the backing + /// threshold. + Insufficient, + /// The manifest is malformed. + Malformed, + /// The manifest was not allowed to be sent. + Disallowed, +} + +/// The knowledge we are aware of counterparties having of manifests. +#[derive(Default)] +struct ReceivedManifests { + received: HashMap, + // group -> seconded counts. + seconded_counts: HashMap>, +} + +impl ReceivedManifests { + fn candidate_statement_filter( + &self, + candidate_hash: &CandidateHash, + ) -> Option { + self.received.get(candidate_hash).map(|m| m.statement_knowledge.clone()) + } + + /// Attempt to import a received manifest from a counterparty. + /// + /// This will reject manifests which are either duplicate, conflicting, + /// or imply an irrational amount of `Seconded` statements. + /// + /// This assumes that the manifest has already been checked for + /// validity - i.e. that the bitvecs match the claimed group in size + /// and that the manifest includes at least one `Seconded` + /// attestation and includes enough attestations for the candidate + /// to be backed. + /// + /// This also should only be invoked when we are intended to track + /// the knowledge of this peer as determined by the [`SessionTopology`]. + fn import_received( + &mut self, + group_size: usize, + seconding_limit: usize, + candidate_hash: CandidateHash, + manifest_summary: ManifestSummary, + ) -> Result<(), ManifestImportError> { + match self.received.entry(candidate_hash) { + Entry::Occupied(mut e) => { + // occupied entry. + + // filter out clearly conflicting data. + { + let prev = e.get(); + if prev.claimed_group_index != manifest_summary.claimed_group_index { + return Err(ManifestImportError::Conflicting) + } + + if prev.claimed_parent_hash != manifest_summary.claimed_parent_hash { + return Err(ManifestImportError::Conflicting) + } + + if !manifest_summary + .statement_knowledge + .seconded_in_group + .contains(&prev.statement_knowledge.seconded_in_group) + { + return Err(ManifestImportError::Conflicting) + } + + if !manifest_summary + .statement_knowledge + .validated_in_group + .contains(&prev.statement_knowledge.validated_in_group) + { + return Err(ManifestImportError::Conflicting) + } + + let mut fresh_seconded = + manifest_summary.statement_knowledge.seconded_in_group.clone(); + fresh_seconded |= &prev.statement_knowledge.seconded_in_group; + + let within_limits = updating_ensure_within_seconding_limit( + &mut self.seconded_counts, + manifest_summary.claimed_group_index, + group_size, + seconding_limit, + &fresh_seconded, + ); + + if !within_limits { + return Err(ManifestImportError::Overflow) + } + } + + // All checks passed. Overwrite: guaranteed to be + // superset. + *e.get_mut() = manifest_summary; + Ok(()) + }, + Entry::Vacant(e) => { + let within_limits = updating_ensure_within_seconding_limit( + &mut self.seconded_counts, + manifest_summary.claimed_group_index, + group_size, + seconding_limit, + &manifest_summary.statement_knowledge.seconded_in_group, + ); + + if within_limits { + e.insert(manifest_summary); + Ok(()) + } else { + Err(ManifestImportError::Overflow) + } + }, + } + } +} + +// updates validator-seconded records but only if the new statements +// are OK. returns `true` if alright and `false` otherwise. +// +// The seconding limit is a per-validator limit. It ensures an upper bound on the total number of +// candidates entering the system. +fn updating_ensure_within_seconding_limit( + seconded_counts: &mut HashMap>, + group_index: GroupIndex, + group_size: usize, + seconding_limit: usize, + new_seconded: &BitSlice, +) -> bool { + if seconding_limit == 0 { + return false + } + + // due to the check above, if this was non-existent this function will + // always return `true`. + let counts = seconded_counts.entry(group_index).or_insert_with(|| vec![0; group_size]); + + for i in new_seconded.iter_ones() { + if counts[i] == seconding_limit { + return false + } + } + + for i in new_seconded.iter_ones() { + counts[i] += 1; + } + + true +} + +#[derive(Debug, Clone, Copy)] +enum StatementKind { + Seconded, + Valid, +} + +trait FilterQuery { + fn contains(&self, index: usize, statement_kind: StatementKind) -> bool; + fn set(&mut self, index: usize, statement_kind: StatementKind); +} + +impl FilterQuery for StatementFilter { + fn contains(&self, index: usize, statement_kind: StatementKind) -> bool { + match statement_kind { + StatementKind::Seconded => self.seconded_in_group.get(index).map_or(false, |x| *x), + StatementKind::Valid => self.validated_in_group.get(index).map_or(false, |x| *x), + } + } + + fn set(&mut self, index: usize, statement_kind: StatementKind) { + let b = match statement_kind { + StatementKind::Seconded => self.seconded_in_group.get_mut(index), + StatementKind::Valid => self.validated_in_group.get_mut(index), + }; + + if let Some(mut b) = b { + *b = true; + } + } +} + +/// Knowledge that we have about a remote peer concerning a candidate, and that they have about us +/// concerning the candidate. +#[derive(Debug, Clone)] +struct MutualKnowledge { + /// Knowledge the remote peer has about the candidate, as far as we're aware. + /// `Some` only if they have advertised, acknowledged, or requested the candidate. + remote_knowledge: Option, + /// Knowledge we have indicated to the remote peer about the candidate. + /// `Some` only if we have advertised, acknowledged, or requested the candidate + /// from them. + local_knowledge: Option, +} + +// A utility struct for keeping track of metadata about candidates +// we have confirmed as having been backed. +#[derive(Debug, Clone)] +struct KnownBackedCandidate { + group_index: GroupIndex, + local_knowledge: StatementFilter, + mutual_knowledge: HashMap, +} + +impl KnownBackedCandidate { + fn has_received_manifest_from(&self, validator: ValidatorIndex) -> bool { + self.mutual_knowledge + .get(&validator) + .map_or(false, |k| k.remote_knowledge.is_some()) + } + + fn has_sent_manifest_to(&self, validator: ValidatorIndex) -> bool { + self.mutual_knowledge + .get(&validator) + .map_or(false, |k| k.local_knowledge.is_some()) + } + + fn manifest_sent_to(&mut self, validator: ValidatorIndex, local_knowledge: StatementFilter) { + let k = self + .mutual_knowledge + .entry(validator) + .or_insert_with(|| MutualKnowledge { remote_knowledge: None, local_knowledge: None }); + + k.local_knowledge = Some(local_knowledge); + } + + fn manifest_received_from( + &mut self, + validator: ValidatorIndex, + remote_knowledge: StatementFilter, + ) { + let k = self + .mutual_knowledge + .entry(validator) + .or_insert_with(|| MutualKnowledge { remote_knowledge: None, local_knowledge: None }); + + k.remote_knowledge = Some(remote_knowledge); + } + + fn direct_statement_senders( + &self, + group_index: GroupIndex, + originator_index_in_group: usize, + statement_kind: StatementKind, + ) -> Vec { + if group_index != self.group_index { + return Vec::new() + } + + self.mutual_knowledge + .iter() + .filter(|(_, k)| k.remote_knowledge.is_some()) + .filter(|(_, k)| { + k.local_knowledge + .as_ref() + .map_or(false, |r| !r.contains(originator_index_in_group, statement_kind)) + }) + .map(|(v, _)| *v) + .collect() + } + + fn direct_statement_recipients( + &self, + group_index: GroupIndex, + originator_index_in_group: usize, + statement_kind: StatementKind, + ) -> Vec { + if group_index != self.group_index { + return Vec::new() + } + + self.mutual_knowledge + .iter() + .filter(|(_, k)| k.local_knowledge.is_some()) + .filter(|(_, k)| { + k.remote_knowledge + .as_ref() + .map_or(false, |r| !r.contains(originator_index_in_group, statement_kind)) + }) + .map(|(v, _)| *v) + .collect() + } + + fn note_fresh_statement( + &mut self, + statement_index_in_group: usize, + statement_kind: StatementKind, + ) -> bool { + let really_fresh = !self.local_knowledge.contains(statement_index_in_group, statement_kind); + self.local_knowledge.set(statement_index_in_group, statement_kind); + + really_fresh + } + + fn sent_or_received_direct_statement( + &mut self, + validator: ValidatorIndex, + statement_index_in_group: usize, + statement_kind: StatementKind, + ) { + if let Some(k) = self.mutual_knowledge.get_mut(&validator) { + if let (Some(r), Some(l)) = (k.remote_knowledge.as_mut(), k.local_knowledge.as_mut()) { + r.set(statement_index_in_group, statement_kind); + l.set(statement_index_in_group, statement_kind); + } + } + } + + fn is_pending_statement( + &self, + validator: ValidatorIndex, + statement_index_in_group: usize, + statement_kind: StatementKind, + ) -> bool { + // existence of both remote & local knowledge indicate we have exchanged + // manifests. + // then, everything that is not in the remote knowledge is pending + self.mutual_knowledge + .get(&validator) + .filter(|k| k.local_knowledge.is_some()) + .and_then(|k| k.remote_knowledge.as_ref()) + .map(|k| !k.contains(statement_index_in_group, statement_kind)) + .unwrap_or(false) + } + + fn pending_statements(&self, validator: ValidatorIndex) -> Option { + // existence of both remote & local knowledge indicate we have exchanged + // manifests. + // then, everything that is not in the remote knowledge is pending, and we + // further limit this by what is in the local knowledge itself. we use the + // full local knowledge, as the local knowledge stored here may be outdated. + let full_local = &self.local_knowledge; + + self.mutual_knowledge + .get(&validator) + .filter(|k| k.local_knowledge.is_some()) + .and_then(|k| k.remote_knowledge.as_ref()) + .map(|remote| StatementFilter { + seconded_in_group: full_local.seconded_in_group.clone() & + !remote.seconded_in_group.clone(), + validated_in_group: full_local.validated_in_group.clone() & + !remote.validated_in_group.clone(), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + use polkadot_node_network_protocol::grid_topology::TopologyPeerInfo; + use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair; + use sp_core::crypto::Pair as PairT; + + fn dummy_groups(group_size: usize) -> Groups { + let groups = vec![(0..(group_size as u32)).map(ValidatorIndex).collect()].into(); + + Groups::new(groups) + } + + #[test] + fn topology_empty_for_no_index() { + let base_topology = SessionGridTopology::new( + vec![0, 1, 2], + vec![ + TopologyPeerInfo { + peer_ids: Vec::new(), + validator_index: ValidatorIndex(0), + discovery_id: AuthorityDiscoveryPair::generate().0.public(), + }, + TopologyPeerInfo { + peer_ids: Vec::new(), + validator_index: ValidatorIndex(1), + discovery_id: AuthorityDiscoveryPair::generate().0.public(), + }, + TopologyPeerInfo { + peer_ids: Vec::new(), + validator_index: ValidatorIndex(2), + discovery_id: AuthorityDiscoveryPair::generate().0.public(), + }, + ], + ); + + let t = build_session_topology( + &[vec![ValidatorIndex(0)], vec![ValidatorIndex(1)], vec![ValidatorIndex(2)]], + &base_topology, + None, + ); + + assert!(t.group_views.is_empty()); + } + + #[test] + fn topology_setup() { + let base_topology = SessionGridTopology::new( + (0..9).collect(), + (0..9) + .map(|i| TopologyPeerInfo { + peer_ids: Vec::new(), + validator_index: ValidatorIndex(i), + discovery_id: AuthorityDiscoveryPair::generate().0.public(), + }) + .collect(), + ); + + let t = build_session_topology( + &[ + vec![ValidatorIndex(0), ValidatorIndex(3), ValidatorIndex(6)], + vec![ValidatorIndex(4), ValidatorIndex(2), ValidatorIndex(7)], + vec![ValidatorIndex(8), ValidatorIndex(5), ValidatorIndex(1)], + ], + &base_topology, + Some(ValidatorIndex(0)), + ); + + assert_eq!(t.group_views.len(), 3); + + // 0 1 2 + // 3 4 5 + // 6 7 8 + + // our group: we send to all row/column neighbors which are not in our + // group and receive nothing. + assert_eq!( + t.group_views.get(&GroupIndex(0)).unwrap().sending, + vec![1, 2].into_iter().map(ValidatorIndex).collect::>(), + ); + assert_eq!(t.group_views.get(&GroupIndex(0)).unwrap().receiving, HashSet::new(),); + + // we share a row with '2' and have indirect connections to '4' and '7'. + + assert_eq!( + t.group_views.get(&GroupIndex(1)).unwrap().sending, + vec![3, 6].into_iter().map(ValidatorIndex).collect::>(), + ); + assert_eq!( + t.group_views.get(&GroupIndex(1)).unwrap().receiving, + vec![1, 2, 3, 6].into_iter().map(ValidatorIndex).collect::>(), + ); + + // we share a row with '1' and have indirect connections to '5' and '8'. + + assert_eq!( + t.group_views.get(&GroupIndex(2)).unwrap().sending, + vec![3, 6].into_iter().map(ValidatorIndex).collect::>(), + ); + assert_eq!( + t.group_views.get(&GroupIndex(2)).unwrap().receiving, + vec![1, 2, 3, 6].into_iter().map(ValidatorIndex).collect::>(), + ); + } + + #[test] + fn knowledge_rejects_conflicting_manifest() { + let mut knowledge = ReceivedManifests::default(); + + let expected_manifest_summary = ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(2), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + }, + }; + + knowledge + .import_received( + 3, + 2, + CandidateHash(Hash::repeat_byte(1)), + expected_manifest_summary.clone(), + ) + .unwrap(); + + // conflicting group + + let mut s = expected_manifest_summary.clone(); + s.claimed_group_index = GroupIndex(1); + assert_matches!( + knowledge.import_received(3, 2, CandidateHash(Hash::repeat_byte(1)), s,), + Err(ManifestImportError::Conflicting) + ); + + // conflicting parent hash + + let mut s = expected_manifest_summary.clone(); + s.claimed_parent_hash = Hash::repeat_byte(3); + assert_matches!( + knowledge.import_received(3, 2, CandidateHash(Hash::repeat_byte(1)), s,), + Err(ManifestImportError::Conflicting) + ); + + // conflicting seconded statements bitfield + + let mut s = expected_manifest_summary.clone(); + s.statement_knowledge.seconded_in_group = bitvec::bitvec![u8, Lsb0; 0, 1, 0]; + assert_matches!( + knowledge.import_received(3, 2, CandidateHash(Hash::repeat_byte(1)), s,), + Err(ManifestImportError::Conflicting) + ); + + // conflicting valid statements bitfield + + let mut s = expected_manifest_summary.clone(); + s.statement_knowledge.validated_in_group = bitvec::bitvec![u8, Lsb0; 0, 1, 0]; + assert_matches!( + knowledge.import_received(3, 2, CandidateHash(Hash::repeat_byte(1)), s,), + Err(ManifestImportError::Conflicting) + ); + } + + // Make sure we don't import manifests that would put a validator in a group over the limit of + // candidates they are allowed to second (aka seconding limit). + #[test] + fn reject_overflowing_manifests() { + let mut knowledge = ReceivedManifests::default(); + knowledge + .import_received( + 3, + 2, + CandidateHash(Hash::repeat_byte(1)), + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0xA), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + }, + }, + ) + .unwrap(); + + knowledge + .import_received( + 3, + 2, + CandidateHash(Hash::repeat_byte(2)), + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0xB), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + }, + }, + ) + .unwrap(); + + // Reject a seconding validator that is already at the seconding limit. Seconding counts for + // the validators should not be applied. + assert_matches!( + knowledge.import_received( + 3, + 2, + CandidateHash(Hash::repeat_byte(3)), + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0xC), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + } + }, + ), + Err(ManifestImportError::Overflow) + ); + + // Don't reject validators that have seconded less than the limit so far. + knowledge + .import_received( + 3, + 2, + CandidateHash(Hash::repeat_byte(3)), + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0xC), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + }, + }, + ) + .unwrap(); + } + + #[test] + fn reject_disallowed_manifest() { + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: vec![ValidatorIndex(0)].into_iter().collect(), + }, + )] + .into_iter() + .collect(), + }; + + let groups = dummy_groups(3); + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + assert_eq!(groups.get_size_and_backing_threshold(GroupIndex(0)), Some((3, 2)),); + + // Known group, disallowed receiving validator. + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + } + }, + ManifestKind::Full, + ValidatorIndex(1), + ), + Err(ManifestImportError::Disallowed) + ); + + // Unknown group + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(1), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Err(ManifestImportError::Disallowed) + ); + } + + #[test] + fn reject_malformed_wrong_group_size() { + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: vec![ValidatorIndex(0)].into_iter().collect(), + }, + )] + .into_iter() + .collect(), + }; + + let groups = dummy_groups(3); + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + assert_eq!(groups.get_size_and_backing_threshold(GroupIndex(0)), Some((3, 2)),); + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Err(ManifestImportError::Malformed) + ); + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1, 0], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Err(ManifestImportError::Malformed) + ); + } + + #[test] + fn reject_malformed_no_seconders() { + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: vec![ValidatorIndex(0)].into_iter().collect(), + }, + )] + .into_iter() + .collect(), + }; + + let groups = dummy_groups(3); + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + assert_eq!(groups.get_size_and_backing_threshold(GroupIndex(0)), Some((3, 2)),); + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Err(ManifestImportError::Malformed) + ); + } + + #[test] + fn reject_insufficient_below_threshold() { + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: HashSet::from([ValidatorIndex(0)]), + }, + )] + .into_iter() + .collect(), + }; + + let groups = dummy_groups(3); + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + assert_eq!(groups.get_size_and_backing_threshold(GroupIndex(0)), Some((3, 2)),); + + // only one vote + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Err(ManifestImportError::Insufficient) + ); + + // seconding + validating still not enough to reach '2' threshold + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Err(ManifestImportError::Insufficient) + ); + + // finally good. + + assert_matches!( + tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: GroupIndex(0), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + } + }, + ManifestKind::Full, + ValidatorIndex(0), + ), + Ok(false) + ); + } + + // Test that when we add a candidate as backed and advertise it to the sending group, they can + // provide an acknowledgement manifest in response. + #[test] + fn senders_can_provide_manifests_in_acknowledgement() { + let validator_index = ValidatorIndex(0); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::from([validator_index]), + receiving: HashSet::from([ValidatorIndex(1)]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Add the candidate as backed. + let receivers = tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + // Validator 0 is in the sending group. Advertise onward to it. + // + // Validator 1 is in the receiving group, but we have not received from it, so we're not + // expected to send it an acknowledgement. + assert_eq!(receivers, vec![(validator_index, ManifestKind::Full)]); + + // Note the manifest as 'sent' to validator 0. + tracker.manifest_sent_to(&groups, validator_index, candidate_hash, local_knowledge); + + // Import manifest of kind `Acknowledgement` from validator 0. + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Acknowledgement, + validator_index, + ); + assert_matches!(ack, Ok(false)); + } + + // Check that pending communication is set correctly when receiving a manifest on a confirmed + // candidate. + // + // It should also overwrite any existing `Full` ManifestKind. + #[test] + fn pending_communication_receiving_manifest_on_confirmed_candidate() { + let validator_index = ValidatorIndex(0); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::from([validator_index]), + receiving: HashSet::from([ValidatorIndex(1)]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Manifest should not be pending yet. + let pending_manifest = tracker.is_manifest_pending_for(validator_index, &candidate_hash); + assert_eq!(pending_manifest, None); + + // Add the candidate as backed. + tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + + // Manifest should be pending as `Full`. + let pending_manifest = tracker.is_manifest_pending_for(validator_index, &candidate_hash); + assert_eq!(pending_manifest, Some(ManifestKind::Full)); + + // Note the manifest as 'sent' to validator 0. + tracker.manifest_sent_to(&groups, validator_index, candidate_hash, local_knowledge); + + // Import manifest. + // + // Should overwrite existing `Full` manifest. + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Acknowledgement, + validator_index, + ); + assert_matches!(ack, Ok(false)); + + let pending_manifest = tracker.is_manifest_pending_for(validator_index, &candidate_hash); + assert_eq!(pending_manifest, None); + } + + // Check that pending communication is cleared correctly in `manifest_sent_to` + // + // Also test a scenario where manifest import returns `Ok(true)` (should acknowledge). + #[test] + fn pending_communication_is_cleared() { + let validator_index = ValidatorIndex(0); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: HashSet::from([validator_index]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Add the candidate as backed. + tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + + // Manifest should not be pending yet. + let pending_manifest = tracker.is_manifest_pending_for(validator_index, &candidate_hash); + assert_eq!(pending_manifest, None); + + // Import manifest. The candidate is confirmed backed and we are expected to receive from + // validator 0, so send it an acknowledgement. + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Full, + validator_index, + ); + assert_matches!(ack, Ok(true)); + + // Acknowledgement manifest should be pending. + let pending_manifest = tracker.is_manifest_pending_for(validator_index, &candidate_hash); + assert_eq!(pending_manifest, Some(ManifestKind::Acknowledgement)); + + // Note the candidate as advertised. + tracker.manifest_sent_to(&groups, validator_index, candidate_hash, local_knowledge); + + // Pending manifest should be cleared. + let pending_manifest = tracker.is_manifest_pending_for(validator_index, &candidate_hash); + assert_eq!(pending_manifest, None); + } + + /// A manifest exchange means that both `manifest_sent_to` and `manifest_received_from` have + /// been invoked. + /// + /// In practice, it means that one of three things have happened: + /// + /// - They announced, we acknowledged + /// + /// - We announced, they acknowledged + /// + /// - We announced, they announced (not sure if this can actually happen; it would happen if 2 + /// nodes had each other in their sending set and they sent manifests at the same time. The + /// code accounts for this anyway) + #[test] + fn pending_statements_are_updated_after_manifest_exchange() { + let send_to = ValidatorIndex(0); + let receive_from = ValidatorIndex(1); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::from([send_to]), + receiving: HashSet::from([receive_from]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Confirm the candidate. + let receivers = tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + assert_eq!(receivers, vec![(send_to, ManifestKind::Full)]); + + // Learn a statement from a different validator. + tracker.learned_fresh_statement( + &groups, + &session_topology, + ValidatorIndex(2), + &CompactStatement::Seconded(candidate_hash), + ); + + // Test receiving followed by sending an ack. + { + // Should start with no pending statements. + assert_eq!(tracker.pending_statements_for(receive_from, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(receive_from), vec![]); + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Full, + receive_from, + ); + assert_matches!(ack, Ok(true)); + + // Send ack now. + tracker.manifest_sent_to( + &groups, + receive_from, + candidate_hash, + local_knowledge.clone(), + ); + + // There should be pending statements now. + assert_eq!( + tracker.pending_statements_for(receive_from, candidate_hash), + Some(StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }) + ); + assert_eq!( + tracker.all_pending_statements_for(receive_from), + vec![(ValidatorIndex(2), CompactStatement::Seconded(candidate_hash))] + ); + } + + // Test sending followed by receiving an ack. + { + // Should start with no pending statements. + assert_eq!(tracker.pending_statements_for(send_to, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(send_to), vec![]); + + tracker.manifest_sent_to(&groups, send_to, candidate_hash, local_knowledge.clone()); + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + }, + }, + ManifestKind::Acknowledgement, + send_to, + ); + assert_matches!(ack, Ok(false)); + + // There should be pending statements now. + assert_eq!( + tracker.pending_statements_for(send_to, candidate_hash), + Some(StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }) + ); + assert_eq!( + tracker.all_pending_statements_for(send_to), + vec![(ValidatorIndex(2), CompactStatement::Seconded(candidate_hash))] + ); + } + } + + #[test] + fn invalid_fresh_statement_import() { + let validator_index = ValidatorIndex(0); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: HashSet::from([validator_index]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Should start with no pending statements. + assert_eq!(tracker.pending_statements_for(validator_index, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(validator_index), vec![]); + + // Try to import fresh statement. Candidate not backed. + let statement = CompactStatement::Seconded(candidate_hash); + tracker.learned_fresh_statement(&groups, &session_topology, validator_index, &statement); + + assert_eq!(tracker.pending_statements_for(validator_index, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(validator_index), vec![]); + + // Add the candidate as backed. + tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + + // Try to import fresh statement. Unknown group for validator index. + let statement = CompactStatement::Seconded(candidate_hash); + tracker.learned_fresh_statement(&groups, &session_topology, ValidatorIndex(1), &statement); + + assert_eq!(tracker.pending_statements_for(validator_index, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(validator_index), vec![]); + } + + #[test] + fn pending_statements_updated_when_importing_fresh_statement() { + let validator_index = ValidatorIndex(0); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: HashSet::from([validator_index]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Should start with no pending statements. + assert_eq!(tracker.pending_statements_for(validator_index, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(validator_index), vec![]); + + // Add the candidate as backed. + tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + + // Import fresh statement. + + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Full, + validator_index, + ); + assert_matches!(ack, Ok(true)); + tracker.manifest_sent_to(&groups, validator_index, candidate_hash, local_knowledge); + let statement = CompactStatement::Seconded(candidate_hash); + tracker.learned_fresh_statement(&groups, &session_topology, validator_index, &statement); + + // There should be pending statements now. + let statements = StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }; + assert_eq!( + tracker.pending_statements_for(validator_index, candidate_hash), + Some(statements.clone()) + ); + assert_eq!( + tracker.all_pending_statements_for(validator_index), + vec![(ValidatorIndex(0), CompactStatement::Seconded(candidate_hash))] + ); + + // After successful import, try importing again. Nothing should change. + + tracker.learned_fresh_statement(&groups, &session_topology, validator_index, &statement); + assert_eq!( + tracker.pending_statements_for(validator_index, candidate_hash), + Some(statements) + ); + assert_eq!( + tracker.all_pending_statements_for(validator_index), + vec![(ValidatorIndex(0), CompactStatement::Seconded(candidate_hash))] + ); + } + + // After learning fresh statements, we should not generate pending statements for knowledge that + // the validator already has. + #[test] + fn pending_statements_respect_remote_knowledge() { + let validator_index = ValidatorIndex(0); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: HashSet::from([validator_index]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Should start with no pending statements. + assert_eq!(tracker.pending_statements_for(validator_index, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(validator_index), vec![]); + + // Add the candidate as backed. + tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + + // Import fresh statement. + let ack = tracker.import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }, + ManifestKind::Full, + validator_index, + ); + assert_matches!(ack, Ok(true)); + tracker.manifest_sent_to(&groups, validator_index, candidate_hash, local_knowledge); + tracker.learned_fresh_statement( + &groups, + &session_topology, + validator_index, + &CompactStatement::Seconded(candidate_hash), + ); + tracker.learned_fresh_statement( + &groups, + &session_topology, + validator_index, + &CompactStatement::Valid(candidate_hash), + ); + + // The pending statements should respect the remote knowledge (meaning the Seconded + // statement is ignored, but not the Valid statement). + let statements = StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 0], + }; + assert_eq!( + tracker.pending_statements_for(validator_index, candidate_hash), + Some(statements.clone()) + ); + assert_eq!( + tracker.all_pending_statements_for(validator_index), + vec![(ValidatorIndex(0), CompactStatement::Valid(candidate_hash))] + ); + } + + #[test] + fn pending_statements_cleared_when_sending() { + let validator_index = ValidatorIndex(0); + let counterparty = ValidatorIndex(1); + + let mut tracker = GridTracker::default(); + let session_topology = SessionTopologyView { + group_views: vec![( + GroupIndex(0), + GroupSubView { + sending: HashSet::new(), + receiving: HashSet::from([validator_index, counterparty]), + }, + )] + .into_iter() + .collect(), + }; + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let group_index = GroupIndex(0); + let group_size = 3; + let local_knowledge = StatementFilter::blank(group_size); + + let groups = dummy_groups(group_size); + + // Should start with no pending statements. + assert_eq!(tracker.pending_statements_for(validator_index, candidate_hash), None); + assert_eq!(tracker.all_pending_statements_for(validator_index), vec![]); + + // Add the candidate as backed. + tracker.add_backed_candidate( + &session_topology, + candidate_hash, + group_index, + local_knowledge.clone(), + ); + + // Import statement for originator. + tracker + .import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Full, + validator_index, + ) + .ok() + .unwrap(); + tracker.manifest_sent_to(&groups, validator_index, candidate_hash, local_knowledge.clone()); + let statement = CompactStatement::Seconded(candidate_hash); + tracker.learned_fresh_statement(&groups, &session_topology, validator_index, &statement); + + // Import statement for counterparty. + tracker + .import_manifest( + &session_topology, + &groups, + candidate_hash, + 3, + ManifestSummary { + claimed_parent_hash: Hash::repeat_byte(0), + claimed_group_index: group_index, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + }, + }, + ManifestKind::Full, + counterparty, + ) + .ok() + .unwrap(); + tracker.manifest_sent_to(&groups, counterparty, candidate_hash, local_knowledge); + let statement = CompactStatement::Seconded(candidate_hash); + tracker.learned_fresh_statement(&groups, &session_topology, counterparty, &statement); + + // There should be pending statements now. + let statements = StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }; + assert_eq!( + tracker.pending_statements_for(validator_index, candidate_hash), + Some(statements.clone()) + ); + assert_eq!( + tracker.all_pending_statements_for(validator_index), + vec![(ValidatorIndex(0), CompactStatement::Seconded(candidate_hash))] + ); + assert_eq!( + tracker.pending_statements_for(counterparty, candidate_hash), + Some(statements.clone()) + ); + assert_eq!( + tracker.all_pending_statements_for(counterparty), + vec![(ValidatorIndex(0), CompactStatement::Seconded(candidate_hash))] + ); + + tracker.learned_fresh_statement(&groups, &session_topology, validator_index, &statement); + tracker.sent_or_received_direct_statement( + &groups, + validator_index, + counterparty, + &statement, + ); + + // There should be no pending statements now (for the counterparty). + assert_eq!( + tracker.pending_statements_for(counterparty, candidate_hash), + Some(StatementFilter::blank(group_size)) + ); + assert_eq!(tracker.all_pending_statements_for(counterparty), vec![]); + } +} diff --git a/node/network/statement-distribution/src/vstaging/groups.rs b/node/network/statement-distribution/src/vstaging/groups.rs new file mode 100644 index 000000000000..86321b30f220 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/groups.rs @@ -0,0 +1,70 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A utility for tracking groups and their members within a session. + +use polkadot_node_primitives::minimum_votes; +use polkadot_primitives::vstaging::{GroupIndex, IndexedVec, ValidatorIndex}; + +use std::collections::HashMap; + +/// Validator groups within a session, plus some helpful indexing for +/// looking up groups by validator indices or authority discovery ID. +#[derive(Debug, Clone)] +pub struct Groups { + groups: IndexedVec>, + by_validator_index: HashMap, +} + +impl Groups { + /// Create a new [`Groups`] tracker with the groups and discovery keys + /// from the session. + pub fn new(groups: IndexedVec>) -> Self { + let mut by_validator_index = HashMap::new(); + + for (i, group) in groups.iter().enumerate() { + let index = GroupIndex(i as _); + for v in group { + by_validator_index.insert(*v, index); + } + } + + Groups { groups, by_validator_index } + } + + /// Access all the underlying groups. + pub fn all(&self) -> &IndexedVec> { + &self.groups + } + + /// Get the underlying group validators by group index. + pub fn get(&self, group_index: GroupIndex) -> Option<&[ValidatorIndex]> { + self.groups.get(group_index).map(|x| &x[..]) + } + + /// Get the backing group size and backing threshold. + pub fn get_size_and_backing_threshold( + &self, + group_index: GroupIndex, + ) -> Option<(usize, usize)> { + self.get(group_index).map(|g| (g.len(), minimum_votes(g.len()))) + } + + /// Get the group index for a validator by index. + pub fn by_validator_index(&self, validator_index: ValidatorIndex) -> Option { + self.by_validator_index.get(&validator_index).map(|x| *x) + } +} diff --git a/node/network/statement-distribution/src/vstaging/mod.rs b/node/network/statement-distribution/src/vstaging/mod.rs new file mode 100644 index 000000000000..03af4ce81598 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/mod.rs @@ -0,0 +1,2810 @@ +// Copyright 2022 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 . + +//! Implementation of the v2 statement distribution protocol, +//! designed for asynchronous backing. + +use polkadot_node_network_protocol::{ + self as net_protocol, + grid_topology::SessionGridTopology, + peer_set::ValidationVersion, + request_response::{ + incoming::OutgoingResponse, + vstaging::{AttestedCandidateRequest, AttestedCandidateResponse}, + IncomingRequest, IncomingRequestReceiver, Requests, + MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS, + }, + vstaging::{self as protocol_vstaging, StatementFilter}, + IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, +}; +use polkadot_node_primitives::{ + SignedFullStatementWithPVD, StatementWithPVD as FullStatementWithPVD, +}; +use polkadot_node_subsystem::{ + messages::{ + CandidateBackingMessage, HypotheticalCandidate, HypotheticalFrontierRequest, + NetworkBridgeEvent, NetworkBridgeTxMessage, ProspectiveParachainsMessage, + }, + overseer, ActivatedLeaf, +}; +use polkadot_node_subsystem_util::{ + backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator, + runtime::ProspectiveParachainsMode, +}; +use polkadot_primitives::vstaging::{ + AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, IndexedVec, SessionIndex, SessionInfo, SignedStatement, + SigningContext, UncheckedSignedStatement, ValidatorId, ValidatorIndex, +}; + +use sp_keystore::KeystorePtr; + +use fatality::Nested; +use futures::{ + channel::{mpsc, oneshot}, + stream::FuturesUnordered, + SinkExt, StreamExt, +}; + +use std::{ + collections::{ + hash_map::{Entry, HashMap}, + HashSet, + }, + time::{Duration, Instant}, +}; + +use crate::{ + error::{JfyiError, JfyiErrorResult}, + LOG_TARGET, +}; +use candidates::{BadAdvertisement, Candidates, PostConfirmation}; +use cluster::{Accept as ClusterAccept, ClusterTracker, RejectIncoming as ClusterRejectIncoming}; +use grid::GridTracker; +use groups::Groups; +use requests::{CandidateIdentifier, RequestProperties}; +use statement_store::{StatementOrigin, StatementStore}; + +pub use requests::{RequestManager, ResponseManager, UnhandledResponse}; + +mod candidates; +mod cluster; +mod grid; +mod groups; +mod requests; +mod statement_store; + +#[cfg(test)] +mod tests; + +const COST_UNEXPECTED_STATEMENT: Rep = Rep::CostMinor("Unexpected Statement"); +const COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE: Rep = + Rep::CostMinor("Unexpected Statement, missing knowledge for relay parent"); +const COST_EXCESSIVE_SECONDED: Rep = Rep::CostMinor("Sent Excessive `Seconded` Statements"); + +const COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE: Rep = + Rep::CostMinor("Unexpected Manifest, missing knowlege for relay parent"); +const COST_UNEXPECTED_MANIFEST_DISALLOWED: Rep = + Rep::CostMinor("Unexpected Manifest, Peer Disallowed"); +const COST_CONFLICTING_MANIFEST: Rep = Rep::CostMajor("Manifest conflicts with previous"); +const COST_INSUFFICIENT_MANIFEST: Rep = + Rep::CostMajor("Manifest statements insufficient to back candidate"); +const COST_MALFORMED_MANIFEST: Rep = Rep::CostMajor("Manifest is malformed"); +const COST_UNEXPECTED_ACKNOWLEDGEMENT_UNKNOWN_CANDIDATE: Rep = + Rep::CostMinor("Unexpected acknowledgement, unknown candidate"); + +const COST_INVALID_SIGNATURE: Rep = Rep::CostMajor("Invalid Statement Signature"); +const COST_IMPROPERLY_DECODED_RESPONSE: Rep = + Rep::CostMajor("Improperly Encoded Candidate Response"); +const COST_INVALID_RESPONSE: Rep = Rep::CostMajor("Invalid Candidate Response"); +const COST_UNREQUESTED_RESPONSE_STATEMENT: Rep = + Rep::CostMajor("Un-requested Statement In Response"); +const COST_INACCURATE_ADVERTISEMENT: Rep = + Rep::CostMajor("Peer advertised a candidate inaccurately"); + +const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Peer sent unparsable request"); +const COST_INVALID_REQUEST_BITFIELD_SIZE: Rep = + Rep::CostMajor("Attested candidate request bitfields have wrong size"); +const COST_UNEXPECTED_REQUEST: Rep = Rep::CostMajor("Unexpected attested candidate request"); + +const BENEFIT_VALID_RESPONSE: Rep = Rep::BenefitMajor("Peer Answered Candidate Request"); +const BENEFIT_VALID_STATEMENT: Rep = Rep::BenefitMajor("Peer provided a valid statement"); +const BENEFIT_VALID_STATEMENT_FIRST: Rep = + Rep::BenefitMajorFirst("Peer was the first to provide a given valid statement"); + +/// The amount of time to wait before retrying when the node sends a request and it is dropped. +pub(crate) const REQUEST_RETRY_DELAY: Duration = Duration::from_secs(1); + +struct PerRelayParentState { + local_validator: Option, + statement_store: StatementStore, + availability_cores: Vec, + group_rotation_info: GroupRotationInfo, + seconding_limit: usize, + session: SessionIndex, +} + +// per-relay-parent local validator state. +struct LocalValidatorState { + // The index of the validator. + index: ValidatorIndex, + // our validator group + group: GroupIndex, + // the assignment of our validator group, if any. + assignment: Option, + // the 'direct-in-group' communication at this relay-parent. + cluster_tracker: ClusterTracker, + // the grid-level communication at this relay-parent. + grid_tracker: GridTracker, +} + +#[derive(Debug)] +struct PerSessionState { + session_info: SessionInfo, + groups: Groups, + authority_lookup: HashMap, + // is only `None` in the time between seeing a session and + // getting the topology from the gossip-support subsystem + grid_view: Option, + local_validator: Option, +} + +impl PerSessionState { + fn new(session_info: SessionInfo, keystore: &KeystorePtr) -> Self { + let groups = Groups::new(session_info.validator_groups.clone()); + let mut authority_lookup = HashMap::new(); + for (i, ad) in session_info.discovery_keys.iter().cloned().enumerate() { + authority_lookup.insert(ad, ValidatorIndex(i as _)); + } + + let local_validator = polkadot_node_subsystem_util::signing_key_and_index( + session_info.validators.iter(), + keystore, + ); + + PerSessionState { + session_info, + groups, + authority_lookup, + grid_view: None, + local_validator: local_validator.map(|(_key, index)| index), + } + } + + fn supply_topology(&mut self, topology: &SessionGridTopology) { + let grid_view = grid::build_session_topology( + self.session_info.validator_groups.iter(), + topology, + self.local_validator, + ); + + self.grid_view = Some(grid_view); + } +} + +pub(crate) struct State { + /// The utility for managing the implicit and explicit views in a consistent way. + /// + /// We only feed leaves which have prospective parachains enabled to this view. + implicit_view: ImplicitView, + candidates: Candidates, + per_relay_parent: HashMap, + per_session: HashMap, + peers: HashMap, + keystore: KeystorePtr, + authorities: HashMap, + request_manager: RequestManager, + response_manager: ResponseManager, +} + +impl State { + /// Create a new state. + pub(crate) fn new(keystore: KeystorePtr) -> Self { + State { + implicit_view: Default::default(), + candidates: Default::default(), + per_relay_parent: HashMap::new(), + per_session: HashMap::new(), + peers: HashMap::new(), + keystore, + authorities: HashMap::new(), + request_manager: RequestManager::new(), + response_manager: ResponseManager::new(), + } + } + + pub(crate) fn request_and_response_managers( + &mut self, + ) -> (&mut RequestManager, &mut ResponseManager) { + (&mut self.request_manager, &mut self.response_manager) + } +} + +// For the provided validator index, if there is a connected peer controlling the given authority +// ID, then return that peer's `PeerId`. +fn connected_validator_peer( + authorities: &HashMap, + per_session: &PerSessionState, + validator_index: ValidatorIndex, +) -> Option { + per_session + .session_info + .discovery_keys + .get(validator_index.0 as usize) + .and_then(|k| authorities.get(k)) + .map(|p| *p) +} + +struct PeerState { + view: View, + implicit_view: HashSet, + discovery_ids: Option>, +} + +impl PeerState { + // Update the view, returning a vector of implicit relay-parents which weren't previously + // part of the view. + fn update_view(&mut self, new_view: View, local_implicit: &ImplicitView) -> Vec { + let next_implicit = new_view + .iter() + .flat_map(|x| local_implicit.known_allowed_relay_parents_under(x, None)) + .flatten() + .cloned() + .collect::>(); + + let fresh_implicit = next_implicit + .iter() + .filter(|x| !self.implicit_view.contains(x)) + .cloned() + .collect(); + + self.view = new_view; + self.implicit_view = next_implicit; + + fresh_implicit + } + + // Attempt to reconcile the view with new information about the implicit relay parents + // under an active leaf. + fn reconcile_active_leaf(&mut self, leaf_hash: Hash, implicit: &[Hash]) -> Vec { + if !self.view.contains(&leaf_hash) { + return Vec::new() + } + + let mut v = Vec::with_capacity(implicit.len()); + for i in implicit { + if self.implicit_view.insert(*i) { + v.push(*i); + } + } + v + } + + // Whether we know that a peer knows a relay-parent. + // The peer knows the relay-parent if it is either implicit or explicit + // in their view. However, if it is implicit via an active-leaf we don't + // recognize, we will not accurately be able to recognize them as 'knowing' + // the relay-parent. + fn knows_relay_parent(&self, relay_parent: &Hash) -> bool { + self.implicit_view.contains(relay_parent) || self.view.contains(relay_parent) + } + + fn is_authority(&self, authority_id: &AuthorityDiscoveryId) -> bool { + self.discovery_ids.as_ref().map_or(false, |x| x.contains(authority_id)) + } + + fn iter_known_discovery_ids(&self) -> impl Iterator { + self.discovery_ids.as_ref().into_iter().flatten() + } +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn handle_network_update( + ctx: &mut Context, + state: &mut State, + update: NetworkBridgeEvent, + reputation: &mut ReputationAggregator, +) { + match update { + NetworkBridgeEvent::PeerConnected(peer_id, role, protocol_version, mut authority_ids) => { + gum::trace!(target: LOG_TARGET, ?peer_id, ?role, ?protocol_version, "Peer connected"); + + if protocol_version != ValidationVersion::VStaging.into() { + return + } + + if let Some(ref mut authority_ids) = authority_ids { + authority_ids.retain(|a| match state.authorities.entry(a.clone()) { + Entry::Vacant(e) => { + e.insert(peer_id); + true + }, + Entry::Occupied(e) => { + gum::trace!( + target: LOG_TARGET, + authority_id = ?a, + existing_peer = ?e.get(), + new_peer = ?peer_id, + "Ignoring new peer with duplicate authority ID as a bearer of that identity" + ); + + false + }, + }); + } + + state.peers.insert( + peer_id, + PeerState { + view: View::default(), + implicit_view: HashSet::new(), + discovery_ids: authority_ids, + }, + ); + }, + NetworkBridgeEvent::PeerDisconnected(peer_id) => { + if let Some(p) = state.peers.remove(&peer_id) { + for discovery_key in p.discovery_ids.into_iter().flatten() { + state.authorities.remove(&discovery_key); + } + } + }, + NetworkBridgeEvent::NewGossipTopology(topology) => { + let new_session_index = topology.session; + let new_topology = topology.topology; + + if let Some(per_session) = state.per_session.get_mut(&new_session_index) { + per_session.supply_topology(&new_topology); + } + + // TODO [https://github.com/paritytech/polkadot/issues/6194] + // technically, we should account for the fact that the session topology might + // come late, and for all relay-parents with this session, send all grid peers + // any `BackedCandidateInv` messages they might need. + // + // in practice, this is a small issue & the API of receiving topologies could + // be altered to fix it altogether. + }, + NetworkBridgeEvent::PeerMessage(peer_id, message) => match message { + net_protocol::StatementDistributionMessage::V1(_) => return, + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), + ) => return, + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) => + handle_incoming_statement(ctx, state, peer_id, relay_parent, statement, reputation) + .await, + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(inner), + ) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation).await, + net_protocol::StatementDistributionMessage::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(inner), + ) => handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation).await, + }, + NetworkBridgeEvent::PeerViewChange(peer_id, view) => + handle_peer_view_update(ctx, state, peer_id, view).await, + NetworkBridgeEvent::OurViewChange(_view) => { + // handled by `handle_activated_leaf` + }, + NetworkBridgeEvent::UpdatedAuthorityIds(peer_id, authority_ids) => { + gum::trace!( + target: LOG_TARGET, + ?peer_id, + ?authority_ids, + "Updated `AuthorityDiscoveryId`s" + ); + + // Remove the authority IDs which were previously mapped to the peer + // but aren't part of the new set. + state.authorities.retain(|a, p| p != &peer_id || authority_ids.contains(a)); + + // Map the new authority IDs to the peer. + for a in authority_ids.iter().cloned() { + state.authorities.insert(a, peer_id); + } + + if let Some(peer_state) = state.peers.get_mut(&peer_id) { + peer_state.discovery_ids = Some(authority_ids); + } + }, + } +} + +/// If there is a new leaf, this should only be called for leaves which support +/// prospective parachains. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn handle_active_leaves_update( + ctx: &mut Context, + state: &mut State, + activated: &ActivatedLeaf, + leaf_mode: ProspectiveParachainsMode, +) -> JfyiErrorResult<()> { + let seconding_limit = match leaf_mode { + ProspectiveParachainsMode::Disabled => return Ok(()), + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth + 1, + }; + + state + .implicit_view + .activate_leaf(ctx.sender(), activated.hash) + .await + .map_err(JfyiError::ActivateLeafFailure)?; + + let new_relay_parents = + state.implicit_view.all_allowed_relay_parents().cloned().collect::>(); + for new_relay_parent in new_relay_parents.iter().cloned() { + if state.per_relay_parent.contains_key(&new_relay_parent) { + continue + } + + // New leaf: fetch info from runtime API and initialize + // `per_relay_parent`. + + let session_index = polkadot_node_subsystem_util::request_session_index_for_child( + new_relay_parent, + ctx.sender(), + ) + .await + .await + .map_err(JfyiError::RuntimeApiUnavailable)? + .map_err(JfyiError::FetchSessionIndex)?; + + let availability_cores = polkadot_node_subsystem_util::request_availability_cores( + new_relay_parent, + ctx.sender(), + ) + .await + .await + .map_err(JfyiError::RuntimeApiUnavailable)? + .map_err(JfyiError::FetchAvailabilityCores)?; + + let group_rotation_info = + polkadot_node_subsystem_util::request_validator_groups(new_relay_parent, ctx.sender()) + .await + .await + .map_err(JfyiError::RuntimeApiUnavailable)? + .map_err(JfyiError::FetchValidatorGroups)? + .1; + + if !state.per_session.contains_key(&session_index) { + let session_info = polkadot_node_subsystem_util::request_session_info( + new_relay_parent, + session_index, + ctx.sender(), + ) + .await + .await + .map_err(JfyiError::RuntimeApiUnavailable)? + .map_err(JfyiError::FetchSessionInfo)?; + + let session_info = match session_info { + None => { + gum::warn!( + target: LOG_TARGET, + relay_parent = ?new_relay_parent, + "No session info available for current session" + ); + + continue + }, + Some(s) => s, + }; + + state + .per_session + .insert(session_index, PerSessionState::new(session_info, &state.keystore)); + } + + let per_session = state + .per_session + .get(&session_index) + .expect("either existed or just inserted; qed"); + + let local_validator = per_session.local_validator.and_then(|v| { + find_local_validator_state( + v, + &per_session.groups, + &availability_cores, + &group_rotation_info, + seconding_limit, + ) + }); + + state.per_relay_parent.insert( + new_relay_parent, + PerRelayParentState { + local_validator, + statement_store: StatementStore::new(&per_session.groups), + availability_cores, + group_rotation_info, + seconding_limit, + session: session_index, + }, + ); + } + + // Reconcile all peers' views with the active leaf and any relay parents + // it implies. If they learned about the block before we did, this reconciliation will give + // non-empty results and we should send them messages concerning all activated relay-parents. + { + let mut update_peers = Vec::new(); + for (peer, peer_state) in state.peers.iter_mut() { + let fresh = peer_state.reconcile_active_leaf(activated.hash, &new_relay_parents); + if !fresh.is_empty() { + update_peers.push((*peer, fresh)); + } + } + + for (peer, fresh) in update_peers { + for fresh_relay_parent in fresh { + send_peer_messages_for_relay_parent(ctx, state, peer, fresh_relay_parent).await; + } + } + } + + new_leaf_fragment_tree_updates(ctx, state, activated.hash).await; + + Ok(()) +} + +fn find_local_validator_state( + validator_index: ValidatorIndex, + groups: &Groups, + availability_cores: &[CoreState], + group_rotation_info: &GroupRotationInfo, + seconding_limit: usize, +) -> Option { + if groups.all().is_empty() { + return None + } + + let our_group = groups.by_validator_index(validator_index)?; + + // note: this won't work well for on-demand parachains because it only works + // when core assignments to paras are static throughout the session. + + let core = group_rotation_info.core_for_group(our_group, availability_cores.len()); + let para = availability_cores.get(core.0 as usize).and_then(|c| c.para_id()); + let group_validators = groups.get(our_group)?.to_owned(); + + Some(LocalValidatorState { + index: validator_index, + group: our_group, + assignment: para, + cluster_tracker: ClusterTracker::new(group_validators, seconding_limit) + .expect("group is non-empty because we are in it; qed"), + grid_tracker: GridTracker::default(), + }) +} + +pub(crate) fn handle_deactivate_leaves(state: &mut State, leaves: &[Hash]) { + // deactivate the leaf in the implicit view. + for leaf in leaves { + state.implicit_view.deactivate_leaf(*leaf); + } + + let relay_parents = state.implicit_view.all_allowed_relay_parents().collect::>(); + + // fast exit for no-op. + if relay_parents.len() == state.per_relay_parent.len() { + return + } + + // clean up per-relay-parent data based on everything removed. + state.per_relay_parent.retain(|r, _| relay_parents.contains(r)); + + // Clean up all requests + for leaf in leaves { + state.request_manager.remove_by_relay_parent(*leaf); + } + + state.candidates.on_deactivate_leaves(&leaves, |h| relay_parents.contains(h)); + + // clean up sessions based on everything remaining. + let sessions: HashSet<_> = state.per_relay_parent.values().map(|r| r.session).collect(); + state.per_session.retain(|s, _| sessions.contains(s)); +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_peer_view_update( + ctx: &mut Context, + state: &mut State, + peer: PeerId, + new_view: View, +) { + let fresh_implicit = { + let peer_data = match state.peers.get_mut(&peer) { + None => return, + Some(p) => p, + }; + + peer_data.update_view(new_view, &state.implicit_view) + }; + + for new_relay_parent in fresh_implicit { + send_peer_messages_for_relay_parent(ctx, state, peer, new_relay_parent).await; + } +} + +// Returns an iterator over known validator indices, given an iterator over discovery IDs +// and a mapping from discovery IDs to validator indices. +fn find_validator_ids<'a>( + known_discovery_ids: impl IntoIterator, + discovery_mapping: impl Fn(&AuthorityDiscoveryId) -> Option<&'a ValidatorIndex>, +) -> impl Iterator { + known_discovery_ids.into_iter().filter_map(discovery_mapping).cloned() +} + +/// Send a peer, apparently just becoming aware of a relay-parent, all messages +/// concerning that relay-parent. +/// +/// In particular, we send all statements pertaining to our common cluster, +/// as well as all manifests, acknowledgements, or other grid statements. +/// +/// Note that due to the way we handle views, our knowledge of peers' relay parents +/// may "oscillate" with relay parents repeatedly leaving and entering the +/// view of a peer based on the implicit view of active leaves. +/// +/// This function is designed to be cheap and not to send duplicate messages in repeated +/// cases. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_peer_messages_for_relay_parent( + ctx: &mut Context, + state: &mut State, + peer: PeerId, + relay_parent: Hash, +) { + let peer_data = match state.peers.get_mut(&peer) { + None => return, + Some(p) => p, + }; + + let relay_parent_state = match state.per_relay_parent.get_mut(&relay_parent) { + None => return, + Some(s) => s, + }; + + let per_session_state = match state.per_session.get(&relay_parent_state.session) { + None => return, + Some(s) => s, + }; + + for validator_id in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { + per_session_state.authority_lookup.get(a) + }) { + if let Some(local_validator_state) = relay_parent_state.local_validator.as_mut() { + send_pending_cluster_statements( + ctx, + relay_parent, + &peer, + validator_id, + &mut local_validator_state.cluster_tracker, + &state.candidates, + &relay_parent_state.statement_store, + ) + .await; + } + + send_pending_grid_messages( + ctx, + relay_parent, + &peer, + validator_id, + &per_session_state.groups, + relay_parent_state, + &state.candidates, + ) + .await; + } +} + +fn pending_statement_network_message( + statement_store: &StatementStore, + relay_parent: Hash, + peer: &PeerId, + originator: ValidatorIndex, + compact: CompactStatement, +) -> Option<(Vec, net_protocol::VersionedValidationProtocol)> { + statement_store + .validator_statement(originator, compact) + .map(|s| s.as_unchecked().clone()) + .map(|signed| { + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, signed) + }) + .map(|msg| (vec![*peer], Versioned::VStaging(msg).into())) +} + +/// Send a peer all pending cluster statements for a relay parent. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_pending_cluster_statements( + ctx: &mut Context, + relay_parent: Hash, + peer_id: &PeerId, + peer_validator_id: ValidatorIndex, + cluster_tracker: &mut ClusterTracker, + candidates: &Candidates, + statement_store: &StatementStore, +) { + let pending_statements = cluster_tracker.pending_statements_for(peer_validator_id); + let network_messages = pending_statements + .into_iter() + .filter_map(|(originator, compact)| { + if !candidates.is_confirmed(compact.candidate_hash()) { + return None + } + + let res = pending_statement_network_message( + &statement_store, + relay_parent, + peer_id, + originator, + compact.clone(), + ); + + if res.is_some() { + cluster_tracker.note_sent(peer_validator_id, originator, compact); + } + + res + }) + .collect::>(); + + if network_messages.is_empty() { + return + } + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(network_messages)) + .await; +} + +/// Send a peer all pending grid messages / acknowledgements / follow up statements +/// upon learning about a new relay parent. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_pending_grid_messages( + ctx: &mut Context, + relay_parent: Hash, + peer_id: &PeerId, + peer_validator_id: ValidatorIndex, + groups: &Groups, + relay_parent_state: &mut PerRelayParentState, + candidates: &Candidates, +) { + let pending_manifests = { + let local_validator = match relay_parent_state.local_validator.as_mut() { + None => return, + Some(l) => l, + }; + + let grid_tracker = &mut local_validator.grid_tracker; + grid_tracker.pending_manifests_for(peer_validator_id) + }; + + let mut messages: Vec<(Vec, net_protocol::VersionedValidationProtocol)> = Vec::new(); + for (candidate_hash, kind) in pending_manifests { + let confirmed_candidate = match candidates.get_confirmed(&candidate_hash) { + None => continue, // sanity + Some(c) => c, + }; + + let group_index = confirmed_candidate.group_index(); + + let local_knowledge = { + let group_size = match groups.get(group_index) { + None => return, // sanity + Some(x) => x.len(), + }; + + local_knowledge_filter( + group_size, + group_index, + candidate_hash, + &relay_parent_state.statement_store, + ) + }; + + match kind { + grid::ManifestKind::Full => { + let manifest = protocol_vstaging::BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index, + para_id: confirmed_candidate.para_id(), + parent_head_data_hash: confirmed_candidate.parent_head_data_hash(), + statement_knowledge: local_knowledge.clone(), + }; + + let grid = &mut relay_parent_state + .local_validator + .as_mut() + .expect("determined to be some earlier in this function; qed") + .grid_tracker; + + grid.manifest_sent_to( + groups, + peer_validator_id, + candidate_hash, + local_knowledge.clone(), + ); + + messages.push(( + vec![*peer_id], + Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest, + ), + ) + .into(), + )); + }, + grid::ManifestKind::Acknowledgement => { + messages.extend(acknowledgement_and_statement_messages( + *peer_id, + peer_validator_id, + groups, + relay_parent_state, + relay_parent, + group_index, + candidate_hash, + local_knowledge, + )); + }, + } + } + + // Send all remaining pending grid statements for a validator, not just + // those for the acknowledgements we've sent. + // + // otherwise, we might receive statements while the grid peer is "out of view" and then + // not send them when they get back "in view". problem! + { + let grid_tracker = &mut relay_parent_state + .local_validator + .as_mut() + .expect("checked earlier; qed") + .grid_tracker; + + let pending_statements = grid_tracker.all_pending_statements_for(peer_validator_id); + + let extra_statements = + pending_statements.into_iter().filter_map(|(originator, compact)| { + let res = pending_statement_network_message( + &relay_parent_state.statement_store, + relay_parent, + peer_id, + originator, + compact.clone(), + ); + + if res.is_some() { + grid_tracker.sent_or_received_direct_statement( + groups, + originator, + peer_validator_id, + &compact, + ); + } + + res + }); + + messages.extend(extra_statements); + } + + if messages.is_empty() { + return + } + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(messages)).await; +} + +// Imports a locally originating statement and distributes it to peers. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn share_local_statement( + ctx: &mut Context, + state: &mut State, + relay_parent: Hash, + statement: SignedFullStatementWithPVD, + reputation: &mut ReputationAggregator, +) -> JfyiErrorResult<()> { + let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { + None => return Err(JfyiError::InvalidShare), + Some(x) => x, + }; + + gum::debug!( + target: LOG_TARGET, + statement = ?statement.payload().to_compact(), + "Sharing Statement", + ); + + let per_session = match state.per_session.get(&per_relay_parent.session) { + Some(s) => s, + None => return Ok(()), + }; + + let (local_index, local_assignment, local_group) = + match per_relay_parent.local_validator.as_ref() { + None => return Err(JfyiError::InvalidShare), + Some(l) => (l.index, l.assignment, l.group), + }; + + // Two possibilities: either the statement is `Seconded` or we already + // have the candidate. Sanity: check the para-id is valid. + let expected = match statement.payload() { + FullStatementWithPVD::Seconded(ref c, _) => + Some((c.descriptor().para_id, c.descriptor().relay_parent)), + FullStatementWithPVD::Valid(hash) => + state.candidates.get_confirmed(&hash).map(|c| (c.para_id(), c.relay_parent())), + }; + + let is_seconded = match statement.payload() { + FullStatementWithPVD::Seconded(_, _) => true, + FullStatementWithPVD::Valid(_) => false, + }; + + let (expected_para, expected_relay_parent) = match expected { + None => return Err(JfyiError::InvalidShare), + Some(x) => x, + }; + + if local_index != statement.validator_index() { + return Err(JfyiError::InvalidShare) + } + + if is_seconded && + per_relay_parent.statement_store.seconded_count(&local_index) == + per_relay_parent.seconding_limit + { + gum::warn!( + target: LOG_TARGET, + limit = ?per_relay_parent.seconding_limit, + "Local node has issued too many `Seconded` statements", + ); + return Err(JfyiError::InvalidShare) + } + + if local_assignment != Some(expected_para) || relay_parent != expected_relay_parent { + return Err(JfyiError::InvalidShare) + } + + let mut post_confirmation = None; + + // Insert candidate if unknown + more sanity checks. + let compact_statement = { + let compact_statement = FullStatementWithPVD::signed_to_compact(statement.clone()); + let candidate_hash = CandidateHash(*statement.payload().candidate_hash()); + + if let FullStatementWithPVD::Seconded(ref c, ref pvd) = statement.payload() { + post_confirmation = state.candidates.confirm_candidate( + candidate_hash, + c.clone(), + pvd.clone(), + local_group, + ); + }; + + match per_relay_parent.statement_store.insert( + &per_session.groups, + compact_statement.clone(), + StatementOrigin::Local, + ) { + Ok(false) | Err(_) => { + gum::warn!( + target: LOG_TARGET, + statement = ?compact_statement.payload(), + "Candidate backing issued redundant statement?", + ); + return Err(JfyiError::InvalidShare) + }, + Ok(true) => {}, + } + + { + let l = per_relay_parent.local_validator.as_mut().expect("checked above; qed"); + l.cluster_tracker.note_issued(local_index, compact_statement.payload().clone()); + } + + if let Some(ref session_topology) = per_session.grid_view { + let l = per_relay_parent.local_validator.as_mut().expect("checked above; qed"); + l.grid_tracker.learned_fresh_statement( + &per_session.groups, + session_topology, + local_index, + &compact_statement.payload(), + ); + } + + compact_statement + }; + + // send the compact version of the statement to any peers which need it. + circulate_statement( + ctx, + relay_parent, + per_relay_parent, + per_session, + &state.candidates, + &state.authorities, + &state.peers, + compact_statement, + ) + .await; + + if let Some(post_confirmation) = post_confirmation { + apply_post_confirmation(ctx, state, post_confirmation, reputation).await; + } + + Ok(()) +} + +// two kinds of targets: those in our 'cluster' (currently just those in the same group), +// and those we are propagating to through the grid. +#[derive(Debug)] +enum DirectTargetKind { + Cluster, + Grid, +} + +// Circulates a compact statement to all peers who need it: those in the current group of the +// local validator and grid peers which have already indicated that they know the candidate as +// backed. +// +// We only circulate statements for which we have the confirmed candidate, even to the local group. +// +// The group index which is _canonically assigned_ to this parachain must be +// specified already. This function should not be used when the candidate receipt and +// therefore the canonical group for the parachain is unknown. +// +// preconditions: the candidate entry exists in the state under the relay parent +// and the statement has already been imported into the entry. If this is a `Valid` +// statement, then there must be at least one `Seconded` statement. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn circulate_statement( + ctx: &mut Context, + relay_parent: Hash, + relay_parent_state: &mut PerRelayParentState, + per_session: &PerSessionState, + candidates: &Candidates, + authorities: &HashMap, + peers: &HashMap, + statement: SignedStatement, +) { + let session_info = &per_session.session_info; + + let candidate_hash = *statement.payload().candidate_hash(); + + let compact_statement = statement.payload().clone(); + let is_confirmed = candidates.is_confirmed(&candidate_hash); + + let originator = statement.validator_index(); + let (local_validator, targets) = { + let local_validator = match relay_parent_state.local_validator.as_mut() { + Some(v) => v, + None => return, // sanity: nothing to propagate if not a validator. + }; + + let statement_group = per_session.groups.by_validator_index(originator); + + // We're not meant to circulate statements in the cluster until we have the confirmed + // candidate. + let cluster_relevant = Some(local_validator.group) == statement_group; + let cluster_targets = if is_confirmed && cluster_relevant { + Some( + local_validator + .cluster_tracker + .targets() + .iter() + .filter(|&&v| { + local_validator + .cluster_tracker + .can_send(v, originator, compact_statement.clone()) + .is_ok() + }) + .filter(|&v| v != &local_validator.index) + .map(|v| (*v, DirectTargetKind::Cluster)), + ) + } else { + None + }; + + let grid_targets = local_validator + .grid_tracker + .direct_statement_targets(&per_session.groups, originator, &compact_statement) + .into_iter() + .filter(|v| !cluster_relevant || !local_validator.cluster_tracker.targets().contains(v)) + .map(|v| (v, DirectTargetKind::Grid)); + + let targets = cluster_targets + .into_iter() + .flatten() + .chain(grid_targets) + .filter_map(|(v, k)| { + session_info.discovery_keys.get(v.0 as usize).map(|a| (v, a.clone(), k)) + }) + .collect::>(); + + (local_validator, targets) + }; + + let mut statement_to = Vec::new(); + for (target, authority_id, kind) in targets { + // Find peer ID based on authority ID, and also filter to connected. + let peer_id: PeerId = match authorities.get(&authority_id) { + Some(p) if peers.get(p).map_or(false, |p| p.knows_relay_parent(&relay_parent)) => *p, + None | Some(_) => continue, + }; + + match kind { + DirectTargetKind::Cluster => { + // At this point, all peers in the cluster should 'know' + // the candidate, so we don't expect for this to fail. + if let Ok(()) = local_validator.cluster_tracker.can_send( + target, + originator, + compact_statement.clone(), + ) { + local_validator.cluster_tracker.note_sent( + target, + originator, + compact_statement.clone(), + ); + statement_to.push(peer_id); + } + }, + DirectTargetKind::Grid => { + statement_to.push(peer_id); + local_validator.grid_tracker.sent_or_received_direct_statement( + &per_session.groups, + originator, + target, + &compact_statement, + ); + }, + } + } + + // ship off the network messages to the network bridge. + if !statement_to.is_empty() { + gum::debug!( + target: LOG_TARGET, + ?compact_statement, + n_peers = ?statement_to.len(), + "Sending statement to peers", + ); + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + statement_to, + Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + statement.as_unchecked().clone(), + )) + .into(), + )) + .await; + } +} +/// Check a statement signature under this parent hash. +fn check_statement_signature( + session_index: SessionIndex, + validators: &IndexedVec, + relay_parent: Hash, + statement: UncheckedSignedStatement, +) -> std::result::Result { + let signing_context = SigningContext { session_index, parent_hash: relay_parent }; + + validators + .get(statement.unchecked_validator_index()) + .ok_or_else(|| statement.clone()) + .and_then(|v| statement.try_into_checked(&signing_context, v)) +} + +/// Modify the reputation of a peer based on its behavior. +async fn modify_reputation( + reputation: &mut ReputationAggregator, + sender: &mut impl overseer::StatementDistributionSenderTrait, + peer: PeerId, + rep: Rep, +) { + reputation.modify(sender, peer, rep).await; +} + +/// Handle an incoming statement. +/// +/// This checks whether the sender is allowed to send the statement, +/// either via the cluster or the grid. +/// +/// This also checks the signature of the statement. +/// If the statement is fresh, this function guarantees that after completion +/// - The statement is re-circulated to all relevant peers in both the cluster and the grid +/// - If the candidate is out-of-cluster and is backable and importable, all statements about the +/// candidate have been sent to backing +/// - If the candidate is in-cluster and is importable, the statement has been sent to backing +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_incoming_statement( + ctx: &mut Context, + state: &mut State, + peer: PeerId, + relay_parent: Hash, + statement: UncheckedSignedStatement, + reputation: &mut ReputationAggregator, +) { + let peer_state = match state.peers.get(&peer) { + None => { + // sanity: should be impossible. + return + }, + Some(p) => p, + }; + + // Ensure we know the relay parent. + let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { + None => { + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_STATEMENT_MISSING_KNOWLEDGE, + ) + .await; + return + }, + Some(p) => p, + }; + + let per_session = match state.per_session.get(&per_relay_parent.session) { + None => { + gum::warn!( + target: LOG_TARGET, + session = ?per_relay_parent.session, + "Missing expected session info.", + ); + + return + }, + Some(s) => s, + }; + let session_info = &per_session.session_info; + + let local_validator = match per_relay_parent.local_validator.as_mut() { + None => { + // we shouldn't be receiving statements unless we're a validator + // this session. + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + return + }, + Some(l) => l, + }; + + let originator_group = + match per_session.groups.by_validator_index(statement.unchecked_validator_index()) { + Some(g) => g, + None => { + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + return + }, + }; + + let cluster_sender_index = { + // This block of code only returns `Some` when both the originator and + // the sending peer are in the cluster. + + let allowed_senders = local_validator + .cluster_tracker + .senders_for_originator(statement.unchecked_validator_index()); + + allowed_senders + .iter() + .filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (*i, ad))) + .filter(|(_, ad)| peer_state.is_authority(ad)) + .map(|(i, _)| i) + .next() + }; + + let checked_statement = if let Some(cluster_sender_index) = cluster_sender_index { + match handle_cluster_statement( + relay_parent, + &mut local_validator.cluster_tracker, + per_relay_parent.session, + &per_session.session_info, + statement, + cluster_sender_index, + ) { + Ok(Some(s)) => s, + Ok(None) => return, + Err(rep) => { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + return + }, + } + } else { + let grid_sender_index = local_validator + .grid_tracker + .direct_statement_providers( + &per_session.groups, + statement.unchecked_validator_index(), + statement.unchecked_payload(), + ) + .into_iter() + .filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad))) + .filter(|(_, ad)| peer_state.is_authority(ad)) + .map(|(i, _)| i) + .next(); + + if let Some(grid_sender_index) = grid_sender_index { + match handle_grid_statement( + relay_parent, + &mut local_validator.grid_tracker, + per_relay_parent.session, + &per_session, + statement, + grid_sender_index, + ) { + Ok(s) => s, + Err(rep) => { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + return + }, + } + } else { + // Not a cluster or grid peer. + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + return + } + }; + + let statement = checked_statement.payload().clone(); + let originator_index = checked_statement.validator_index(); + let candidate_hash = *checked_statement.payload().candidate_hash(); + + // Insert an unconfirmed candidate entry if needed. Note that if the candidate is already + // confirmed, this ensures that the assigned group of the originator matches the expected group + // of the parachain. + { + let res = state.candidates.insert_unconfirmed( + peer, + candidate_hash, + relay_parent, + originator_group, + None, + ); + + if let Err(BadAdvertisement) = res { + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await; + return + } + } + + let confirmed = state.candidates.get_confirmed(&candidate_hash); + let is_confirmed = state.candidates.is_confirmed(&candidate_hash); + if !is_confirmed { + // If the candidate is not confirmed, note that we should attempt + // to request it from the given peer. + let mut request_entry = + state + .request_manager + .get_or_insert(relay_parent, candidate_hash, originator_group); + + request_entry.add_peer(peer); + + // We only successfully accept statements from the grid on confirmed + // candidates, therefore this check only passes if the statement is from the cluster + request_entry.set_cluster_priority(); + } + + let was_fresh = match per_relay_parent.statement_store.insert( + &per_session.groups, + checked_statement.clone(), + StatementOrigin::Remote, + ) { + Err(statement_store::ValidatorUnknown) => { + // sanity: should never happen. + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + validator_index = ?originator_index, + "Error - accepted message from unknown validator." + ); + + return + }, + Ok(known) => known, + }; + + if was_fresh { + modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT_FIRST).await; + let is_importable = state.candidates.is_importable(&candidate_hash); + + if let Some(ref session_topology) = per_session.grid_view { + local_validator.grid_tracker.learned_fresh_statement( + &per_session.groups, + session_topology, + local_validator.index, + &statement, + ); + } + + if let (true, &Some(confirmed)) = (is_importable, &confirmed) { + send_backing_fresh_statements( + ctx, + candidate_hash, + originator_group, + &relay_parent, + &mut *per_relay_parent, + confirmed, + per_session, + ) + .await; + } + + // We always circulate statements at this point. + circulate_statement( + ctx, + relay_parent, + per_relay_parent, + per_session, + &state.candidates, + &state.authorities, + &state.peers, + checked_statement, + ) + .await; + } else { + modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT).await; + } +} + +/// Checks whether a statement is allowed, whether the signature is accurate, +/// and importing into the cluster tracker if successful. +/// +/// if successful, this returns a checked signed statement if it should be imported +/// or otherwise an error indicating a reputational fault. +fn handle_cluster_statement( + relay_parent: Hash, + cluster_tracker: &mut ClusterTracker, + session: SessionIndex, + session_info: &SessionInfo, + statement: UncheckedSignedStatement, + cluster_sender_index: ValidatorIndex, +) -> Result, Rep> { + // additional cluster checks. + let should_import = { + match cluster_tracker.can_receive( + cluster_sender_index, + statement.unchecked_validator_index(), + statement.unchecked_payload().clone(), + ) { + Ok(ClusterAccept::Ok) => true, + Ok(ClusterAccept::WithPrejudice) => false, + Err(ClusterRejectIncoming::ExcessiveSeconded) => return Err(COST_EXCESSIVE_SECONDED), + Err(ClusterRejectIncoming::CandidateUnknown | ClusterRejectIncoming::Duplicate) => + return Err(COST_UNEXPECTED_STATEMENT), + Err(ClusterRejectIncoming::NotInGroup) => { + // sanity: shouldn't be possible; we already filtered this + // out above. + return Err(COST_UNEXPECTED_STATEMENT) + }, + } + }; + + // Ensure the statement is correctly signed. + let checked_statement = + match check_statement_signature(session, &session_info.validators, relay_parent, statement) + { + Ok(s) => s, + Err(_) => return Err(COST_INVALID_SIGNATURE), + }; + + cluster_tracker.note_received( + cluster_sender_index, + checked_statement.validator_index(), + checked_statement.payload().clone(), + ); + + Ok(if should_import { Some(checked_statement) } else { None }) +} + +/// Checks whether the signature is accurate, +/// importing into the grid tracker if successful. +/// +/// if successful, this returns a checked signed statement if it should be imported +/// or otherwise an error indicating a reputational fault. +fn handle_grid_statement( + relay_parent: Hash, + grid_tracker: &mut GridTracker, + session: SessionIndex, + per_session: &PerSessionState, + statement: UncheckedSignedStatement, + grid_sender_index: ValidatorIndex, +) -> Result { + // Ensure the statement is correctly signed. + let checked_statement = match check_statement_signature( + session, + &per_session.session_info.validators, + relay_parent, + statement, + ) { + Ok(s) => s, + Err(_) => return Err(COST_INVALID_SIGNATURE), + }; + + grid_tracker.sent_or_received_direct_statement( + &per_session.groups, + checked_statement.validator_index(), + grid_sender_index, + &checked_statement.payload(), + ); + + Ok(checked_statement) +} + +/// Send backing fresh statements. This should only be performed on importable & confirmed +/// candidates. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_backing_fresh_statements( + ctx: &mut Context, + candidate_hash: CandidateHash, + group_index: GroupIndex, + relay_parent: &Hash, + relay_parent_state: &mut PerRelayParentState, + confirmed: &candidates::ConfirmedCandidate, + per_session: &PerSessionState, +) { + let group_validators = per_session.groups.get(group_index).unwrap_or(&[]); + let mut imported = Vec::new(); + + for statement in relay_parent_state + .statement_store + .fresh_statements_for_backing(group_validators, candidate_hash) + { + let v = statement.validator_index(); + let compact = statement.payload().clone(); + imported.push((v, compact)); + let carrying_pvd = statement + .clone() + .convert_to_superpayload_with(|statement| match statement { + CompactStatement::Seconded(_) => FullStatementWithPVD::Seconded( + (&**confirmed.candidate_receipt()).clone(), + confirmed.persisted_validation_data().clone(), + ), + CompactStatement::Valid(c_hash) => FullStatementWithPVD::Valid(c_hash), + }) + .expect("statements refer to same candidate; qed"); + + ctx.send_message(CandidateBackingMessage::Statement(*relay_parent, carrying_pvd)) + .await; + } + + for (v, s) in imported { + relay_parent_state.statement_store.note_known_by_backing(v, s); + } +} + +fn local_knowledge_filter( + group_size: usize, + group_index: GroupIndex, + candidate_hash: CandidateHash, + statement_store: &StatementStore, +) -> StatementFilter { + let mut f = StatementFilter::blank(group_size); + statement_store.fill_statement_filter(group_index, candidate_hash, &mut f); + f +} + +// This provides a backable candidate to the grid and dispatches backable candidate announcements +// and acknowledgements via the grid topology. If the session topology is not yet +// available, this will be a no-op. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn provide_candidate_to_grid( + ctx: &mut Context, + candidate_hash: CandidateHash, + relay_parent_state: &mut PerRelayParentState, + confirmed_candidate: &candidates::ConfirmedCandidate, + per_session: &PerSessionState, + authorities: &HashMap, + peers: &HashMap, +) { + let local_validator = match relay_parent_state.local_validator { + Some(ref mut v) => v, + None => return, + }; + + let relay_parent = confirmed_candidate.relay_parent(); + let group_index = confirmed_candidate.group_index(); + + let grid_view = match per_session.grid_view { + Some(ref t) => t, + None => { + gum::debug!( + target: LOG_TARGET, + session = relay_parent_state.session, + "Cannot handle backable candidate due to lack of topology", + ); + + return + }, + }; + + let group_size = match per_session.groups.get(group_index) { + None => { + gum::warn!( + target: LOG_TARGET, + ?candidate_hash, + ?relay_parent, + ?group_index, + session = relay_parent_state.session, + "Handled backed candidate with unknown group?", + ); + + return + }, + Some(g) => g.len(), + }; + + let filter = local_knowledge_filter( + group_size, + group_index, + candidate_hash, + &relay_parent_state.statement_store, + ); + + let actions = local_validator.grid_tracker.add_backed_candidate( + grid_view, + candidate_hash, + group_index, + filter.clone(), + ); + + let manifest = protocol_vstaging::BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index, + para_id: confirmed_candidate.para_id(), + parent_head_data_hash: confirmed_candidate.parent_head_data_hash(), + statement_knowledge: filter.clone(), + }; + let acknowledgement = protocol_vstaging::BackedCandidateAcknowledgement { + candidate_hash, + statement_knowledge: filter.clone(), + }; + + let manifest_message = Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ); + let ack_message = Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(acknowledgement), + ); + + let mut manifest_peers = Vec::new(); + let mut ack_peers = Vec::new(); + + let mut post_statements = Vec::new(); + for (v, action) in actions { + let p = match connected_validator_peer(authorities, per_session, v) { + None => continue, + Some(p) => + if peers.get(&p).map_or(false, |d| d.knows_relay_parent(&relay_parent)) { + p + } else { + continue + }, + }; + + match action { + grid::ManifestKind::Full => manifest_peers.push(p), + grid::ManifestKind::Acknowledgement => ack_peers.push(p), + } + + local_validator.grid_tracker.manifest_sent_to( + &per_session.groups, + v, + candidate_hash, + filter.clone(), + ); + post_statements.extend( + post_acknowledgement_statement_messages( + v, + relay_parent, + &mut local_validator.grid_tracker, + &relay_parent_state.statement_store, + &per_session.groups, + group_index, + candidate_hash, + ) + .into_iter() + .map(|m| (vec![p], m)), + ); + } + + if !manifest_peers.is_empty() { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + n_peers = manifest_peers.len(), + "Sending manifest to peers" + ); + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + manifest_peers, + manifest_message.into(), + )) + .await; + } + + if !ack_peers.is_empty() { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + n_peers = ack_peers.len(), + "Sending acknowledgement to peers" + ); + + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( + ack_peers, + ack_message.into(), + )) + .await; + } + + if !post_statements.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(post_statements)) + .await; + } +} + +fn group_for_para( + availability_cores: &[CoreState], + group_rotation_info: &GroupRotationInfo, + para_id: ParaId, +) -> Option { + // Note: this won't work well for on-demand parachains as it assumes that core assignments are + // fixed across blocks. + let core_index = availability_cores.iter().position(|c| c.para_id() == Some(para_id)); + + core_index + .map(|c| group_rotation_info.group_for_core(CoreIndex(c as _), availability_cores.len())) +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn fragment_tree_update_inner( + ctx: &mut Context, + state: &mut State, + active_leaf_hash: Option, + required_parent_info: Option<(Hash, ParaId)>, + known_hypotheticals: Option>, +) { + // 1. get hypothetical candidates + let hypotheticals = match known_hypotheticals { + None => state.candidates.frontier_hypotheticals(required_parent_info), + Some(h) => h, + }; + + // 2. find out which are in the frontier + let frontier = { + let (tx, rx) = oneshot::channel(); + ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalFrontier( + HypotheticalFrontierRequest { + candidates: hypotheticals, + fragment_tree_relay_parent: active_leaf_hash, + backed_in_path_only: false, + }, + tx, + )) + .await; + + match rx.await { + Ok(frontier) => frontier, + Err(oneshot::Canceled) => return, + } + }; + // 3. note that they are importable under a given leaf hash. + for (hypo, membership) in frontier { + // skip parablocks outside of the frontier + if membership.is_empty() { + continue + } + + for (leaf_hash, _) in membership { + state.candidates.note_importable_under(&hypo, leaf_hash); + } + + // 4. for confirmed candidates, send all statements which are new to backing. + if let HypotheticalCandidate::Complete { + candidate_hash, + receipt, + persisted_validation_data: _, + } = hypo + { + let confirmed_candidate = state.candidates.get_confirmed(&candidate_hash); + let prs = state.per_relay_parent.get_mut(&receipt.descriptor().relay_parent); + if let (Some(confirmed), Some(prs)) = (confirmed_candidate, prs) { + let group_index = group_for_para( + &prs.availability_cores, + &prs.group_rotation_info, + receipt.descriptor().para_id, + ); + + let per_session = state.per_session.get(&prs.session); + if let (Some(per_session), Some(group_index)) = (per_session, group_index) { + send_backing_fresh_statements( + ctx, + candidate_hash, + group_index, + &receipt.descriptor().relay_parent, + prs, + confirmed, + per_session, + ) + .await; + } + } + } + } +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn new_leaf_fragment_tree_updates( + ctx: &mut Context, + state: &mut State, + leaf_hash: Hash, +) { + fragment_tree_update_inner(ctx, state, Some(leaf_hash), None, None).await +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn prospective_backed_notification_fragment_tree_updates( + ctx: &mut Context, + state: &mut State, + para_id: ParaId, + para_head: Hash, +) { + fragment_tree_update_inner(ctx, state, None, Some((para_head, para_id)), None).await +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn new_confirmed_candidate_fragment_tree_updates( + ctx: &mut Context, + state: &mut State, + candidate: HypotheticalCandidate, +) { + fragment_tree_update_inner(ctx, state, None, None, Some(vec![candidate])).await +} + +struct ManifestImportSuccess<'a> { + relay_parent_state: &'a mut PerRelayParentState, + per_session: &'a PerSessionState, + acknowledge: bool, + sender_index: ValidatorIndex, +} + +/// Handles the common part of incoming manifests of both types (full & acknowledgement) +/// +/// Basic sanity checks around data, importing the manifest into the grid tracker, finding the +/// sending peer's validator index, reporting the peer for any misbehavior, etc. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_incoming_manifest_common<'a, Context>( + ctx: &mut Context, + peer: PeerId, + peers: &HashMap, + per_relay_parent: &'a mut HashMap, + per_session: &'a HashMap, + candidates: &mut Candidates, + candidate_hash: CandidateHash, + relay_parent: Hash, + para_id: ParaId, + manifest_summary: grid::ManifestSummary, + manifest_kind: grid::ManifestKind, + reputation: &mut ReputationAggregator, +) -> Option> { + // 1. sanity checks: peer is connected, relay-parent in state, para ID matches group index. + let peer_state = match peers.get(&peer) { + None => return None, + Some(p) => p, + }; + + let relay_parent_state = match per_relay_parent.get_mut(&relay_parent) { + None => { + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE, + ) + .await; + return None + }, + Some(s) => s, + }; + + let per_session = match per_session.get(&relay_parent_state.session) { + None => return None, + Some(s) => s, + }; + + let local_validator = match relay_parent_state.local_validator.as_mut() { + None => { + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE, + ) + .await; + return None + }, + Some(x) => x, + }; + + let expected_group = group_for_para( + &relay_parent_state.availability_cores, + &relay_parent_state.group_rotation_info, + para_id, + ); + + if expected_group != Some(manifest_summary.claimed_group_index) { + modify_reputation(reputation, ctx.sender(), peer, COST_MALFORMED_MANIFEST).await; + return None + } + + let grid_topology = match per_session.grid_view.as_ref() { + None => return None, + Some(x) => x, + }; + + let sender_index = grid_topology + .iter_sending_for_group(manifest_summary.claimed_group_index, manifest_kind) + .filter_map(|i| per_session.session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad))) + .filter(|(_, ad)| peer_state.is_authority(ad)) + .map(|(i, _)| i) + .next(); + + let sender_index = match sender_index { + None => { + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_MANIFEST_DISALLOWED) + .await; + return None + }, + Some(s) => s, + }; + + // 2. sanity checks: peer is validator, bitvec size, import into grid tracker + let group_index = manifest_summary.claimed_group_index; + let claimed_parent_hash = manifest_summary.claimed_parent_hash; + let acknowledge = match local_validator.grid_tracker.import_manifest( + grid_topology, + &per_session.groups, + candidate_hash, + relay_parent_state.seconding_limit, + manifest_summary, + manifest_kind, + sender_index, + ) { + Ok(x) => x, + Err(grid::ManifestImportError::Conflicting) => { + modify_reputation(reputation, ctx.sender(), peer, COST_CONFLICTING_MANIFEST).await; + return None + }, + Err(grid::ManifestImportError::Overflow) => { + modify_reputation(reputation, ctx.sender(), peer, COST_EXCESSIVE_SECONDED).await; + return None + }, + Err(grid::ManifestImportError::Insufficient) => { + modify_reputation(reputation, ctx.sender(), peer, COST_INSUFFICIENT_MANIFEST).await; + return None + }, + Err(grid::ManifestImportError::Malformed) => { + modify_reputation(reputation, ctx.sender(), peer, COST_MALFORMED_MANIFEST).await; + return None + }, + Err(grid::ManifestImportError::Disallowed) => { + modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_MANIFEST_DISALLOWED) + .await; + return None + }, + }; + + // 3. if accepted by grid, insert as unconfirmed. + if let Err(BadAdvertisement) = candidates.insert_unconfirmed( + peer, + candidate_hash, + relay_parent, + group_index, + Some((claimed_parent_hash, para_id)), + ) { + modify_reputation(reputation, ctx.sender(), peer, COST_INACCURATE_ADVERTISEMENT).await; + return None + } + + Some(ManifestImportSuccess { relay_parent_state, per_session, acknowledge, sender_index }) +} + +/// Produce a list of network messages to send to a peer, following acknowledgement of a manifest. +/// This notes the messages as sent within the grid state. +fn post_acknowledgement_statement_messages( + recipient: ValidatorIndex, + relay_parent: Hash, + grid_tracker: &mut GridTracker, + statement_store: &StatementStore, + groups: &Groups, + group_index: GroupIndex, + candidate_hash: CandidateHash, +) -> Vec { + let sending_filter = match grid_tracker.pending_statements_for(recipient, candidate_hash) { + None => return Vec::new(), + Some(f) => f, + }; + + let mut messages = Vec::new(); + for statement in + statement_store.group_statements(groups, group_index, candidate_hash, &sending_filter) + { + grid_tracker.sent_or_received_direct_statement( + groups, + statement.validator_index(), + recipient, + statement.payload(), + ); + + messages.push(Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + statement.as_unchecked().clone(), + ) + .into(), + )); + } + + messages +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_incoming_manifest( + ctx: &mut Context, + state: &mut State, + peer: PeerId, + manifest: net_protocol::vstaging::BackedCandidateManifest, + reputation: &mut ReputationAggregator, +) { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?manifest.candidate_hash, + ?peer, + "Received incoming manifest", + ); + + let x = match handle_incoming_manifest_common( + ctx, + peer, + &state.peers, + &mut state.per_relay_parent, + &state.per_session, + &mut state.candidates, + manifest.candidate_hash, + manifest.relay_parent, + manifest.para_id, + grid::ManifestSummary { + claimed_parent_hash: manifest.parent_head_data_hash, + claimed_group_index: manifest.group_index, + statement_knowledge: manifest.statement_knowledge, + }, + grid::ManifestKind::Full, + reputation, + ) + .await + { + Some(x) => x, + None => return, + }; + + let ManifestImportSuccess { relay_parent_state, per_session, acknowledge, sender_index } = x; + + if acknowledge { + // 4. if already known within grid (confirmed & backed), acknowledge candidate + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?manifest.candidate_hash, + "Known candidate - acknowledging manifest", + ); + + let local_knowledge = { + let group_size = match per_session.groups.get(manifest.group_index) { + None => return, // sanity + Some(x) => x.len(), + }; + + local_knowledge_filter( + group_size, + manifest.group_index, + manifest.candidate_hash, + &relay_parent_state.statement_store, + ) + }; + + let messages = acknowledgement_and_statement_messages( + peer, + sender_index, + &per_session.groups, + relay_parent_state, + manifest.relay_parent, + manifest.group_index, + manifest.candidate_hash, + local_knowledge, + ); + + if !messages.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(messages)).await; + } + } else if !state.candidates.is_confirmed(&manifest.candidate_hash) { + // 5. if unconfirmed, add request entry + gum::trace!( + target: LOG_TARGET, + candidate_hash = ?manifest.candidate_hash, + "Unknown candidate - requesting", + ); + + state + .request_manager + .get_or_insert(manifest.relay_parent, manifest.candidate_hash, manifest.group_index) + .add_peer(peer); + } +} + +/// Produces acknowledgement and statement messages to be sent over the network, +/// noting that they have been sent within the grid topology tracker as well. +fn acknowledgement_and_statement_messages( + peer: PeerId, + validator_index: ValidatorIndex, + groups: &Groups, + relay_parent_state: &mut PerRelayParentState, + relay_parent: Hash, + group_index: GroupIndex, + candidate_hash: CandidateHash, + local_knowledge: StatementFilter, +) -> Vec<(Vec, net_protocol::VersionedValidationProtocol)> { + let local_validator = match relay_parent_state.local_validator.as_mut() { + None => return Vec::new(), + Some(l) => l, + }; + + let acknowledgement = protocol_vstaging::BackedCandidateAcknowledgement { + candidate_hash, + statement_knowledge: local_knowledge.clone(), + }; + + let msg = Versioned::VStaging( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(acknowledgement), + ); + + let mut messages = vec![(vec![peer], msg.into())]; + + local_validator.grid_tracker.manifest_sent_to( + groups, + validator_index, + candidate_hash, + local_knowledge.clone(), + ); + + let statement_messages = post_acknowledgement_statement_messages( + validator_index, + relay_parent, + &mut local_validator.grid_tracker, + &relay_parent_state.statement_store, + &groups, + group_index, + candidate_hash, + ); + + messages.extend(statement_messages.into_iter().map(|m| (vec![peer], m))); + + messages +} + +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn handle_incoming_acknowledgement( + ctx: &mut Context, + state: &mut State, + peer: PeerId, + acknowledgement: net_protocol::vstaging::BackedCandidateAcknowledgement, + reputation: &mut ReputationAggregator, +) { + // The key difference between acknowledgments and full manifests is that only + // the candidate hash is included alongside the bitfields, so the candidate + // must be confirmed for us to even process it. + + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?acknowledgement.candidate_hash, + ?peer, + "Received incoming acknowledgement", + ); + + let candidate_hash = acknowledgement.candidate_hash; + let (relay_parent, parent_head_data_hash, group_index, para_id) = { + match state.candidates.get_confirmed(&candidate_hash) { + Some(c) => (c.relay_parent(), c.parent_head_data_hash(), c.group_index(), c.para_id()), + None => { + modify_reputation( + reputation, + ctx.sender(), + peer, + COST_UNEXPECTED_ACKNOWLEDGEMENT_UNKNOWN_CANDIDATE, + ) + .await; + return + }, + } + }; + + let x = match handle_incoming_manifest_common( + ctx, + peer, + &state.peers, + &mut state.per_relay_parent, + &state.per_session, + &mut state.candidates, + candidate_hash, + relay_parent, + para_id, + grid::ManifestSummary { + claimed_parent_hash: parent_head_data_hash, + claimed_group_index: group_index, + statement_knowledge: acknowledgement.statement_knowledge, + }, + grid::ManifestKind::Acknowledgement, + reputation, + ) + .await + { + Some(x) => x, + None => return, + }; + + let ManifestImportSuccess { relay_parent_state, per_session, sender_index, .. } = x; + + let local_validator = match relay_parent_state.local_validator.as_mut() { + None => return, + Some(l) => l, + }; + + let messages = post_acknowledgement_statement_messages( + sender_index, + relay_parent, + &mut local_validator.grid_tracker, + &relay_parent_state.statement_store, + &per_session.groups, + group_index, + candidate_hash, + ); + + if !messages.is_empty() { + ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages( + messages.into_iter().map(|m| (vec![peer], m)).collect(), + )) + .await; + } +} + +/// Handle a notification of a candidate being backed. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn handle_backed_candidate_message( + ctx: &mut Context, + state: &mut State, + candidate_hash: CandidateHash, +) { + // If the candidate is unknown or unconfirmed, it's a race (pruned before receiving message) + // or a bug. Ignore if so + let confirmed = match state.candidates.get_confirmed(&candidate_hash) { + None => { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + "Received backed candidate notification for unknown or unconfirmed", + ); + + return + }, + Some(c) => c, + }; + + let relay_parent_state = match state.per_relay_parent.get_mut(&confirmed.relay_parent()) { + None => return, + Some(s) => s, + }; + + let per_session = match state.per_session.get(&relay_parent_state.session) { + None => return, + Some(s) => s, + }; + + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + group_index = ?confirmed.group_index(), + "Candidate Backed - initiating grid distribution & child fetches" + ); + + provide_candidate_to_grid( + ctx, + candidate_hash, + relay_parent_state, + confirmed, + per_session, + &state.authorities, + &state.peers, + ) + .await; + + // Search for children of the backed candidate to request. + prospective_backed_notification_fragment_tree_updates( + ctx, + state, + confirmed.para_id(), + confirmed.candidate_receipt().descriptor().para_head, + ) + .await; +} + +/// Sends all messages about a candidate to all peers in the cluster, +/// with `Seconded` statements first. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn send_cluster_candidate_statements( + ctx: &mut Context, + state: &mut State, + candidate_hash: CandidateHash, + relay_parent: Hash, +) { + let relay_parent_state = match state.per_relay_parent.get_mut(&relay_parent) { + None => return, + Some(s) => s, + }; + + let per_session = match state.per_session.get(&relay_parent_state.session) { + None => return, + Some(s) => s, + }; + + let local_group = match relay_parent_state.local_validator.as_mut() { + None => return, + Some(v) => v.group, + }; + + let group_size = match per_session.groups.get(local_group) { + None => return, + Some(g) => g.len(), + }; + + let statements: Vec<_> = relay_parent_state + .statement_store + .group_statements( + &per_session.groups, + local_group, + candidate_hash, + &StatementFilter::full(group_size), + ) + .map(|x| x.clone()) + .collect(); + + for statement in statements { + circulate_statement( + ctx, + relay_parent, + relay_parent_state, + per_session, + &state.candidates, + &state.authorities, + &state.peers, + statement, + ) + .await; + } +} + +/// Applies state & p2p updates as a result of a newly confirmed candidate. +/// +/// This punishes peers which advertised the candidate incorrectly, as well as +/// doing an importability analysis of the confirmed candidate and providing +/// statements to the backing subsystem if importable. It also cleans up +/// any pending requests for the candidate. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +async fn apply_post_confirmation( + ctx: &mut Context, + state: &mut State, + post_confirmation: PostConfirmation, + reputation: &mut ReputationAggregator, +) { + for peer in post_confirmation.reckoning.incorrect { + modify_reputation(reputation, ctx.sender(), peer, COST_INACCURATE_ADVERTISEMENT).await; + } + + let candidate_hash = post_confirmation.hypothetical.candidate_hash(); + state.request_manager.remove_for(candidate_hash); + + send_cluster_candidate_statements( + ctx, + state, + candidate_hash, + post_confirmation.hypothetical.relay_parent(), + ) + .await; + new_confirmed_candidate_fragment_tree_updates(ctx, state, post_confirmation.hypothetical).await; +} + +/// Dispatch pending requests for candidate data & statements. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn dispatch_requests(ctx: &mut Context, state: &mut State) { + if !state.request_manager.has_pending_requests() { + return + } + + let peers = &state.peers; + let peer_advertised = |identifier: &CandidateIdentifier, peer: &_| { + let peer_data = peers.get(peer)?; + + let relay_parent_state = state.per_relay_parent.get(&identifier.relay_parent)?; + let per_session = state.per_session.get(&relay_parent_state.session)?; + + let local_validator = relay_parent_state.local_validator.as_ref()?; + + for validator_id in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { + per_session.authority_lookup.get(a) + }) { + // For cluster members, they haven't advertised any statements in particular, + // but have surely sent us some. + if local_validator + .cluster_tracker + .knows_candidate(validator_id, identifier.candidate_hash) + { + return Some(StatementFilter::blank(local_validator.cluster_tracker.targets().len())) + } + + let filter = local_validator + .grid_tracker + .advertised_statements(validator_id, &identifier.candidate_hash); + + if let Some(f) = filter { + return Some(f) + } + } + + None + }; + let request_props = |identifier: &CandidateIdentifier| { + let &CandidateIdentifier { relay_parent, group_index, .. } = identifier; + + let relay_parent_state = state.per_relay_parent.get(&relay_parent)?; + let per_session = state.per_session.get(&relay_parent_state.session)?; + let group = per_session.groups.get(group_index)?; + let seconding_limit = relay_parent_state.seconding_limit; + + // Request nothing which would be an 'over-seconded' statement. + let mut unwanted_mask = StatementFilter::blank(group.len()); + for (i, v) in group.iter().enumerate() { + if relay_parent_state.statement_store.seconded_count(v) >= seconding_limit { + unwanted_mask.seconded_in_group.set(i, true); + } + } + + // don't require a backing threshold for cluster candidates. + let require_backing = relay_parent_state.local_validator.as_ref()?.group != group_index; + + Some(RequestProperties { + unwanted_mask, + backing_threshold: if require_backing { + Some(polkadot_node_primitives::minimum_votes(group.len())) + } else { + None + }, + }) + }; + + while let Some(request) = state.request_manager.next_request( + &mut state.response_manager, + request_props, + peer_advertised, + ) { + // Peer is supposedly connected. + ctx.send_message(NetworkBridgeTxMessage::SendRequests( + vec![Requests::AttestedCandidateVStaging(request)], + IfDisconnected::ImmediateError, + )) + .await; + } +} + +/// Wait on the next incoming response. If there are no requests pending, this +/// future never resolves. It is the responsibility of the user of this API +/// to interrupt the future. +pub(crate) async fn receive_response(response_manager: &mut ResponseManager) -> UnhandledResponse { + match response_manager.incoming().await { + Some(r) => r, + None => futures::future::pending().await, + } +} + +/// Wait on the next soonest retry on a pending request. If there are no retries pending, this +/// future never resolves. Note that this only signals that a request is ready to retry; the user of +/// this API must call `dispatch_requests`. +pub(crate) async fn next_retry(request_manager: &mut RequestManager) { + match request_manager.next_retry_time() { + Some(instant) => + futures_timer::Delay::new(instant.saturating_duration_since(Instant::now())).await, + None => futures::future::pending().await, + } +} + +/// Handles an incoming response. This does the actual work of validating the response, +/// importing statements, sending acknowledgements, etc. +#[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] +pub(crate) async fn handle_response( + ctx: &mut Context, + state: &mut State, + response: UnhandledResponse, + reputation: &mut ReputationAggregator, +) { + let &requests::CandidateIdentifier { relay_parent, candidate_hash, group_index } = + response.candidate_identifier(); + + let post_confirmation = { + let relay_parent_state = match state.per_relay_parent.get_mut(&relay_parent) { + None => return, + Some(s) => s, + }; + + let per_session = match state.per_session.get(&relay_parent_state.session) { + None => return, + Some(s) => s, + }; + + let group = match per_session.groups.get(group_index) { + None => return, + Some(g) => g, + }; + + let res = response.validate_response( + &mut state.request_manager, + group, + relay_parent_state.session, + |v| per_session.session_info.validators.get(v).map(|x| x.clone()), + |para, g_index| { + let expected_group = group_for_para( + &relay_parent_state.availability_cores, + &relay_parent_state.group_rotation_info, + para, + ); + + Some(g_index) == expected_group + }, + ); + + for (peer, rep) in res.reputation_changes { + modify_reputation(reputation, ctx.sender(), peer, rep).await; + } + + let (candidate, pvd, statements) = match res.request_status { + requests::CandidateRequestStatus::Outdated => return, + requests::CandidateRequestStatus::Incomplete => return, + requests::CandidateRequestStatus::Complete { + candidate, + persisted_validation_data, + statements, + } => (candidate, persisted_validation_data, statements), + }; + + for statement in statements { + let _ = relay_parent_state.statement_store.insert( + &per_session.groups, + statement, + StatementOrigin::Remote, + ); + } + + if let Some(post_confirmation) = + state.candidates.confirm_candidate(candidate_hash, candidate, pvd, group_index) + { + post_confirmation + } else { + gum::warn!( + target: LOG_TARGET, + ?candidate_hash, + "Candidate re-confirmed by request/response: logic error", + ); + + return + } + }; + + // Note that this implicitly circulates all statements via the cluster. + apply_post_confirmation(ctx, state, post_confirmation, reputation).await; + + let confirmed = state.candidates.get_confirmed(&candidate_hash).expect("just confirmed; qed"); + + // Although the candidate is confirmed, it isn't yet on the + // hypothetical frontier of the fragment tree. Later, when it is, + // we will import statements. + if !confirmed.is_importable(None) { + return + } + + let relay_parent_state = match state.per_relay_parent.get_mut(&relay_parent) { + None => return, + Some(s) => s, + }; + + let per_session = match state.per_session.get(&relay_parent_state.session) { + None => return, + Some(s) => s, + }; + + send_backing_fresh_statements( + ctx, + candidate_hash, + group_index, + &relay_parent, + relay_parent_state, + confirmed, + per_session, + ) + .await; + + // we don't need to send acknowledgement yet because + // 1. the candidate is not known yet, so cannot be backed. any previous confirmation is a bug, + // because `apply_post_confirmation` is meant to clear requests. + // 2. providing the statements to backing will lead to 'Backed' message. + // 3. on 'Backed' we will send acknowledgements/follow up statements when this becomes + // includable. +} + +/// Answer an incoming request for a candidate. +pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) { + let ResponderMessage { request, sent_feedback } = message; + let AttestedCandidateRequest { candidate_hash, ref mask } = &request.payload; + + // Signal to the responder that we started processing this request. + let _ = sent_feedback.send(()); + + let confirmed = match state.candidates.get_confirmed(&candidate_hash) { + None => return, // drop request, candidate not known. + Some(c) => c, + }; + + let relay_parent_state = match state.per_relay_parent.get(&confirmed.relay_parent()) { + None => return, + Some(s) => s, + }; + + let local_validator = match relay_parent_state.local_validator.as_ref() { + None => return, + Some(s) => s, + }; + + let per_session = match state.per_session.get(&relay_parent_state.session) { + None => return, + Some(s) => s, + }; + + let peer_data = match state.peers.get(&request.peer) { + None => return, + Some(d) => d, + }; + + let group_size = per_session + .groups + .get(confirmed.group_index()) + .expect("group from session's candidate always known; qed") + .len(); + + // check request bitfields are right size. + if mask.seconded_in_group.len() != group_size || mask.validated_in_group.len() != group_size { + let _ = request.send_outgoing_response(OutgoingResponse { + result: Err(()), + reputation_changes: vec![COST_INVALID_REQUEST_BITFIELD_SIZE], + sent_feedback: None, + }); + + return + } + + // check peer is allowed to request the candidate (i.e. we've sent them a manifest) + { + let mut can_request = false; + for validator_id in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| { + per_session.authority_lookup.get(a) + }) { + if local_validator.grid_tracker.can_request(validator_id, *candidate_hash) { + can_request = true; + break + } + } + + if !can_request { + let _ = request.send_outgoing_response(OutgoingResponse { + result: Err(()), + reputation_changes: vec![COST_UNEXPECTED_REQUEST], + sent_feedback: None, + }); + + return + } + } + + // Transform mask with 'OR' semantics into one with 'AND' semantics for the API used + // below. + let and_mask = StatementFilter { + seconded_in_group: !mask.seconded_in_group.clone(), + validated_in_group: !mask.validated_in_group.clone(), + }; + + let response = AttestedCandidateResponse { + candidate_receipt: (&**confirmed.candidate_receipt()).clone(), + persisted_validation_data: confirmed.persisted_validation_data().clone(), + statements: relay_parent_state + .statement_store + .group_statements( + &per_session.groups, + confirmed.group_index(), + *candidate_hash, + &and_mask, + ) + .map(|s| s.as_unchecked().clone()) + .collect(), + }; + + let _ = request.send_response(response); +} + +/// Messages coming from the background respond task. +pub(crate) struct ResponderMessage { + request: IncomingRequest, + sent_feedback: oneshot::Sender<()>, +} + +/// A fetching task, taking care of fetching candidates via request/response. +/// +/// Runs in a background task and feeds request to [`answer_request`] through [`MuxedMessage`]. +pub(crate) async fn respond_task( + mut receiver: IncomingRequestReceiver, + mut sender: mpsc::Sender, +) { + let mut pending_out = FuturesUnordered::new(); + loop { + // Ensure we are not handling too many requests in parallel. + if pending_out.len() >= MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as usize { + // Wait for one to finish: + pending_out.next().await; + } + + let req = match receiver.recv(|| vec![COST_INVALID_REQUEST]).await.into_nested() { + Ok(Ok(v)) => v, + Err(fatal) => { + gum::debug!(target: LOG_TARGET, error = ?fatal, "Shutting down request responder"); + return + }, + Ok(Err(jfyi)) => { + gum::debug!(target: LOG_TARGET, error = ?jfyi, "Decoding request failed"); + continue + }, + }; + + let (pending_sent_tx, pending_sent_rx) = oneshot::channel(); + if let Err(err) = sender + .feed(ResponderMessage { request: req, sent_feedback: pending_sent_tx }) + .await + { + gum::debug!(target: LOG_TARGET, ?err, "Shutting down responder"); + return + } + pending_out.push(pending_sent_rx); + } +} diff --git a/node/network/statement-distribution/src/vstaging/requests.rs b/node/network/statement-distribution/src/vstaging/requests.rs new file mode 100644 index 000000000000..2593d81ba0b2 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/requests.rs @@ -0,0 +1,1248 @@ +// Copyright 2022 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. + +//! A requester for full information on candidates. +//! +//! 1. We use `RequestManager::get_or_insert().get_mut()` to add and mutate [`RequestedCandidate`]s, +//! either setting the +//! priority or adding a peer we know has the candidate. We currently prioritize "cluster" +//! candidates (those from our own group, although the cluster mechanism could be made to include +//! multiple groups in the future) over "grid" candidates (those from other groups). +//! +//! 2. The main loop of the module will invoke [`RequestManager::next_request`] in a loop until it +//! returns `None`, +//! dispatching all requests with the `NetworkBridgeTxMessage`. The receiving half of the channel is +//! owned by the [`RequestManager`]. +//! +//! 3. The main loop of the module will also select over [`RequestManager::await_incoming`] to +//! receive +//! [`UnhandledResponse`]s, which it then validates using [`UnhandledResponse::validate_response`] +//! (which requires state not owned by the request manager). + +use super::{ + BENEFIT_VALID_RESPONSE, BENEFIT_VALID_STATEMENT, COST_IMPROPERLY_DECODED_RESPONSE, + COST_INVALID_RESPONSE, COST_INVALID_SIGNATURE, COST_UNREQUESTED_RESPONSE_STATEMENT, + REQUEST_RETRY_DELAY, +}; +use crate::LOG_TARGET; + +use polkadot_node_network_protocol::{ + request_response::{ + outgoing::{Recipient as RequestRecipient, RequestError}, + vstaging::{AttestedCandidateRequest, AttestedCandidateResponse}, + OutgoingRequest, OutgoingResult, MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS, + }, + vstaging::StatementFilter, + PeerId, UnifiedReputationChange as Rep, +}; +use polkadot_primitives::vstaging::{ + CandidateHash, CommittedCandidateReceipt, CompactStatement, GroupIndex, Hash, ParaId, + PersistedValidationData, SessionIndex, SignedStatement, SigningContext, ValidatorId, + ValidatorIndex, +}; + +use futures::{future::BoxFuture, prelude::*, stream::FuturesUnordered}; + +use std::{ + collections::{ + hash_map::{Entry as HEntry, HashMap}, + HashSet, VecDeque, + }, + time::Instant, +}; + +/// An identifier for a candidate. +/// +/// In this module, we are requesting candidates +/// for which we have no information other than the candidate hash and statements signed +/// by validators. It is possible for validators for multiple groups to abuse this lack of +/// information: until we actually get the preimage of this candidate we cannot confirm +/// anything other than the candidate hash. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct CandidateIdentifier { + /// The relay-parent this candidate is ostensibly under. + pub relay_parent: Hash, + /// The hash of the candidate. + pub candidate_hash: CandidateHash, + /// The index of the group claiming to be assigned to the candidate's + /// para. + pub group_index: GroupIndex, +} + +struct TaggedResponse { + identifier: CandidateIdentifier, + requested_peer: PeerId, + props: RequestProperties, + response: OutgoingResult, +} + +/// A pending request. +#[derive(Debug)] +pub struct RequestedCandidate { + priority: Priority, + known_by: VecDeque, + /// Has the request been sent out and a response not yet received? + in_flight: bool, + /// The timestamp for the next time we should retry, if the response failed. + next_retry_time: Option, +} + +impl RequestedCandidate { + fn is_pending(&self) -> bool { + if self.in_flight { + return false + } + + if let Some(next_retry_time) = self.next_retry_time { + let can_retry = Instant::now() >= next_retry_time; + if !can_retry { + return false + } + } + + true + } +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum Origin { + Cluster = 0, + Unspecified = 1, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Priority { + origin: Origin, + attempts: usize, +} + +/// An entry for manipulating a requested candidate. +pub struct Entry<'a> { + prev_index: usize, + identifier: CandidateIdentifier, + by_priority: &'a mut Vec<(Priority, CandidateIdentifier)>, + requested: &'a mut RequestedCandidate, +} + +impl<'a> Entry<'a> { + /// Add a peer to the set of known peers. + pub fn add_peer(&mut self, peer: PeerId) { + if !self.requested.known_by.contains(&peer) { + self.requested.known_by.push_back(peer); + } + } + + /// Note that the candidate is required for the cluster. + pub fn set_cluster_priority(&mut self) { + self.requested.priority.origin = Origin::Cluster; + + insert_or_update_priority( + &mut *self.by_priority, + Some(self.prev_index), + self.identifier.clone(), + self.requested.priority.clone(), + ); + } +} + +/// A manager for outgoing requests. +pub struct RequestManager { + requests: HashMap, + // sorted by priority. + by_priority: Vec<(Priority, CandidateIdentifier)>, + // all unique identifiers for the candidate. + unique_identifiers: HashMap>, +} + +impl RequestManager { + /// Create a new [`RequestManager`]. + pub fn new() -> Self { + RequestManager { + requests: HashMap::new(), + by_priority: Vec::new(), + unique_identifiers: HashMap::new(), + } + } + + /// Gets an [`Entry`] for mutating a request and inserts it if the + /// manager doesn't store this request already. + pub fn get_or_insert( + &mut self, + relay_parent: Hash, + candidate_hash: CandidateHash, + group_index: GroupIndex, + ) -> Entry { + let identifier = CandidateIdentifier { relay_parent, candidate_hash, group_index }; + + let (candidate, fresh) = match self.requests.entry(identifier.clone()) { + HEntry::Occupied(e) => (e.into_mut(), false), + HEntry::Vacant(e) => ( + e.insert(RequestedCandidate { + priority: Priority { attempts: 0, origin: Origin::Unspecified }, + known_by: VecDeque::new(), + in_flight: false, + next_retry_time: None, + }), + true, + ), + }; + + let priority_index = if fresh { + self.unique_identifiers + .entry(candidate_hash) + .or_default() + .insert(identifier.clone()); + + insert_or_update_priority( + &mut self.by_priority, + None, + identifier.clone(), + candidate.priority.clone(), + ) + } else { + match self + .by_priority + .binary_search(&(candidate.priority.clone(), identifier.clone())) + { + Ok(i) => i, + Err(_) => unreachable!("requested candidates always have a priority entry; qed"), + } + }; + + Entry { + prev_index: priority_index, + identifier, + by_priority: &mut self.by_priority, + requested: candidate, + } + } + + /// Remove all pending requests for the given candidate. + pub fn remove_for(&mut self, candidate: CandidateHash) { + if let Some(identifiers) = self.unique_identifiers.remove(&candidate) { + self.by_priority.retain(|(_priority, id)| !identifiers.contains(&id)); + for id in identifiers { + self.requests.remove(&id); + } + } + } + + /// Remove based on relay-parent. + pub fn remove_by_relay_parent(&mut self, relay_parent: Hash) { + let mut candidate_hashes = HashSet::new(); + + // Remove from `by_priority` and `requests`. + self.by_priority.retain(|(_priority, id)| { + let retain = relay_parent != id.relay_parent; + if !retain { + self.requests.remove(id); + candidate_hashes.insert(id.candidate_hash); + } + retain + }); + + // Remove from `unique_identifiers`. + for candidate_hash in candidate_hashes { + match self.unique_identifiers.entry(candidate_hash) { + HEntry::Occupied(mut entry) => { + entry.get_mut().retain(|id| relay_parent != id.relay_parent); + if entry.get().is_empty() { + entry.remove(); + } + }, + // We can expect to encounter vacant entries, but only if nodes are misbehaving and + // we don't use a deduplicating collection; there are no issues from ignoring it. + HEntry::Vacant(_) => (), + } + } + } + + /// Returns true if there are pending requests that are dispatchable. + pub fn has_pending_requests(&self) -> bool { + for (_id, entry) in &self.requests { + if entry.is_pending() { + return true + } + } + + false + } + + /// Returns an instant at which the next request to be retried will be ready. + pub fn next_retry_time(&mut self) -> Option { + let mut next = None; + for (_id, request) in &self.requests { + if let Some(next_retry_time) = request.next_retry_time { + if next.map_or(true, |next| next_retry_time < next) { + next = Some(next_retry_time); + } + } + } + next + } + + /// Yields the next request to dispatch, if there is any. + /// + /// This function accepts two closures as an argument. + /// + /// The first closure is used to gather information about the desired + /// properties of a response, which is used to select targets and validate + /// the response later on. + /// + /// The second closure is used to determine the specific advertised + /// statements by a peer, to be compared against the mask and backing + /// threshold and returns `None` if the peer is no longer connected. + pub fn next_request( + &mut self, + response_manager: &mut ResponseManager, + request_props: impl Fn(&CandidateIdentifier) -> Option, + peer_advertised: impl Fn(&CandidateIdentifier, &PeerId) -> Option, + ) -> Option> { + if response_manager.len() >= MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as usize { + return None + } + + let mut res = None; + + // loop over all requests, in order of priority. + // do some active maintenance of the connected peers. + // dispatch the first request which is not in-flight already. + + let mut cleanup_outdated = Vec::new(); + for (i, (_priority, id)) in self.by_priority.iter().enumerate() { + let entry = match self.requests.get_mut(&id) { + None => { + gum::error!( + target: LOG_TARGET, + identifier = ?id, + "Missing entry for priority queue member", + ); + + continue + }, + Some(e) => e, + }; + + if !entry.is_pending() { + continue + } + + let props = match request_props(&id) { + None => { + cleanup_outdated.push((i, id.clone())); + continue + }, + Some(s) => s, + }; + + let target = match find_request_target_with_update( + &mut entry.known_by, + id, + &props, + &peer_advertised, + ) { + None => continue, + Some(t) => t, + }; + + let (request, response_fut) = OutgoingRequest::new( + RequestRecipient::Peer(target), + AttestedCandidateRequest { + candidate_hash: id.candidate_hash, + mask: props.unwanted_mask.clone(), + }, + ); + + let stored_id = id.clone(); + response_manager.push(Box::pin(async move { + TaggedResponse { + identifier: stored_id, + requested_peer: target, + props, + response: response_fut.await, + } + })); + + entry.in_flight = true; + + res = Some(request); + break + } + + for (priority_index, identifier) in cleanup_outdated.into_iter().rev() { + self.by_priority.remove(priority_index); + self.requests.remove(&identifier); + if let HEntry::Occupied(mut e) = + self.unique_identifiers.entry(identifier.candidate_hash) + { + e.get_mut().remove(&identifier); + if e.get().is_empty() { + e.remove(); + } + } + } + + res + } +} + +/// A manager for pending responses. +pub struct ResponseManager { + pending_responses: FuturesUnordered>, +} + +impl ResponseManager { + pub fn new() -> Self { + Self { pending_responses: FuturesUnordered::new() } + } + + /// Await the next incoming response to a sent request, or immediately + /// return `None` if there are no pending responses. + pub async fn incoming(&mut self) -> Option { + self.pending_responses + .next() + .await + .map(|response| UnhandledResponse { response }) + } + + fn len(&self) -> usize { + self.pending_responses.len() + } + + fn push(&mut self, response: BoxFuture<'static, TaggedResponse>) { + self.pending_responses.push(response); + } +} + +/// Properties used in target selection and validation of a request. +#[derive(Clone)] +pub struct RequestProperties { + /// A mask for limiting the statements the response is allowed to contain. + /// The mask has `OR` semantics: statements by validators corresponding to bits + /// in the mask are not desired. It also returns the required backing threshold + /// for the candidate. + pub unwanted_mask: StatementFilter, + /// The required backing threshold, if any. If this is `Some`, then requests will only + /// be made to peers which can provide enough statements to back the candidate, when + /// taking into account the `unwanted_mask`, and a response will only be validated + /// in the case of those statements. + /// + /// If this is `None`, it is assumed that only the candidate itself is needed. + pub backing_threshold: Option, +} + +/// Finds a valid request target, returning `None` if none exists. +/// Cleans up disconnected peers and places the returned peer at the back of the queue. +fn find_request_target_with_update( + known_by: &mut VecDeque, + candidate_identifier: &CandidateIdentifier, + props: &RequestProperties, + peer_advertised: impl Fn(&CandidateIdentifier, &PeerId) -> Option, +) -> Option { + let mut prune = Vec::new(); + let mut target = None; + for (i, p) in known_by.iter().enumerate() { + let mut filter = match peer_advertised(candidate_identifier, p) { + None => { + prune.push(i); + continue + }, + Some(f) => f, + }; + + filter.mask_seconded(&props.unwanted_mask.seconded_in_group); + filter.mask_valid(&props.unwanted_mask.validated_in_group); + if seconded_and_sufficient(&filter, props.backing_threshold) { + target = Some((i, *p)); + break + } + } + + let prune_count = prune.len(); + for i in prune { + known_by.remove(i); + } + + if let Some((i, p)) = target { + known_by.remove(i - prune_count); + known_by.push_back(p); + Some(p) + } else { + None + } +} + +fn seconded_and_sufficient(filter: &StatementFilter, backing_threshold: Option) -> bool { + backing_threshold.map_or(true, |t| filter.has_seconded() && filter.backing_validators() >= t) +} + +/// A response to a request, which has not yet been handled. +pub struct UnhandledResponse { + response: TaggedResponse, +} + +impl UnhandledResponse { + /// Get the candidate identifier which the corresponding request + /// was classified under. + pub fn candidate_identifier(&self) -> &CandidateIdentifier { + &self.response.identifier + } + + /// Validate the response. If the response is valid, this will yield the + /// candidate, the [`PersistedValidationData`] of the candidate, and requested + /// checked statements. + /// + /// Valid responses are defined as those which provide a valid candidate + /// and signatures which match the identifier, and provide enough statements to back the + /// candidate. + /// + /// This will also produce a record of misbehaviors by peers: + /// * If the response is partially valid, misbehavior by the responding peer. + /// * If there are other peers which have advertised the same candidate for different + /// relay-parents or para-ids, misbehavior reports for those peers will also be generated. + /// + /// Finally, in the case that the response is either valid or partially valid, + /// this will clean up all remaining requests for the candidate in the manager. + /// + /// As parameters, the user should supply the canonical group array as well + /// as a mapping from validator index to validator ID. The validator pubkey mapping + /// will not be queried except for validator indices in the group. + pub fn validate_response( + self, + manager: &mut RequestManager, + group: &[ValidatorIndex], + session: SessionIndex, + validator_key_lookup: impl Fn(ValidatorIndex) -> Option, + allowed_para_lookup: impl Fn(ParaId, GroupIndex) -> bool, + ) -> ResponseValidationOutput { + let UnhandledResponse { + response: TaggedResponse { identifier, requested_peer, props, response }, + } = self; + + // handle races if the candidate is no longer known. + // this could happen if we requested the candidate under two + // different identifiers at the same time, and received a valid + // response on the other. + // + // it could also happen in the case that we had a request in-flight + // and the request entry was garbage-collected on outdated relay parent. + let entry = match manager.requests.get_mut(&identifier) { + None => + return ResponseValidationOutput { + requested_peer, + reputation_changes: Vec::new(), + request_status: CandidateRequestStatus::Outdated, + }, + Some(e) => e, + }; + + let priority_index = match manager + .by_priority + .binary_search(&(entry.priority.clone(), identifier.clone())) + { + Ok(i) => i, + Err(_) => unreachable!("requested candidates always have a priority entry; qed"), + }; + + // Set the next retry time before clearing the `in_flight` flag. + entry.next_retry_time = Some(Instant::now() + REQUEST_RETRY_DELAY); + entry.in_flight = false; + entry.priority.attempts += 1; + + // update the location in the priority queue. + insert_or_update_priority( + &mut manager.by_priority, + Some(priority_index), + identifier.clone(), + entry.priority.clone(), + ); + + let complete_response = match response { + Err(RequestError::InvalidResponse(e)) => { + gum::trace!( + target: LOG_TARGET, + err = ?e, + peer = ?requested_peer, + "Improperly encoded response" + ); + + return ResponseValidationOutput { + requested_peer, + reputation_changes: vec![(requested_peer, COST_IMPROPERLY_DECODED_RESPONSE)], + request_status: CandidateRequestStatus::Incomplete, + } + }, + Err(RequestError::NetworkError(_) | RequestError::Canceled(_)) => + return ResponseValidationOutput { + requested_peer, + reputation_changes: vec![], + request_status: CandidateRequestStatus::Incomplete, + }, + Ok(response) => response, + }; + + let output = validate_complete_response( + &identifier, + props, + complete_response, + requested_peer, + group, + session, + validator_key_lookup, + allowed_para_lookup, + ); + + if let CandidateRequestStatus::Complete { .. } = output.request_status { + manager.remove_for(identifier.candidate_hash); + } + + output + } +} + +fn validate_complete_response( + identifier: &CandidateIdentifier, + props: RequestProperties, + response: AttestedCandidateResponse, + requested_peer: PeerId, + group: &[ValidatorIndex], + session: SessionIndex, + validator_key_lookup: impl Fn(ValidatorIndex) -> Option, + allowed_para_lookup: impl Fn(ParaId, GroupIndex) -> bool, +) -> ResponseValidationOutput { + let RequestProperties { backing_threshold, mut unwanted_mask } = props; + + // sanity check bitmask size. this is based entirely on + // local logic here. + if !unwanted_mask.has_len(group.len()) { + gum::error!( + target: LOG_TARGET, + group_len = group.len(), + "Logic bug: group size != sent bitmask len" + ); + + // resize and attempt to continue. + unwanted_mask.seconded_in_group.resize(group.len(), true); + unwanted_mask.validated_in_group.resize(group.len(), true); + } + + let invalid_candidate_output = || ResponseValidationOutput { + request_status: CandidateRequestStatus::Incomplete, + reputation_changes: vec![(requested_peer, COST_INVALID_RESPONSE)], + requested_peer, + }; + + // sanity-check candidate response. + // note: roughly ascending cost of operations + { + if response.candidate_receipt.descriptor.relay_parent != identifier.relay_parent { + return invalid_candidate_output() + } + + if response.candidate_receipt.descriptor.persisted_validation_data_hash != + response.persisted_validation_data.hash() + { + return invalid_candidate_output() + } + + if !allowed_para_lookup( + response.candidate_receipt.descriptor.para_id, + identifier.group_index, + ) { + return invalid_candidate_output() + } + + if response.candidate_receipt.hash() != identifier.candidate_hash { + return invalid_candidate_output() + } + } + + // statement checks. + let mut rep_changes = Vec::new(); + let statements = { + let mut statements = + Vec::with_capacity(std::cmp::min(response.statements.len(), group.len() * 2)); + + let mut received_filter = StatementFilter::blank(group.len()); + + let index_in_group = |v: ValidatorIndex| group.iter().position(|x| &v == x); + + let signing_context = + SigningContext { parent_hash: identifier.relay_parent, session_index: session }; + + for unchecked_statement in response.statements.into_iter().take(group.len() * 2) { + // ensure statement is from a validator in the group. + let i = match index_in_group(unchecked_statement.unchecked_validator_index()) { + Some(i) => i, + None => { + rep_changes.push((requested_peer, COST_UNREQUESTED_RESPONSE_STATEMENT)); + continue + }, + }; + + // ensure statement is on the correct candidate hash. + if unchecked_statement.unchecked_payload().candidate_hash() != + &identifier.candidate_hash + { + rep_changes.push((requested_peer, COST_UNREQUESTED_RESPONSE_STATEMENT)); + continue + } + + // filter out duplicates or statements outside the mask. + // note on indexing: we have ensured that the bitmask and the + // duplicate trackers have the correct size for the group. + match unchecked_statement.unchecked_payload() { + CompactStatement::Seconded(_) => { + if unwanted_mask.seconded_in_group[i] { + rep_changes.push((requested_peer, COST_UNREQUESTED_RESPONSE_STATEMENT)); + continue + } + + if received_filter.seconded_in_group[i] { + rep_changes.push((requested_peer, COST_UNREQUESTED_RESPONSE_STATEMENT)); + continue + } + }, + CompactStatement::Valid(_) => { + if unwanted_mask.validated_in_group[i] { + rep_changes.push((requested_peer, COST_UNREQUESTED_RESPONSE_STATEMENT)); + continue + } + + if received_filter.validated_in_group[i] { + rep_changes.push((requested_peer, COST_UNREQUESTED_RESPONSE_STATEMENT)); + continue + } + }, + } + + let validator_public = + match validator_key_lookup(unchecked_statement.unchecked_validator_index()) { + None => { + rep_changes.push((requested_peer, COST_INVALID_SIGNATURE)); + continue + }, + Some(p) => p, + }; + + let checked_statement = + match unchecked_statement.try_into_checked(&signing_context, &validator_public) { + Err(_) => { + rep_changes.push((requested_peer, COST_INVALID_SIGNATURE)); + continue + }, + Ok(checked) => checked, + }; + + match checked_statement.payload() { + CompactStatement::Seconded(_) => { + received_filter.seconded_in_group.set(i, true); + }, + CompactStatement::Valid(_) => { + received_filter.validated_in_group.set(i, true); + }, + } + + statements.push(checked_statement); + rep_changes.push((requested_peer, BENEFIT_VALID_STATEMENT)); + } + + // Only accept responses which are sufficient, according to our + // required backing threshold. + if !seconded_and_sufficient(&received_filter, backing_threshold) { + return invalid_candidate_output() + } + + statements + }; + + rep_changes.push((requested_peer, BENEFIT_VALID_RESPONSE)); + + ResponseValidationOutput { + requested_peer, + request_status: CandidateRequestStatus::Complete { + candidate: response.candidate_receipt, + persisted_validation_data: response.persisted_validation_data, + statements, + }, + reputation_changes: rep_changes, + } +} + +/// The status of the candidate request after the handling of a response. +#[derive(Debug, PartialEq)] +pub enum CandidateRequestStatus { + /// The request was outdated at the point of receiving the response. + Outdated, + /// The response either did not arrive or was invalid. + Incomplete, + /// The response completed the request. Statements sent beyond the + /// mask have been ignored. + Complete { + candidate: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + statements: Vec, + }, +} + +/// Output of the response validation. +#[derive(Debug, PartialEq)] +pub struct ResponseValidationOutput { + /// The peer we requested from. + pub requested_peer: PeerId, + /// The status of the request. + pub request_status: CandidateRequestStatus, + /// Any reputation changes as a result of validating the response. + pub reputation_changes: Vec<(PeerId, Rep)>, +} + +fn insert_or_update_priority( + priority_sorted: &mut Vec<(Priority, CandidateIdentifier)>, + prev_index: Option, + candidate_identifier: CandidateIdentifier, + new_priority: Priority, +) -> usize { + if let Some(prev_index) = prev_index { + // GIGO: this behaves strangely if prev-index is not for the + // expected identifier. + if priority_sorted[prev_index].0 == new_priority { + // unchanged. + return prev_index + } else { + priority_sorted.remove(prev_index); + } + } + + let item = (new_priority, candidate_identifier); + match priority_sorted.binary_search(&item) { + Ok(i) => i, // ignore if already present. + Err(i) => { + priority_sorted.insert(i, item); + i + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use polkadot_primitives::HeadData; + use polkadot_primitives_test_helpers as test_helpers; + + fn dummy_pvd() -> PersistedValidationData { + PersistedValidationData { + parent_head: HeadData(vec![7, 8, 9]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + } + } + + #[test] + fn test_remove_by_relay_parent() { + let parent_a = Hash::from_low_u64_le(1); + let parent_b = Hash::from_low_u64_le(2); + let parent_c = Hash::from_low_u64_le(3); + + let candidate_a1 = CandidateHash(Hash::from_low_u64_le(11)); + let candidate_a2 = CandidateHash(Hash::from_low_u64_le(12)); + let candidate_b1 = CandidateHash(Hash::from_low_u64_le(21)); + let candidate_b2 = CandidateHash(Hash::from_low_u64_le(22)); + let candidate_c1 = CandidateHash(Hash::from_low_u64_le(31)); + let duplicate_hash = CandidateHash(Hash::from_low_u64_le(31)); + + let mut request_manager = RequestManager::new(); + request_manager.get_or_insert(parent_a, candidate_a1, 1.into()); + request_manager.get_or_insert(parent_a, candidate_a2, 1.into()); + request_manager.get_or_insert(parent_b, candidate_b1, 1.into()); + request_manager.get_or_insert(parent_b, candidate_b2, 2.into()); + request_manager.get_or_insert(parent_c, candidate_c1, 2.into()); + request_manager.get_or_insert(parent_a, duplicate_hash, 1.into()); + + assert_eq!(request_manager.requests.len(), 6); + assert_eq!(request_manager.by_priority.len(), 6); + assert_eq!(request_manager.unique_identifiers.len(), 5); + + request_manager.remove_by_relay_parent(parent_a); + + assert_eq!(request_manager.requests.len(), 3); + assert_eq!(request_manager.by_priority.len(), 3); + assert_eq!(request_manager.unique_identifiers.len(), 3); + + assert!(!request_manager.unique_identifiers.contains_key(&candidate_a1)); + assert!(!request_manager.unique_identifiers.contains_key(&candidate_a2)); + // Duplicate hash should still be there (under a different parent). + assert!(request_manager.unique_identifiers.contains_key(&duplicate_hash)); + + request_manager.remove_by_relay_parent(parent_b); + + assert_eq!(request_manager.requests.len(), 1); + assert_eq!(request_manager.by_priority.len(), 1); + assert_eq!(request_manager.unique_identifiers.len(), 1); + + assert!(!request_manager.unique_identifiers.contains_key(&candidate_b1)); + assert!(!request_manager.unique_identifiers.contains_key(&candidate_b2)); + + request_manager.remove_by_relay_parent(parent_c); + + assert!(request_manager.requests.is_empty()); + assert!(request_manager.by_priority.is_empty()); + assert!(request_manager.unique_identifiers.is_empty()); + } + + #[test] + fn test_priority_ordering() { + let parent_a = Hash::from_low_u64_le(1); + let parent_b = Hash::from_low_u64_le(2); + let parent_c = Hash::from_low_u64_le(3); + + let candidate_a1 = CandidateHash(Hash::from_low_u64_le(11)); + let candidate_a2 = CandidateHash(Hash::from_low_u64_le(12)); + let candidate_b1 = CandidateHash(Hash::from_low_u64_le(21)); + let candidate_b2 = CandidateHash(Hash::from_low_u64_le(22)); + let candidate_c1 = CandidateHash(Hash::from_low_u64_le(31)); + + let mut request_manager = RequestManager::new(); + + // Add some entries, set a couple of them to cluster (high) priority. + let identifier_a1 = request_manager + .get_or_insert(parent_a, candidate_a1, 1.into()) + .identifier + .clone(); + let identifier_a2 = { + let mut entry = request_manager.get_or_insert(parent_a, candidate_a2, 1.into()); + entry.set_cluster_priority(); + entry.identifier.clone() + }; + let identifier_b1 = request_manager + .get_or_insert(parent_b, candidate_b1, 1.into()) + .identifier + .clone(); + let identifier_b2 = request_manager + .get_or_insert(parent_b, candidate_b2, 2.into()) + .identifier + .clone(); + let identifier_c1 = { + let mut entry = request_manager.get_or_insert(parent_c, candidate_c1, 2.into()); + entry.set_cluster_priority(); + entry.identifier.clone() + }; + + let attempts = 0; + assert_eq!( + request_manager.by_priority, + vec![ + (Priority { origin: Origin::Cluster, attempts }, identifier_a2), + (Priority { origin: Origin::Cluster, attempts }, identifier_c1), + (Priority { origin: Origin::Unspecified, attempts }, identifier_a1), + (Priority { origin: Origin::Unspecified, attempts }, identifier_b1), + (Priority { origin: Origin::Unspecified, attempts }, identifier_b2), + ] + ); + } + + // Test case where candidate is requested under two different identifiers at the same time. + // Should result in `Outdated` error. + #[test] + fn handle_outdated_response_due_to_requests_for_different_identifiers() { + let mut request_manager = RequestManager::new(); + let mut response_manager = ResponseManager::new(); + + let relay_parent = Hash::from_low_u64_le(1); + let mut candidate_receipt = test_helpers::dummy_committed_candidate_receipt(relay_parent); + let persisted_validation_data = dummy_pvd(); + candidate_receipt.descriptor.persisted_validation_data_hash = + persisted_validation_data.hash(); + let candidate = candidate_receipt.hash(); + let requested_peer = PeerId::random(); + + let identifier1 = request_manager + .get_or_insert(relay_parent, candidate, 1.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate, 1.into()) + .add_peer(requested_peer); + let identifier2 = request_manager + .get_or_insert(relay_parent, candidate, 2.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate, 2.into()) + .add_peer(requested_peer); + + assert_ne!(identifier1, identifier2); + assert_eq!(request_manager.requests.len(), 2); + + let group_size = 3; + let group = &[ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(2)]; + + let unwanted_mask = StatementFilter::blank(group_size); + let request_properties = RequestProperties { unwanted_mask, backing_threshold: None }; + + // Get requests. + { + let request_props = + |_identifier: &CandidateIdentifier| Some((&request_properties).clone()); + let peer_advertised = |_identifier: &CandidateIdentifier, _peer: &_| { + Some(StatementFilter::full(group_size)) + }; + let outgoing = request_manager + .next_request(&mut response_manager, request_props, peer_advertised) + .unwrap(); + assert_eq!(outgoing.payload.candidate_hash, candidate); + let outgoing = request_manager + .next_request(&mut response_manager, request_props, peer_advertised) + .unwrap(); + assert_eq!(outgoing.payload.candidate_hash, candidate); + } + + // Validate first response. + { + let statements = vec![]; + let response = UnhandledResponse { + response: TaggedResponse { + identifier: identifier1, + requested_peer, + props: request_properties.clone(), + response: Ok(AttestedCandidateResponse { + candidate_receipt: candidate_receipt.clone(), + persisted_validation_data: persisted_validation_data.clone(), + statements, + }), + }, + }; + let validator_key_lookup = |_v| None; + let allowed_para_lookup = |_para, _g_index| true; + let statements = vec![]; + let output = response.validate_response( + &mut request_manager, + group, + 0, + validator_key_lookup, + allowed_para_lookup, + ); + assert_eq!( + output, + ResponseValidationOutput { + requested_peer, + request_status: CandidateRequestStatus::Complete { + candidate: candidate_receipt.clone(), + persisted_validation_data: persisted_validation_data.clone(), + statements, + }, + reputation_changes: vec![(requested_peer, BENEFIT_VALID_RESPONSE)], + } + ); + } + + // Try to validate second response. + { + let statements = vec![]; + let response = UnhandledResponse { + response: TaggedResponse { + identifier: identifier2, + requested_peer, + props: request_properties, + response: Ok(AttestedCandidateResponse { + candidate_receipt: candidate_receipt.clone(), + persisted_validation_data: persisted_validation_data.clone(), + statements, + }), + }, + }; + let validator_key_lookup = |_v| None; + let allowed_para_lookup = |_para, _g_index| true; + let output = response.validate_response( + &mut request_manager, + group, + 0, + validator_key_lookup, + allowed_para_lookup, + ); + assert_eq!( + output, + ResponseValidationOutput { + requested_peer, + request_status: CandidateRequestStatus::Outdated, + reputation_changes: vec![], + } + ); + } + } + + // Test case where we had a request in-flight and the request entry was garbage-collected on + // outdated relay parent. + #[test] + fn handle_outdated_response_due_to_garbage_collection() { + let mut request_manager = RequestManager::new(); + let mut response_manager = ResponseManager::new(); + + let relay_parent = Hash::from_low_u64_le(1); + let mut candidate_receipt = test_helpers::dummy_committed_candidate_receipt(relay_parent); + let persisted_validation_data = dummy_pvd(); + candidate_receipt.descriptor.persisted_validation_data_hash = + persisted_validation_data.hash(); + let candidate = candidate_receipt.hash(); + let requested_peer = PeerId::random(); + + let identifier = request_manager + .get_or_insert(relay_parent, candidate, 1.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate, 1.into()) + .add_peer(requested_peer); + + let group_size = 3; + let group = &[ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(2)]; + + let unwanted_mask = StatementFilter::blank(group_size); + let request_properties = RequestProperties { unwanted_mask, backing_threshold: None }; + let peer_advertised = + |_identifier: &CandidateIdentifier, _peer: &_| Some(StatementFilter::full(group_size)); + + // Get request once successfully. + { + let request_props = + |_identifier: &CandidateIdentifier| Some((&request_properties).clone()); + let outgoing = request_manager + .next_request(&mut response_manager, request_props, peer_advertised) + .unwrap(); + assert_eq!(outgoing.payload.candidate_hash, candidate); + } + + // Garbage collect based on relay parent. + request_manager.remove_by_relay_parent(relay_parent); + + // Try to validate response. + { + let statements = vec![]; + let response = UnhandledResponse { + response: TaggedResponse { + identifier, + requested_peer, + props: request_properties, + response: Ok(AttestedCandidateResponse { + candidate_receipt: candidate_receipt.clone(), + persisted_validation_data: persisted_validation_data.clone(), + statements, + }), + }, + }; + let validator_key_lookup = |_v| None; + let allowed_para_lookup = |_para, _g_index| true; + let output = response.validate_response( + &mut request_manager, + group, + 0, + validator_key_lookup, + allowed_para_lookup, + ); + assert_eq!( + output, + ResponseValidationOutput { + requested_peer, + request_status: CandidateRequestStatus::Outdated, + reputation_changes: vec![], + } + ); + } + } + + #[test] + fn should_clean_up_after_successful_requests() { + let mut request_manager = RequestManager::new(); + let mut response_manager = ResponseManager::new(); + + let relay_parent = Hash::from_low_u64_le(1); + let mut candidate_receipt = test_helpers::dummy_committed_candidate_receipt(relay_parent); + let persisted_validation_data = dummy_pvd(); + candidate_receipt.descriptor.persisted_validation_data_hash = + persisted_validation_data.hash(); + let candidate = candidate_receipt.hash(); + let requested_peer = PeerId::random(); + + let identifier = request_manager + .get_or_insert(relay_parent, candidate, 1.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate, 1.into()) + .add_peer(requested_peer); + + assert_eq!(request_manager.requests.len(), 1); + assert_eq!(request_manager.by_priority.len(), 1); + + let group_size = 3; + let group = &[ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(2)]; + + let unwanted_mask = StatementFilter::blank(group_size); + let request_properties = RequestProperties { unwanted_mask, backing_threshold: None }; + let peer_advertised = + |_identifier: &CandidateIdentifier, _peer: &_| Some(StatementFilter::full(group_size)); + + // Get request once successfully. + { + let request_props = + |_identifier: &CandidateIdentifier| Some((&request_properties).clone()); + let outgoing = request_manager + .next_request(&mut response_manager, request_props, peer_advertised) + .unwrap(); + assert_eq!(outgoing.payload.candidate_hash, candidate); + } + + // Validate response. + { + let statements = vec![]; + let response = UnhandledResponse { + response: TaggedResponse { + identifier, + requested_peer, + props: request_properties.clone(), + response: Ok(AttestedCandidateResponse { + candidate_receipt: candidate_receipt.clone(), + persisted_validation_data: persisted_validation_data.clone(), + statements, + }), + }, + }; + let validator_key_lookup = |_v| None; + let allowed_para_lookup = |_para, _g_index| true; + let statements = vec![]; + let output = response.validate_response( + &mut request_manager, + group, + 0, + validator_key_lookup, + allowed_para_lookup, + ); + assert_eq!( + output, + ResponseValidationOutput { + requested_peer, + request_status: CandidateRequestStatus::Complete { + candidate: candidate_receipt.clone(), + persisted_validation_data: persisted_validation_data.clone(), + statements, + }, + reputation_changes: vec![(requested_peer, BENEFIT_VALID_RESPONSE)], + } + ); + } + + // Ensure that cleanup occurred. + assert_eq!(request_manager.requests.len(), 0); + assert_eq!(request_manager.by_priority.len(), 0); + } +} diff --git a/node/network/statement-distribution/src/vstaging/statement_store.rs b/node/network/statement-distribution/src/vstaging/statement_store.rs new file mode 100644 index 000000000000..50ac99d0a813 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/statement_store.rs @@ -0,0 +1,283 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A store of all statements under a given relay-parent. +//! +//! This structure doesn't attempt to do any spam protection, which must +//! be provided at a higher level. +//! +//! This keeps track of statements submitted with a number of different of +//! views into this data: views based on the candidate, views based on the validator +//! groups, and views based on the validators themselves. + +use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; +use polkadot_node_network_protocol::vstaging::StatementFilter; +use polkadot_primitives::vstaging::{ + CandidateHash, CompactStatement, GroupIndex, SignedStatement, ValidatorIndex, +}; +use std::collections::hash_map::{Entry as HEntry, HashMap}; + +use super::groups::Groups; + +/// Possible origins of a statement. +pub enum StatementOrigin { + /// The statement originated locally. + Local, + /// The statement originated from a remote peer. + Remote, +} + +impl StatementOrigin { + fn is_local(&self) -> bool { + match *self { + StatementOrigin::Local => true, + StatementOrigin::Remote => false, + } + } +} + +struct StoredStatement { + statement: SignedStatement, + known_by_backing: bool, +} + +/// Storage for statements. Intended to be used for statements signed under +/// the same relay-parent. See module docs for more details. +pub struct StatementStore { + validator_meta: HashMap, + + // we keep statements per-group because even though only one group _should_ be + // producing statements about a candidate, until we have the candidate receipt + // itself, we can't tell which group that is. + group_statements: HashMap<(GroupIndex, CandidateHash), GroupStatements>, + known_statements: HashMap, +} + +impl StatementStore { + /// Create a new [`StatementStore`] + pub fn new(groups: &Groups) -> Self { + let mut validator_meta = HashMap::new(); + for (g, group) in groups.all().iter().enumerate() { + for (i, v) in group.iter().enumerate() { + validator_meta.insert( + *v, + ValidatorMeta { + seconded_count: 0, + within_group_index: i, + group: GroupIndex(g as _), + }, + ); + } + } + + StatementStore { + validator_meta, + group_statements: HashMap::new(), + known_statements: HashMap::new(), + } + } + + /// Insert a statement. Returns `true` if was not known already, `false` if it was. + /// Ignores statements by unknown validators and returns an error. + pub fn insert( + &mut self, + groups: &Groups, + statement: SignedStatement, + origin: StatementOrigin, + ) -> Result { + let validator_index = statement.validator_index(); + let validator_meta = match self.validator_meta.get_mut(&validator_index) { + None => return Err(ValidatorUnknown), + Some(m) => m, + }; + + let compact = statement.payload().clone(); + let fingerprint = (validator_index, compact.clone()); + match self.known_statements.entry(fingerprint) { + HEntry::Occupied(mut e) => { + if let StatementOrigin::Local = origin { + e.get_mut().known_by_backing = true; + } + + return Ok(false) + }, + HEntry::Vacant(e) => { + e.insert(StoredStatement { statement, known_by_backing: origin.is_local() }); + }, + } + + let candidate_hash = *compact.candidate_hash(); + let seconded = if let CompactStatement::Seconded(_) = compact { true } else { false }; + + // cross-reference updates. + { + let group_index = validator_meta.group; + let group = match groups.get(group_index) { + Some(g) => g, + None => { + gum::error!( + target: crate::LOG_TARGET, + ?group_index, + "groups passed into `insert` differ from those used at store creation" + ); + + return Err(ValidatorUnknown) + }, + }; + + let group_statements = self + .group_statements + .entry((group_index, candidate_hash)) + .or_insert_with(|| GroupStatements::with_group_size(group.len())); + + if seconded { + validator_meta.seconded_count += 1; + group_statements.note_seconded(validator_meta.within_group_index); + } else { + group_statements.note_validated(validator_meta.within_group_index); + } + } + + Ok(true) + } + + /// Fill a `StatementFilter` to be used in the grid topology with all statements + /// we are already aware of. + pub fn fill_statement_filter( + &self, + group_index: GroupIndex, + candidate_hash: CandidateHash, + statement_filter: &mut StatementFilter, + ) { + if let Some(statements) = self.group_statements.get(&(group_index, candidate_hash)) { + statement_filter.seconded_in_group |= statements.seconded.as_bitslice(); + statement_filter.validated_in_group |= statements.valid.as_bitslice(); + } + } + + /// Get an iterator over stored signed statements by the group conforming to the + /// given filter. + /// + /// Seconded statements are provided first. + pub fn group_statements<'a>( + &'a self, + groups: &'a Groups, + group_index: GroupIndex, + candidate_hash: CandidateHash, + filter: &'a StatementFilter, + ) -> impl Iterator + 'a { + let group_validators = groups.get(group_index); + + let seconded_statements = filter + .seconded_in_group + .iter_ones() + .filter_map(move |i| group_validators.as_ref().and_then(|g| g.get(i))) + .filter_map(move |v| { + self.known_statements.get(&(*v, CompactStatement::Seconded(candidate_hash))) + }) + .map(|s| &s.statement); + + let valid_statements = filter + .validated_in_group + .iter_ones() + .filter_map(move |i| group_validators.as_ref().and_then(|g| g.get(i))) + .filter_map(move |v| { + self.known_statements.get(&(*v, CompactStatement::Valid(candidate_hash))) + }) + .map(|s| &s.statement); + + seconded_statements.chain(valid_statements) + } + + /// Get the full statement of this kind issued by this validator, if it is known. + pub fn validator_statement( + &self, + validator_index: ValidatorIndex, + statement: CompactStatement, + ) -> Option<&SignedStatement> { + self.known_statements.get(&(validator_index, statement)).map(|s| &s.statement) + } + + /// Get an iterator over all statements marked as being unknown by the backing subsystem. + pub fn fresh_statements_for_backing<'a>( + &'a self, + validators: &'a [ValidatorIndex], + candidate_hash: CandidateHash, + ) -> impl Iterator + 'a { + let s_st = CompactStatement::Seconded(candidate_hash); + let v_st = CompactStatement::Valid(candidate_hash); + + validators + .iter() + .flat_map(move |v| { + let a = self.known_statements.get(&(*v, s_st.clone())); + let b = self.known_statements.get(&(*v, v_st.clone())); + + a.into_iter().chain(b) + }) + .filter(|stored| !stored.known_by_backing) + .map(|stored| &stored.statement) + } + + /// Get the amount of known `Seconded` statements by the given validator index. + pub fn seconded_count(&self, validator_index: &ValidatorIndex) -> usize { + self.validator_meta.get(validator_index).map_or(0, |m| m.seconded_count) + } + + /// Note that a statement is known by the backing subsystem. + pub fn note_known_by_backing( + &mut self, + validator_index: ValidatorIndex, + statement: CompactStatement, + ) { + if let Some(stored) = self.known_statements.get_mut(&(validator_index, statement)) { + stored.known_by_backing = true; + } + } +} + +/// Error indicating that the validator was unknown. +pub struct ValidatorUnknown; + +type Fingerprint = (ValidatorIndex, CompactStatement); + +struct ValidatorMeta { + group: GroupIndex, + within_group_index: usize, + seconded_count: usize, +} + +struct GroupStatements { + seconded: BitVec, + valid: BitVec, +} + +impl GroupStatements { + fn with_group_size(group_size: usize) -> Self { + GroupStatements { + seconded: BitVec::repeat(false, group_size), + valid: BitVec::repeat(false, group_size), + } + } + + fn note_seconded(&mut self, within_group_index: usize) { + self.seconded.set(within_group_index, true); + } + + fn note_validated(&mut self, within_group_index: usize) { + self.valid.set(within_group_index, true); + } +} diff --git a/node/network/statement-distribution/src/vstaging/tests/cluster.rs b/node/network/statement-distribution/src/vstaging/tests/cluster.rs new file mode 100644 index 000000000000..1ff53d3fd99e --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/tests/cluster.rs @@ -0,0 +1,1257 @@ +// Copyright 2023 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 polkadot_primitives_test_helpers::make_candidate; + +#[test] +fn share_seconded_circulated_to_cluster() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + let other_group_validators = state.group_validators(local_validator.group_index, true); + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let full_signed = state + .sign_statement( + local_validator.validator_index, + CompactStatement::Seconded(candidate_hash), + &SigningContext { session_index: 1, parent_hash: relay_parent }, + ) + .convert_to_superpayload(StatementWithPVD::Seconded(candidate.clone(), pvd.clone())) + .unwrap(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, full_signed), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement( + r, + s, + ) + )) + )) => { + assert_eq!(peers, vec![peer_a.clone()]); + assert_eq!(r, relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), local_validator.validator_index); + } + ); + + // sharing a `Seconded` message confirms a candidate, which leads to new + // fragment tree updates. + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + overseer + }); +} + +#[test] +fn cluster_valid_statement_before_seconded_ignored() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + // peer A is in group, has relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let signed_valid = state.sign_statement( + v_a, + CompactStatement::Valid(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + signed_valid.as_unchecked().clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) => { + assert_eq!(p, peer_a); + assert_eq!(r, COST_UNEXPECTED_STATEMENT.into()); + } + ); + + overseer + }); +} + +#[test] +fn cluster_statement_bad_signature() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + // peer A is in group, has relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // sign statements with wrong signing context, leading to bad signature. + let statements = vec![ + (v_a, CompactStatement::Seconded(candidate_hash)), + (v_b, CompactStatement::Seconded(candidate_hash)), + ] + .into_iter() + .map(|(v, s)| { + state.sign_statement( + v, + s, + &SigningContext { parent_hash: Hash::repeat_byte(69), session_index: 1 }, + ) + }) + .map(|s| s.as_unchecked().clone()); + + for statement in statements { + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + statement.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_INVALID_SIGNATURE.into() => { }, + "{:?}", + statement + ); + } + + overseer + }); +} + +#[test] +fn useful_cluster_statement_from_non_cluster_peer_rejected() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + // peer A is not in group, has relay parent in view. + let not_our_group = + if local_validator.group_index.0 == 0 { GroupIndex(1) } else { GroupIndex(0) }; + + let that_group_validators = state.group_validators(not_our_group, false); + let v_non = that_group_validators[0]; + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_non)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let statement = state + .sign_statement( + v_non, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNEXPECTED_STATEMENT.into() => { } + ); + + overseer + }); +} + +#[test] +fn statement_from_non_cluster_originator_unexpected() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + // peer A is not in group, has relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + + connect_peer(&mut overseer, peer_a.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNEXPECTED_STATEMENT.into() => { } + ); + + overseer + }); +} + +#[test] +fn seconded_statement_leads_to_request() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, has relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + vec![], + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + overseer + }); +} + +#[test] +fn cluster_statements_shared_seconded_first() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, no relay parent in view. + { + let other_group_validators = state.group_validators(local_validator.group_index, true); + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let full_signed = state + .sign_statement( + local_validator.validator_index, + CompactStatement::Seconded(candidate_hash), + &SigningContext { session_index: 1, parent_hash: relay_parent }, + ) + .convert_to_superpayload(StatementWithPVD::Seconded(candidate.clone(), pvd.clone())) + .unwrap(); + + let valid_signed = state + .sign_statement( + local_validator.validator_index, + CompactStatement::Valid(candidate_hash), + &SigningContext { session_index: 1, parent_hash: relay_parent }, + ) + .convert_to_superpayload(StatementWithPVD::Valid(candidate_hash)) + .unwrap(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, full_signed), + }) + .await; + + // result of new confirmed candidate. + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, valid_signed), + }) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessages(messages)) => { + assert_eq!(messages.len(), 2); + + assert_eq!(messages[0].0, vec![peer_a]); + assert_eq!(messages[1].0, vec![peer_a]); + + assert_matches!( + &messages[0].1, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement( + r, + s, + ) + )) if r == &relay_parent + && s.unchecked_payload() == &CompactStatement::Seconded(candidate_hash) => {} + ); + + assert_matches!( + &messages[1].1, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement( + r, + s, + ) + )) if r == &relay_parent + && s.unchecked_payload() == &CompactStatement::Valid(candidate_hash) => {} + ); + } + ); + + overseer + }); +} + +#[test] +fn cluster_accounts_for_implicit_view() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + { + let other_group_validators = state.group_validators(local_validator.group_index, true); + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let full_signed = state + .sign_statement( + local_validator.validator_index, + CompactStatement::Seconded(candidate_hash), + &SigningContext { session_index: 1, parent_hash: relay_parent }, + ) + .convert_to_superpayload(StatementWithPVD::Seconded(candidate.clone(), pvd.clone())) + .unwrap(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, full_signed), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement( + r, + s, + ) + )) + )) => { + assert_eq!(peers, vec![peer_a.clone()]); + assert_eq!(r, relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), local_validator.validator_index); + } + ); + + // sharing a `Seconded` message confirms a candidate, which leads to new + // fragment tree updates. + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + // activate new leaf, which has relay-parent in implicit view. + let next_relay_parent = Hash::repeat_byte(2); + let mut next_test_leaf = state.make_dummy_leaf(next_relay_parent); + next_test_leaf.parent_hash = relay_parent; + next_test_leaf.number = 2; + + activate_leaf(&mut overseer, &next_test_leaf, &state, false).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(next_relay_parent), + false, + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![next_relay_parent]).await; + send_peer_view_change(&mut overseer, peer_b.clone(), view![next_relay_parent]).await; + + // peer B never had the relay parent in its view, so this tests that + // the implicit view is working correctly for B. + // + // the fact that the statement isn't sent again to A also indicates that it works + // it's working. + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessages(messages)) => { + assert_eq!(messages.len(), 1); + assert_matches!( + &messages[0], + ( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement( + r, + s, + ) + )) + ) => { + assert_eq!(peers, &vec![peer_b.clone()]); + assert_eq!(r, &relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), local_validator.validator_index); + } + ) + } + ); + + overseer + }); +} + +#[test] +fn cluster_messages_imported_after_confirmed_candidate_importable_check() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, has relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Peer sends `Seconded` statement. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + a_seconded, + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response. + { + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + vec![], + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() + ); + } + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![( + HypotheticalCandidate::Complete { + candidate_hash, + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }, + vec![(relay_parent, vec![0])], + )], + None, + false, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::CandidateBacking(CandidateBackingMessage::Statement( + r, + s, + )) if r == relay_parent => { + assert_matches!( + s.payload(), + FullStatementWithPVD::Seconded(c, p) + if c == &candidate && p == &pvd => {} + ); + assert_eq!(s.validator_index(), v_a); + } + ); + + overseer + }); +} + +#[test] +fn cluster_messages_imported_after_new_leaf_importable_check() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, has relay parent in view. + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Peer sends `Seconded` statement. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + a_seconded, + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response. + { + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + vec![], + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + } + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + let next_relay_parent = Hash::repeat_byte(2); + let mut next_test_leaf = state.make_dummy_leaf(next_relay_parent); + next_test_leaf.parent_hash = relay_parent; + next_test_leaf.number = 2; + + activate_leaf(&mut overseer, &next_test_leaf, &state, false).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![( + HypotheticalCandidate::Complete { + candidate_hash, + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }, + vec![(relay_parent, vec![0])], + )], + Some(next_relay_parent), + false, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::CandidateBacking(CandidateBackingMessage::Statement( + r, + s, + )) if r == relay_parent => { + assert_matches!( + s.payload(), + FullStatementWithPVD::Seconded(c, p) + if c == &candidate && p == &pvd + ); + assert_eq!(s.validator_index(), v_a); + } + ); + + overseer + }); +} + +#[test] +fn ensure_seconding_limit_is_respected() { + // `max_candidate_depth: 1` for a `seconding_limit` of 2. + let config = TestConfig { + validator_count: 20, + group_size: 4, + local_validator: true, + async_backing_params: Some(AsyncBackingParams { + max_candidate_depth: 1, + allowed_ancestry_len: 3, + }), + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate_1, pvd_1) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let (candidate_2, pvd_2) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![7, 8, 9].into(), + Hash::repeat_byte(43).into(), + ); + let (candidate_3, _pvd_3) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![10, 11, 12].into(), + Hash::repeat_byte(44).into(), + ); + let candidate_hash_1 = candidate_1.hash(); + let candidate_hash_2 = candidate_2.hash(); + let candidate_hash_3 = candidate_3.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + + // peers A,B,C are in group, have relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Confirm the candidates locally so that we don't send out requests. + + // Candidate 1. + { + let validator_index = state.local.as_ref().unwrap().validator_index; + let statement = state + .sign_full_statement( + validator_index, + Statement::Seconded(candidate_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + pvd_1, + ) + .clone(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, statement), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Candidate 2. + { + let validator_index = state.local.as_ref().unwrap().validator_index; + let statement = state + .sign_full_statement( + validator_index, + Statement::Seconded(candidate_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + pvd_2, + ) + .clone(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, statement), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Send first statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send second statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send third statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash_3), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_EXCESSIVE_SECONDED.into() => { } + ); + } + + overseer + }); +} diff --git a/node/network/statement-distribution/src/vstaging/tests/grid.rs b/node/network/statement-distribution/src/vstaging/tests/grid.rs new file mode 100644 index 000000000000..0c9fa60ed2e6 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/tests/grid.rs @@ -0,0 +1,2455 @@ +// Copyright 2023 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 bitvec::order::Lsb0; +use polkadot_node_network_protocol::vstaging::{ + BackedCandidateAcknowledgement, BackedCandidateManifest, +}; +use polkadot_node_subsystem::messages::CandidateBackingMessage; +use polkadot_primitives_test_helpers::make_candidate; + +// Backed candidate leads to advertisement to relevant validators with relay-parent. +#[test] +fn backed_candidate_leads_to_advertisement() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let target_group_validators = + state.group_validators((local_validator.group_index.0 + 1).into(), true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(v_b)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Confirm the candidate locally so that we don't send out requests. + { + let statement = state + .sign_full_statement( + local_validator.validator_index, + Statement::Seconded(candidate.clone()), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + pvd.clone(), + ) + .clone(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, statement), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Send enough statements to make candidate backable, make sure announcements are sent. + + // Send statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send statement from peer B. + { + let statement = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_b.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_b && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + } + + // Send Backed notification. + { + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Backed(candidate_hash), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(manifest, BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: local_validator.group_index, + para_id: local_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + overseer + }); +} + +#[test] +fn received_advertisement_before_confirmation_leads_to_request() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let target_group_validators = state.group_validators(other_group, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + // peer D is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(v_b)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Receive an advertisement from C on an unconfirmed candidate. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ) + .await; + + let statements = vec![ + state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + // C provided two statements we're seeing for the first time. + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() => { } + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + overseer + }); +} + +// 1. We receive manifest from grid peer, request, pass votes to backing, then receive Backed +// message. Only then should we send an acknowledgement to the grid peer. +// +// 2. (starting from end state of (1)) we receive a manifest about the same candidate from another +// grid peer and instantaneously acknowledge. +// +// Bit more context about this design choice: Statement-distribution doesn't fully emulate the +// statement logic of backing and only focuses on the number of statements. That means that we might +// request a manifest and for some reason the backing subsystem would still not consider the +// candidate as backed. So, in particular, we don't want to advertise such an unbacked candidate +// along the grid & increase load on ourselves and our peers for serving & importing such a +// candidate. +#[test] +fn received_advertisement_after_backing_leads_to_acknowledgement() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + let statement_c = state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statement_d = state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + // Receive an advertisement from C. + { + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + // Should send a request to C. + let statements = vec![ + statement_c.clone(), + statement_d.clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Receive Backed message. + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Backed(candidate_hash), + }) + .await; + + // Should send an acknowledgement back to C. + { + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(ack, BackedCandidateAcknowledgement { + candidate_hash, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Receive a manifest about the same candidate from peer D. + { + send_peer_message( + &mut overseer, + peer_d.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + let expected_ack = BackedCandidateAcknowledgement { + candidate_hash, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + // Instantaneously acknowledge. + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessages(messages) + ) => { + assert_eq!(messages.len(), 1); + assert_eq!(messages[0].0, vec![peer_d]); + + assert_matches!( + &messages[0].1, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack) + )) if *ack == expected_ack + ); + } + ); + } + + overseer + }); +} + +// Received advertisement after confirmation but before backing leads to nothing. +#[test] +fn received_advertisement_after_confirmation_before_backing() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + let statement_c = state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statement_d = state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + // Receive an advertisement from C. + { + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + // Should send a request to C. + let statements = vec![ + statement_c.clone(), + statement_d.clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Receive advertisement from peer D (after confirmation but before backing). + { + send_peer_message( + &mut overseer, + peer_d.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + } + + overseer + }); +} + +#[test] +fn additional_statements_are_shared_after_manifest_exchange() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Receive an advertisement from C. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + } + + // Should send a request to C. + { + let statements = vec![ + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + } + + let hypothetical = HypotheticalCandidate::Complete { + candidate_hash, + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let membership = vec![(relay_parent, vec![0])]; + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![(hypothetical, membership)], + None, + false, + ) + .await; + + // Statements are sent to the Backing subsystem. + { + assert_matches!( + overseer.recv().await, + AllMessages::CandidateBacking( + CandidateBackingMessage::Statement(hash, statement) + ) => { + assert_eq!(hash, relay_parent); + assert_matches!( + statement.payload(), + FullStatementWithPVD::Seconded(c, p) + if c == &candidate && p == &pvd + ); + } + ); + assert_matches!( + overseer.recv().await, + AllMessages::CandidateBacking( + CandidateBackingMessage::Statement(hash, statement) + ) => { + assert_eq!(hash, relay_parent); + assert_matches!( + statement.payload(), + FullStatementWithPVD::Seconded(c, p) + if c == &candidate && p == &pvd + ); + } + ); + } + + // Receive Backed message. + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Backed(candidate_hash), + }) + .await; + + // Should send an acknowledgement back to C. + { + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(ack, BackedCandidateAcknowledgement { + candidate_hash, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Receive a manifest about the same candidate from peer D. Contains different statements. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + send_peer_message( + &mut overseer, + peer_d.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + let expected_ack = BackedCandidateAcknowledgement { + candidate_hash, + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + // Instantaneously acknowledge. + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessages(messages) + ) => { + assert_eq!(messages.len(), 2); + assert_eq!(messages[0].0, vec![peer_d]); + assert_eq!(messages[1].0, vec![peer_d]); + + assert_matches!( + &messages[0].1, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(ack) + )) if *ack == expected_ack + ); + + assert_matches!( + &messages[1].1, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement(r, s) + )) if *r == relay_parent && s.unchecked_payload() == &CompactStatement::Seconded(candidate_hash) && s.unchecked_validator_index() == v_e + ); + } + ); + } + + overseer + }); +} + +// Grid-sending validator view entering relay-parent leads to advertisement. +#[test] +fn advertisement_sent_when_peer_enters_relay_parent_view() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let target_group_validators = + state.group_validators((local_validator.group_index.0 + 1).into(), true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(v_b)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Confirm the candidate locally so that we don't send out requests. + { + let statement = state + .sign_full_statement( + local_validator.validator_index, + Statement::Seconded(candidate.clone()), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + pvd.clone(), + ) + .clone(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, statement), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Send enough statements to make candidate backable, make sure announcements are sent. + + // Send statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send statement from peer B. + { + let statement = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_b.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_b && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + } + + // Send Backed notification. + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Backed(candidate_hash), + }) + .await; + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + // Relay parent enters view of peer C. + { + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + + let expected_manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: local_validator.group_index, + para_id: local_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessages(messages) + ) => { + assert_eq!(messages.len(), 1); + assert_eq!(messages[0].0, vec![peer_c]); + + assert_matches!( + &messages[0].1, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest) + )) => { + assert_eq!(*manifest, expected_manifest); + } + ); + } + ); + } + + overseer + }); +} + +// Advertisement not re-sent after re-entering relay parent (view oscillation). +#[test] +fn advertisement_not_re_sent_when_peer_re_enters_view() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let target_group_validators = + state.group_validators((local_validator.group_index.0 + 1).into(), true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(v_b)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Confirm the candidate locally so that we don't send out requests. + { + let statement = state + .sign_full_statement( + local_validator.validator_index, + Statement::Seconded(candidate.clone()), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + pvd.clone(), + ) + .clone(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, statement), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Send enough statements to make candidate backable, make sure announcements are sent. + + // Send statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send statement from peer B. + { + let statement = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_b.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_b && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + } + + // Send Backed notification. + { + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Backed(candidate_hash), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(manifest, BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: local_validator.group_index, + para_id: local_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Peer leaves view. + send_peer_view_change(&mut overseer, peer_c.clone(), view![]).await; + + // Peer re-enters view. + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + + overseer + }); +} + +// Grid statements imported to backing once candidate enters hypothetical frontier. +#[test] +fn grid_statements_imported_to_backing() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Receive an advertisement from C. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + } + + // Should send a request to C. + { + let statements = vec![ + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + } + + let hypothetical = HypotheticalCandidate::Complete { + candidate_hash, + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let membership = vec![(relay_parent, vec![0])]; + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![(hypothetical, membership)], + None, + false, + ) + .await; + + // Receive messages from Backing subsystem. + { + assert_matches!( + overseer.recv().await, + AllMessages::CandidateBacking( + CandidateBackingMessage::Statement(hash, statement) + ) => { + assert_eq!(hash, relay_parent); + assert_matches!( + statement.payload(), + FullStatementWithPVD::Seconded(c, p) + if c == &candidate && p == &pvd + ); + } + ); + assert_matches!( + overseer.recv().await, + AllMessages::CandidateBacking( + CandidateBackingMessage::Statement(hash, statement) + ) => { + assert_eq!(hash, relay_parent); + assert_matches!( + statement.payload(), + FullStatementWithPVD::Seconded(c, p) + if c == &candidate && p == &pvd + ); + } + ); + } + + overseer + }); +} + +#[test] +fn advertisements_rejected_from_incorrect_peers() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let target_group_validators = state.group_validators(other_group, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(v_b)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + // Receive an advertisement from A (our group). + { + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNEXPECTED_MANIFEST_DISALLOWED.into() => { } + ); + } + + // Receive an advertisement from B (our group). + { + send_peer_message( + &mut overseer, + peer_b.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_b && r == COST_UNEXPECTED_MANIFEST_DISALLOWED.into() => { } + ); + } + + overseer + }); +} + +#[test] +fn manifest_rejected_with_unknown_relay_parent() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let unknown_parent = Hash::repeat_byte(2); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + unknown_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent: unknown_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + // Receive an advertisement from C. + { + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE.into() => { } + ); + } + + overseer + }); +} + +#[test] +fn manifest_rejected_when_not_a_validator() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: false, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let other_group = GroupIndex::from(0); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + // Receive an advertisement from C. + { + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE.into() => { } + ); + } + + overseer + }); +} + +#[test] +fn manifest_rejected_when_group_does_not_match_para() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + // Create a mismatch between group and para. + let other_para = next_group_index(other_group, validator_count, group_size); + let other_para = ParaId::from(other_para.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + // Receive an advertisement from C. + { + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == COST_MALFORMED_MANIFEST.into() => { } + ); + } + + overseer + }); +} + +#[test] +fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + }, + }; + + let statement_c = state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statement_d = state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + // Receive an advertisement from C. + { + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + // Should send a request to C. + let statements = vec![ + statement_c.clone(), + statement_d.clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Receive conflicting advertisement from peer C after confirmation. + // + // NOTE: This causes a conflict because we track received manifests on a per-validator + // basis, and this is the second time we're getting a manifest from C. + { + let mut manifest = manifest.clone(); + manifest.statement_knowledge = StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }; + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == COST_CONFLICTING_MANIFEST.into() + ); + } + + overseer + }); +} diff --git a/node/network/statement-distribution/src/vstaging/tests/mod.rs b/node/network/statement-distribution/src/vstaging/tests/mod.rs new file mode 100644 index 000000000000..f5f4c8443257 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/tests/mod.rs @@ -0,0 +1,606 @@ +// Copyright 2023 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 . + +#![allow(clippy::clone_on_copy)] + +use super::*; +use crate::*; +use polkadot_node_network_protocol::{ + grid_topology::TopologyPeerInfo, + request_response::{outgoing::Recipient, ReqProtocolNames}, + view, ObservedRole, +}; +use polkadot_node_primitives::Statement; +use polkadot_node_subsystem::messages::{ + network_bridge_event::NewGossipTopology, AllMessages, ChainApiMessage, FragmentTreeMembership, + HypotheticalCandidate, NetworkBridgeEvent, ProspectiveParachainsMessage, ReportPeerMessage, + RuntimeApiMessage, RuntimeApiRequest, +}; +use polkadot_node_subsystem_test_helpers as test_helpers; +use polkadot_node_subsystem_types::{jaeger, ActivatedLeaf, LeafStatus}; +use polkadot_node_subsystem_util::TimeoutExt; +use polkadot_primitives::vstaging::{ + AssignmentPair, AsyncBackingParams, BlockNumber, CommittedCandidateReceipt, CoreState, + GroupRotationInfo, HeadData, Header, IndexedVec, PersistedValidationData, ScheduledCore, + SessionIndex, SessionInfo, ValidatorPair, +}; +use sc_keystore::LocalKeystore; +use sp_application_crypto::Pair as PairT; +use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair; +use sp_keyring::Sr25519Keyring; + +use assert_matches::assert_matches; +use futures::Future; +use parity_scale_codec::Encode; +use rand::{Rng, SeedableRng}; + +use std::sync::Arc; + +mod cluster; +mod grid; +mod requests; + +type VirtualOverseer = test_helpers::TestSubsystemContextHandle; + +const DEFAULT_ASYNC_BACKING_PARAMETERS: AsyncBackingParams = + AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; + +// Some deterministic genesis hash for req/res protocol names +const GENESIS_HASH: Hash = Hash::repeat_byte(0xff); + +struct TestConfig { + validator_count: usize, + // how many validators to place in each group. + group_size: usize, + // whether the local node should be a validator + local_validator: bool, + async_backing_params: Option, +} + +#[derive(Debug, Clone)] +struct TestLocalValidator { + validator_index: ValidatorIndex, + group_index: GroupIndex, +} + +struct TestState { + config: TestConfig, + local: Option, + validators: Vec, + session_info: SessionInfo, + req_sender: async_channel::Sender, +} + +impl TestState { + fn from_config( + config: TestConfig, + req_sender: async_channel::Sender, + rng: &mut impl Rng, + ) -> Self { + if config.group_size == 0 { + panic!("group size cannot be 0"); + } + + let mut validators = Vec::new(); + let mut discovery_keys = Vec::new(); + let mut assignment_keys = Vec::new(); + let mut validator_groups = Vec::new(); + + let local_validator_pos = if config.local_validator { + // ensure local validator is always in a full group. + Some(rng.gen_range(0..config.validator_count).saturating_sub(config.group_size - 1)) + } else { + None + }; + + for i in 0..config.validator_count { + let validator_pair = if Some(i) == local_validator_pos { + // Note: the specific key is used to ensure the keystore holds + // this key and the subsystem can detect that it is a validator. + Sr25519Keyring::Ferdie.pair().into() + } else { + ValidatorPair::generate().0 + }; + let assignment_id = AssignmentPair::generate().0.public(); + let discovery_id = AuthorityDiscoveryPair::generate().0.public(); + + let group_index = i / config.group_size; + validators.push(validator_pair); + discovery_keys.push(discovery_id); + assignment_keys.push(assignment_id); + if validator_groups.len() == group_index { + validator_groups.push(vec![ValidatorIndex(i as _)]); + } else { + validator_groups.last_mut().unwrap().push(ValidatorIndex(i as _)); + } + } + + let local = if let Some(local_pos) = local_validator_pos { + Some(TestLocalValidator { + validator_index: ValidatorIndex(local_pos as _), + group_index: GroupIndex((local_pos / config.group_size) as _), + }) + } else { + None + }; + + let validator_public = validator_pubkeys(&validators); + let session_info = SessionInfo { + validators: validator_public, + discovery_keys, + validator_groups: IndexedVec::from(validator_groups), + assignment_keys, + n_cores: 0, + zeroth_delay_tranche_width: 0, + relay_vrf_modulo_samples: 0, + n_delay_tranches: 0, + no_show_slots: 0, + needed_approvals: 0, + active_validator_indices: vec![], + dispute_period: 6, + random_seed: [0u8; 32], + }; + + TestState { config, local, validators, session_info, req_sender } + } + + fn make_dummy_leaf(&self, relay_parent: Hash) -> TestLeaf { + TestLeaf { + number: 1, + hash: relay_parent, + parent_hash: Hash::repeat_byte(0), + session: 1, + availability_cores: self.make_availability_cores(|i| { + CoreState::Scheduled(ScheduledCore { + para_id: ParaId::from(i as u32), + collator: None, + }) + }), + para_data: (0..self.session_info.validator_groups.len()) + .map(|i| (ParaId::from(i as u32), PerParaData::new(1, vec![1, 2, 3].into()))) + .collect(), + } + } + + fn make_availability_cores(&self, f: impl Fn(usize) -> CoreState) -> Vec { + (0..self.session_info.validator_groups.len()).map(f).collect() + } + + fn make_dummy_topology(&self) -> NewGossipTopology { + let validator_count = self.config.validator_count; + NewGossipTopology { + session: 1, + topology: SessionGridTopology::new( + (0..validator_count).collect(), + (0..validator_count) + .map(|i| TopologyPeerInfo { + peer_ids: Vec::new(), + validator_index: ValidatorIndex(i as u32), + discovery_id: AuthorityDiscoveryPair::generate().0.public(), + }) + .collect(), + ), + local_index: self.local.as_ref().map(|local| local.validator_index), + } + } + + fn group_validators( + &self, + group_index: GroupIndex, + exclude_local: bool, + ) -> Vec { + self.session_info + .validator_groups + .get(group_index) + .unwrap() + .iter() + .cloned() + .filter(|&i| { + self.local.as_ref().map_or(true, |l| !exclude_local || l.validator_index != i) + }) + .collect() + } + + fn discovery_id(&self, validator_index: ValidatorIndex) -> AuthorityDiscoveryId { + self.session_info.discovery_keys[validator_index.0 as usize].clone() + } + + fn sign_statement( + &self, + validator_index: ValidatorIndex, + statement: CompactStatement, + context: &SigningContext, + ) -> SignedStatement { + let payload = statement.signing_payload(context); + let pair = &self.validators[validator_index.0 as usize]; + let signature = pair.sign(&payload[..]); + + SignedStatement::new(statement, validator_index, signature, context, &pair.public()) + .unwrap() + } + + fn sign_full_statement( + &self, + validator_index: ValidatorIndex, + statement: Statement, + context: &SigningContext, + pvd: PersistedValidationData, + ) -> SignedFullStatementWithPVD { + let payload = statement.to_compact().signing_payload(context); + let pair = &self.validators[validator_index.0 as usize]; + let signature = pair.sign(&payload[..]); + + SignedFullStatementWithPVD::new( + statement.supply_pvd(pvd), + validator_index, + signature, + context, + &pair.public(), + ) + .unwrap() + } + + // send a request out, returning a future which expects a response. + async fn send_request( + &mut self, + peer: PeerId, + request: AttestedCandidateRequest, + ) -> impl Future { + let (tx, rx) = futures::channel::oneshot::channel(); + let req = sc_network::config::IncomingRequest { + peer, + payload: request.encode(), + pending_response: tx, + }; + self.req_sender.send(req).await.unwrap(); + + rx.map(|r| r.unwrap()) + } +} + +fn test_harness>( + config: TestConfig, + test: impl FnOnce(TestState, VirtualOverseer) -> T, +) { + let pool = sp_core::testing::TaskExecutor::new(); + let keystore = if config.local_validator { + test_helpers::mock::make_ferdie_keystore() + } else { + Arc::new(LocalKeystore::in_memory()) as KeystorePtr + }; + let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None); + let (statement_req_receiver, _) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (candidate_req_receiver, req_cfg) = + IncomingRequest::get_config_receiver(&req_protocol_names); + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0); + + let test_state = TestState::from_config(config, req_cfg.inbound_queue.unwrap(), &mut rng); + + let (context, virtual_overseer) = test_helpers::make_subsystem_context(pool.clone()); + let subsystem = async move { + let subsystem = crate::StatementDistributionSubsystem { + keystore, + v1_req_receiver: Some(statement_req_receiver), + req_receiver: Some(candidate_req_receiver), + metrics: Default::default(), + rng, + reputation: ReputationAggregator::new(|_| true), + }; + + if let Err(e) = subsystem.run(context).await { + panic!("Fatal error: {:?}", e); + } + }; + + let test_fut = test(test_state, virtual_overseer); + + futures::pin_mut!(test_fut); + futures::pin_mut!(subsystem); + futures::executor::block_on(future::join( + async move { + let mut virtual_overseer = test_fut.await; + // Ensure we have handled all responses. + if let Ok(Some(msg)) = virtual_overseer.rx.try_next() { + panic!("Did not handle all responses: {:?}", msg); + } + // Conclude. + virtual_overseer.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; + }, + subsystem, + )); +} + +struct PerParaData { + min_relay_parent: BlockNumber, + head_data: HeadData, +} + +impl PerParaData { + pub fn new(min_relay_parent: BlockNumber, head_data: HeadData) -> Self { + Self { min_relay_parent, head_data } + } +} + +struct TestLeaf { + number: BlockNumber, + hash: Hash, + parent_hash: Hash, + session: SessionIndex, + availability_cores: Vec, + para_data: Vec<(ParaId, PerParaData)>, +} + +impl TestLeaf { + pub fn para_data(&self, para_id: ParaId) -> &PerParaData { + self.para_data + .iter() + .find_map(|(p_id, data)| if *p_id == para_id { Some(data) } else { None }) + .unwrap() + } +} + +async fn activate_leaf( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + test_state: &TestState, + expect_session_info_request: bool, +) { + let activated = ActivatedLeaf { + hash: leaf.hash, + number: leaf.number, + status: LeafStatus::Fresh, + span: Arc::new(jaeger::Span::Disabled), + }; + + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( + activated, + )))) + .await; + + handle_leaf_activation(virtual_overseer, leaf, test_state, expect_session_info_request).await; +} + +async fn handle_leaf_activation( + virtual_overseer: &mut VirtualOverseer, + leaf: &TestLeaf, + test_state: &TestState, + expect_session_info_request: bool, +) { + let TestLeaf { number, hash, parent_hash, para_data, session, availability_cores } = leaf; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParams(tx)) + ) if parent == *hash => { + tx.send(Ok(test_state.config.async_backing_params.unwrap_or(DEFAULT_ASYNC_BACKING_PARAMETERS))).unwrap(); + } + ); + + let mrp_response: Vec<(ParaId, BlockNumber)> = para_data + .iter() + .map(|(para_id, data)| (*para_id, data.min_relay_parent)) + .collect(); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetMinimumRelayParents(parent, tx) + ) if parent == *hash => { + tx.send(mrp_response).unwrap(); + } + ); + + let header = Header { + parent_hash: *parent_hash, + number: *number, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + }; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ChainApi( + ChainApiMessage::BlockHeader(parent, tx) + ) if parent == *hash => { + tx.send(Ok(Some(header))).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx))) if parent == *hash => { + tx.send(Ok(*session)).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx))) if parent == *hash => { + tx.send(Ok(availability_cores.clone())).unwrap(); + } + ); + + let validator_groups = test_state.session_info.validator_groups.to_vec(); + let group_rotation_info = + GroupRotationInfo { session_start_block: 1, group_rotation_frequency: 12, now: 1 }; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx))) if parent == *hash => { + tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); + } + ); + + if expect_session_info_request { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionInfo(s, tx))) if parent == *hash && s == *session => { + tx.send(Ok(Some(test_state.session_info.clone()))).unwrap(); + } + ); + } +} + +/// Intercepts an outgoing request, checks the fields, and sends the response. +async fn handle_sent_request( + virtual_overseer: &mut VirtualOverseer, + peer: PeerId, + candidate_hash: CandidateHash, + mask: StatementFilter, + candidate_receipt: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + statements: Vec, +) { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendRequests(mut requests, IfDisconnected::ImmediateError)) => { + assert_eq!(requests.len(), 1); + assert_matches!( + requests.pop().unwrap(), + Requests::AttestedCandidateVStaging(outgoing) => { + assert_eq!(outgoing.peer, Recipient::Peer(peer)); + assert_eq!(outgoing.payload.candidate_hash, candidate_hash); + assert_eq!(outgoing.payload.mask, mask); + + let res = AttestedCandidateResponse { + candidate_receipt, + persisted_validation_data, + statements, + }; + outgoing.pending_response.send(Ok(res.encode())).unwrap(); + } + ); + } + ); +} + +async fn answer_expected_hypothetical_depth_request( + virtual_overseer: &mut VirtualOverseer, + responses: Vec<(HypotheticalCandidate, FragmentTreeMembership)>, + expected_leaf_hash: Option, + expected_backed_in_path_only: bool, +) { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetHypotheticalFrontier(req, tx) + ) => { + assert_eq!(req.fragment_tree_relay_parent, expected_leaf_hash); + assert_eq!(req.backed_in_path_only, expected_backed_in_path_only); + for (i, (candidate, _)) in responses.iter().enumerate() { + assert!( + req.candidates.iter().any(|c| &c == &candidate), + "did not receive request for hypothetical candidate {}", + i, + ); + } + + tx.send(responses).unwrap(); + } + ) +} + +fn validator_pubkeys(val_ids: &[ValidatorPair]) -> IndexedVec { + val_ids.iter().map(|v| v.public().into()).collect() +} + +async fn connect_peer( + virtual_overseer: &mut VirtualOverseer, + peer: PeerId, + authority_ids: Option>, +) { + virtual_overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerConnected( + peer, + ObservedRole::Authority, + ValidationVersion::VStaging.into(), + authority_ids, + ), + ), + }) + .await; +} + +// TODO: Add some tests using this? +#[allow(dead_code)] +async fn disconnect_peer(virtual_overseer: &mut VirtualOverseer, peer: PeerId) { + virtual_overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerDisconnected(peer), + ), + }) + .await; +} + +async fn send_peer_view_change(virtual_overseer: &mut VirtualOverseer, peer: PeerId, view: View) { + virtual_overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerViewChange(peer, view), + ), + }) + .await; +} + +async fn send_peer_message( + virtual_overseer: &mut VirtualOverseer, + peer: PeerId, + message: protocol_vstaging::StatementDistributionMessage, +) { + virtual_overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerMessage(peer, Versioned::VStaging(message)), + ), + }) + .await; +} + +async fn send_new_topology(virtual_overseer: &mut VirtualOverseer, topology: NewGossipTopology) { + virtual_overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::NewGossipTopology(topology), + ), + }) + .await; +} + +async fn overseer_recv_with_timeout( + overseer: &mut VirtualOverseer, + timeout: Duration, +) -> Option { + gum::trace!("waiting for message..."); + overseer.recv().timeout(timeout).await +} + +fn next_group_index( + group_index: GroupIndex, + validator_count: usize, + group_size: usize, +) -> GroupIndex { + let next_group = group_index.0 + 1; + let num_groups = + validator_count / group_size + if validator_count % group_size > 0 { 1 } else { 0 }; + GroupIndex::from(next_group % num_groups as u32) +} diff --git a/node/network/statement-distribution/src/vstaging/tests/requests.rs b/node/network/statement-distribution/src/vstaging/tests/requests.rs new file mode 100644 index 000000000000..a86ef97f7807 --- /dev/null +++ b/node/network/statement-distribution/src/vstaging/tests/requests.rs @@ -0,0 +1,1871 @@ +// Copyright 2023 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 bitvec::order::Lsb0; +use parity_scale_codec::{Decode, Encode}; +use polkadot_node_network_protocol::{ + request_response::vstaging as request_vstaging, vstaging::BackedCandidateManifest, +}; +use polkadot_primitives_test_helpers::make_candidate; +use sc_network::config::{ + IncomingRequest as RawIncomingRequest, OutgoingResponse as RawOutgoingResponse, +}; + +#[test] +fn cluster_peer_allowed_to_send_incomplete_statements() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + a_seconded, + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include just one statement. + { + let b_seconded = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded.clone()]; + // `1` indicates statements NOT to request. + let mask = StatementFilter::blank(group_size); + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + mask, + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement(hash, statement), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_a]); + assert_eq!(hash, relay_parent); + assert_eq!(statement, b_seconded); + } + ); + } + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + overseer + }); +} + +#[test] +fn peer_reported_for_providing_statements_meant_to_be_masked_out() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: Some(AsyncBackingParams { + // Makes `seconding_limit: 2` (easier to hit the limit). + max_candidate_depth: 1, + allowed_ancestry_len: 3, + }), + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate_1, pvd_1) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let (candidate_2, pvd_2) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![7, 8, 9].into(), + Hash::repeat_byte(43).into(), + ); + let (candidate_3, pvd_3) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![10, 11, 12].into(), + Hash::repeat_byte(44).into(), + ); + let candidate_hash_1 = candidate_1.hash(); + let candidate_hash_2 = candidate_2.hash(); + let candidate_hash_3 = candidate_3.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Peer C advertises candidate 1. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash: candidate_hash_1, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd_1.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + let statements = vec![ + state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash_1, + StatementFilter::blank(group_size), + candidate_1.clone(), + pvd_1.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Peer C advertises candidate 2. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash: candidate_hash_2, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd_2.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + let statements = vec![ + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash_2, + StatementFilter::blank(group_size), + candidate_2.clone(), + pvd_2.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Peer C sends an announcement for candidate 3. Should hit seconding limit for validator 1. + // + // NOTE: The manifest is immediately rejected before a request is made due to + // "over-seconding" validator 1. On the other hand, if the manifest does not include + // validator 1 as a seconder, then including its Second statement in the response instead + // would fail with "Un-requested Statement In Response". + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash: candidate_hash_3, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd_3.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }; + + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == COST_EXCESSIVE_SECONDED.into() + ); + } + + overseer + }); +} + +// Peer reported for not providing enough statements, request retried. +#[test] +fn peer_reported_for_not_enough_statements() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + }, + }; + + // Peer sends an announcement. + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + let c_seconded = state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![c_seconded.clone()]; + // `1` indicates statements NOT to request. + let mask = StatementFilter::blank(group_size); + + // We send a request to peer. Mock its response to include just one statement. + { + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + mask.clone(), + candidate.clone(), + pvd.clone(), + statements.clone(), + ) + .await; + + // The peer is reported for only sending one statement. + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == COST_INVALID_RESPONSE.into() => { } + ); + } + + // We re-try the request. + { + let statements = vec![ + c_seconded, + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash, + mask, + candidate.clone(), + pvd.clone(), + statements.clone(), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + overseer + }); +} + +// Test that a peer answering an `AttestedCandidateRequest` with duplicate statements is punished. +#[test] +fn peer_reported_for_duplicate_statements() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + a_seconded, + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include two identical statements. + { + let b_seconded = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded.clone(), b_seconded.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNREQUESTED_RESPONSE_STATEMENT.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement(hash, statement), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_a]); + assert_eq!(hash, relay_parent); + assert_eq!(statement, b_seconded); + } + ); + } + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + + overseer + }); +} + +#[test] +fn peer_reported_for_providing_statements_with_invalid_signatures() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + state.group_validators((local_validator.group_index.0 + 1).into(), true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + a_seconded, + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include invalid statements. + { + // Sign statement with wrong signing context, leading to bad signature. + let b_seconded_invalid = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: Hash::repeat_byte(42), session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded_invalid.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_INVALID_SIGNATURE.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + overseer + }); +} + +#[test] +fn peer_reported_for_providing_statements_with_wrong_validator_id() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let next_group_validators = + state.group_validators((local_validator.group_index.0 + 1).into(), true); + let v_a = other_group_validators[0]; + let v_c = next_group_validators[0]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + a_seconded, + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include a wrong validator ID. + { + let c_seconded_invalid = state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![c_seconded_invalid.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNREQUESTED_RESPONSE_STATEMENT.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + overseer + }); +} + +#[test] +fn local_node_sanity_checks_incoming_requests() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |mut state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + let other_group_validators = state.group_validators(local_validator.group_index, true); + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + let mask = StatementFilter::blank(state.config.group_size); + + // Should drop requests for unknown candidates. + { + let (pending_response, rx) = oneshot::channel(); + state + .req_sender + .send(RawIncomingRequest { + // Request from peer that received manifest. + peer: peer_c, + payload: request_vstaging::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask: mask.clone(), + } + .encode(), + pending_response, + }) + .await + .unwrap(); + + assert_matches!(rx.await, Err(oneshot::Canceled)); + } + + // Confirm candidate. + { + let full_signed = state + .sign_statement( + local_validator.validator_index, + CompactStatement::Seconded(candidate_hash), + &SigningContext { session_index: 1, parent_hash: relay_parent }, + ) + .convert_to_superpayload(StatementWithPVD::Seconded(candidate.clone(), pvd.clone())) + .unwrap(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, full_signed), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging(protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::Statement( + r, + s, + ) + )) + )) => { + assert_eq!(peers, vec![peer_a.clone()]); + assert_eq!(r, relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), local_validator.validator_index); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Should drop requests from unknown peers. + { + let (pending_response, rx) = oneshot::channel(); + state + .req_sender + .send(RawIncomingRequest { + // Request from peer that received manifest. + peer: peer_d, + payload: request_vstaging::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask: mask.clone(), + } + .encode(), + pending_response, + }) + .await + .unwrap(); + + assert_matches!(rx.await, Err(oneshot::Canceled)); + } + + // Should drop requests with bitfields of the wrong size. + { + let mask = StatementFilter::blank(state.config.group_size + 1); + let response = state + .send_request( + peer_c, + request_vstaging::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask, + }, + ) + .await + .await; + + assert_matches!( + response, + RawOutgoingResponse { + result, + reputation_changes, + sent_feedback + } => { + assert_matches!(result, Err(())); + assert_eq!(reputation_changes, vec![COST_INVALID_REQUEST_BITFIELD_SIZE.into()]); + assert_matches!(sent_feedback, None); + } + ); + } + + // Local node should reject requests if we did not send a manifest to that peer. + { + let response = state + .send_request( + peer_c, + request_vstaging::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask: mask.clone(), + }, + ) + .await + .await; + + // Should get `COST_UNEXPECTED_REQUEST` response. + assert_matches!( + response, + RawOutgoingResponse { + result, + reputation_changes, + sent_feedback + } => { + assert_matches!(result, Err(())); + assert_eq!(reputation_changes, vec![COST_UNEXPECTED_REQUEST.into()]); + assert_matches!(sent_feedback, None); + } + ); + } + + overseer + }); +} + +#[test] +fn local_node_respects_statement_mask() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + + test_harness(config, |mut state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_para = ParaId::from(local_validator.group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate, pvd) = make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_validator.group_index, true); + let target_group_validators = + state.group_validators((local_validator.group_index.0 + 1).into(), true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + // peer D is not in group, has no relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_a)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(v_b)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // Confirm the candidate locally so that we don't send out requests. + { + let statement = state + .sign_full_statement( + local_validator.validator_index, + Statement::Seconded(candidate.clone()), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + pvd.clone(), + ) + .clone(); + + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Share(relay_parent, statement), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Send enough statements to make candidate backable, make sure announcements are sent. + + // Send statement from peer A. + { + let statement = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send statement from peer B. + let statement_b = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + { + send_peer_message( + &mut overseer, + peer_b.clone(), + protocol_vstaging::StatementDistributionMessage::Statement( + relay_parent, + statement_b.clone(), + ), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_b && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] + ); + } + + // Send Backed notification. + { + overseer + .send(FromOrchestra::Communication { + msg: StatementDistributionMessage::Backed(candidate_hash), + }) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages:: NetworkBridgeTx( + NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::VStaging( + protocol_vstaging::ValidationProtocol::StatementDistribution( + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + ), + ), + ) + ) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(manifest, BackedCandidateManifest { + relay_parent, + candidate_hash, + group_index: local_validator.group_index, + para_id: local_para, + parent_head_data_hash: pvd.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }, + }); + } + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // `1` indicates statements NOT to request. + let mask = StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0], + }; + + // Incoming request to local node. Local node should send statements, respecting mask. + { + let response = state + .send_request( + peer_c, + request_vstaging::AttestedCandidateRequest { + candidate_hash: candidate.hash(), + mask, + }, + ) + .await + .await; + + let expected_statements = vec![statement_b]; + assert_matches!(response, full_response => { + // Response is the same for vstaging. + let request_vstaging::AttestedCandidateResponse { candidate_receipt, persisted_validation_data, statements } = + request_vstaging::AttestedCandidateResponse::decode( + &mut full_response.result.expect("We should have a proper answer").as_ref(), + ).expect("Decoding should work"); + assert_eq!(candidate_receipt, candidate); + assert_eq!(persisted_validation_data, pvd); + assert_eq!(statements, expected_statements); + }); + } + + overseer + }); +} + +#[test] +fn should_delay_before_retrying_dropped_requests() { + let validator_count = 6; + let group_size = 3; + let config = TestConfig { + validator_count, + group_size, + local_validator: true, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_c = PeerId::random(); + let peer_d = PeerId::random(); + let peer_e = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + + let other_group = + next_group_index(local_validator.group_index, validator_count, group_size); + let other_para = ParaId::from(other_group.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (candidate_1, pvd_1) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + let (candidate_2, pvd_2) = make_candidate( + relay_parent, + 1, + other_para, + test_leaf.para_data(other_para).head_data.clone(), + vec![7, 8, 9].into(), + Hash::repeat_byte(43).into(), + ); + let candidate_hash_1 = candidate_1.hash(); + let candidate_hash_2 = candidate_2.hash(); + + let target_group_validators = state.group_validators(other_group, true); + let v_c = target_group_validators[0]; + let v_d = target_group_validators[1]; + let v_e = target_group_validators[2]; + + // Connect C, D, E + { + connect_peer( + &mut overseer, + peer_c.clone(), + Some(vec![state.discovery_id(v_c)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_d.clone(), + Some(vec![state.discovery_id(v_d)].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_e.clone(), + Some(vec![state.discovery_id(v_e)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true).await; + + answer_expected_hypothetical_depth_request( + &mut overseer, + vec![], + Some(relay_parent), + false, + ) + .await; + + // Send gossip topology. + send_new_topology(&mut overseer, state.make_dummy_topology()).await; + + // `1` indicates statements NOT to request. + let mask = StatementFilter::blank(group_size); + + // Send a request about a candidate. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash: candidate_hash_1, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd_1.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + }, + }; + + // Peer sends an announcement. + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + // We send a request to peer. Drop the request without sending a response. + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendRequests(mut requests, IfDisconnected::ImmediateError)) => { + assert_eq!(requests.len(), 1); + assert_matches!( + requests.pop().unwrap(), + Requests::AttestedCandidateVStaging(outgoing) => { + assert_eq!(outgoing.peer, Recipient::Peer(peer_c)); + assert_eq!(outgoing.payload.candidate_hash, candidate_hash_1); + assert_eq!(outgoing.payload.mask, mask); + } + ); + } + ); + + assert_matches!( + overseer_recv_with_timeout(&mut overseer, Duration::from_millis(100)).await, + None + ); + } + + // We still send requests about different candidates as per usual. + { + let manifest = BackedCandidateManifest { + relay_parent, + candidate_hash: candidate_hash_2, + group_index: other_group, + para_id: other_para, + parent_head_data_hash: pvd_2.parent_head.hash(), + statement_knowledge: StatementFilter { + seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1], + validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 0], + }, + }; + + // Peer sends an announcement. + send_peer_message( + &mut overseer, + peer_c.clone(), + protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + manifest.clone(), + ), + ) + .await; + + let statements = vec![ + state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash_2), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + + // Don't drop this request. + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash_2, + mask.clone(), + candidate_2.clone(), + pvd_2.clone(), + statements.clone(), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + // Sleep for the given amount of time. This should reset the delay for the first candidate. + futures_timer::Delay::new(REQUEST_RETRY_DELAY).await; + + // We re-try the first request. + { + let statements = vec![ + state + .sign_statement( + v_c, + CompactStatement::Seconded(candidate_hash_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_d, + CompactStatement::Seconded(candidate_hash_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + state + .sign_statement( + v_e, + CompactStatement::Seconded(candidate_hash_1), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(), + ]; + handle_sent_request( + &mut overseer, + peer_c, + candidate_hash_1, + mask, + candidate_1.clone(), + pvd_1.clone(), + statements.clone(), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_STATEMENT.into() + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() + ); + + answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await; + } + + overseer + }); +} diff --git a/node/overseer/src/dummy.rs b/node/overseer/src/dummy.rs index d93236ac98e8..79daba140676 100644 --- a/node/overseer/src/dummy.rs +++ b/node/overseer/src/dummy.rs @@ -89,6 +89,7 @@ pub fn dummy_overseer_builder( DummySubsystem, DummySubsystem, DummySubsystem, + DummySubsystem, >, SubsystemError, > @@ -131,6 +132,7 @@ pub fn one_for_all_overseer_builder( Sub, Sub, Sub, + Sub, >, SubsystemError, > @@ -159,7 +161,8 @@ where + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> - + Subsystem, SubsystemError>, + + Subsystem, SubsystemError> + + Subsystem, SubsystemError>, { let metrics = ::register(registry)?; @@ -185,7 +188,8 @@ where .gossip_support(subsystem.clone()) .dispute_coordinator(subsystem.clone()) .dispute_distribution(subsystem.clone()) - .chain_selection(subsystem) + .chain_selection(subsystem.clone()) + .prospective_parachains(subsystem.clone()) .activation_external_listeners(Default::default()) .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) diff --git a/node/overseer/src/lib.rs b/node/overseer/src/lib.rs index ebf33d5247b1..5655a3ef79c1 100644 --- a/node/overseer/src/lib.rs +++ b/node/overseer/src/lib.rs @@ -81,7 +81,8 @@ use polkadot_node_subsystem_types::messages::{ CandidateBackingMessage, CandidateValidationMessage, ChainApiMessage, ChainSelectionMessage, CollationGenerationMessage, CollatorProtocolMessage, DisputeCoordinatorMessage, DisputeDistributionMessage, GossipSupportMessage, NetworkBridgeRxMessage, - NetworkBridgeTxMessage, ProvisionerMessage, RuntimeApiMessage, StatementDistributionMessage, + NetworkBridgeTxMessage, ProspectiveParachainsMessage, ProvisionerMessage, RuntimeApiMessage, + StatementDistributionMessage, }; pub use polkadot_node_subsystem_types::{ @@ -466,11 +467,13 @@ pub struct Overseer { #[subsystem(CandidateBackingMessage, sends: [ CandidateValidationMessage, CollatorProtocolMessage, + ChainApiMessage, AvailabilityDistributionMessage, AvailabilityStoreMessage, StatementDistributionMessage, ProvisionerMessage, RuntimeApiMessage, + ProspectiveParachainsMessage, ])] candidate_backing: CandidateBacking, @@ -478,6 +481,8 @@ pub struct Overseer { NetworkBridgeTxMessage, CandidateBackingMessage, RuntimeApiMessage, + ProspectiveParachainsMessage, + ChainApiMessage, ])] statement_distribution: StatementDistribution, @@ -516,6 +521,7 @@ pub struct Overseer { CandidateBackingMessage, ChainApiMessage, DisputeCoordinatorMessage, + ProspectiveParachainsMessage, ])] provisioner: Provisioner, @@ -555,6 +561,8 @@ pub struct Overseer { NetworkBridgeTxMessage, RuntimeApiMessage, CandidateBackingMessage, + ChainApiMessage, + ProspectiveParachainsMessage, ])] collator_protocol: CollatorProtocol, @@ -605,6 +613,12 @@ pub struct Overseer { #[subsystem(blocking, ChainSelectionMessage, sends: [ChainApiMessage])] chain_selection: ChainSelection, + #[subsystem(ProspectiveParachainsMessage, sends: [ + RuntimeApiMessage, + ChainApiMessage, + ])] + prospective_parachains: ProspectiveParachains, + /// External listeners waiting for a hash to be in the active-leave set. pub activation_external_listeners: HashMap>>>, diff --git a/node/overseer/src/tests.rs b/node/overseer/src/tests.rs index c53050e9fb0a..4ac538a7fd3a 100644 --- a/node/overseer/src/tests.rs +++ b/node/overseer/src/tests.rs @@ -30,8 +30,8 @@ use polkadot_node_subsystem_types::{ ActivatedLeaf, LeafStatus, }; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CollatorPair, InvalidDisputeStatementKind, PvfExecTimeoutKind, - SessionIndex, ValidDisputeStatementKind, ValidatorIndex, + CandidateHash, CandidateReceipt, CollatorPair, Id as ParaId, InvalidDisputeStatementKind, + PvfExecTimeoutKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, }; use crate::{ @@ -786,7 +786,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { fn test_candidate_backing_msg() -> CandidateBackingMessage { let (sender, _) = oneshot::channel(); - CandidateBackingMessage::GetBackedCandidates(Default::default(), Vec::new(), sender) + CandidateBackingMessage::GetBackedCandidates(Vec::new(), sender) } fn test_chain_api_msg() -> ChainApiMessage { @@ -797,7 +797,7 @@ fn test_chain_api_msg() -> ChainApiMessage { fn test_collator_generation_msg() -> CollationGenerationMessage { CollationGenerationMessage::Initialize(CollationGenerationConfig { key: CollatorPair::generate().0, - collator: Box::new(|_, _| TestCollator.boxed()), + collator: Some(Box::new(|_, _| TestCollator.boxed())), para_id: Default::default(), }) } @@ -912,10 +912,17 @@ fn test_chain_selection_msg() -> ChainSelectionMessage { ChainSelectionMessage::Approved(Default::default()) } +fn test_prospective_parachains_msg() -> ProspectiveParachainsMessage { + ProspectiveParachainsMessage::CandidateBacked( + ParaId::from(5), + CandidateHash(Hash::repeat_byte(0)), + ) +} + // Checks that `stop`, `broadcast_signal` and `broadcast_message` are implemented correctly. #[test] fn overseer_all_subsystems_receive_signals_and_messages() { - const NUM_SUBSYSTEMS: usize = 22; + const NUM_SUBSYSTEMS: usize = 23; // -4 for BitfieldSigning, GossipSupport, AvailabilityDistribution and PvfCheckerSubsystem. const NUM_SUBSYSTEMS_MESSAGED: usize = NUM_SUBSYSTEMS - 4; @@ -1003,6 +1010,9 @@ fn overseer_all_subsystems_receive_signals_and_messages() { handle .send_msg_anon(AllMessages::ChainSelection(test_chain_selection_msg())) .await; + handle + .send_msg_anon(AllMessages::ProspectiveParachains(test_prospective_parachains_msg())) + .await; // handle.send_msg_anon(AllMessages::PvfChecker(test_pvf_checker_msg())).await; // Wait until all subsystems have received. Otherwise the messages might race against @@ -1059,6 +1069,7 @@ fn context_holds_onto_message_until_enough_signals_received() { let (dispute_distribution_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (chain_selection_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (pvf_checker_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); + let (prospective_parachains_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (candidate_validation_unbounded_tx, _) = metered::unbounded(); let (candidate_backing_unbounded_tx, _) = metered::unbounded(); @@ -1082,6 +1093,7 @@ fn context_holds_onto_message_until_enough_signals_received() { let (dispute_distribution_unbounded_tx, _) = metered::unbounded(); let (chain_selection_unbounded_tx, _) = metered::unbounded(); let (pvf_checker_unbounded_tx, _) = metered::unbounded(); + let (prospective_parachains_unbounded_tx, _) = metered::unbounded(); let channels_out = ChannelsOut { candidate_validation: candidate_validation_bounded_tx.clone(), @@ -1106,6 +1118,7 @@ fn context_holds_onto_message_until_enough_signals_received() { dispute_distribution: dispute_distribution_bounded_tx.clone(), chain_selection: chain_selection_bounded_tx.clone(), pvf_checker: pvf_checker_bounded_tx.clone(), + prospective_parachains: prospective_parachains_bounded_tx.clone(), candidate_validation_unbounded: candidate_validation_unbounded_tx.clone(), candidate_backing_unbounded: candidate_backing_unbounded_tx.clone(), @@ -1129,6 +1142,7 @@ fn context_holds_onto_message_until_enough_signals_received() { dispute_distribution_unbounded: dispute_distribution_unbounded_tx.clone(), chain_selection_unbounded: chain_selection_unbounded_tx.clone(), pvf_checker_unbounded: pvf_checker_unbounded_tx.clone(), + prospective_parachains_unbounded: prospective_parachains_unbounded_tx.clone(), }; let (mut signal_tx, signal_rx) = metered::channel(CHANNEL_CAPACITY); diff --git a/node/primitives/src/disputes/mod.rs b/node/primitives/src/disputes/mod.rs index 5e8e5815258d..ae8602dd5fc4 100644 --- a/node/primitives/src/disputes/mod.rs +++ b/node/primitives/src/disputes/mod.rs @@ -24,10 +24,10 @@ use parity_scale_codec::{Decode, Encode}; use sp_application_crypto::AppCrypto; use sp_keystore::{Error as KeystoreError, KeystorePtr}; -use super::{Statement, UncheckedSignedFullStatement}; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, DisputeStatement, InvalidDisputeStatementKind, SessionIndex, - SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + CandidateHash, CandidateReceipt, CompactStatement, DisputeStatement, EncodeAs, + InvalidDisputeStatementKind, SessionIndex, SigningContext, UncheckedSigned, + ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; /// `DisputeMessage` and related types. @@ -270,19 +270,23 @@ impl SignedDisputeStatement { /// along with the signing context. /// /// This does signature checks again with the data provided. - pub fn from_backing_statement( - backing_statement: &UncheckedSignedFullStatement, + pub fn from_backing_statement( + backing_statement: &UncheckedSigned, signing_context: SigningContext, validator_public: ValidatorId, - ) -> Result { - let (statement_kind, candidate_hash) = match backing_statement.unchecked_payload() { - Statement::Seconded(candidate) => ( + ) -> Result + where + for<'a> &'a T: Into, + T: EncodeAs, + { + let (statement_kind, candidate_hash) = match backing_statement.unchecked_payload().into() { + CompactStatement::Seconded(candidate_hash) => ( ValidDisputeStatementKind::BackingSeconded(signing_context.parent_hash), - candidate.hash(), + candidate_hash, ), - Statement::Valid(candidate_hash) => ( + CompactStatement::Valid(candidate_hash) => ( ValidDisputeStatementKind::BackingValid(signing_context.parent_hash), - *candidate_hash, + candidate_hash, ), }; diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index d49cd806d54e..392781783319 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -32,8 +32,8 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use polkadot_primitives::{ BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, CollatorPair, CommittedCandidateReceipt, CompactStatement, EncodeAs, Hash, HashT, HeadData, Id as ParaId, - PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode, ValidatorIndex, - MAX_CODE_SIZE, MAX_POV_SIZE, + PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode, + ValidationCodeHash, ValidatorIndex, MAX_CODE_SIZE, MAX_POV_SIZE, }; pub use sp_consensus_babe::{ AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch, @@ -197,6 +197,14 @@ impl Statement { Statement::Valid(hash) => CompactStatement::Valid(hash), } } + + /// Add the [`PersistedValidationData`] to the statement, if seconded. + pub fn supply_pvd(self, pvd: PersistedValidationData) -> StatementWithPVD { + match self { + Statement::Seconded(c) => StatementWithPVD::Seconded(c, pvd), + Statement::Valid(hash) => StatementWithPVD::Valid(hash), + } + } } impl From<&'_ Statement> for CompactStatement { @@ -211,6 +219,84 @@ impl EncodeAs for Statement { } } +/// A statement, exactly the same as [`Statement`] but where seconded messages carry +/// the [`PersistedValidationData`]. +#[derive(Clone, PartialEq, Eq)] +pub enum StatementWithPVD { + /// A statement that a validator seconds a candidate. + Seconded(CommittedCandidateReceipt, PersistedValidationData), + /// A statement that a validator has deemed a candidate valid. + Valid(CandidateHash), +} + +impl std::fmt::Debug for StatementWithPVD { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StatementWithPVD::Seconded(seconded, _) => + write!(f, "Seconded: {:?}", seconded.descriptor), + StatementWithPVD::Valid(hash) => write!(f, "Valid: {:?}", hash), + } + } +} + +impl StatementWithPVD { + /// Get the candidate hash referenced by this statement. + /// + /// If this is a `Statement::Seconded`, this does hash the candidate receipt, which may be + /// expensive for large candidates. + pub fn candidate_hash(&self) -> CandidateHash { + match *self { + StatementWithPVD::Valid(ref h) => *h, + StatementWithPVD::Seconded(ref c, _) => c.hash(), + } + } + + /// Transform this statement into its compact version, which references only the hash + /// of the candidate. + pub fn to_compact(&self) -> CompactStatement { + match *self { + StatementWithPVD::Seconded(ref c, _) => CompactStatement::Seconded(c.hash()), + StatementWithPVD::Valid(hash) => CompactStatement::Valid(hash), + } + } + + /// Drop the [`PersistedValidationData`] from the statement. + pub fn drop_pvd(self) -> Statement { + match self { + StatementWithPVD::Seconded(c, _) => Statement::Seconded(c), + StatementWithPVD::Valid(c_h) => Statement::Valid(c_h), + } + } + + /// Drop the [`PersistedValidationData`] from the statement in a signed + /// variant. + pub fn drop_pvd_from_signed(signed: SignedFullStatementWithPVD) -> SignedFullStatement { + signed + .convert_to_superpayload_with(|s| s.drop_pvd()) + .expect("persisted_validation_data doesn't affect encode_as; qed") + } + + /// Converts the statement to a compact signed statement by dropping the + /// [`CommittedCandidateReceipt`] and the [`PersistedValidationData`]. + pub fn signed_to_compact(signed: SignedFullStatementWithPVD) -> Signed { + signed + .convert_to_superpayload_with(|s| s.to_compact()) + .expect("doesn't affect encode_as; qed") + } +} + +impl From<&'_ StatementWithPVD> for CompactStatement { + fn from(stmt: &StatementWithPVD) -> Self { + stmt.to_compact() + } +} + +impl EncodeAs for StatementWithPVD { + fn encode_as(&self) -> Vec { + self.to_compact().encode() + } +} + /// A statement, the corresponding signature, and the index of the sender. /// /// Signing context and validator set should be apparent from context. @@ -222,6 +308,13 @@ pub type SignedFullStatement = Signed; /// Variant of `SignedFullStatement` where the signature has not yet been verified. pub type UncheckedSignedFullStatement = UncheckedSigned; +/// A statement, the corresponding signature, and the index of the sender. +/// +/// Seconded statements are accompanied by the [`PersistedValidationData`] +/// +/// Signing context and validator set should be apparent from context. +pub type SignedFullStatementWithPVD = Signed; + /// Candidate invalidity details #[derive(Debug)] pub enum InvalidCandidate { @@ -287,6 +380,18 @@ pub enum MaybeCompressedPoV { Compressed(PoV), } +#[cfg(not(target_os = "unknown"))] +impl std::fmt::Debug for MaybeCompressedPoV { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let (variant, size) = match self { + MaybeCompressedPoV::Raw(pov) => ("Raw", pov.block_data.0.len()), + MaybeCompressedPoV::Compressed(pov) => ("Compressed", pov.block_data.0.len()), + }; + + write!(f, "{} PoV ({} bytes)", variant, size) + } +} + #[cfg(not(target_os = "unknown"))] impl MaybeCompressedPoV { /// Convert into a compressed [`PoV`]. @@ -306,7 +411,7 @@ impl MaybeCompressedPoV { /// /// - does not contain the erasure root; that's computed at the Polkadot level, not at Cumulus /// - contains a proof of validity. -#[derive(Clone, Encode, Decode)] +#[derive(Debug, Clone, Encode, Decode)] #[cfg(not(target_os = "unknown"))] pub struct Collation { /// Messages destined to be interpreted by the Relay chain itself. @@ -384,7 +489,10 @@ pub struct CollationGenerationConfig { /// Collator's authentication key, so it can sign things. pub key: CollatorPair, /// Collation function. See [`CollatorFn`] for more details. - pub collator: CollatorFn, + /// + /// If this is `None`, it implies that collations are intended to be submitted + /// out-of-band and not pulled out of the function. + pub collator: Option, /// The parachain that this collator collates for pub para_id: ParaId, } @@ -396,6 +504,25 @@ impl std::fmt::Debug for CollationGenerationConfig { } } +/// Parameters for [`CollationGenerationMessage::SubmitCollation`]. +#[derive(Debug)] +pub struct SubmitCollationParams { + /// The relay-parent the collation is built against. + pub relay_parent: Hash, + /// The collation itself (PoV and commitments) + pub collation: Collation, + /// The parent block's head-data. + pub parent_head: HeadData, + /// The hash of the validation code the collation was created against. + pub validation_code_hash: ValidationCodeHash, + /// An optional result sender that should be informed about a successfully seconded collation. + /// + /// There is no guarantee that this sender is informed ever about any result, it is completely + /// okay to just drop it. However, if it is called, it should be called with the signed + /// statement of a parachain validator seconding the collation. + pub result_sender: Option>, +} + /// This is the data we keep available for each candidate included in the relay chain. #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)] pub struct AvailableData { @@ -528,3 +655,10 @@ pub fn maybe_compress_pov(pov: PoV) -> PoV { let pov = PoV { block_data: BlockData(raw) }; pov } + +/// How many votes we need to consider a candidate backed. +/// +/// WARNING: This has to be kept in sync with the runtime check in the inclusion module. +pub fn minimum_votes(n_validators: usize) -> usize { + std::cmp::min(2, n_validators) +} diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml index 8cd9e4434bbd..6cb9dc4ba58e 100644 --- a/node/service/Cargo.toml +++ b/node/service/Cargo.toml @@ -135,6 +135,7 @@ polkadot-node-core-candidate-validation = { path = "../core/candidate-validation polkadot-node-core-chain-api = { path = "../core/chain-api", optional = true } polkadot-node-core-chain-selection = { path = "../core/chain-selection", optional = true } polkadot-node-core-dispute-coordinator = { path = "../core/dispute-coordinator", optional = true } +polkadot-node-core-prospective-parachains = { path = "../core/prospective-parachains", optional = true } polkadot-node-core-provisioner = { path = "../core/provisioner", optional = true } polkadot-node-core-pvf = { path = "../core/pvf", optional = true } polkadot-node-core-pvf-checker = { path = "../core/pvf-checker", optional = true } @@ -173,6 +174,7 @@ full-node = [ "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", + "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-runtime-api", "polkadot-statement-distribution", @@ -220,3 +222,5 @@ runtime-metrics = [ "polkadot-runtime?/runtime-metrics", "polkadot-runtime-parachains/runtime-metrics" ] + +network-protocol-staging = ["polkadot-node-network-protocol/network-protocol-staging"] diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 2e46bf7329e2..3d9486ccc87b 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -859,13 +859,20 @@ pub fn new_full( net_config.add_request_response_protocol(cfg); let (chunk_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); - let (collation_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); + let (collation_req_v1_receiver, cfg) = + IncomingRequest::get_config_receiver(&req_protocol_names); + net_config.add_request_response_protocol(cfg); + let (collation_req_vstaging_receiver, cfg) = + IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); let (available_data_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); let (statement_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); + let (candidate_req_vstaging_receiver, cfg) = + IncomingRequest::get_config_receiver(&req_protocol_names); + net_config.add_request_response_protocol(cfg); let (dispute_req_receiver, cfg) = IncomingRequest::get_config_receiver(&req_protocol_names); net_config.add_request_response_protocol(cfg); @@ -1050,9 +1057,11 @@ pub fn new_full( authority_discovery_service, pov_req_receiver, chunk_req_receiver, - collation_req_receiver, + collation_req_v1_receiver, + collation_req_vstaging_receiver, available_data_req_receiver, statement_req_receiver, + candidate_req_vstaging_receiver, dispute_req_receiver, registry: prometheus_registry.as_ref(), spawner, diff --git a/node/service/src/overseer.rs b/node/service/src/overseer.rs index b315d2847c07..cb6b80eb83c8 100644 --- a/node/service/src/overseer.rs +++ b/node/service/src/overseer.rs @@ -28,7 +28,9 @@ use polkadot_node_core_chain_selection::Config as ChainSelectionConfig; use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, - request_response::{v1 as request_v1, IncomingRequestReceiver, ReqProtocolNames}, + request_response::{ + v1 as request_v1, vstaging as request_vstaging, IncomingRequestReceiver, ReqProtocolNames, + }, }; #[cfg(any(feature = "malus", test))] pub use polkadot_overseer::{ @@ -70,6 +72,7 @@ pub use polkadot_node_core_candidate_validation::CandidateValidationSubsystem; pub use polkadot_node_core_chain_api::ChainApiSubsystem; pub use polkadot_node_core_chain_selection::ChainSelectionSubsystem; pub use polkadot_node_core_dispute_coordinator::DisputeCoordinatorSubsystem; +pub use polkadot_node_core_prospective_parachains::ProspectiveParachainsSubsystem; pub use polkadot_node_core_provisioner::ProvisionerSubsystem; pub use polkadot_node_core_pvf_checker::PvfCheckerSubsystem; pub use polkadot_node_core_runtime_api::RuntimeApiSubsystem; @@ -95,13 +98,24 @@ where pub sync_service: Arc>, /// Underlying authority discovery service. pub authority_discovery_service: AuthorityDiscoveryService, - /// POV request receiver + /// POV request receiver. pub pov_req_receiver: IncomingRequestReceiver, + /// Erasure chunks request receiver. pub chunk_req_receiver: IncomingRequestReceiver, - pub collation_req_receiver: IncomingRequestReceiver, + /// Collations request receiver for network protocol v1. + pub collation_req_v1_receiver: IncomingRequestReceiver, + /// Collations request receiver for network protocol vstaging. + pub collation_req_vstaging_receiver: + IncomingRequestReceiver, + /// Receiver for available data requests. pub available_data_req_receiver: IncomingRequestReceiver, + /// Receiver for incoming large statement requests. pub statement_req_receiver: IncomingRequestReceiver, + /// Receiver for incoming candidate requests. + pub candidate_req_vstaging_receiver: + IncomingRequestReceiver, + /// Receiver for incoming disputes. pub dispute_req_receiver: IncomingRequestReceiver, /// Prometheus registry, commonly used for production systems, less so for test. pub registry: Option<&'a Registry>, @@ -143,9 +157,11 @@ pub fn prepared_overseer_builder( authority_discovery_service, pov_req_receiver, chunk_req_receiver, - collation_req_receiver, + collation_req_v1_receiver, + collation_req_vstaging_receiver, available_data_req_receiver, statement_req_receiver, + candidate_req_vstaging_receiver, dispute_req_receiver, registry, spawner, @@ -193,6 +209,7 @@ pub fn prepared_overseer_builder( DisputeCoordinatorSubsystem, DisputeDistributionSubsystem, ChainSelectionSubsystem, + ProspectiveParachainsSubsystem, >, Error, > @@ -267,12 +284,13 @@ where .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) .collator_protocol({ let side = match is_parachain_node { - IsParachainNode::Collator(collator_pair) => ProtocolSide::Collator( - network_service.local_peer_id(), + IsParachainNode::Collator(collator_pair) => ProtocolSide::Collator { + peer_id: network_service.local_peer_id(), collator_pair, - collation_req_receiver, - Metrics::register(registry)?, - ), + request_receiver_v1: collation_req_v1_receiver, + request_receiver_vstaging: collation_req_vstaging_receiver, + metrics: Metrics::register(registry)?, + }, IsParachainNode::FullNode => ProtocolSide::None, IsParachainNode::No => ProtocolSide::Validator { keystore: keystore.clone(), @@ -291,6 +309,7 @@ where .statement_distribution(StatementDistributionSubsystem::new( keystore.clone(), statement_req_receiver, + candidate_req_vstaging_receiver, Metrics::register(registry)?, rand::rngs::StdRng::from_entropy(), )) @@ -320,6 +339,7 @@ where Metrics::register(registry)?, )) .chain_selection(ChainSelectionSubsystem::new(chain_selection_config, parachains_db)) + .prospective_parachains(ProspectiveParachainsSubsystem::new(Metrics::register(registry)?)) .activation_external_listeners(Default::default()) .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) diff --git a/node/subsystem-types/src/messages.rs b/node/subsystem-types/src/messages.rs index d5dcea7a2565..8adc39eed56d 100644 --- a/node/subsystem-types/src/messages.rs +++ b/node/subsystem-types/src/messages.rs @@ -35,16 +35,18 @@ use polkadot_node_primitives::{ approval::{BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote}, AvailableData, BabeEpoch, BlockWeight, CandidateVotes, CollationGenerationConfig, CollationSecondedSignal, DisputeMessage, DisputeStatus, ErasureChunk, PoV, - SignedDisputeStatement, SignedFullStatement, ValidationResult, + SignedDisputeStatement, SignedFullStatement, SignedFullStatementWithPVD, SubmitCollationParams, + ValidationResult, }; use polkadot_primitives::{ - slashing, AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash, - CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreState, - DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, PvfExecTimeoutKind, - SessionIndex, SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + slashing, vstaging as vstaging_primitives, AuthorityDiscoveryId, BackedCandidate, BlockNumber, + CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, + PvfCheckStatement, PvfExecTimeoutKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, + SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -56,20 +58,42 @@ use std::{ pub mod network_bridge_event; pub use network_bridge_event::NetworkBridgeEvent; +/// A request to the candidate backing subsystem to check whether +/// there exists vacant membership in some fragment tree. +#[derive(Debug, Copy, Clone)] +pub struct CanSecondRequest { + /// Para id of the candidate. + pub candidate_para_id: ParaId, + /// The relay-parent of the candidate. + pub candidate_relay_parent: Hash, + /// Hash of the candidate. + pub candidate_hash: CandidateHash, + /// Parent head data hash. + pub parent_head_data_hash: Hash, +} + /// Messages received by the Candidate Backing subsystem. #[derive(Debug)] pub enum CandidateBackingMessage { - /// Requests a set of backable candidates that could be backed in a child of the given - /// relay-parent, referenced by its hash. - GetBackedCandidates(Hash, Vec, oneshot::Sender>), + /// Requests a set of backable candidates attested by the subsystem. + /// + /// Each pair is (candidate_hash, candidate_relay_parent). + GetBackedCandidates(Vec<(CandidateHash, Hash)>, oneshot::Sender>), + /// Request the subsystem to check whether it's allowed to second given candidate. + /// The rule is to only fetch collations that are either built on top of the root + /// of some fragment tree or have a parent node which represents backed candidate. + /// + /// Always responses with `false` if async backing is disabled for candidate's relay + /// parent. + CanSecond(CanSecondRequest, oneshot::Sender), /// Note that the Candidate Backing subsystem should second the given candidate in the context /// of the given relay-parent (ref. by hash). This candidate must be validated. - Second(Hash, CandidateReceipt, PoV), - /// Note a validator's statement about a particular candidate. Disagreements about validity - /// must be escalated to a broader check by the Disputes Subsystem, though that escalation is - /// deferred until the approval voting stage to guarantee availability. Agreements are simply - /// tallied until a quorum is reached. - Statement(Hash, SignedFullStatement), + Second(Hash, CandidateReceipt, PersistedValidationData, PoV), + /// Note a validator's statement about a particular candidate in the context of the given + /// relay-parent. Disagreements about validity must be escalated to a broader check by the + /// Disputes Subsystem, though that escalation is deferred until the approval voting stage to + /// guarantee availability. Agreements are simply tallied until a quorum is reached. + Statement(Hash, SignedFullStatementWithPVD), } /// Blanket error for validation failing for internal reasons. @@ -165,10 +189,16 @@ pub enum CollatorProtocolMessage { /// This should be sent before any `DistributeCollation` message. CollateOn(ParaId), /// Provide a collation to distribute to validators with an optional result sender. + /// The second argument is the parent head-data hash. /// /// The result sender should be informed when at least one parachain validator seconded the /// collation. It is also completely okay to just drop the sender. - DistributeCollation(CandidateReceipt, PoV, Option>), + DistributeCollation( + CandidateReceipt, + Hash, + PoV, + Option>, + ), /// Report a collator as having provided an invalid collation. This should lead to disconnect /// and blacklist of the collator. ReportCollator(CollatorId), @@ -184,6 +214,13 @@ pub enum CollatorProtocolMessage { /// /// The hash is the relay parent. Seconded(Hash, SignedFullStatement), + /// The candidate received enough validity votes from the backing group. + Backed { + /// Candidate's para id. + para_id: ParaId, + /// Hash of the para head generated by candidate. + para_head: Hash, + }, } impl Default for CollatorProtocolMessage { @@ -527,7 +564,7 @@ pub enum ChainApiMessage { /// Request the last finalized block number. /// This request always succeeds. FinalizedBlockNumber(ChainApiResponseChannel), - /// Request the `k` ancestors block hashes of a block with the given hash. + /// Request the `k` ancestor block hashes of a block with the given hash. /// The response channel may return a `Vec` of size up to `k` /// filled with ancestors hashes with the following order: /// `parent`, `grandparent`, ... up to the hash of genesis block @@ -654,6 +691,14 @@ pub enum RuntimeApiRequest { slashing::OpaqueKeyOwnershipProof, RuntimeApiSender>, ), + + /// Get the backing state of the given para. + /// This is a staging API that will not be available on production runtimes. + StagingParaBackingState(ParaId, RuntimeApiSender>), + /// Get candidate's acceptance limitations for asynchronous backing for a relay parent. + /// + /// If it's not supported by the Runtime, the async backing is said to be disabled. + StagingAsyncBackingParams(RuntimeApiSender), } impl RuntimeApiRequest { @@ -673,6 +718,11 @@ impl RuntimeApiRequest { /// `SubmitReportDisputeLost` pub const SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT: u32 = 5; + + /// Minimum version for backing state, required for async backing. + /// + /// 99 for now, should be adjusted to VSTAGING/actual runtime version once released. + pub const STAGING_BACKING_STATE: u32 = 99; } /// A message to the Runtime API subsystem. @@ -687,7 +737,14 @@ pub enum RuntimeApiMessage { pub enum StatementDistributionMessage { /// We have originated a signed statement in the context of /// given relay-parent hash and it should be distributed to other validators. - Share(Hash, SignedFullStatement), + Share(Hash, SignedFullStatementWithPVD), + /// The candidate received enough validity votes from the backing group. + /// + /// If the candidate is backed as a result of a local statement, this message MUST + /// be preceded by a `Share` message for that statement. This ensures that Statement + /// Distribution is always aware of full candidates prior to receiving the `Backed` + /// notification, even when the group size is 1 and the candidate is seconded locally. + Backed(CandidateHash), /// Event from the network bridge. #[from] NetworkBridgeUpdate(NetworkBridgeEvent), @@ -740,6 +797,11 @@ pub enum ProvisionerMessage { pub enum CollationGenerationMessage { /// Initialize the collation generation subsystem Initialize(CollationGenerationConfig), + /// Submit a collation to the subsystem. This will package it into a signed + /// [`CommittedCandidateReceipt`] and distribute along the network to validators. + /// + /// If sent before `Initialize`, this will be ignored. + SubmitCollation(SubmitCollationParams), } /// The result type of [`ApprovalVotingMessage::CheckAndImportAssignment`] request. @@ -897,3 +959,175 @@ pub enum GossipSupportMessage { #[from] NetworkBridgeUpdate(NetworkBridgeEvent), } + +/// Request introduction of a candidate into the prospective parachains subsystem. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct IntroduceCandidateRequest { + /// The para-id of the candidate. + pub candidate_para: ParaId, + /// The candidate receipt itself. + pub candidate_receipt: CommittedCandidateReceipt, + /// The persisted validation data of the candidate. + pub persisted_validation_data: PersistedValidationData, +} + +/// A hypothetical candidate to be evaluated for frontier membership +/// in the prospective parachains subsystem. +/// +/// Hypothetical candidates are either complete or incomplete. +/// Complete candidates have already had their (potentially heavy) +/// candidate receipt fetched, while incomplete candidates are simply +/// claims about properties that a fetched candidate would have. +/// +/// Complete candidates can be evaluated more strictly than incomplete candidates. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum HypotheticalCandidate { + /// A complete candidate. + Complete { + /// The hash of the candidate. + candidate_hash: CandidateHash, + /// The receipt of the candidate. + receipt: Arc, + /// The persisted validation data of the candidate. + persisted_validation_data: PersistedValidationData, + }, + /// An incomplete candidate. + Incomplete { + /// The claimed hash of the candidate. + candidate_hash: CandidateHash, + /// The claimed para-ID of the candidate. + candidate_para: ParaId, + /// The claimed head-data hash of the candidate. + parent_head_data_hash: Hash, + /// The claimed relay parent of the candidate. + candidate_relay_parent: Hash, + }, +} + +impl HypotheticalCandidate { + /// Get the `CandidateHash` of the hypothetical candidate. + pub fn candidate_hash(&self) -> CandidateHash { + match *self { + HypotheticalCandidate::Complete { candidate_hash, .. } => candidate_hash, + HypotheticalCandidate::Incomplete { candidate_hash, .. } => candidate_hash, + } + } + + /// Get the `ParaId` of the hypothetical candidate. + pub fn candidate_para(&self) -> ParaId { + match *self { + HypotheticalCandidate::Complete { ref receipt, .. } => receipt.descriptor().para_id, + HypotheticalCandidate::Incomplete { candidate_para, .. } => candidate_para, + } + } + + /// Get parent head data hash of the hypothetical candidate. + pub fn parent_head_data_hash(&self) -> Hash { + match *self { + HypotheticalCandidate::Complete { ref persisted_validation_data, .. } => + persisted_validation_data.parent_head.hash(), + HypotheticalCandidate::Incomplete { parent_head_data_hash, .. } => + parent_head_data_hash, + } + } + + /// Get candidate's relay parent. + pub fn relay_parent(&self) -> Hash { + match *self { + HypotheticalCandidate::Complete { ref receipt, .. } => + receipt.descriptor().relay_parent, + HypotheticalCandidate::Incomplete { candidate_relay_parent, .. } => + candidate_relay_parent, + } + } +} + +/// Request specifying which candidates are either already included +/// or might be included in the hypothetical frontier of fragment trees +/// under a given active leaf. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct HypotheticalFrontierRequest { + /// Candidates, in arbitrary order, which should be checked for + /// possible membership in fragment trees. + pub candidates: Vec, + /// Either a specific fragment tree to check, otherwise all. + pub fragment_tree_relay_parent: Option, + /// Only return membership if all candidates in the path from the + /// root are backed. + pub backed_in_path_only: bool, +} + +/// A request for the persisted validation data stored in the prospective +/// parachains subsystem. +#[derive(Debug)] +pub struct ProspectiveValidationDataRequest { + /// The para-id of the candidate. + pub para_id: ParaId, + /// The relay-parent of the candidate. + pub candidate_relay_parent: Hash, + /// The parent head-data hash. + pub parent_head_data_hash: Hash, +} + +/// Indicates the relay-parents whose fragment tree a candidate +/// is present in and the depths of that tree the candidate is present in. +pub type FragmentTreeMembership = Vec<(Hash, Vec)>; + +/// Messages sent to the Prospective Parachains subsystem. +#[derive(Debug)] +pub enum ProspectiveParachainsMessage { + /// Inform the Prospective Parachains Subsystem of a new candidate. + /// + /// The response sender accepts the candidate membership, which is the existing + /// membership of the candidate if it was already known. + IntroduceCandidate(IntroduceCandidateRequest, oneshot::Sender), + /// Inform the Prospective Parachains Subsystem that a previously introduced candidate + /// has been seconded. This requires that the candidate was successfully introduced in + /// the past. + CandidateSeconded(ParaId, CandidateHash), + /// Inform the Prospective Parachains Subsystem that a previously introduced candidate + /// has been backed. This requires that the candidate was successfully introduced in + /// the past. + CandidateBacked(ParaId, CandidateHash), + /// Get a backable candidate hash along with its relay parent for the given parachain, + /// under the given relay-parent hash, which is a descendant of the given candidate hashes. + /// Returns `None` on the channel if no such candidate exists. + GetBackableCandidate( + Hash, + ParaId, + Vec, + oneshot::Sender>, + ), + /// Get the hypothetical frontier membership of candidates with the given properties + /// under the specified active leaves' fragment trees. + /// + /// For any candidate which is already known, this returns the depths the candidate + /// occupies. + GetHypotheticalFrontier( + HypotheticalFrontierRequest, + oneshot::Sender>, + ), + /// Get the membership of the candidate in all fragment trees. + GetTreeMembership(ParaId, CandidateHash, oneshot::Sender), + /// Get the minimum accepted relay-parent number for each para in the fragment tree + /// for the given relay-chain block hash. + /// + /// That is, if the block hash is known and is an active leaf, this returns the + /// minimum relay-parent block number in the same branch of the relay chain which + /// is accepted in the fragment tree for each para-id. + /// + /// If the block hash is not an active leaf, this will return an empty vector. + /// + /// Para-IDs which are omitted from this list can be assumed to have no + /// valid candidate relay-parents under the given relay-chain block hash. + /// + /// Para-IDs are returned in no particular order. + GetMinimumRelayParents(Hash, oneshot::Sender>), + /// Get the validation data of some prospective candidate. The candidate doesn't need + /// to be part of any fragment tree, but this only succeeds if the parent head-data and + /// relay-parent are part of some fragment tree. + GetProspectiveValidationData( + ProspectiveValidationDataRequest, + oneshot::Sender>, + ), +} diff --git a/node/subsystem-types/src/runtime_client.rs b/node/subsystem-types/src/runtime_client.rs index 4d8eddde73e9..312cc4eec6ce 100644 --- a/node/subsystem-types/src/runtime_client.rs +++ b/node/subsystem-types/src/runtime_client.rs @@ -212,13 +212,6 @@ pub trait RuntimeApiSubsystemClient { key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, ) -> Result, ApiError>; - /// Get the execution environment parameter set by parent hash, if stored - async fn session_executor_params( - &self, - at: Hash, - session_index: SessionIndex, - ) -> Result, ApiError>; - // === BABE API === /// Returns information regarding the current epoch. @@ -231,6 +224,29 @@ pub trait RuntimeApiSubsystemClient { &self, at: Hash, ) -> std::result::Result, ApiError>; + + /// Get the execution environment parameter set by parent hash, if stored + async fn session_executor_params( + &self, + at: Hash, + session_index: SessionIndex, + ) -> Result, ApiError>; + + // === Asynchronous backing API === + + /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. + async fn staging_async_backing_params( + &self, + at: Hash, + ) -> Result; + + /// Returns the state of parachain backing for a given para. + /// This is a staging method! Do not use on production runtimes! + async fn staging_para_backing_state( + &self, + at: Hash, + para_id: Id, + ) -> Result, ApiError>; } /// Default implementation of [`RuntimeApiSubsystemClient`] using the client. @@ -456,4 +472,20 @@ where runtime_api.submit_report_dispute_lost(at, dispute_proof, key_ownership_proof) } + + async fn staging_para_backing_state( + &self, + at: Hash, + para_id: Id, + ) -> Result, ApiError> { + self.client.runtime_api().staging_para_backing_state(at, para_id) + } + + /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. + async fn staging_async_backing_params( + &self, + at: Hash, + ) -> Result { + self.client.runtime_api().staging_async_backing_params(at) + } } diff --git a/node/subsystem-util/src/backing_implicit_view.rs b/node/subsystem-util/src/backing_implicit_view.rs new file mode 100644 index 000000000000..adf7fbd54258 --- /dev/null +++ b/node/subsystem-util/src/backing_implicit_view.rs @@ -0,0 +1,739 @@ +// Copyright 2022 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 futures::channel::oneshot; +use polkadot_node_subsystem::{ + errors::ChainApiError, + messages::{ChainApiMessage, ProspectiveParachainsMessage}, + SubsystemSender, +}; +use polkadot_primitives::vstaging::{BlockNumber, Hash, Id as ParaId}; + +use std::collections::HashMap; + +// Always aim to retain 1 block before the active leaves. +const MINIMUM_RETAIN_LENGTH: BlockNumber = 2; + +/// Handles the implicit view of the relay chain derived from the immediate view, which +/// is composed of active leaves, and the minimum relay-parents allowed for +/// candidates of various parachains at those leaves. +#[derive(Default, Clone)] +pub struct View { + leaves: HashMap, + block_info_storage: HashMap, +} + +// Minimum relay parents implicitly relative to a particular block. +#[derive(Debug, Clone)] +struct AllowedRelayParents { + // minimum relay parents can only be fetched for active leaves, + // so this will be empty for all blocks that haven't ever been + // witnessed as active leaves. + minimum_relay_parents: HashMap, + // Ancestry, in descending order, starting from the block hash itself down + // to and including the minimum of `minimum_relay_parents`. + allowed_relay_parents_contiguous: Vec, +} + +impl AllowedRelayParents { + fn allowed_relay_parents_for( + &self, + para_id: Option, + base_number: BlockNumber, + ) -> &[Hash] { + let para_id = match para_id { + None => return &self.allowed_relay_parents_contiguous[..], + Some(p) => p, + }; + + let para_min = match self.minimum_relay_parents.get(¶_id) { + Some(p) => *p, + None => return &[], + }; + + if base_number < para_min { + return &[] + } + + let diff = base_number - para_min; + + // difference of 0 should lead to slice len of 1 + let slice_len = ((diff + 1) as usize).min(self.allowed_relay_parents_contiguous.len()); + &self.allowed_relay_parents_contiguous[..slice_len] + } +} + +#[derive(Debug, Clone)] +struct ActiveLeafPruningInfo { + // The minimum block in the same branch of the relay-chain that should be + // preserved. + retain_minimum: BlockNumber, +} + +#[derive(Debug, Clone)] +struct BlockInfo { + block_number: BlockNumber, + // If this was previously an active leaf, this will be `Some` + // and is useful for understanding the views of peers in the network + // which may not be in perfect synchrony with our own view. + // + // If they are ahead of us in getting a new leaf, there's nothing we + // can do as it's an unrecognized block hash. But if they're behind us, + // it's useful for us to retain some information about previous leaves' + // implicit views so we can continue to send relevant messages to them + // until they catch up. + maybe_allowed_relay_parents: Option, + parent_hash: Hash, +} + +impl View { + /// Get an iterator over active leaves in the view. + pub fn leaves(&self) -> impl Iterator { + self.leaves.keys() + } + + /// Activate a leaf in the view. + /// This will request the minimum relay parents from the + /// Prospective Parachains subsystem for each leaf and will load headers in the ancestry of each + /// leaf in the view as needed. These are the 'implicit ancestors' of the leaf. + /// + /// To maximize reuse of outdated leaves, it's best to activate new leaves before + /// deactivating old ones. + /// + /// This returns a list of para-ids which are relevant to the leaf, + /// and the allowed relay parents for these paras under this leaf can be + /// queried with [`View::known_allowed_relay_parents_under`]. + /// + /// No-op for known leaves. + pub async fn activate_leaf( + &mut self, + sender: &mut Sender, + leaf_hash: Hash, + ) -> Result, FetchError> + where + Sender: SubsystemSender, + Sender: SubsystemSender, + { + if self.leaves.contains_key(&leaf_hash) { + return Err(FetchError::AlreadyKnown) + } + + let res = fetch_fresh_leaf_and_insert_ancestry( + leaf_hash, + &mut self.block_info_storage, + &mut *sender, + ) + .await; + + match res { + Ok(fetched) => { + // Retain at least `MINIMUM_RETAIN_LENGTH` blocks in storage. + // This helps to avoid Chain API calls when activating leaves in the + // same chain. + let retain_minimum = std::cmp::min( + fetched.minimum_ancestor_number, + fetched.leaf_number.saturating_sub(MINIMUM_RETAIN_LENGTH), + ); + + self.leaves.insert(leaf_hash, ActiveLeafPruningInfo { retain_minimum }); + + Ok(fetched.relevant_paras) + }, + Err(e) => Err(e), + } + } + + /// Deactivate a leaf in the view. This prunes any outdated implicit ancestors as well. + /// + /// Returns hashes of blocks pruned from storage. + pub fn deactivate_leaf(&mut self, leaf_hash: Hash) -> Vec { + let mut removed = Vec::new(); + + if self.leaves.remove(&leaf_hash).is_none() { + return removed + } + + // Prune everything before the minimum out of all leaves, + // pruning absolutely everything if there are no leaves (empty view) + // + // Pruning by block number does leave behind orphaned forks slightly longer + // but the memory overhead is negligible. + { + let minimum = self.leaves.values().map(|l| l.retain_minimum).min(); + + self.block_info_storage.retain(|hash, i| { + let keep = minimum.map_or(false, |m| i.block_number >= m); + if !keep { + removed.push(*hash); + } + keep + }); + + removed + } + } + + /// Get an iterator over all allowed relay-parents in the view with no particular order. + /// + /// **Important**: not all blocks are guaranteed to be allowed for some leaves, it may + /// happen that a block info is only kept in the view storage because of a retaining rule. + /// + /// For getting relay-parents that are valid for parachain candidates use + /// [`View::known_allowed_relay_parents_under`]. + pub fn all_allowed_relay_parents(&self) -> impl Iterator { + self.block_info_storage.keys() + } + + /// Get the known, allowed relay-parents that are valid for parachain candidates + /// which could be backed in a child of a given block for a given para ID. + /// + /// This is expressed as a contiguous slice of relay-chain block hashes which may + /// include the provided block hash itself. + /// + /// If `para_id` is `None`, this returns all valid relay-parents across all paras + /// for the leaf. + /// + /// `None` indicates that the block hash isn't part of the implicit view or that + /// there are no known allowed relay parents. + /// + /// This always returns `Some` for active leaves or for blocks that previously + /// were active leaves. + /// + /// This can return the empty slice, which indicates that no relay-parents are allowed + /// for the para, e.g. if the para is not scheduled at the given block hash. + pub fn known_allowed_relay_parents_under( + &self, + block_hash: &Hash, + para_id: Option, + ) -> Option<&[Hash]> { + let block_info = self.block_info_storage.get(block_hash)?; + block_info + .maybe_allowed_relay_parents + .as_ref() + .map(|mins| mins.allowed_relay_parents_for(para_id, block_info.block_number)) + } +} + +/// Errors when fetching a leaf and associated ancestry. +#[fatality::fatality] +pub enum FetchError { + /// Activated leaf is already present in view. + #[error("Leaf was already known")] + AlreadyKnown, + + /// Request to the prospective parachains subsystem failed. + #[error("The prospective parachains subsystem was unavailable")] + ProspectiveParachainsUnavailable, + + /// Failed to fetch the block header. + #[error("A block header was unavailable")] + BlockHeaderUnavailable(Hash, BlockHeaderUnavailableReason), + + /// A block header was unavailable due to a chain API error. + #[error("A block header was unavailable due to a chain API error")] + ChainApiError(Hash, ChainApiError), + + /// Request to the Chain API subsystem failed. + #[error("The chain API subsystem was unavailable")] + ChainApiUnavailable, +} + +/// Reasons a block header might have been unavailable. +#[derive(Debug)] +pub enum BlockHeaderUnavailableReason { + /// Block header simply unknown. + Unknown, + /// Internal Chain API error. + Internal(ChainApiError), + /// The subsystem was unavailable. + SubsystemUnavailable, +} + +struct FetchSummary { + minimum_ancestor_number: BlockNumber, + leaf_number: BlockNumber, + relevant_paras: Vec, +} + +async fn fetch_fresh_leaf_and_insert_ancestry( + leaf_hash: Hash, + block_info_storage: &mut HashMap, + sender: &mut Sender, +) -> Result +where + Sender: SubsystemSender, + Sender: SubsystemSender, +{ + let min_relay_parents_raw = { + let (tx, rx) = oneshot::channel(); + sender + .send_message(ProspectiveParachainsMessage::GetMinimumRelayParents(leaf_hash, tx)) + .await; + + match rx.await { + Ok(m) => m, + Err(_) => return Err(FetchError::ProspectiveParachainsUnavailable), + } + }; + + let leaf_header = { + let (tx, rx) = oneshot::channel(); + sender.send_message(ChainApiMessage::BlockHeader(leaf_hash, tx)).await; + + match rx.await { + Ok(Ok(Some(header))) => header, + Ok(Ok(None)) => + return Err(FetchError::BlockHeaderUnavailable( + leaf_hash, + BlockHeaderUnavailableReason::Unknown, + )), + Ok(Err(e)) => + return Err(FetchError::BlockHeaderUnavailable( + leaf_hash, + BlockHeaderUnavailableReason::Internal(e), + )), + Err(_) => + return Err(FetchError::BlockHeaderUnavailable( + leaf_hash, + BlockHeaderUnavailableReason::SubsystemUnavailable, + )), + } + }; + + let min_min = min_relay_parents_raw.iter().map(|x| x.1).min().unwrap_or(leaf_header.number); + let relevant_paras = min_relay_parents_raw.iter().map(|x| x.0).collect(); + let expected_ancestry_len = (leaf_header.number.saturating_sub(min_min) as usize) + 1; + + let ancestry = if leaf_header.number > 0 { + let mut next_ancestor_number = leaf_header.number - 1; + let mut next_ancestor_hash = leaf_header.parent_hash; + + let mut ancestry = Vec::with_capacity(expected_ancestry_len); + ancestry.push(leaf_hash); + + // Ensure all ancestors up to and including `min_min` are in the + // block storage. When views advance incrementally, everything + // should already be present. + while next_ancestor_number >= min_min { + let parent_hash = if let Some(info) = block_info_storage.get(&next_ancestor_hash) { + info.parent_hash + } else { + // load the header and insert into block storage. + let (tx, rx) = oneshot::channel(); + sender.send_message(ChainApiMessage::BlockHeader(next_ancestor_hash, tx)).await; + + let header = match rx.await { + Ok(Ok(Some(header))) => header, + Ok(Ok(None)) => + return Err(FetchError::BlockHeaderUnavailable( + next_ancestor_hash, + BlockHeaderUnavailableReason::Unknown, + )), + Ok(Err(e)) => + return Err(FetchError::BlockHeaderUnavailable( + next_ancestor_hash, + BlockHeaderUnavailableReason::Internal(e), + )), + Err(_) => + return Err(FetchError::BlockHeaderUnavailable( + next_ancestor_hash, + BlockHeaderUnavailableReason::SubsystemUnavailable, + )), + }; + + block_info_storage.insert( + next_ancestor_hash, + BlockInfo { + block_number: next_ancestor_number, + parent_hash: header.parent_hash, + maybe_allowed_relay_parents: None, + }, + ); + + header.parent_hash + }; + + ancestry.push(next_ancestor_hash); + if next_ancestor_number == 0 { + break + } + + next_ancestor_number -= 1; + next_ancestor_hash = parent_hash; + } + + ancestry + } else { + vec![leaf_hash] + }; + + let fetched_ancestry = FetchSummary { + minimum_ancestor_number: min_min, + leaf_number: leaf_header.number, + relevant_paras, + }; + + let allowed_relay_parents = AllowedRelayParents { + minimum_relay_parents: min_relay_parents_raw.iter().cloned().collect(), + allowed_relay_parents_contiguous: ancestry, + }; + + let leaf_block_info = BlockInfo { + parent_hash: leaf_header.parent_hash, + block_number: leaf_header.number, + maybe_allowed_relay_parents: Some(allowed_relay_parents), + }; + + block_info_storage.insert(leaf_hash, leaf_block_info); + + Ok(fetched_ancestry) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::TimeoutExt; + use assert_matches::assert_matches; + use futures::future::{join, FutureExt}; + use polkadot_node_subsystem::AllMessages; + use polkadot_node_subsystem_test_helpers::{ + make_subsystem_context, TestSubsystemContextHandle, + }; + use polkadot_overseer::SubsystemContext; + use polkadot_primitives::Header; + use sp_core::testing::TaskExecutor; + use std::time::Duration; + + const PARA_A: ParaId = ParaId::new(0); + const PARA_B: ParaId = ParaId::new(1); + const PARA_C: ParaId = ParaId::new(2); + + const GENESIS_HASH: Hash = Hash::repeat_byte(0xFF); + const GENESIS_NUMBER: BlockNumber = 0; + + // Chains A and B are forks of genesis. + + const CHAIN_A: &[Hash] = + &[Hash::repeat_byte(0x01), Hash::repeat_byte(0x02), Hash::repeat_byte(0x03)]; + + const CHAIN_B: &[Hash] = &[ + Hash::repeat_byte(0x04), + Hash::repeat_byte(0x05), + Hash::repeat_byte(0x06), + Hash::repeat_byte(0x07), + Hash::repeat_byte(0x08), + Hash::repeat_byte(0x09), + ]; + + type VirtualOverseer = TestSubsystemContextHandle; + + const TIMEOUT: Duration = Duration::from_secs(2); + + async fn overseer_recv(virtual_overseer: &mut VirtualOverseer) -> AllMessages { + virtual_overseer + .recv() + .timeout(TIMEOUT) + .await + .expect("overseer `recv` timed out") + } + + fn default_header() -> Header { + Header { + parent_hash: Hash::zero(), + number: 0, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + } + } + + fn get_block_header(chain: &[Hash], hash: &Hash) -> Option

{ + let idx = chain.iter().position(|h| h == hash)?; + let parent_hash = idx.checked_sub(1).map(|i| chain[i]).unwrap_or(GENESIS_HASH); + let number = + if *hash == GENESIS_HASH { GENESIS_NUMBER } else { GENESIS_NUMBER + idx as u32 + 1 }; + Some(Header { parent_hash, number, ..default_header() }) + } + + async fn assert_block_header_requests( + virtual_overseer: &mut VirtualOverseer, + chain: &[Hash], + blocks: &[Hash], + ) { + for block in blocks.iter().rev() { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ChainApi( + ChainApiMessage::BlockHeader(hash, tx) + ) => { + assert_eq!(*block, hash, "unexpected block header request"); + let header = if block == &GENESIS_HASH { + Header { + number: GENESIS_NUMBER, + ..default_header() + } + } else { + get_block_header(chain, block).expect("unknown block") + }; + + tx.send(Ok(Some(header))).unwrap(); + } + ); + } + } + + async fn assert_min_relay_parents_request( + virtual_overseer: &mut VirtualOverseer, + leaf: &Hash, + response: Vec<(ParaId, u32)>, + ) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetMinimumRelayParents( + leaf_hash, + tx + ) + ) => { + assert_eq!(*leaf, leaf_hash, "received unexpected leaf hash"); + tx.send(response).unwrap(); + } + ); + } + + #[test] + fn construct_fresh_view() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = make_subsystem_context::(pool); + + let mut view = View::default(); + + // Chain B. + const PARA_A_MIN_PARENT: u32 = 4; + const PARA_B_MIN_PARENT: u32 = 3; + + let prospective_response = vec![(PARA_A, PARA_A_MIN_PARENT), (PARA_B, PARA_B_MIN_PARENT)]; + + let leaf = CHAIN_B.last().unwrap(); + let min_min_idx = (PARA_B_MIN_PARENT - GENESIS_NUMBER - 1) as usize; + + let fut = view.activate_leaf(ctx.sender(), *leaf).timeout(TIMEOUT).map(|res| { + let paras = res.expect("`activate_leaf` timed out").unwrap(); + assert_eq!(paras, vec![PARA_A, PARA_B]); + }); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, leaf, prospective_response).await; + assert_block_header_requests(&mut ctx_handle, CHAIN_B, &CHAIN_B[min_min_idx..]).await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + for i in min_min_idx..(CHAIN_B.len() - 1) { + // No allowed relay parents constructed for ancestry. + assert!(view.known_allowed_relay_parents_under(&CHAIN_B[i], None).is_none()); + } + + let leaf_info = + view.block_info_storage.get(leaf).expect("block must be present in storage"); + assert_matches!( + leaf_info.maybe_allowed_relay_parents, + Some(ref allowed_relay_parents) => { + assert_eq!(allowed_relay_parents.minimum_relay_parents[&PARA_A], PARA_A_MIN_PARENT); + assert_eq!(allowed_relay_parents.minimum_relay_parents[&PARA_B], PARA_B_MIN_PARENT); + let expected_ancestry: Vec = + CHAIN_B[min_min_idx..].iter().rev().copied().collect(); + assert_eq!( + allowed_relay_parents.allowed_relay_parents_contiguous, + expected_ancestry + ); + } + ); + + // Suppose the whole test chain A is allowed up to genesis for para C. + const PARA_C_MIN_PARENT: u32 = 0; + let prospective_response = vec![(PARA_C, PARA_C_MIN_PARENT)]; + let leaf = CHAIN_A.last().unwrap(); + let blocks = [&[GENESIS_HASH], CHAIN_A].concat(); + + let fut = view.activate_leaf(ctx.sender(), *leaf).timeout(TIMEOUT).map(|res| { + let paras = res.expect("`activate_leaf` timed out").unwrap(); + assert_eq!(paras, vec![PARA_C]); + }); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, leaf, prospective_response).await; + assert_block_header_requests(&mut ctx_handle, CHAIN_A, &blocks).await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + assert_eq!(view.leaves.len(), 2); + } + + #[test] + fn reuse_block_info_storage() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = make_subsystem_context::(pool); + + let mut view = View::default(); + + const PARA_A_MIN_PARENT: u32 = 1; + let leaf_a_number = 3; + let leaf_a = CHAIN_B[leaf_a_number - 1]; + let min_min_idx = (PARA_A_MIN_PARENT - GENESIS_NUMBER - 1) as usize; + + let prospective_response = vec![(PARA_A, PARA_A_MIN_PARENT)]; + + let fut = view.activate_leaf(ctx.sender(), leaf_a).timeout(TIMEOUT).map(|res| { + let paras = res.expect("`activate_leaf` timed out").unwrap(); + assert_eq!(paras, vec![PARA_A]); + }); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, &leaf_a, prospective_response).await; + assert_block_header_requests( + &mut ctx_handle, + CHAIN_B, + &CHAIN_B[min_min_idx..leaf_a_number], + ) + .await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + // Blocks up to the 3rd are present in storage. + const PARA_B_MIN_PARENT: u32 = 2; + let leaf_b_number = 5; + let leaf_b = CHAIN_B[leaf_b_number - 1]; + + let prospective_response = vec![(PARA_B, PARA_B_MIN_PARENT)]; + + let fut = view.activate_leaf(ctx.sender(), leaf_b).timeout(TIMEOUT).map(|res| { + let paras = res.expect("`activate_leaf` timed out").unwrap(); + assert_eq!(paras, vec![PARA_B]); + }); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, &leaf_b, prospective_response).await; + assert_block_header_requests( + &mut ctx_handle, + CHAIN_B, + &CHAIN_B[leaf_a_number..leaf_b_number], // Note the expected range. + ) + .await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + // Allowed relay parents for leaf A are preserved. + let leaf_a_info = + view.block_info_storage.get(&leaf_a).expect("block must be present in storage"); + assert_matches!( + leaf_a_info.maybe_allowed_relay_parents, + Some(ref allowed_relay_parents) => { + assert_eq!(allowed_relay_parents.minimum_relay_parents[&PARA_A], PARA_A_MIN_PARENT); + let expected_ancestry: Vec = + CHAIN_B[min_min_idx..leaf_a_number].iter().rev().copied().collect(); + let ancestry = view.known_allowed_relay_parents_under(&leaf_a, Some(PARA_A)).unwrap().to_vec(); + assert_eq!(ancestry, expected_ancestry); + } + ); + } + + #[test] + fn pruning() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = make_subsystem_context::(pool); + + let mut view = View::default(); + + const PARA_A_MIN_PARENT: u32 = 3; + let leaf_a = CHAIN_B.iter().rev().nth(1).unwrap(); + let leaf_a_idx = CHAIN_B.len() - 2; + let min_a_idx = (PARA_A_MIN_PARENT - GENESIS_NUMBER - 1) as usize; + + let prospective_response = vec![(PARA_A, PARA_A_MIN_PARENT)]; + + let fut = view + .activate_leaf(ctx.sender(), *leaf_a) + .timeout(TIMEOUT) + .map(|res| res.unwrap().unwrap()); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, &leaf_a, prospective_response).await; + assert_block_header_requests( + &mut ctx_handle, + CHAIN_B, + &CHAIN_B[min_a_idx..=leaf_a_idx], + ) + .await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + // Also activate a leaf with a lesser minimum relay parent. + const PARA_B_MIN_PARENT: u32 = 2; + let leaf_b = CHAIN_B.last().unwrap(); + let min_b_idx = (PARA_B_MIN_PARENT - GENESIS_NUMBER - 1) as usize; + + let prospective_response = vec![(PARA_B, PARA_B_MIN_PARENT)]; + // Headers will be requested for the minimum block and the leaf. + let blocks = &[CHAIN_B[min_b_idx], *leaf_b]; + + let fut = view + .activate_leaf(ctx.sender(), *leaf_b) + .timeout(TIMEOUT) + .map(|res| res.expect("`activate_leaf` timed out").unwrap()); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, &leaf_b, prospective_response).await; + assert_block_header_requests(&mut ctx_handle, CHAIN_B, blocks).await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + // Prune implicit ancestor (no-op). + let block_info_len = view.block_info_storage.len(); + view.deactivate_leaf(CHAIN_B[leaf_a_idx - 1]); + assert_eq!(block_info_len, view.block_info_storage.len()); + + // Prune a leaf with a greater minimum relay parent. + view.deactivate_leaf(*leaf_b); + for hash in CHAIN_B.iter().take(PARA_B_MIN_PARENT as usize) { + assert!(!view.block_info_storage.contains_key(hash)); + } + + // Prune the last leaf. + view.deactivate_leaf(*leaf_a); + assert!(view.block_info_storage.is_empty()); + } + + #[test] + fn genesis_ancestry() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = make_subsystem_context::(pool); + + let mut view = View::default(); + + const PARA_A_MIN_PARENT: u32 = 0; + + let prospective_response = vec![(PARA_A, PARA_A_MIN_PARENT)]; + let fut = view.activate_leaf(ctx.sender(), GENESIS_HASH).timeout(TIMEOUT).map(|res| { + let paras = res.expect("`activate_leaf` timed out").unwrap(); + assert_eq!(paras, vec![PARA_A]); + }); + let overseer_fut = async { + assert_min_relay_parents_request(&mut ctx_handle, &GENESIS_HASH, prospective_response) + .await; + assert_block_header_requests(&mut ctx_handle, &[GENESIS_HASH], &[GENESIS_HASH]).await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + assert_matches!( + view.known_allowed_relay_parents_under(&GENESIS_HASH, None), + Some(hashes) if !hashes.is_empty() + ); + } +} diff --git a/node/subsystem-util/src/inclusion_emulator/mod.rs b/node/subsystem-util/src/inclusion_emulator/mod.rs new file mode 100644 index 000000000000..6ab19fa660bd --- /dev/null +++ b/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -0,0 +1,14 @@ +// Copyright 2017-2022 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. + +pub mod staging; diff --git a/node/subsystem-util/src/inclusion_emulator/staging.rs b/node/subsystem-util/src/inclusion_emulator/staging.rs new file mode 100644 index 000000000000..a4b85775981d --- /dev/null +++ b/node/subsystem-util/src/inclusion_emulator/staging.rs @@ -0,0 +1,1450 @@ +// Copyright 2017-2022 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. + +//! The implementation of the inclusion emulator for the 'staging' runtime version. +//! +//! # Overview +//! +//! A set of utilities for node-side code to emulate the logic the runtime uses for checking +//! parachain blocks in order to build prospective parachains that are produced ahead of the +//! relay chain. These utilities allow the node-side to predict, with high accuracy, what +//! the relay-chain will accept in the near future. +//! +//! This module has 2 key data types: [`Constraints`] and [`Fragment`]s. [`Constraints`] +//! exhaustively define the set of valid inputs and outputs to parachain execution. A [`Fragment`] +//! indicates a parachain block, anchored to the relay-chain at a particular relay-chain block, +//! known as the relay-parent. +//! +//! ## Fragment Validity +//! +//! Every relay-parent is implicitly associated with a unique set of [`Constraints`] that describe +//! the properties that must be true for a block to be included in a direct child of that block, +//! assuming there is no intermediate parachain block pending availability. +//! +//! However, the key factor that makes asynchronously-grown prospective chains +//! possible is the fact that the relay-chain accepts candidate blocks based on whether they +//! are valid under the constraints of the present moment, not based on whether they were +//! valid at the time of construction. +//! +//! As such, [`Fragment`]s are often, but not always constructed in such a way that they are +//! invalid at first and become valid later on, as the relay chain grows. +//! +//! # Usage +//! +//! It's expected that the users of this module will be building up trees of +//! [`Fragment`]s and consistently pruning and adding to the tree. +//! +//! ## Operating Constraints +//! +//! The *operating constraints* of a `Fragment` are the constraints with which that fragment +//! was intended to comply. The operating constraints are defined as the base constraints +//! of the relay-parent of the fragment modified by the cumulative modifications of all +//! fragments between the relay-parent and the current fragment. +//! +//! What the operating constraints are, in practice, is a prediction about the state of the +//! relay-chain in the future. The relay-chain is aware of some current state, and we want to +//! make an intelligent prediction about what might be accepted in the future based on +//! prior fragments that also exist off-chain. +//! +//! ## Fragment Trees +//! +//! As the relay-chain grows, some predictions come true and others come false. +//! And new predictions get made. These three changes correspond distinctly to the +//! 3 primary operations on fragment trees. +//! +//! A fragment tree is a mental model for thinking about a forking series of predictions +//! about a single parachain. There may be one or more fragment trees per parachain. +//! +//! In expectation, most parachains will have a plausibly-unique authorship method which means that +//! they should really be much closer to fragment-chains, maybe with an occasional fork. +//! +//! Avoiding fragment-tree blowup is beyond the scope of this module. +//! +//! ### Pruning Fragment Trees +//! +//! When the relay-chain advances, we want to compare the new constraints of that relay-parent to +//! the roots of the fragment trees we have. There are 3 cases: +//! +//! 1. The root fragment is still valid under the new constraints. In this case, we do nothing. This +//! is the "prediction still uncertain" case. +//! +//! 2. The root fragment is invalid under the new constraints because it has been subsumed by the +//! relay-chain. In this case, we can discard the root and split & re-root the fragment tree under +//! its descendents and compare to the new constraints again. This is the "prediction came true" +//! case. +//! +//! 3. The root fragment is invalid under the new constraints because a competing parachain block +//! has been included or it would never be accepted for some other reason. In this case we can +//! discard the entire fragment tree. This is the "prediction came false" case. +//! +//! This is all a bit of a simplification because it assumes that the relay-chain advances without +//! forks and is finalized instantly. In practice, the set of fragment-trees needs to be observable +//! from the perspective of a few different possible forks of the relay-chain and not pruned +//! too eagerly. +//! +//! Note that the fragments themselves don't need to change and the only thing we care about +//! is whether the predictions they represent are still valid. +//! +//! ### Extending Fragment Trees +//! +//! As predictions fade into the past, new ones should be stacked on top. +//! +//! Every new relay-chain block is an opportunity to make a new prediction about the future. +//! Higher-level logic should select the leaves of the fragment-trees to build upon or whether +//! to create a new fragment-tree. +//! +//! ### Code Upgrades +//! +//! Code upgrades are the main place where this emulation fails. The on-chain PVF upgrade scheduling +//! logic is very path-dependent and intricate so we just assume that code upgrades +//! can't be initiated and applied within a single fragment-tree. Fragment-trees aren't deep, +//! in practice and code upgrades are fairly rare. So what's likely to happen around code +//! upgrades is that the entire fragment-tree has to get discarded at some point. +//! +//! That means a few blocks of execution time lost, which is not a big deal for code upgrades +//! in practice at most once every few weeks. + +use polkadot_primitives::vstaging::{ + BlockNumber, CandidateCommitments, CollatorId, CollatorSignature, + Constraints as PrimitiveConstraints, Hash, HeadData, Id as ParaId, PersistedValidationData, + UpgradeRestriction, ValidationCodeHash, +}; +use std::{ + borrow::{Borrow, Cow}, + collections::HashMap, +}; + +/// Constraints on inbound HRMP channels. +#[derive(Debug, Clone, PartialEq)] +pub struct InboundHrmpLimitations { + /// An exhaustive set of all valid watermarks, sorted ascending + pub valid_watermarks: Vec, +} + +/// Constraints on outbound HRMP channels. +#[derive(Debug, Clone, PartialEq)] +pub struct OutboundHrmpChannelLimitations { + /// The maximum bytes that can be written to the channel. + pub bytes_remaining: usize, + /// The maximum messages that can be written to the channel. + pub messages_remaining: usize, +} + +/// Constraints on the actions that can be taken by a new parachain +/// block. These limitations are implicitly associated with some particular +/// parachain, which should be apparent from usage. +#[derive(Debug, Clone, PartialEq)] +pub struct Constraints { + /// The minimum relay-parent number accepted under these constraints. + pub min_relay_parent_number: BlockNumber, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: usize, + /// The maximum new validation code size allowed, in bytes. + pub max_code_size: usize, + /// The amount of UMP messages remaining. + pub ump_remaining: usize, + /// The amount of UMP bytes remaining. + pub ump_remaining_bytes: usize, + /// The maximum number of UMP messages allowed per candidate. + pub max_ump_num_per_candidate: usize, + /// Remaining DMP queue. Only includes sent-at block numbers. + pub dmp_remaining_messages: Vec, + /// The limitations of all registered inbound HRMP channels. + pub hrmp_inbound: InboundHrmpLimitations, + /// The limitations of all registered outbound HRMP channels. + pub hrmp_channels_out: HashMap, + /// The maximum number of HRMP messages allowed per candidate. + pub max_hrmp_num_per_candidate: usize, + /// The required parent head-data of the parachain. + pub required_parent: HeadData, + /// The expected validation-code-hash of this parachain. + pub validation_code_hash: ValidationCodeHash, + /// The code upgrade restriction signal as-of this parachain. + pub upgrade_restriction: Option, + /// The future validation code hash, if any, and at what relay-parent + /// number the upgrade would be minimally applied. + pub future_validation_code: Option<(BlockNumber, ValidationCodeHash)>, +} + +impl From for Constraints { + fn from(c: PrimitiveConstraints) -> Self { + Constraints { + min_relay_parent_number: c.min_relay_parent_number, + max_pov_size: c.max_pov_size as _, + max_code_size: c.max_code_size as _, + ump_remaining: c.ump_remaining as _, + ump_remaining_bytes: c.ump_remaining_bytes as _, + max_ump_num_per_candidate: c.max_ump_num_per_candidate as _, + dmp_remaining_messages: c.dmp_remaining_messages, + hrmp_inbound: InboundHrmpLimitations { + valid_watermarks: c.hrmp_inbound.valid_watermarks, + }, + hrmp_channels_out: c + .hrmp_channels_out + .into_iter() + .map(|(para_id, limits)| { + ( + para_id, + OutboundHrmpChannelLimitations { + bytes_remaining: limits.bytes_remaining as _, + messages_remaining: limits.messages_remaining as _, + }, + ) + }) + .collect(), + max_hrmp_num_per_candidate: c.max_hrmp_num_per_candidate as _, + required_parent: c.required_parent, + validation_code_hash: c.validation_code_hash, + upgrade_restriction: c.upgrade_restriction, + future_validation_code: c.future_validation_code, + } + } +} + +/// Kinds of errors that can occur when modifying constraints. +#[derive(Debug, Clone, PartialEq)] +pub enum ModificationError { + /// The HRMP watermark is not allowed. + DisallowedHrmpWatermark(BlockNumber), + /// No such HRMP outbound channel. + NoSuchHrmpChannel(ParaId), + /// Too many messages submitted to HRMP channel. + HrmpMessagesOverflow { + /// The ID of the recipient. + para_id: ParaId, + /// The amount of remaining messages in the capacity of the channel. + messages_remaining: usize, + /// The amount of messages submitted to the channel. + messages_submitted: usize, + }, + /// Too many bytes submitted to HRMP channel. + HrmpBytesOverflow { + /// The ID of the recipient. + para_id: ParaId, + /// The amount of remaining bytes in the capacity of the channel. + bytes_remaining: usize, + /// The amount of bytes submitted to the channel. + bytes_submitted: usize, + }, + /// Too many messages submitted to UMP. + UmpMessagesOverflow { + /// The amount of remaining messages in the capacity of UMP. + messages_remaining: usize, + /// The amount of messages submitted to UMP. + messages_submitted: usize, + }, + /// Too many bytes submitted to UMP. + UmpBytesOverflow { + /// The amount of remaining bytes in the capacity of UMP. + bytes_remaining: usize, + /// The amount of bytes submitted to UMP. + bytes_submitted: usize, + }, + /// Too many messages processed from DMP. + DmpMessagesUnderflow { + /// The amount of messages waiting to be processed from DMP. + messages_remaining: usize, + /// The amount of messages processed. + messages_processed: usize, + }, + /// No validation code upgrade to apply. + AppliedNonexistentCodeUpgrade, +} + +impl Constraints { + /// Check modifications against constraints. + pub fn check_modifications( + &self, + modifications: &ConstraintModifications, + ) -> Result<(), ModificationError> { + if let Some(HrmpWatermarkUpdate::Trunk(hrmp_watermark)) = modifications.hrmp_watermark { + // head updates are always valid. + if self.hrmp_inbound.valid_watermarks.iter().all(|w| w != &hrmp_watermark) { + return Err(ModificationError::DisallowedHrmpWatermark(hrmp_watermark)) + } + } + + for (id, outbound_hrmp_mod) in &modifications.outbound_hrmp { + if let Some(outbound) = self.hrmp_channels_out.get(&id) { + outbound.bytes_remaining.checked_sub(outbound_hrmp_mod.bytes_submitted).ok_or( + ModificationError::HrmpBytesOverflow { + para_id: *id, + bytes_remaining: outbound.bytes_remaining, + bytes_submitted: outbound_hrmp_mod.bytes_submitted, + }, + )?; + + outbound + .messages_remaining + .checked_sub(outbound_hrmp_mod.messages_submitted) + .ok_or(ModificationError::HrmpMessagesOverflow { + para_id: *id, + messages_remaining: outbound.messages_remaining, + messages_submitted: outbound_hrmp_mod.messages_submitted, + })?; + } else { + return Err(ModificationError::NoSuchHrmpChannel(*id)) + } + } + + self.ump_remaining.checked_sub(modifications.ump_messages_sent).ok_or( + ModificationError::UmpMessagesOverflow { + messages_remaining: self.ump_remaining, + messages_submitted: modifications.ump_messages_sent, + }, + )?; + + self.ump_remaining_bytes.checked_sub(modifications.ump_bytes_sent).ok_or( + ModificationError::UmpBytesOverflow { + bytes_remaining: self.ump_remaining_bytes, + bytes_submitted: modifications.ump_bytes_sent, + }, + )?; + + self.dmp_remaining_messages + .len() + .checked_sub(modifications.dmp_messages_processed) + .ok_or(ModificationError::DmpMessagesUnderflow { + messages_remaining: self.dmp_remaining_messages.len(), + messages_processed: modifications.dmp_messages_processed, + })?; + + if self.future_validation_code.is_none() && modifications.code_upgrade_applied { + return Err(ModificationError::AppliedNonexistentCodeUpgrade) + } + + Ok(()) + } + + /// Apply modifications to these constraints. If this succeeds, it passes + /// all sanity-checks. + pub fn apply_modifications( + &self, + modifications: &ConstraintModifications, + ) -> Result { + let mut new = self.clone(); + + if let Some(required_parent) = modifications.required_parent.as_ref() { + new.required_parent = required_parent.clone(); + } + + if let Some(ref hrmp_watermark) = modifications.hrmp_watermark { + match new.hrmp_inbound.valid_watermarks.binary_search(&hrmp_watermark.watermark()) { + Ok(pos) => { + // Exact match, so this is OK in all cases. + let _ = new.hrmp_inbound.valid_watermarks.drain(..pos + 1); + }, + Err(pos) => match hrmp_watermark { + HrmpWatermarkUpdate::Head(_) => { + // Updates to Head are always OK. + let _ = new.hrmp_inbound.valid_watermarks.drain(..pos); + }, + HrmpWatermarkUpdate::Trunk(n) => { + // Trunk update landing on disallowed watermark is not OK. + return Err(ModificationError::DisallowedHrmpWatermark(*n)) + }, + }, + } + } + + for (id, outbound_hrmp_mod) in &modifications.outbound_hrmp { + if let Some(outbound) = new.hrmp_channels_out.get_mut(&id) { + outbound.bytes_remaining = outbound + .bytes_remaining + .checked_sub(outbound_hrmp_mod.bytes_submitted) + .ok_or(ModificationError::HrmpBytesOverflow { + para_id: *id, + bytes_remaining: outbound.bytes_remaining, + bytes_submitted: outbound_hrmp_mod.bytes_submitted, + })?; + + outbound.messages_remaining = outbound + .messages_remaining + .checked_sub(outbound_hrmp_mod.messages_submitted) + .ok_or(ModificationError::HrmpMessagesOverflow { + para_id: *id, + messages_remaining: outbound.messages_remaining, + messages_submitted: outbound_hrmp_mod.messages_submitted, + })?; + } else { + return Err(ModificationError::NoSuchHrmpChannel(*id)) + } + } + + new.ump_remaining = new.ump_remaining.checked_sub(modifications.ump_messages_sent).ok_or( + ModificationError::UmpMessagesOverflow { + messages_remaining: new.ump_remaining, + messages_submitted: modifications.ump_messages_sent, + }, + )?; + + new.ump_remaining_bytes = new + .ump_remaining_bytes + .checked_sub(modifications.ump_bytes_sent) + .ok_or(ModificationError::UmpBytesOverflow { + bytes_remaining: new.ump_remaining_bytes, + bytes_submitted: modifications.ump_bytes_sent, + })?; + + if modifications.dmp_messages_processed > new.dmp_remaining_messages.len() { + return Err(ModificationError::DmpMessagesUnderflow { + messages_remaining: new.dmp_remaining_messages.len(), + messages_processed: modifications.dmp_messages_processed, + }) + } else { + new.dmp_remaining_messages = + new.dmp_remaining_messages[modifications.dmp_messages_processed..].to_vec(); + } + + if modifications.code_upgrade_applied { + new.validation_code_hash = new + .future_validation_code + .take() + .ok_or(ModificationError::AppliedNonexistentCodeUpgrade)? + .1; + } + + Ok(new) + } +} + +/// Information about a relay-chain block. +#[derive(Debug, Clone, PartialEq)] +pub struct RelayChainBlockInfo { + /// The hash of the relay-chain block. + pub hash: Hash, + /// The number of the relay-chain block. + pub number: BlockNumber, + /// The storage-root of the relay-chain block. + pub storage_root: Hash, +} + +/// An update to outbound HRMP channels. +#[derive(Debug, Clone, PartialEq, Default)] +pub struct OutboundHrmpChannelModification { + /// The number of bytes submitted to the channel. + pub bytes_submitted: usize, + /// The number of messages submitted to the channel. + pub messages_submitted: usize, +} + +/// An update to the HRMP Watermark. +#[derive(Debug, Clone, PartialEq)] +pub enum HrmpWatermarkUpdate { + /// This is an update placing the watermark at the head of the chain, + /// which is always legal. + Head(BlockNumber), + /// This is an update placing the watermark behind the head of the + /// chain, which is only legal if it lands on a block where messages + /// were queued. + Trunk(BlockNumber), +} + +impl HrmpWatermarkUpdate { + fn watermark(&self) -> BlockNumber { + match *self { + HrmpWatermarkUpdate::Head(n) | HrmpWatermarkUpdate::Trunk(n) => n, + } + } +} + +/// Modifications to constraints as a result of prospective candidates. +#[derive(Debug, Clone, PartialEq)] +pub struct ConstraintModifications { + /// The required parent head to build upon. + pub required_parent: Option, + /// The new HRMP watermark + pub hrmp_watermark: Option, + /// Outbound HRMP channel modifications. + pub outbound_hrmp: HashMap, + /// The amount of UMP messages sent. + pub ump_messages_sent: usize, + /// The amount of UMP bytes sent. + pub ump_bytes_sent: usize, + /// The amount of DMP messages processed. + pub dmp_messages_processed: usize, + /// Whether a pending code upgrade has been applied. + pub code_upgrade_applied: bool, +} + +impl ConstraintModifications { + /// The 'identity' modifications: these can be applied to + /// any constraints and yield the exact same result. + pub fn identity() -> Self { + ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: HashMap::new(), + ump_messages_sent: 0, + ump_bytes_sent: 0, + dmp_messages_processed: 0, + code_upgrade_applied: false, + } + } + + /// Stack other modifications on top of these. + /// + /// This does no sanity-checking, so if `other` is garbage relative + /// to `self`, then the new value will be garbage as well. + /// + /// This is an addition which is not commutative. + pub fn stack(&mut self, other: &Self) { + if let Some(ref new_parent) = other.required_parent { + self.required_parent = Some(new_parent.clone()); + } + if let Some(ref new_hrmp_watermark) = other.hrmp_watermark { + self.hrmp_watermark = Some(new_hrmp_watermark.clone()); + } + + for (id, mods) in &other.outbound_hrmp { + let record = self.outbound_hrmp.entry(*id).or_default(); + record.messages_submitted += mods.messages_submitted; + record.bytes_submitted += mods.bytes_submitted; + } + + self.ump_messages_sent += other.ump_messages_sent; + self.ump_bytes_sent += other.ump_bytes_sent; + self.dmp_messages_processed += other.dmp_messages_processed; + self.code_upgrade_applied |= other.code_upgrade_applied; + } +} + +/// The prospective candidate. +/// +/// This comprises the key information that represent a candidate +/// without pinning it to a particular session. For example, everything +/// to do with the collator's signature and commitments are represented +/// here. But the erasure-root is not. This means that prospective candidates +/// are not correlated to any session in particular. +#[derive(Debug, Clone, PartialEq)] +pub struct ProspectiveCandidate<'a> { + /// The commitments to the output of the execution. + pub commitments: Cow<'a, CandidateCommitments>, + /// The collator that created the candidate. + pub collator: CollatorId, + /// The signature of the collator on the payload. + pub collator_signature: CollatorSignature, + /// The persisted validation data used to create the candidate. + pub persisted_validation_data: PersistedValidationData, + /// The hash of the PoV. + pub pov_hash: Hash, + /// The validation code hash used by the candidate. + pub validation_code_hash: ValidationCodeHash, +} + +impl<'a> ProspectiveCandidate<'a> { + fn into_owned(self) -> ProspectiveCandidate<'static> { + ProspectiveCandidate { commitments: Cow::Owned(self.commitments.into_owned()), ..self } + } + + /// Partially clone the prospective candidate, but borrow the + /// parts which are potentially heavy. + pub fn partial_clone(&self) -> ProspectiveCandidate { + ProspectiveCandidate { + commitments: Cow::Borrowed(self.commitments.borrow()), + collator: self.collator.clone(), + collator_signature: self.collator_signature.clone(), + persisted_validation_data: self.persisted_validation_data.clone(), + pov_hash: self.pov_hash, + validation_code_hash: self.validation_code_hash, + } + } +} + +#[cfg(test)] +impl ProspectiveCandidate<'static> { + fn commitments_mut(&mut self) -> &mut CandidateCommitments { + self.commitments.to_mut() + } +} + +/// Kinds of errors with the validity of a fragment. +#[derive(Debug, Clone, PartialEq)] +pub enum FragmentValidityError { + /// The validation code of the candidate doesn't match the + /// operating constraints. + /// + /// Expected, Got + ValidationCodeMismatch(ValidationCodeHash, ValidationCodeHash), + /// The persisted-validation-data doesn't match. + /// + /// Expected, Got + PersistedValidationDataMismatch(PersistedValidationData, PersistedValidationData), + /// The outputs of the candidate are invalid under the operating + /// constraints. + OutputsInvalid(ModificationError), + /// New validation code size too big. + /// + /// Max allowed, new. + CodeSizeTooLarge(usize, usize), + /// Relay parent too old. + /// + /// Min allowed, current. + RelayParentTooOld(BlockNumber, BlockNumber), + /// Para is required to process at least one DMP message from the queue. + DmpAdvancementRule, + /// Too many messages upward messages submitted. + UmpMessagesPerCandidateOverflow { + /// The amount of messages a single candidate can submit. + messages_allowed: usize, + /// The amount of messages sent to all HRMP channels. + messages_submitted: usize, + }, + /// Too many messages submitted to all HRMP channels. + HrmpMessagesPerCandidateOverflow { + /// The amount of messages a single candidate can submit. + messages_allowed: usize, + /// The amount of messages sent to all HRMP channels. + messages_submitted: usize, + }, + /// Code upgrade not allowed. + CodeUpgradeRestricted, + /// HRMP messages are not ascending or are duplicate. + /// + /// The `usize` is the index into the outbound HRMP messages of + /// the candidate. + HrmpMessagesDescendingOrDuplicate(usize), +} + +/// A parachain fragment, representing another prospective parachain block. +/// +/// This is a type which guarantees that the candidate is valid under the +/// operating constraints. +#[derive(Debug, Clone, PartialEq)] +pub struct Fragment<'a> { + /// The new relay-parent. + relay_parent: RelayChainBlockInfo, + /// The constraints this fragment is operating under. + operating_constraints: Constraints, + /// The core information about the prospective candidate. + candidate: ProspectiveCandidate<'a>, + /// Modifications to the constraints based on the outputs of + /// the candidate. + modifications: ConstraintModifications, +} + +impl<'a> Fragment<'a> { + /// Create a new fragment. + /// + /// This fails if the fragment isn't in line with the operating + /// constraints. That is, either its inputs or its outputs fail + /// checks against the constraints. + /// + /// This doesn't check that the collator signature is valid or + /// whether the PoV is small enough. + pub fn new( + relay_parent: RelayChainBlockInfo, + operating_constraints: Constraints, + candidate: ProspectiveCandidate<'a>, + ) -> Result { + let modifications = { + let commitments = &candidate.commitments; + ConstraintModifications { + required_parent: Some(commitments.head_data.clone()), + hrmp_watermark: Some({ + if commitments.hrmp_watermark == relay_parent.number { + HrmpWatermarkUpdate::Head(commitments.hrmp_watermark) + } else { + HrmpWatermarkUpdate::Trunk(commitments.hrmp_watermark) + } + }), + outbound_hrmp: { + let mut outbound_hrmp = HashMap::<_, OutboundHrmpChannelModification>::new(); + + let mut last_recipient = None::; + for (i, message) in commitments.horizontal_messages.iter().enumerate() { + if let Some(last) = last_recipient { + if last >= message.recipient { + return Err( + FragmentValidityError::HrmpMessagesDescendingOrDuplicate(i), + ) + } + } + + last_recipient = Some(message.recipient); + let record = outbound_hrmp.entry(message.recipient).or_default(); + + record.bytes_submitted += message.data.len(); + record.messages_submitted += 1; + } + + outbound_hrmp + }, + ump_messages_sent: commitments.upward_messages.len(), + ump_bytes_sent: commitments.upward_messages.iter().map(|msg| msg.len()).sum(), + dmp_messages_processed: commitments.processed_downward_messages as _, + code_upgrade_applied: operating_constraints + .future_validation_code + .map_or(false, |(at, _)| relay_parent.number >= at), + } + }; + + validate_against_constraints( + &operating_constraints, + &relay_parent, + &candidate, + &modifications, + )?; + + Ok(Fragment { relay_parent, operating_constraints, candidate, modifications }) + } + + /// Access the relay parent information. + pub fn relay_parent(&self) -> &RelayChainBlockInfo { + &self.relay_parent + } + + /// Access the operating constraints + pub fn operating_constraints(&self) -> &Constraints { + &self.operating_constraints + } + + /// Access the underlying prospective candidate. + pub fn candidate(&self) -> &ProspectiveCandidate<'a> { + &self.candidate + } + + /// Modifications to constraints based on the outputs of the candidate. + pub fn constraint_modifications(&self) -> &ConstraintModifications { + &self.modifications + } + + /// Convert the fragment into an owned variant. + pub fn into_owned(self) -> Fragment<'static> { + Fragment { candidate: self.candidate.into_owned(), ..self } + } + + /// Validate this fragment against some set of constraints + /// instead of the operating constraints. + pub fn validate_against_constraints( + &self, + constraints: &Constraints, + ) -> Result<(), FragmentValidityError> { + validate_against_constraints( + constraints, + &self.relay_parent, + &self.candidate, + &self.modifications, + ) + } +} + +fn validate_against_constraints( + constraints: &Constraints, + relay_parent: &RelayChainBlockInfo, + candidate: &ProspectiveCandidate, + modifications: &ConstraintModifications, +) -> Result<(), FragmentValidityError> { + let expected_pvd = PersistedValidationData { + parent_head: constraints.required_parent.clone(), + relay_parent_number: relay_parent.number, + relay_parent_storage_root: relay_parent.storage_root, + max_pov_size: constraints.max_pov_size as u32, + }; + + if expected_pvd != candidate.persisted_validation_data { + return Err(FragmentValidityError::PersistedValidationDataMismatch( + expected_pvd, + candidate.persisted_validation_data.clone(), + )) + } + + if constraints.validation_code_hash != candidate.validation_code_hash { + return Err(FragmentValidityError::ValidationCodeMismatch( + constraints.validation_code_hash, + candidate.validation_code_hash, + )) + } + + if relay_parent.number < constraints.min_relay_parent_number { + return Err(FragmentValidityError::RelayParentTooOld( + constraints.min_relay_parent_number, + relay_parent.number, + )) + } + + if candidate.commitments.new_validation_code.is_some() { + match constraints.upgrade_restriction { + None => {}, + Some(UpgradeRestriction::Present) => + return Err(FragmentValidityError::CodeUpgradeRestricted), + } + } + + let announced_code_size = candidate + .commitments + .new_validation_code + .as_ref() + .map_or(0, |code| code.0.len()); + + if announced_code_size > constraints.max_code_size { + return Err(FragmentValidityError::CodeSizeTooLarge( + constraints.max_code_size, + announced_code_size, + )) + } + + if modifications.dmp_messages_processed == 0 { + if constraints + .dmp_remaining_messages + .get(0) + .map_or(false, |&msg_sent_at| msg_sent_at <= relay_parent.number) + { + return Err(FragmentValidityError::DmpAdvancementRule) + } + } + + if candidate.commitments.horizontal_messages.len() > constraints.max_hrmp_num_per_candidate { + return Err(FragmentValidityError::HrmpMessagesPerCandidateOverflow { + messages_allowed: constraints.max_hrmp_num_per_candidate, + messages_submitted: candidate.commitments.horizontal_messages.len(), + }) + } + + if candidate.commitments.upward_messages.len() > constraints.max_ump_num_per_candidate { + return Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { + messages_allowed: constraints.max_ump_num_per_candidate, + messages_submitted: candidate.commitments.upward_messages.len(), + }) + } + + constraints + .check_modifications(&modifications) + .map_err(FragmentValidityError::OutputsInvalid) +} + +#[cfg(test)] +mod tests { + use super::*; + use polkadot_primitives::vstaging::{ + CollatorPair, HorizontalMessages, OutboundHrmpMessage, ValidationCode, + }; + use sp_application_crypto::Pair; + + #[test] + fn stack_modifications() { + let para_a = ParaId::from(1u32); + let para_b = ParaId::from(2u32); + let para_c = ParaId::from(3u32); + + let a = ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: { + let mut map = HashMap::new(); + map.insert( + para_a, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map.insert( + para_b, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map + }, + ump_messages_sent: 6, + ump_bytes_sent: 1000, + dmp_messages_processed: 5, + code_upgrade_applied: true, + }; + + let b = ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: { + let mut map = HashMap::new(); + map.insert( + para_b, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map.insert( + para_c, + OutboundHrmpChannelModification { bytes_submitted: 100, messages_submitted: 5 }, + ); + + map + }, + ump_messages_sent: 6, + ump_bytes_sent: 1000, + dmp_messages_processed: 5, + code_upgrade_applied: true, + }; + + let mut c = a.clone(); + c.stack(&b); + + assert_eq!( + c, + ConstraintModifications { + required_parent: None, + hrmp_watermark: None, + outbound_hrmp: { + let mut map = HashMap::new(); + map.insert( + para_a, + OutboundHrmpChannelModification { + bytes_submitted: 100, + messages_submitted: 5, + }, + ); + + map.insert( + para_b, + OutboundHrmpChannelModification { + bytes_submitted: 200, + messages_submitted: 10, + }, + ); + + map.insert( + para_c, + OutboundHrmpChannelModification { + bytes_submitted: 100, + messages_submitted: 5, + }, + ); + + map + }, + ump_messages_sent: 12, + ump_bytes_sent: 2000, + dmp_messages_processed: 10, + code_upgrade_applied: true, + }, + ); + + let mut d = ConstraintModifications::identity(); + d.stack(&a); + d.stack(&b); + + assert_eq!(c, d); + } + + fn make_constraints() -> Constraints { + let para_a = ParaId::from(1u32); + let para_b = ParaId::from(2u32); + let para_c = ParaId::from(3u32); + + Constraints { + min_relay_parent_number: 5, + max_pov_size: 1000, + max_code_size: 1000, + ump_remaining: 10, + ump_remaining_bytes: 1024, + max_ump_num_per_candidate: 5, + dmp_remaining_messages: Vec::new(), + hrmp_inbound: InboundHrmpLimitations { valid_watermarks: vec![6, 8] }, + hrmp_channels_out: { + let mut map = HashMap::new(); + + map.insert( + para_a, + OutboundHrmpChannelLimitations { messages_remaining: 5, bytes_remaining: 512 }, + ); + + map.insert( + para_b, + OutboundHrmpChannelLimitations { + messages_remaining: 10, + bytes_remaining: 1024, + }, + ); + + map.insert( + para_c, + OutboundHrmpChannelLimitations { messages_remaining: 1, bytes_remaining: 128 }, + ); + + map + }, + max_hrmp_num_per_candidate: 5, + required_parent: HeadData::from(vec![1, 2, 3]), + validation_code_hash: ValidationCode(vec![4, 5, 6]).hash(), + upgrade_restriction: None, + future_validation_code: None, + } + } + + #[test] + fn constraints_disallowed_trunk_watermark() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.hrmp_watermark = Some(HrmpWatermarkUpdate::Trunk(7)); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::DisallowedHrmpWatermark(7)), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::DisallowedHrmpWatermark(7)), + ); + } + + #[test] + fn constraints_always_allow_head_watermark() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.hrmp_watermark = Some(HrmpWatermarkUpdate::Head(7)); + + assert!(constraints.check_modifications(&modifications).is_ok()); + + let new_constraints = constraints.apply_modifications(&modifications).unwrap(); + assert_eq!(new_constraints.hrmp_inbound.valid_watermarks, vec![8]); + } + + #[test] + fn constraints_no_such_hrmp_channel() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + let bad_para = ParaId::from(100u32); + modifications.outbound_hrmp.insert( + bad_para, + OutboundHrmpChannelModification { bytes_submitted: 0, messages_submitted: 0 }, + ); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::NoSuchHrmpChannel(bad_para)), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::NoSuchHrmpChannel(bad_para)), + ); + } + + #[test] + fn constraints_hrmp_messages_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + let para_a = ParaId::from(1u32); + modifications.outbound_hrmp.insert( + para_a, + OutboundHrmpChannelModification { bytes_submitted: 0, messages_submitted: 6 }, + ); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::HrmpMessagesOverflow { + para_id: para_a, + messages_remaining: 5, + messages_submitted: 6, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::HrmpMessagesOverflow { + para_id: para_a, + messages_remaining: 5, + messages_submitted: 6, + }), + ); + } + + #[test] + fn constraints_hrmp_bytes_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + let para_a = ParaId::from(1u32); + modifications.outbound_hrmp.insert( + para_a, + OutboundHrmpChannelModification { bytes_submitted: 513, messages_submitted: 1 }, + ); + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::HrmpBytesOverflow { + para_id: para_a, + bytes_remaining: 512, + bytes_submitted: 513, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::HrmpBytesOverflow { + para_id: para_a, + bytes_remaining: 512, + bytes_submitted: 513, + }), + ); + } + + #[test] + fn constraints_ump_messages_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.ump_messages_sent = 11; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::UmpMessagesOverflow { + messages_remaining: 10, + messages_submitted: 11, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::UmpMessagesOverflow { + messages_remaining: 10, + messages_submitted: 11, + }), + ); + } + + #[test] + fn constraints_ump_bytes_overflow() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.ump_bytes_sent = 1025; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::UmpBytesOverflow { + bytes_remaining: 1024, + bytes_submitted: 1025, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::UmpBytesOverflow { + bytes_remaining: 1024, + bytes_submitted: 1025, + }), + ); + } + + #[test] + fn constraints_dmp_messages() { + let mut constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + assert!(constraints.check_modifications(&modifications).is_ok()); + assert!(constraints.apply_modifications(&modifications).is_ok()); + + modifications.dmp_messages_processed = 6; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::DmpMessagesUnderflow { + messages_remaining: 0, + messages_processed: 6, + }), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::DmpMessagesUnderflow { + messages_remaining: 0, + messages_processed: 6, + }), + ); + + constraints.dmp_remaining_messages = vec![1, 4, 8, 10]; + modifications.dmp_messages_processed = 2; + assert!(constraints.check_modifications(&modifications).is_ok()); + let constraints = constraints + .apply_modifications(&modifications) + .expect("modifications are valid"); + + assert_eq!(&constraints.dmp_remaining_messages, &[8, 10]); + } + + #[test] + fn constraints_nonexistent_code_upgrade() { + let constraints = make_constraints(); + let mut modifications = ConstraintModifications::identity(); + modifications.code_upgrade_applied = true; + + assert_eq!( + constraints.check_modifications(&modifications), + Err(ModificationError::AppliedNonexistentCodeUpgrade), + ); + + assert_eq!( + constraints.apply_modifications(&modifications), + Err(ModificationError::AppliedNonexistentCodeUpgrade), + ); + } + + fn make_candidate( + constraints: &Constraints, + relay_parent: &RelayChainBlockInfo, + ) -> ProspectiveCandidate<'static> { + let collator_pair = CollatorPair::generate().0; + let collator = collator_pair.public(); + + let sig = collator_pair.sign(b"blabla".as_slice()); + + ProspectiveCandidate { + commitments: Cow::Owned(CandidateCommitments { + upward_messages: Default::default(), + horizontal_messages: Default::default(), + new_validation_code: None, + head_data: HeadData::from(vec![1, 2, 3, 4, 5]), + processed_downward_messages: 0, + hrmp_watermark: relay_parent.number, + }), + collator, + collator_signature: sig, + persisted_validation_data: PersistedValidationData { + parent_head: constraints.required_parent.clone(), + relay_parent_number: relay_parent.number, + relay_parent_storage_root: relay_parent.storage_root, + max_pov_size: constraints.max_pov_size as u32, + }, + pov_hash: Hash::repeat_byte(1), + validation_code_hash: constraints.validation_code_hash, + } + } + + #[test] + fn fragment_validation_code_mismatch() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let expected_code = constraints.validation_code_hash; + let got_code = ValidationCode(vec![9, 9, 9]).hash(); + + candidate.validation_code_hash = got_code; + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::ValidationCodeMismatch(expected_code, got_code,)), + ) + } + + #[test] + fn fragment_pvd_mismatch() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let relay_parent_b = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0b), + storage_root: Hash::repeat_byte(0xee), + }; + + let constraints = make_constraints(); + let candidate = make_candidate(&constraints, &relay_parent); + + let expected_pvd = PersistedValidationData { + parent_head: constraints.required_parent.clone(), + relay_parent_number: relay_parent_b.number, + relay_parent_storage_root: relay_parent_b.storage_root, + max_pov_size: constraints.max_pov_size as u32, + }; + + let got_pvd = candidate.persisted_validation_data.clone(); + + assert_eq!( + Fragment::new(relay_parent_b, constraints, candidate), + Err(FragmentValidityError::PersistedValidationDataMismatch(expected_pvd, got_pvd,)), + ); + } + + #[test] + fn fragment_code_size_too_large() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let max_code_size = constraints.max_code_size; + candidate.commitments_mut().new_validation_code = Some(vec![0; max_code_size + 1].into()); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::CodeSizeTooLarge(max_code_size, max_code_size + 1,)), + ); + } + + #[test] + fn fragment_relay_parent_too_old() { + let relay_parent = RelayChainBlockInfo { + number: 3, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let candidate = make_candidate(&constraints, &relay_parent); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::RelayParentTooOld(5, 3,)), + ); + } + + #[test] + fn fragment_hrmp_messages_overflow() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let max_hrmp = constraints.max_hrmp_num_per_candidate; + + candidate + .commitments_mut() + .horizontal_messages + .try_extend((0..max_hrmp + 1).map(|i| OutboundHrmpMessage { + recipient: ParaId::from(i as u32), + data: vec![1, 2, 3], + })) + .unwrap(); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::HrmpMessagesPerCandidateOverflow { + messages_allowed: max_hrmp, + messages_submitted: max_hrmp + 1, + }), + ); + } + + #[test] + fn fragment_dmp_advancement_rule() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let mut constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + // Empty dmp queue is ok. + assert!(Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()).is_ok()); + // Unprocessed message that was sent later is ok. + constraints.dmp_remaining_messages = vec![relay_parent.number + 1]; + assert!(Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()).is_ok()); + + for block_number in 0..=relay_parent.number { + constraints.dmp_remaining_messages = vec![block_number]; + + assert_eq!( + Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()), + Err(FragmentValidityError::DmpAdvancementRule), + ); + } + + candidate.commitments.to_mut().processed_downward_messages = 1; + assert!(Fragment::new(relay_parent, constraints, candidate).is_ok()); + } + + #[test] + fn fragment_ump_messages_overflow() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + let max_ump = constraints.max_ump_num_per_candidate; + + candidate + .commitments + .to_mut() + .upward_messages + .try_extend((0..max_ump + 1).map(|i| vec![i as u8])) + .unwrap(); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { + messages_allowed: max_ump, + messages_submitted: max_ump + 1, + }), + ); + } + + #[test] + fn fragment_code_upgrade_restricted() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let mut constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + constraints.upgrade_restriction = Some(UpgradeRestriction::Present); + candidate.commitments_mut().new_validation_code = Some(ValidationCode(vec![1, 2, 3])); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::CodeUpgradeRestricted), + ); + } + + #[test] + fn fragment_hrmp_messages_descending_or_duplicate() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0x0a), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + + candidate.commitments_mut().horizontal_messages = HorizontalMessages::truncate_from(vec![ + OutboundHrmpMessage { recipient: ParaId::from(0 as u32), data: vec![1, 2, 3] }, + OutboundHrmpMessage { recipient: ParaId::from(0 as u32), data: vec![4, 5, 6] }, + ]); + + assert_eq!( + Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()), + Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), + ); + + candidate.commitments_mut().horizontal_messages = HorizontalMessages::truncate_from(vec![ + OutboundHrmpMessage { recipient: ParaId::from(1 as u32), data: vec![1, 2, 3] }, + OutboundHrmpMessage { recipient: ParaId::from(0 as u32), data: vec![4, 5, 6] }, + ]); + + assert_eq!( + Fragment::new(relay_parent, constraints, candidate), + Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), + ); + } +} diff --git a/node/subsystem-util/src/lib.rs b/node/subsystem-util/src/lib.rs index e0b81608ff2f..daee4a8350e5 100644 --- a/node/subsystem-util/src/lib.rs +++ b/node/subsystem-util/src/lib.rs @@ -43,11 +43,11 @@ use futures::channel::{mpsc, oneshot}; use parity_scale_codec::Encode; use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, - EncodeAs, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, - SigningContext, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + vstaging as vstaging_primitives, AuthorityDiscoveryId, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, + Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, + SessionIndex, SessionInfo, Signed, SigningContext, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; pub use rand; use sp_application_crypto::AppCrypto; @@ -67,11 +67,17 @@ pub mod reexports { pub use polkadot_overseer::gen::{SpawnedSubsystem, Spawner, Subsystem, SubsystemContext}; } -/// Convenient and efficient runtime info access. -pub mod runtime; - +/// A utility for managing the implicit view of the relay-chain derived from active +/// leaves and the minimum allowed relay-parents that parachain candidates can have +/// and be backed in those leaves' children. +pub mod backing_implicit_view; /// Database trait for subsystem. pub mod database; +/// An emulator for node-side code to predict the results of on-chain parachain inclusion +/// and predict future constraints. +pub mod inclusion_emulator; +/// Convenient and efficient runtime info access. +pub mod runtime; /// Nested message sending /// @@ -200,6 +206,7 @@ macro_rules! specialize_requests { } specialize_requests! { + fn request_runtime_api_version() -> u32; Version; fn request_authorities() -> Vec; Authorities; fn request_validators() -> Vec; Validators; fn request_validator_groups() -> (Vec>, GroupRotationInfo); ValidatorGroups; @@ -219,6 +226,8 @@ specialize_requests! { fn request_unapplied_slashes() -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>; UnappliedSlashes; fn request_key_ownership_proof(validator_id: ValidatorId) -> Option; KeyOwnershipProof; fn request_submit_report_dispute_lost(dp: slashing::DisputeProof, okop: slashing::OpaqueKeyOwnershipProof) -> Option<()>; SubmitReportDisputeLost; + + fn request_staging_async_backing_params() -> vstaging_primitives::AsyncBackingParams; StagingAsyncBackingParams; } /// Requests executor parameters from the runtime effective at given relay-parent. First obtains @@ -270,17 +279,20 @@ pub async fn executor_params_at_relay_parent( } /// From the given set of validators, find the first key we can sign with, if any. -pub fn signing_key(validators: &[ValidatorId], keystore: &KeystorePtr) -> Option { +pub fn signing_key<'a>( + validators: impl IntoIterator, + keystore: &KeystorePtr, +) -> Option { signing_key_and_index(validators, keystore).map(|(k, _)| k) } /// From the given set of validators, find the first key we can sign with, if any, and return it /// along with the validator index. -pub fn signing_key_and_index( - validators: &[ValidatorId], +pub fn signing_key_and_index<'a>( + validators: impl IntoIterator, keystore: &KeystorePtr, ) -> Option<(ValidatorId, ValidatorIndex)> { - for (i, v) in validators.iter().enumerate() { + for (i, v) in validators.into_iter().enumerate() { if keystore.has_keys(&[(v.to_raw_vec(), ValidatorId::ID)]) { return Some((v.clone(), ValidatorIndex(i as _))) } diff --git a/node/subsystem-util/src/runtime/mod.rs b/node/subsystem-util/src/runtime/mod.rs index 6b84fdfae792..1f5641e3ea95 100644 --- a/node/subsystem-util/src/runtime/mod.rs +++ b/node/subsystem-util/src/runtime/mod.rs @@ -25,7 +25,9 @@ use sp_application_crypto::AppCrypto; use sp_core::crypto::ByteArray; use sp_keystore::{Keystore, KeystorePtr}; -use polkadot_node_subsystem::{messages::RuntimeApiMessage, overseer, SubsystemSender}; +use polkadot_node_subsystem::{ + errors::RuntimeApiError, messages::RuntimeApiMessage, overseer, SubsystemSender, +}; use polkadot_primitives::{ vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, @@ -36,8 +38,8 @@ use polkadot_primitives::{ use crate::{ request_availability_cores, request_candidate_events, request_key_ownership_proof, request_on_chain_votes, request_session_index_for_child, request_session_info, - request_submit_report_dispute_lost, request_unapplied_slashes, request_validation_code_by_hash, - request_validator_groups, + request_staging_async_backing_params, request_submit_report_dispute_lost, + request_unapplied_slashes, request_validation_code_by_hash, request_validator_groups, }; /// Errors that can happen on runtime fetches. @@ -46,6 +48,8 @@ mod error; use error::{recv_runtime, Result}; pub use error::{Error, FatalError, JfyiError}; +const LOG_TARGET: &'static str = "parachain::runtime-info"; + /// Configuration for construction a `RuntimeInfo`. pub struct Config { /// Needed for retrieval of `ValidatorInfo` @@ -393,3 +397,62 @@ where ) .await } + +/// Prospective parachains mode of a relay parent. Defined by +/// the Runtime API version. +/// +/// Needed for the period of transition to asynchronous backing. +#[derive(Debug, Copy, Clone)] +pub enum ProspectiveParachainsMode { + /// Runtime API without support of `async_backing_params`: no prospective parachains. + Disabled, + /// vstaging runtime API: prospective parachains. + Enabled { + /// The maximum number of para blocks between the para head in a relay parent + /// and a new candidate. Restricts nodes from building arbitrary long chains + /// and spamming other validators. + max_candidate_depth: usize, + /// How many ancestors of a relay parent are allowed to build candidates on top + /// of. + allowed_ancestry_len: usize, + }, +} + +impl ProspectiveParachainsMode { + /// Returns `true` if mode is enabled, `false` otherwise. + pub fn is_enabled(&self) -> bool { + matches!(self, ProspectiveParachainsMode::Enabled { .. }) + } +} + +/// Requests prospective parachains mode for a given relay parent based on +/// the Runtime API version. +pub async fn prospective_parachains_mode( + sender: &mut Sender, + relay_parent: Hash, +) -> Result +where + Sender: SubsystemSender, +{ + let result = + recv_runtime(request_staging_async_backing_params(relay_parent, sender).await).await; + + if let Err(error::Error::RuntimeRequest(RuntimeApiError::NotSupported { runtime_api_name })) = + &result + { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + "Prospective parachains are disabled, {} is not supported by the current Runtime API", + runtime_api_name, + ); + + Ok(ProspectiveParachainsMode::Disabled) + } else { + let vstaging::AsyncBackingParams { max_candidate_depth, allowed_ancestry_len } = result?; + Ok(ProspectiveParachainsMode::Enabled { + max_candidate_depth: max_candidate_depth as _, + allowed_ancestry_len: allowed_ancestry_len as _, + }) + } +} diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index 1313b7b90469..be2746daf321 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -340,7 +340,8 @@ impl PolkadotTestNode { para_id: ParaId, collator: CollatorFn, ) { - let config = CollationGenerationConfig { key: collator_key, collator, para_id }; + let config = + CollationGenerationConfig { key: collator_key, collator: Some(collator), para_id }; self.overseer_handle .send_msg(CollationGenerationMessage::Initialize(config), "Collator") diff --git a/parachain/src/primitives.rs b/parachain/src/primitives.rs index 55577618c469..5cea9d3bbf4e 100644 --- a/parachain/src/primitives.rs +++ b/parachain/src/primitives.rs @@ -80,7 +80,8 @@ impl ValidationCode { } } -/// Unit type wrapper around [`type@Hash`] that represents a validation code hash. +/// Unit type wrapper around [`type@Hash`] that represents the blake2-256 hash +/// of validation code in particular. /// /// This type is produced by [`ValidationCode::hash`]. /// diff --git a/parachain/test-parachains/adder/collator/Cargo.toml b/parachain/test-parachains/adder/collator/Cargo.toml index fad51a863a15..5d309cfa3195 100644 --- a/parachain/test-parachains/adder/collator/Cargo.toml +++ b/parachain/test-parachains/adder/collator/Cargo.toml @@ -51,6 +51,7 @@ test-parachain-adder-collator = { path = ".", features = ["test-utils"] } tokio = { version = "1.24.2", features = ["macros"] } [features] +network-protocol-staging = ["polkadot-cli/network-protocol-staging"] # This feature is used to export test code to other crates without putting it in the production build. # This is also used by the `puppet_worker` binary. test-utils = ["polkadot-node-core-pvf/test-utils"] diff --git a/parachain/test-parachains/adder/collator/src/main.rs b/parachain/test-parachains/adder/collator/src/main.rs index ac135a2702a5..dfaa1973206c 100644 --- a/parachain/test-parachains/adder/collator/src/main.rs +++ b/parachain/test-parachains/adder/collator/src/main.rs @@ -96,8 +96,9 @@ fn main() -> Result<()> { let config = CollationGenerationConfig { key: collator.collator_key(), - collator: collator - .create_collation_function(full_node.task_manager.spawn_handle()), + collator: Some( + collator.create_collation_function(full_node.task_manager.spawn_handle()), + ), para_id, }; overseer_handle diff --git a/parachain/test-parachains/undying/collator/src/lib.rs b/parachain/test-parachains/undying/collator/src/lib.rs index cc0f592dc253..e0ecc6b0997d 100644 --- a/parachain/test-parachains/undying/collator/src/lib.rs +++ b/parachain/test-parachains/undying/collator/src/lib.rs @@ -33,7 +33,9 @@ use std::{ }, time::Duration, }; -use test_parachain_undying::{execute, hash_state, BlockData, GraveyardState, HeadData}; +use test_parachain_undying::{ + execute, hash_state, BlockData, GraveyardState, HeadData, StateMismatch, +}; /// Default PoV size which also drives state size. const DEFAULT_POV_SIZE: usize = 1000; @@ -45,7 +47,7 @@ fn calculate_head_and_state_for_number( number: u64, graveyard_size: usize, pvf_complexity: u32, -) -> (HeadData, GraveyardState) { +) -> Result<(HeadData, GraveyardState), StateMismatch> { let index = 0u64; let mut graveyard = vec![0u8; graveyard_size * graveyard_size]; let zombies = 0; @@ -62,13 +64,12 @@ fn calculate_head_and_state_for_number( while head.number < number { let block = BlockData { state, tombstones: 1_000, iterations: pvf_complexity }; - let (new_head, new_state) = - execute(head.hash(), head.clone(), block).expect("Produces valid block"); + let (new_head, new_state) = execute(head.hash(), head.clone(), block)?; head = new_head; state = new_state; } - (head, state) + Ok((head, state)) } /// The state of the undying parachain. @@ -122,39 +123,35 @@ impl State { /// Advance the state and produce a new block based on the given `parent_head`. /// /// Returns the new [`BlockData`] and the new [`HeadData`]. - fn advance(&mut self, parent_head: HeadData) -> (BlockData, HeadData) { + fn advance(&mut self, parent_head: HeadData) -> Result<(BlockData, HeadData), StateMismatch> { self.best_block = parent_head.number; - let state = if let Some(head_data) = self.number_to_head.get(&self.best_block) { - self.head_to_state.get(head_data).cloned().unwrap_or_else(|| { - calculate_head_and_state_for_number( - parent_head.number, - self.graveyard_size, - self.pvf_complexity, - ) - .1 - }) + let state = if let Some(state) = self + .number_to_head + .get(&self.best_block) + .and_then(|head_data| self.head_to_state.get(head_data).cloned()) + { + state } else { let (_, state) = calculate_head_and_state_for_number( parent_head.number, self.graveyard_size, self.pvf_complexity, - ); + )?; state }; // Start with prev state and transaction to execute (place 1000 tombstones). let block = BlockData { state, tombstones: 1000, iterations: self.pvf_complexity }; - let (new_head, new_state) = - execute(parent_head.hash(), parent_head, block.clone()).expect("Produces valid block"); + let (new_head, new_state) = execute(parent_head.hash(), parent_head, block.clone())?; let new_head_arc = Arc::new(new_head.clone()); self.head_to_state.insert(new_head_arc.clone(), new_state); self.number_to_head.insert(new_head.number, new_head_arc); - (block, new_head) + Ok((block, new_head)) } } @@ -233,10 +230,21 @@ impl Collator { let seconded_collations = self.seconded_collations.clone(); Box::new(move |relay_parent, validation_data| { - let parent = HeadData::decode(&mut &validation_data.parent_head.0[..]) - .expect("Decodes parent head"); + let parent = match HeadData::decode(&mut &validation_data.parent_head.0[..]) { + Err(err) => { + log::error!("Requested to build on top of malformed head-data: {:?}", err); + return futures::future::ready(None).boxed() + }, + Ok(p) => p, + }; - let (block_data, head_data) = state.lock().unwrap().advance(parent); + let (block_data, head_data) = match state.lock().unwrap().advance(parent.clone()) { + Err(err) => { + log::error!("Unable to build on top of {:?}: {:?}", parent, err); + return futures::future::ready(None).boxed() + }, + Ok(x) => x, + }; log::info!( "created a new collation on relay-parent({}): {:?}", @@ -280,7 +288,6 @@ impl Collator { "Seconded statement should match our collation: {:?}", res.statement.payload() ); - std::process::exit(-1); } seconded_collations.fetch_add(1, Ordering::Relaxed); @@ -394,10 +401,10 @@ mod tests { let collator = Collator::new(1_000, 1); let graveyard_size = collator.state.lock().unwrap().graveyard_size; - let mut head = calculate_head_and_state_for_number(10, graveyard_size, 1).0; + let mut head = calculate_head_and_state_for_number(10, graveyard_size, 1).unwrap().0; for i in 1..10 { - head = collator.state.lock().unwrap().advance(head).1; + head = collator.state.lock().unwrap().advance(head).unwrap().1; assert_eq!(10 + i, head.number); } @@ -414,7 +421,7 @@ mod tests { .clone(); for _ in 1..20 { - second_head = collator.state.lock().unwrap().advance(second_head.clone()).1; + second_head = collator.state.lock().unwrap().advance(second_head.clone()).unwrap().1; } assert_eq!(second_head, head); diff --git a/parachain/test-parachains/undying/collator/src/main.rs b/parachain/test-parachains/undying/collator/src/main.rs index ac889d7a00e0..e564e221f013 100644 --- a/parachain/test-parachains/undying/collator/src/main.rs +++ b/parachain/test-parachains/undying/collator/src/main.rs @@ -96,8 +96,9 @@ fn main() -> Result<()> { let config = CollationGenerationConfig { key: collator.collator_key(), - collator: collator - .create_collation_function(full_node.task_manager.spawn_handle()), + collator: Some( + collator.create_collation_function(full_node.task_manager.spawn_handle()), + ), para_id, }; overseer_handle diff --git a/primitives/src/runtime_api.rs b/primitives/src/runtime_api.rs index c3a150a642e0..483256fe20f3 100644 --- a/primitives/src/runtime_api.rs +++ b/primitives/src/runtime_api.rs @@ -239,5 +239,16 @@ sp_api::decl_runtime_apis! { dispute_proof: vstaging::slashing::DisputeProof, key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof, ) -> Option<()>; + + /***** Asynchronous backing *****/ + + /// Returns the state of parachain backing for a given para. + /// This is a staging method! Do not use on production runtimes! + #[api_version(99)] + fn staging_para_backing_state(_: ppp::Id) -> Option>; + + /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. + #[api_version(99)] + fn staging_async_backing_params() -> vstaging::AsyncBackingParams; } } diff --git a/primitives/src/v5/mod.rs b/primitives/src/v5/mod.rs index c973bb05bb48..4e107c881d4e 100644 --- a/primitives/src/v5/mod.rs +++ b/primitives/src/v5/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! `V1` Primitives. +//! `V2` Primitives. use bitvec::vec::BitVec; use parity_scale_codec::{Decode, Encode}; @@ -797,7 +797,7 @@ impl TypeIndex for CoreIndex { } /// The unique (during session) index of a validator group. -#[derive(Encode, Decode, Default, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] +#[derive(Encode, Decode, Default, Clone, Copy, Debug, PartialEq, Eq, TypeInfo, PartialOrd, Ord)] #[cfg_attr(feature = "std", derive(Hash))] pub struct GroupIndex(pub u32); @@ -813,7 +813,7 @@ impl TypeIndex for GroupIndex { } } -/// A claim on authoring the next block for a given parathread. +/// A claim on authoring the next block for a given parathread (on-demand parachain). #[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)] pub struct ParathreadClaim(pub Id, pub Option); @@ -1233,10 +1233,10 @@ pub const POLKADOT_ENGINE_ID: runtime_primitives::ConsensusEngineId = *b"POL1"; /// A consensus log item for polkadot validation. To be used with [`POLKADOT_ENGINE_ID`]. #[derive(Decode, Encode, Clone, PartialEq, Eq)] pub enum ConsensusLog { - /// A parachain or parathread upgraded its code. + /// A parachain upgraded its code. #[codec(index = 1)] ParaUpgradeCode(Id, ValidationCodeHash), - /// A parachain or parathread scheduled a code upgrade. + /// A parachain scheduled a code upgrade. #[codec(index = 2)] ParaScheduleUpgradeCode(Id, ValidationCodeHash, BlockNumber), /// Governance requests to auto-approve every candidate included up to the given block @@ -1544,7 +1544,7 @@ const BACKING_STATEMENT_MAGIC: [u8; 4] = *b"BKNG"; /// Statements that can be made about parachain candidates. These are the /// actual values that are signed. -#[derive(Clone, PartialEq, Eq, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Hash))] pub enum CompactStatement { /// Proposal of a parachain candidate. @@ -1559,6 +1559,13 @@ impl CompactStatement { pub fn signing_payload(&self, context: &SigningContext) -> Vec { (self, context).encode() } + + /// Get the underlying candidate hash this references. + pub fn candidate_hash(&self) -> &CandidateHash { + match *self { + CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h, + } + } } // Inner helper for codec on `CompactStatement`. @@ -1607,15 +1614,6 @@ impl parity_scale_codec::Decode for CompactStatement { } } -impl CompactStatement { - /// Get the underlying candidate hash this references. - pub fn candidate_hash(&self) -> &CandidateHash { - match *self { - CompactStatement::Seconded(ref h) | CompactStatement::Valid(ref h) => h, - } - } -} - /// `IndexedVec` struct indexed by type specific indices. #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] diff --git a/primitives/src/v5/signed.rs b/primitives/src/v5/signed.rs index 5eff153ba2a1..96646d54cbba 100644 --- a/primitives/src/v5/signed.rs +++ b/primitives/src/v5/signed.rs @@ -157,7 +157,6 @@ impl, RealPayload: Encode> Signed Result, (Self, SuperPayload)> where SuperPayload: EncodeAs, - Payload: Encode, { if claimed.encode_as() == self.0.payload.encode_as() { Ok(Signed(UncheckedSigned { @@ -170,6 +169,34 @@ impl, RealPayload: Encode> Signed( + self, + convert: F, + ) -> Result, SuperPayload> + where + F: FnOnce(Payload) -> SuperPayload, + SuperPayload: EncodeAs, + { + let expected_encode_as = self.0.payload.encode_as(); + let converted = convert(self.0.payload); + if converted.encode_as() == expected_encode_as { + Ok(Signed(UncheckedSigned { + payload: converted, + validator_index: self.0.validator_index, + signature: self.0.signature, + real_payload: sp_std::marker::PhantomData, + })) + } else { + Err(converted) + } + } } // We can't bound this on `Payload: Into` because that conversion consumes diff --git a/primitives/src/vstaging/mod.rs b/primitives/src/vstaging/mod.rs index 0dbfa8c34cf6..ea341ee5b4fc 100644 --- a/primitives/src/vstaging/mod.rs +++ b/primitives/src/vstaging/mod.rs @@ -24,6 +24,9 @@ use parity_scale_codec::{Decode, Encode}; use primitives::RuntimeDebug; use scale_info::TypeInfo; +/// Useful type alias for Para IDs. +pub type ParaId = Id; + /// Candidate's acceptance limitations for asynchronous backing per relay parent. #[derive( RuntimeDebug, @@ -50,3 +53,85 @@ pub struct AsyncBackingParams { /// When async backing is disabled, the only valid value is 0. pub allowed_ancestry_len: u32, } + +/// Constraints on inbound HRMP channels. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct InboundHrmpLimitations { + /// An exhaustive set of all valid watermarks, sorted ascending. + /// + /// It's only expected to contain block numbers at which messages were + /// previously sent to a para, excluding most recent head. + pub valid_watermarks: Vec, +} + +/// Constraints on outbound HRMP channels. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct OutboundHrmpChannelLimitations { + /// The maximum bytes that can be written to the channel. + pub bytes_remaining: u32, + /// The maximum messages that can be written to the channel. + pub messages_remaining: u32, +} + +/// Constraints on the actions that can be taken by a new parachain +/// block. These limitations are implicitly associated with some particular +/// parachain, which should be apparent from usage. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct Constraints { + /// The minimum relay-parent number accepted under these constraints. + pub min_relay_parent_number: N, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: u32, + /// The maximum new validation code size allowed, in bytes. + pub max_code_size: u32, + /// The amount of UMP messages remaining. + pub ump_remaining: u32, + /// The amount of UMP bytes remaining. + pub ump_remaining_bytes: u32, + /// The maximum number of UMP messages allowed per candidate. + pub max_ump_num_per_candidate: u32, + /// Remaining DMP queue. Only includes sent-at block numbers. + pub dmp_remaining_messages: Vec, + /// The limitations of all registered inbound HRMP channels. + pub hrmp_inbound: InboundHrmpLimitations, + /// The limitations of all registered outbound HRMP channels. + pub hrmp_channels_out: Vec<(ParaId, OutboundHrmpChannelLimitations)>, + /// The maximum number of HRMP messages allowed per candidate. + pub max_hrmp_num_per_candidate: u32, + /// The required parent head-data of the parachain. + pub required_parent: HeadData, + /// The expected validation-code-hash of this parachain. + pub validation_code_hash: ValidationCodeHash, + /// The code upgrade restriction signal as-of this parachain. + pub upgrade_restriction: Option, + /// The future validation code hash, if any, and at what relay-parent + /// number the upgrade would be minimally applied. + pub future_validation_code: Option<(N, ValidationCodeHash)>, +} + +/// A candidate pending availability. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct CandidatePendingAvailability { + /// The hash of the candidate. + pub candidate_hash: CandidateHash, + /// The candidate's descriptor. + pub descriptor: CandidateDescriptor, + /// The commitments of the candidate. + pub commitments: CandidateCommitments, + /// The candidate's relay parent's number. + pub relay_parent_number: N, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: u32, +} + +/// The per-parachain state of the backing system, including +/// state-machine constraints and candidates pending availability. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct BackingState { + /// The state-machine constraints of the parachain. + pub constraints: Constraints, + /// The candidates pending availability. These should be ordered, i.e. they should form + /// a sub-chain, where the first candidate builds on top of the required parent of the + /// constraints and each subsequent builds on top of the previous head-data. + pub pending_availability: Vec>, +} diff --git a/primitives/test-helpers/src/lib.rs b/primitives/test-helpers/src/lib.rs index a8fc0f7ccc26..8ee5f180d342 100644 --- a/primitives/test-helpers/src/lib.rs +++ b/primitives/test-helpers/src/lib.rs @@ -24,14 +24,16 @@ //! contain randomness based data. use polkadot_primitives::{ CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorId, CollatorSignature, - CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, ValidationCode, ValidationCodeHash, - ValidatorId, + CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, PersistedValidationData, + ValidationCode, ValidationCodeHash, ValidatorId, }; pub use rand; use sp_application_crypto::sr25519; use sp_keyring::Sr25519Keyring; use sp_runtime::generic::Digest; +const MAX_POV_SIZE: u32 = 1_000_000; + /// Creates a candidate receipt with filler data. pub fn dummy_candidate_receipt>(relay_parent: H) -> CandidateReceipt { CandidateReceipt:: { @@ -147,6 +149,46 @@ pub fn dummy_collator_signature() -> CollatorSignature { CollatorSignature::from(sr25519::Signature([0u8; 64])) } +/// Create a meaningless persisted validation data. +pub fn dummy_pvd(parent_head: HeadData, relay_parent_number: u32) -> PersistedValidationData { + PersistedValidationData { + parent_head, + relay_parent_number, + max_pov_size: MAX_POV_SIZE, + relay_parent_storage_root: dummy_hash(), + } +} + +/// Create a meaningless candidate, returning its receipt and PVD. +pub fn make_candidate( + relay_parent_hash: Hash, + relay_parent_number: u32, + para_id: ParaId, + parent_head: HeadData, + head_data: HeadData, + validation_code_hash: ValidationCodeHash, +) -> (CommittedCandidateReceipt, PersistedValidationData) { + let pvd = dummy_pvd(parent_head, relay_parent_number); + let commitments = CandidateCommitments { + head_data, + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: relay_parent_number, + }; + + let mut candidate = + dummy_candidate_receipt_bad_sig(relay_parent_hash, Some(Default::default())); + candidate.commitments_hash = commitments.hash(); + candidate.descriptor.para_id = para_id; + candidate.descriptor.persisted_validation_data_hash = pvd.hash(); + candidate.descriptor.validation_code_hash = validation_code_hash; + let candidate = CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments }; + + (candidate, pvd) +} + /// Create a new candidate descriptor, and apply a valid signature /// using the provided `collator` key. pub fn make_valid_candidate_descriptor>( diff --git a/roadmap/implementers-guide/src/SUMMARY.md b/roadmap/implementers-guide/src/SUMMARY.md index 45d1ecb614c9..e997d4d77ad1 100644 --- a/roadmap/implementers-guide/src/SUMMARY.md +++ b/roadmap/implementers-guide/src/SUMMARY.md @@ -12,18 +12,17 @@ - [Messaging Overview](messaging.md) - [PVF Pre-checking](pvf-prechecking.md) - [Runtime Architecture](runtime/README.md) - - [`Initializer` Module](runtime/initializer.md) - - [`Configuration` Module](runtime/configuration.md) - - [`Shared`](runtime/shared.md) - - [`Disputes` Module](runtime/disputes.md) - - [`Paras` Module](runtime/paras.md) - - [`Scheduler` Module](runtime/scheduler.md) - - [`Inclusion` Module](runtime/inclusion.md) - - [`ParaInherent` Module](runtime/parainherent.md) - - [`DMP` Module](runtime/dmp.md) - - [`UMP` Module](runtime/ump.md) - - [`HRMP` Module](runtime/hrmp.md) - - [`Session Info` Module](runtime/session_info.md) + - [`Initializer` Pallet](runtime/initializer.md) + - [`Configuration` Pallet](runtime/configuration.md) + - [`Shared` Pallet](runtime/shared.md) + - [`Disputes` Pallet](runtime/disputes.md) + - [`Paras` Pallet](runtime/paras.md) + - [`Scheduler` Pallet](runtime/scheduler.md) + - [`Inclusion` Pallet](runtime/inclusion.md) + - [`ParaInherent` Pallet](runtime/parainherent.md) + - [`DMP` Pallet](runtime/dmp.md) + - [`HRMP` Pallet](runtime/hrmp.md) + - [`Session Info` Pallet](runtime/session_info.md) - [Runtime APIs](runtime-api/README.md) - [Validators](runtime-api/validators.md) - [Validator Groups](runtime-api/validator-groups.md) @@ -45,7 +44,9 @@ - [Collator Protocol](node/collators/collator-protocol.md) - [Backing Subsystems](node/backing/README.md) - [Candidate Backing](node/backing/candidate-backing.md) + - [Prospective Parachains](node/backing/prospective-parachains.md) - [Statement Distribution](node/backing/statement-distribution.md) + - [Statement Distribution (Legacy)](node/backing/statement-distribution-legacy.md) - [Availability Subsystems](node/availability/README.md) - [Availability Distribution](node/availability/availability-distribution.md) - [Availability Recovery](node/availability/availability-recovery.md) diff --git a/roadmap/implementers-guide/src/glossary.md b/roadmap/implementers-guide/src/glossary.md index ac6680f9befc..a036ccdd668c 100644 --- a/roadmap/implementers-guide/src/glossary.md +++ b/roadmap/implementers-guide/src/glossary.md @@ -24,11 +24,12 @@ exactly one downward message queue. - **Parablock:** A block in a parachain. - **Parachain:** A constituent chain secured by the Relay Chain's validators. - **Parachain Validators:** A subset of validators assigned during a period of time to back candidates for a specific parachain -- **Parathread:** A parachain which is scheduled on a pay-as-you-go basis. +- **On-demand parachain:** A parachain which is scheduled on a pay-as-you-go basis. +- **Lease holding parachain:** A parachain possessing an active slot lease. The lease holder is assigned a single availability core for the duration of the lease, granting consistent blockspace scheduling at the rate 1 parablock per relay block. - **PDK (Parachain Development Kit):** A toolset that allows one to develop a parachain. Cumulus is a PDK. - **Preimage:** In our context, if `H(X) = Y` where `H` is a hash function and `Y` is the hash, then `X` is the hash preimage. - **Proof-of-Validity (PoV):** A stateless-client proof that a parachain candidate is valid, with respect to some validation function. -- **PVF:** Parachain Validation Function. The validation code that is run by validators on parachains or parathreads. +- **PVF:** Parachain Validation Function. The validation code that is run by validators on parachains. - **PVF Prechecking:** This is the process of initially checking the PVF when it is first added. We attempt preparation of the PVF and make sure it succeeds within a given timeout, plus some additional checks. - **PVF Preparation:** This is the process of preparing the WASM blob and includes both prevalidation and compilation. As there is no prevalidation right now, preparation just consists of compilation. - **Relay Parent:** A block in the relay chain, referred to in a context where work is being done in the context of the state at this block. diff --git a/roadmap/implementers-guide/src/node/backing/candidate-backing.md b/roadmap/implementers-guide/src/node/backing/candidate-backing.md index 6c3eace313c3..0eee0cc532ef 100644 --- a/roadmap/implementers-guide/src/node/backing/candidate-backing.md +++ b/roadmap/implementers-guide/src/node/backing/candidate-backing.md @@ -130,7 +130,7 @@ Dispatch a `CandidateValidationMessage::Validate(validation function, candidate, ### Distribute Signed Statement -Dispatch a [`StatementDistributionMessage`][SDM]`::Share(relay_parent, SignedFullStatement)`. +Dispatch a [`StatementDistributionMessage`][SDM]`::Share(relay_parent, SignedFullStatementWithPVD)`. [OverseerSignal]: ../../types/overseer-protocol.md#overseer-signal [Statement]: ../../types/backing.md#statement-type diff --git a/roadmap/implementers-guide/src/node/backing/prospective-parachains.md b/roadmap/implementers-guide/src/node/backing/prospective-parachains.md new file mode 100644 index 000000000000..a48444a46e40 --- /dev/null +++ b/roadmap/implementers-guide/src/node/backing/prospective-parachains.md @@ -0,0 +1,158 @@ +# Prospective Parachains + +## Overview + +**Purpose:** Tracks and handles prospective parachain fragments and informs +other backing-stage subsystems of work to be done. + +"prospective": +- [*prə'spɛktɪv*] adj. +- future, likely, potential + +Asynchronous backing changes the runtime to accept parachain candidates from a +certain allowed range of historic relay-parents. This means we can now build +*prospective parachains* – that is, trees of potential (but likely) future +parachain blocks. This is the subsystem responsible for doing so. + +Other subsystems such as Backing rely on Prospective Parachains, e.g. for +determining if a candidate can be seconded. This subsystem is the main +coordinator of work within the node for the collation and backing phases of +parachain consensus. + +Prospective Parachains is primarily an implementation of fragment trees. It also +handles concerns such as: + +- the relay-chain being forkful +- session changes + +See the following sections for more details. + +### Fragment Trees + +This subsystem builds up fragment trees, which are trees of prospective para +candidates. Each path through the tree represents a possible state transition +path for the para. Each potential candidate is a fragment, or a node, in the +tree. Candidates are validated against constraints as they are added. + +This subsystem builds up trees for each relay-chain block in the view, for each +para. These fragment trees are used for: + +- providing backable candidates to other subsystems +- sanity-checking that candidates can be seconded +- getting seconded candidates under active leaves +- etc. + +For example, here is a tree with several possible paths: + +``` +Para Head registered by the relay chain: included_head + ↲ ↳ +depth 0: head_0_a head_0_b + ↲ ↳ +depth 1: head_1_a head_1_b + ↲ | ↳ +depth 2: head_2_a1 head_2_a2 head_2_a3 +``` + +### The Relay-Chain Being Forkful + +We account for the same candidate possibly appearing in different forks. While +we still build fragment trees for each head in each fork, we are efficient with +how we reference candidates to save space. + +### Session Changes + +Allowed ancestry doesn't cross session boundary. That is, you can only build on +top of the freshest relay parent when the session starts. This is a current +limitation that may be lifted in the future. + +Also, runtime configuration values needed for constraints (such as +`max_pov_size`) are constant within a session. This is important when building +prospective validation data. This is unlikely to change. + +## Messages + +### Incoming + +- `ActiveLeaves` + - Notification of a change in the set of active leaves. + - Constructs fragment trees for each para for each new leaf. +- `ProspectiveParachainsMessage::IntroduceCandidate` + - Informs the subsystem of a new candidate. + - Sent by the Backing Subsystem when it is importing a statement for a + new candidate. +- `ProspectiveParachainsMessage::CandidateSeconded` + - Informs the subsystem that a previously introduced candidate has + been seconded. + - Sent by the Backing Subsystem when it is importing a statement for a + new candidate after it sends `IntroduceCandidate`, if that wasn't + rejected by Prospective Parachains. +- `ProspectiveParachainsMessage::CandidateBacked` + - Informs the subsystem that a previously introduced candidate has + been backed. + - Sent by the Backing Subsystem after it successfully imports a + statement giving a candidate the necessary quorum of backing votes. +- `ProspectiveParachainsMessage::GetBackableCandidate` + - Get a backable candidate hash along with its relay parent for a given parachain, + under a given relay-parent (leaf) hash, which is a descendant of given candidate hashes. + - Sent by the Provisioner when requesting backable candidates, when + selecting candidates for a given relay-parent. +- `ProspectiveParachainsMessage::GetHypotheticalFrontier` + - Gets the hypothetical frontier membership of candidates with the + given properties under the specified active leaves' fragment trees. + - Sent by the Backing Subsystem when sanity-checking whether a candidate can + be seconded based on its hypothetical frontiers. +- `ProspectiveParachainsMessage::GetTreeMembership` + - Gets the membership of the candidate in all fragment trees. + - Sent by the Backing Subsystem when it needs to update the candidates + seconded at various depths under new active leaves. +- `ProspectiveParachainsMessage::GetMinimumRelayParents` + - Gets the minimum accepted relay-parent number for each para in the + fragment tree for the given relay-chain block hash. + - That is, this returns the minimum relay-parent block number in the + same branch of the relay-chain which is accepted in the fragment + tree for each para-id. + - Sent by the Backing, Statement Distribution, and Collator Protocol + subsystems when activating leaves in the implicit view. +- `ProspectiveParachainsMessage::GetProspectiveValidationData` + - Gets the validation data of some prospective candidate. The + candidate doesn't need to be part of any fragment tree. + - Sent by the Collator Protocol subsystem (validator side) when + handling a fetched collation result. + +### Outgoing + +- `RuntimeApiRequest::StagingParaBackingState` + - Gets the backing state of the given para (the constraints of the para and + candidates pending availability). +- `RuntimeApiRequest::AvailabilityCores` + - Gets information on all availability cores. +- `ChainApiMessage::Ancestors` + - Requests the `k` ancestor block hashes of a block with the given + hash. +- `ChainApiMessage::BlockHeader` + - Requests the block header by hash. + +## Glossary + +- **Candidate storage:** Stores candidates and information about them + such as their relay-parents and their backing states. Is indexed in + various ways. +- **Constraints:** + - Constraints on the actions that can be taken by a new parachain + block. + - Exhaustively define the set of valid inputs and outputs to parachain + execution. +- **Fragment:** A prospective para block (that is, a block not yet referenced by + the relay-chain). Fragments are anchored to the relay-chain at a particular + relay-parent. +- **Fragment tree:** + - A tree of fragments. Together, these fragments define one or more + prospective paths a parachain's state may transition through. + - See the "Fragment Tree" section. +- **Inclusion emulation:** Emulation of the logic that the runtime uses + for checking parachain blocks. +- **Relay-parent:** A particular relay-chain block that a fragment is + anchored to. +- **Scope:** The scope of a fragment tree, defining limits on nodes + within the tree. diff --git a/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md b/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md new file mode 100644 index 000000000000..5cbc875d8a73 --- /dev/null +++ b/roadmap/implementers-guide/src/node/backing/statement-distribution-legacy.md @@ -0,0 +1,119 @@ +# Statement Distribution (Legacy) + +This describes the legacy, backwards-compatible version of the Statement +Distribution subsystem. + +**Note:** All the V1 (legacy) code was extracted out to a `legacy_v1` module of +the `statement-distribution` crate, which doesn't alter any logic. V2 (new +protocol) peers also run `legacy_v1` and communicate with V1 peers using V1 +messages and with V2 peers using V2 messages. Once the runtime upgrade goes +through on all networks, this `legacy_v1` code will no longer be triggered and +will be vestigial and can be removed. + +## Overview + +The Statement Distribution Subsystem is responsible for distributing statements about seconded candidates between validators. + +## Protocol + +`PeerSet`: `Validation` + +Input: + +- `NetworkBridgeUpdate(update)` +- `StatementDistributionMessage` + +Output: + +- `NetworkBridge::SendMessage(PeerId, message)` +- `NetworkBridge::SendRequests(StatementFetchingV1)` +- `NetworkBridge::ReportPeer(PeerId, cost_or_benefit)` + +## Functionality + +Implemented as a gossip protocol. Handles updates to our view and peers' views. Neighbor packets are used to inform peers which chain heads we are interested in data for. + +The Statement Distribution Subsystem is responsible for distributing signed statements that we have generated and for forwarding statements generated by other validators. It also detects a variety of Validator misbehaviors for reporting to the [Provisioner Subsystem](../utility/provisioner.md). During the Backing stage of the inclusion pipeline, Statement Distribution is the main point of contact with peer nodes. On receiving a signed statement from a peer in the same backing group, assuming the peer receipt state machine is in an appropriate state, it sends the Candidate Receipt to the [Candidate Backing subsystem](candidate-backing.md) to handle the validator's statement. On receiving `StatementDistributionMessage::Share` we make sure to send messages to our backing group in addition to random other peers, to ensure a fast backing process and getting all statements quickly for distribution. + +This subsystem tracks equivocating validators and stops accepting information from them. It establishes a data-dependency order: + +- In order to receive a `Seconded` message we have the corresponding chain head in our view +- In order to receive a `Valid` message we must have received the corresponding `Seconded` message. + +And respect this data-dependency order from our peers by respecting their views. This subsystem is responsible for checking message signatures. + +The Statement Distribution subsystem sends statements to peer nodes. + +## Peer Receipt State Machine + +There is a very simple state machine which governs which messages we are willing to receive from peers. Not depicted in the state machine: on initial receipt of any [`SignedFullStatement`](../../types/backing.md#signed-statement-type), validate that the provided signature does in fact sign the included data. Note that each individual parablock candidate gets its own instance of this state machine; it is perfectly legal to receive a `Valid(X)` before a `Seconded(Y)`, as long as a `Seconded(X)` has been received. + +A: Initial State. Receive `SignedFullStatement(Statement::Second)`: extract `Statement`, forward to Candidate Backing, proceed to B. Receive any other `SignedFullStatement` variant: drop it. + +B: Receive any `SignedFullStatement`: check signature and determine whether the statement is new to us. if new, forward to Candidate Backing and circulate to other peers. Receive `OverseerMessage::StopWork`: proceed to C. + +C: Receive any message for this block: drop it. + +For large statements (see below), we also keep track of the total received large +statements per peer and have a hard limit on that number for flood protection. +This is necessary as in the current code we only forward statements once we have +all the data, therefore flood protection for large statement is a bit more +subtle. This will become an obsolete problem once [off chain code +upgrades](https://github.com/paritytech/polkadot/issues/2979) are implemented. + +## Peer Knowledge Tracking + +The peer receipt state machine implies that for parsimony of network resources, we should model the knowledge of our peers, and help them out. For example, let's consider a case with peers A, B, and C, validators X and Y, and candidate M. A sends us a `Statement::Second(M)` signed by X. We've double-checked it, and it's valid. While we're checking it, we receive a copy of X's `Statement::Second(M)` from `B`, along with a `Statement::Valid(M)` signed by Y. + +Our response to A is just the `Statement::Valid(M)` signed by Y. However, we haven't heard anything about this from C. Therefore, we send it everything we have: first a copy of X's `Statement::Second`, then Y's `Statement::Valid`. + +This system implies a certain level of duplication of messages--we received X's `Statement::Second` from both our peers, and C may experience the same--but it minimizes the degree to which messages are simply dropped. + +And respect this data-dependency order from our peers. This subsystem is responsible for checking message signatures. + +No jobs. We follow view changes from the [`NetworkBridge`](../utility/network-bridge.md), which in turn is updated by the overseer. + +## Equivocations and Flood Protection + +An equivocation is a double-vote by a validator. The [Candidate Backing](candidate-backing.md) Subsystem is better-suited than this one to detect equivocations as it adds votes to quorum trackers. + +At this level, we are primarily concerned about flood-protection, and to some extent, detecting equivocations is a part of that. In particular, we are interested in detecting equivocations of `Seconded` statements. Since every other statement is dependent on `Seconded` statements, ensuring that we only ever hold a bounded number of `Seconded` statements is sufficient for flood-protection. + +The simple approach is to say that we only receive up to two `Seconded` statements per validator per chain head. However, the marginal cost of equivocation, conditional on having already equivocated, is close to 0, since a single double-vote offence is counted as all double-vote offences for a particular chain-head. Even if it were not, there is some amount of equivocations that can be done such that the marginal cost of issuing further equivocations is close to 0, as there would be an amount of equivocations necessary to be completely and totally obliterated by the slashing algorithm. We fear the validator with nothing left to lose. + +With that in mind, this simple approach has a caveat worth digging deeper into. + +First: We may be aware of two equivocated `Seconded` statements issued by a validator. A totally honest peer of ours can also be aware of one or two different `Seconded` statements issued by the same validator. And yet another peer may be aware of one or two _more_ `Seconded` statements. And so on. This interacts badly with pre-emptive sending logic. Upon sending a `Seconded` statement to a peer, we will want to pre-emptively follow up with all statements relative to that candidate. Waiting for acknowledgment introduces latency at every hop, so that is best avoided. What can happen is that upon receipt of the `Seconded` statement, the peer will discard it as it falls beyond the bound of 2 that it is allowed to store. It cannot store anything in memory about discarded candidates as that would introduce a DoS vector. Then, the peer would receive from us all of the statements pertaining to that candidate, which, from its perspective, would be undesired - they are data-dependent on the `Seconded` statement we sent them, but they have erased all record of that from their memory. Upon receiving a potential flood of undesired statements, this 100% honest peer may choose to disconnect from us. In this way, an adversary may be able to partition the network with careful distribution of equivocated `Seconded` statements. + +The fix is to track, per-peer, the hashes of up to 4 candidates per validator (per relay-parent) that the peer is aware of. It is 4 because we may send them 2 and they may send us 2 different ones. We track the data that they are aware of as the union of things we have sent them and things they have sent us. If we receive a 1st or 2nd `Seconded` statement from a peer, we note it in the peer's known candidates even if we do disregard the data locally. And then, upon receipt of any data dependent on that statement, we do not reduce that peer's standing in our eyes, as the data was not undesired. + +There is another caveat to the fix: we don't want to allow the peer to flood us because it has set things up in a way that it knows we will drop all of its traffic. +We also track how many statements we have received per peer, per candidate, and per chain-head. This is any statement concerning a particular candidate: `Seconded`, `Valid`, or `Invalid`. If we ever receive a statement from a peer which would push any of these counters beyond twice the amount of validators at the chain-head, we begin to lower the peer's standing and eventually disconnect. This bound is a massive overestimate and could be reduced to twice the number of validators in the corresponding validator group. It is worth noting that the goal at the time of writing is to ensure any finite bound on the amount of stored data, as any equivocation results in a large slash. + +## Large statements + +Seconded statements can become quite large on parachain runtime upgrades for +example. For this reason, there exists a `LargeStatement` constructor for the +`StatementDistributionMessage` wire message, which only contains light metadata +of a statement. The actual candidate data is not included. This message type is +used whenever a message is deemed large. The receiver of such a message needs to +request the actual payload via request/response by means of a +`StatementFetchingV1` request. + +This is necessary as distribution of a large payload (mega bytes) via gossip +would make the network collapse and timely distribution of statements would no +longer be possible. By using request/response it is ensured that each peer only +transferes large data once. We only take good care to detect an overloaded +peer early and immediately move on to a different peer for fetching the data. +This mechanism should result in a good load distribution and therefore a rather +optimal distribution path. + +With these optimizations, distribution of payloads in the size of up to 3 to 4 +MB should work with Kusama validator specifications. For scaling up even more, +runtime upgrades and message passing should be done off chain at some point. + +Flood protection considerations: For making DoS attacks slightly harder on this +subsystem, nodes will only respond to large statement requests, when they +previously notified that peer via gossip about that statement. So, it is not +possible to DoS nodes at scale, by requesting candidate data over and over +again. diff --git a/roadmap/implementers-guide/src/node/backing/statement-distribution.md b/roadmap/implementers-guide/src/node/backing/statement-distribution.md index 4ce3ee518c86..2e0142848210 100644 --- a/roadmap/implementers-guide/src/node/backing/statement-distribution.md +++ b/roadmap/implementers-guide/src/node/backing/statement-distribution.md @@ -1,107 +1,479 @@ # Statement Distribution -The Statement Distribution Subsystem is responsible for distributing statements about seconded candidates between validators. +This subsystem is responsible for distributing signed statements that we have generated and forwarding statements generated by our peers. Received candidate receipts and statements are passed to the [Candidate Backing subsystem](candidate-backing.md) to handle producing local statements. On receiving `StatementDistributionMessage::Share`, this subsystem distributes the message across the network with redundency to ensure a fast backing process. -## Protocol - -`PeerSet`: `Validation` - -Input: - -- `NetworkBridgeUpdate(update)` -- `StatementDistributionMessage` - -Output: - -- `NetworkBridge::SendMessage(PeerId, message)` -- `NetworkBridge::SendRequests(StatementFetchingV1)` -- `NetworkBridge::ReportPeer(PeerId, cost_or_benefit)` - -## Functionality - -Implemented as a gossip protocol. Handle updates to our view and peers' views. Neighbor packets are used to inform peers which chain heads we are interested in data for. - -It is responsible for distributing signed statements that we have generated and forwarding them, and for detecting a variety of Validator misbehaviors for reporting to the [Provisioner Subsystem](../utility/provisioner.md). During the Backing stage of the inclusion pipeline, it's the main point of contact with peer nodes. On receiving a signed statement from a peer in the same backing group, assuming the peer receipt state machine is in an appropriate state, it sends the Candidate Receipt to the [Candidate Backing subsystem](candidate-backing.md) to handle the validator's statement. On receiving `StatementDistributionMessage::Share` we make sure to send messages to our backing group in addition to random other peers, to ensure a fast backing process and getting all statements quickly for distribution. - -Track equivocating validators and stop accepting information from them. Establish a data-dependency order: - -- In order to receive a `Seconded` message we have the corresponding chain head in our view -- In order to receive an `Valid` message we must have received the corresponding `Seconded` message. - -And respect this data-dependency order from our peers by respecting their views. This subsystem is responsible for checking message signatures. - -The Statement Distribution subsystem sends statements to peer nodes. - -## Peer Receipt State Machine - -There is a very simple state machine which governs which messages we are willing to receive from peers. Not depicted in the state machine: on initial receipt of any [`SignedFullStatement`](../../types/backing.md#signed-statement-type), validate that the provided signature does in fact sign the included data. Note that each individual parablock candidate gets its own instance of this state machine; it is perfectly legal to receive a `Valid(X)` before a `Seconded(Y)`, as long as a `Seconded(X)` has been received. +## Overview -A: Initial State. Receive `SignedFullStatement(Statement::Second)`: extract `Statement`, forward to Candidate Backing, proceed to B. Receive any other `SignedFullStatement` variant: drop it. +**Goal:** every well-connected node is aware of every next potential parachain +block. -B: Receive any `SignedFullStatement`: check signature and determine whether the statement is new to us. if new, forward to Candidate Backing and circulate to other peers. Receive `OverseerMessage::StopWork`: proceed to C. +Validators can either: -C: Receive any message for this block: drop it. +- receive parachain block from collator, check block, and gossip statement. +- receive statements from other validators, check the parachain block if it + originated within their own group, gossip forward statement if valid. -For large statements (see below), we also keep track of the total received large -statements per peer and have a hard limit on that number for flood protection. -This is necessary as in the current code we only forward statements once we have -all the data, therefore flood protection for large statement is a bit more -subtle. This will become an obsolete problem once [off chain code -upgrades](https://github.com/paritytech/polkadot/issues/2979) are implemented. +Validators must have statements, candidates, and persisted validation from all +other validators. This is because we need to store statements from validators +who've checked the candidate on the relay chain, so we know who to hold +accountable in case of disputes. Any validator can be selected as the next +relay-chain block author, and this is not revealed in advance for security +reasons. As a result, all validators must have a up to date view of all possible +parachain candidates + backing statements that could be placed on-chain in the +next block. -## Peer Knowledge Tracking +[This blog post](https://polkadot.network/blog/polkadot-v1-0-sharding-and-economic-security) +puts it another way: "Validators who aren't assigned to the parachain still +listen for the attestations [statements] because whichever validator ends up +being the author of the relay-chain block needs to bundle up attested parachain +blocks for several parachains and place them into the relay-chain block." -The peer receipt state machine implies that for parsimony of network resources, we should model the knowledge of our peers, and help them out. For example, let's consider a case with peers A, B, and C, validators X and Y, and candidate M. A sends us a `Statement::Second(M)` signed by X. We've double-checked it, and it's valid. While we're checking it, we receive a copy of X's `Statement::Second(M)` from `B`, along with a `Statement::Valid(M)` signed by Y. +Backing-group quorum (that is, enough backing group votes) must be reached +before the block author will consider the candidate. Therefore, validators need +to consider _all_ seconded candidates within their own group, because that's +what they're assigned to work on. Validators only need to consider _backable_ +candidates from other groups. This informs the design of the statement +distribution protocol to have separate phases for in-group and out-group +distribution, respectively called "cluster" and "grid" mode (see below). -Our response to A is just the `Statement::Valid(M)` signed by Y. However, we haven't heard anything about this from C. Therefore, we send it everything we have: first a copy of X's `Statement::Second`, then Y's `Statement::Valid`. +### With Async Backing -This system implies a certain level of duplication of messages--we received X's `Statement::Second` from both our peers, and C may experience the same--but it minimizes the degree to which messages are simply dropped. +Asynchronous backing changes the runtime to accept parachain candidates from a +certain allowed range of historic relay-parents. These candidates must be backed +by the group assigned to the parachain as-of their corresponding relay parents. -And respect this data-dependency order from our peers. This subsystem is responsible for checking message signatures. - -No jobs. We follow view changes from the [`NetworkBridge`](../utility/network-bridge.md), which in turn is updated by the overseer. - -## Equivocations and Flood Protection - -An equivocation is a double-vote by a validator. The [Candidate Backing](candidate-backing.md) Subsystem is better-suited than this one to detect equivocations as it adds votes to quorum trackers. - -At this level, we are primarily concerned about flood-protection, and to some extent, detecting equivocations is a part of that. In particular, we are interested in detecting equivocations of `Seconded` statements. Since every other statement is dependent on `Seconded` statements, ensuring that we only ever hold a bounded number of `Seconded` statements is sufficient for flood-protection. - -The simple approach is to say that we only receive up to two `Seconded` statements per validator per chain head. However, the marginal cost of equivocation, conditional on having already equivocated, is close to 0, since a single double-vote offence is counted as all double-vote offences for a particular chain-head. Even if it were not, there is some amount of equivocations that can be done such that the marginal cost of issuing further equivocations is close to 0, as there would be an amount of equivocations necessary to be completely and totally obliterated by the slashing algorithm. We fear the validator with nothing left to lose. - -With that in mind, this simple approach has a caveat worth digging deeper into. - -First: We may be aware of two equivocated `Seconded` statements issued by a validator. A totally honest peer of ours can also be aware of one or two different `Seconded` statements issued by the same validator. And yet another peer may be aware of one or two _more_ `Seconded` statements. And so on. This interacts badly with pre-emptive sending logic. Upon sending a `Seconded` statement to a peer, we will want to pre-emptively follow up with all statements relative to that candidate. Waiting for acknowledgment introduces latency at every hop, so that is best avoided. What can happen is that upon receipt of the `Seconded` statement, the peer will discard it as it falls beyond the bound of 2 that it is allowed to store. It cannot store anything in memory about discarded candidates as that would introduce a DoS vector. Then, the peer would receive from us all of the statements pertaining to that candidate, which, from its perspective, would be undesired - they are data-dependent on the `Seconded` statement we sent them, but they have erased all record of that from their memory. Upon receiving a potential flood of undesired statements, this 100% honest peer may choose to disconnect from us. In this way, an adversary may be able to partition the network with careful distribution of equivocated `Seconded` statements. - -The fix is to track, per-peer, the hashes of up to 4 candidates per validator (per relay-parent) that the peer is aware of. It is 4 because we may send them 2 and they may send us 2 different ones. We track the data that they are aware of as the union of things we have sent them and things they have sent us. If we receive a 1st or 2nd `Seconded` statement from a peer, we note it in the peer's known candidates even if we do disregard the data locally. And then, upon receipt of any data dependent on that statement, we do not reduce that peer's standing in our eyes, as the data was not undesired. - -There is another caveat to the fix: we don't want to allow the peer to flood us because it has set things up in a way that it knows we will drop all of its traffic. -We also track how many statements we have received per peer, per candidate, and per chain-head. This is any statement concerning a particular candidate: `Seconded`, `Valid`, or `Invalid`. If we ever receive a statement from a peer which would push any of these counters beyond twice the amount of validators at the chain-head, we begin to lower the peer's standing and eventually disconnect. This bound is a massive overestimate and could be reduced to twice the number of validators in the corresponding validator group. It is worth noting that the goal at the time of writing is to ensure any finite bound on the amount of stored data, as any equivocation results in a large slash. - -## Large statements - -Seconded statements can become quite large on parachain runtime upgrades for -example. For this reason, there exists a `LargeStatement` constructor for the -`StatementDistributionMessage` wire message, which only contains light metadata -of a statement. The actual candidate data is not included. This message type is -used whenever a message is deemed large. The receiver of such a message needs to -request the actual payload via request/response by means of a -`StatementFetchingV1` request. - -This is necessary as distribution of a large payload (mega bytes) via gossip -would make the network collapse and timely distribution of statements would no -longer be possible. By using request/response it is ensured that each peer only -transferes large data once. We only take good care to detect an overloaded -peer early and immediately move on to a different peer for fetching the data. -This mechanism should result in a good load distribution and therefore a rather -optimal distribution path. - -With these optimizations, distribution of payloads in the size of up to 3 to 4 -MB should work with Kusama validator specifications. For scaling up even more, -runtime upgrades and message passing should be done off chain at some point. +## Protocol -Flood protection considerations: For making DoS attacks slightly harder on this -subsystem, nodes will only respond to large statement requests, when they -previously notified that peer via gossip about that statement. So, it is not -possible to DoS nodes at scale, by requesting candidate data over and over -again. +To address the concern of dealing with large numbers of spam candidates or +statements, the overall design approach is to combine a focused "clustering" +protocol for legitimate fresh candidates with a broad-distribution "grid" +protocol to quickly get backed candidates into the hands of many validators. +Validators do not eagerly send each other heavy `CommittedCandidateReceipt`, +but instead request these lazily through request/response protocols. + +A high-level description of the protocol follows: + +### Messages + +Nodes can send each other a few kinds of messages: `Statement`, +`BackedCandidateManifest`, `BackedCandidateAcknowledgement`. + +- `Statement` messages contain only a signed compact statement, without full + candidate info. +- `BackedCandidateManifest` messages advertise a description of a backed + candidate and stored statements. +- `BackedCandidateAcknowledgement` messages acknowledge that a backed candidate + is fully known. + +### Request/response protocol + +Nodes can request the full `CommittedCandidateReceipt` and +`PersistedValidationData`, along with statements, over a request/response +protocol. This is the `AttestedCandidateRequest`; the response is +`AttestedCandidateResponse`. + +### Importability and the Hypothetical Frontier + +The **prospective parachains** subsystem maintains prospective "fragment trees" +which can be used to determine whether a particular parachain candidate could +possibly be included in the future. Candidates which either are within a +fragment tree or _would be_ part of a fragment tree if accepted are said to be +in the "hypothetical frontier". + +The **statement-distribution** subsystem keeps track of all candidates, and +updates its knowledge of the hypothetical frontier based on events such as new +relay parents, new confirmed candidates, and newly backed candidates. + +We only consider statements as "importable" when the corresponding candidate is +part of the hypothetical frontier, and only send "importable" statements to the +backing subsystem itself. + +### Cluster Mode + +- Validator nodes are partitioned into groups (with some exceptions), and + validators within a group at a relay-parent can send each other `Statement` + messages for any candidates within that group and based on that relay-parent. +- This is referred to as the "cluster" mode. + - Right now these are the same as backing groups, though "cluster" + specifically refers to the set of nodes communicating with each other in the + first phase of distribution. +- `Seconded` statements must be sent before `Valid` statements. +- `Seconded` statements may only be sent to other members of the group when the + candidate is fully known by the local validator. + - "Fully known" means the validator has the full `CommittedCandidateReceipt` + and `PersistedValidationData`, which it receives on request from other + validators or from a collator. + - The reason for this is that sending a statement (which is always a + `CompactStatement` carrying nothing but a hash and signature) to the + cluster, is also a signal that the sending node is available to request the + candidate from. + - This makes the protocol easier to reason about, while also reducing network + messages about candidates that don't really exist. +- Validators in a cluster receiving messages about unknown candidates request + the candidate (and statements) from other cluster members which have it. +- Spam considerations + - The maximum depth of candidates allowed in asynchronous backing determines + the maximum amount of `Seconded` statements originating from a validator V + which each validator in a cluster may send to others. This bounds the number + of candidates. + - There is a small number of validators in each group, which further limits + the amount of candidates. +- We accept candidates which don't fit in the fragment trees of any relay + parents. + - "Accept" means "attempt to request and store in memory until useful or + expired". + - We listen to prospective parachains subsystem to learn of new additions to + the fragment trees. + - Use this to attempt to import the candidate later. + +### Grid Mode + +- Every consensus session provides randomness and a fixed validator set, which + is used to build a redundant grid topology. + - It's redundant in the sense that there are 2 paths from every node to every + other node. See "Grid Topology" section for more details. +- This grid topology is used to create a sending path from each validator group + to every validator. +- When a node observes a candidate as backed, it sends a + `BackedCandidateManifest` to their "receiving" nodes. +- If receiving nodes don't yet know the candidate, they request it. +- Once they know the candidate, they respond with a + `BackedCandidateAcknowledgement`. +- Once two nodes perform a manifest/acknowledgement exchange, they can send + `Statement` messages directly to each other for any new statements they might + need. + - This limits the amount of statements we'd have to deal with w.r.t. + candidates that don't really exist. See "Manifest Exchange" section. +- There are limitations on the number of candidates that can be advertised by + each peer, similar to those in the cluster. Validators do not request + candidates which exceed these limitations. +- Validators request candidates as soon as they are advertised, but do not + import the statements until the candidate is part of the hypothetical + frontier, and do not re-advertise or acknowledge until the candidate is + considered both backable and part of the hypothetical frontier. +- Note that requesting is not an implicit acknowledgement, and an explicit + acknowledgement must be sent upon receipt. + +## Messages + +### Incoming + +- `ActiveLeaves` + - Notification of a change in the set of active leaves. +- `StatementDistributionMessage::Share` + - Notification of a locally-originating statement. That is, this statement + comes from our node and should be distributed to other nodes. + - Sent by the Backing Subsystem after it successfully imports a + locally-originating statement. +- `StatementDistributionMessage::Backed` + - Notification of a candidate being backed (received enough validity votes + from the backing group). + - Sent by the Backing Subsystem after it successfully imports a statement for + the first time and after sending ~Share~. +- `StatementDistributionMessage::NetworkBridgeUpdate` + - See next section. + +#### Network bridge events + +- v1 compatibility + - Messages for the v1 protocol are routed to the legacy statement + distribution. +- `Statement` + - Notification of a signed statement. + - Sent by a peer's Statement Distribution subsystem when circulating + statements. +- `BackedCandidateManifest` + - Notification of a backed candidate being known by the sending node. + - For the candidate being requested by the receiving node if needed. + - Announcement. + - Sent by a peer's Statement Distribution subsystem. +- `BackedCandidateKnown` + - Notification of a backed candidate being known by the sending node. + - For informing a receiving node which already has the candidate. + - Acknowledgement. + - Sent by a peer's Statement Distribution subsystem. + +### Outgoing + +- `NetworkBridgeTxMessage::SendValidationMessages` + - Sends a peer all pending messages / acknowledgements / statements for a + relay parent, either through the cluster or the grid. +- `NetworkBridgeTxMessage::SendValidationMessage` + - Circulates a compact statement to all peers who need it, either through the + cluster or the grid. +- `NetworkBridgeTxMessage::ReportPeer` + - Reports a peer (either good or bad). +- `CandidateBackingMessage::Statement` + - Note a validator's statement about a particular candidate. +- `ProspectiveParachainsMessage::GetHypotheticalFrontier` + - Gets the hypothetical frontier membership of candidates under active leaves' + fragment trees. +- `NetworkBridgeTxMessage::SendRequests` + - Sends requests, initiating the request/response protocol. + +## Request/Response + +We also have a request/response protocol because validators do not eagerly send +each other heavy `CommittedCandidateReceipt`, but instead need to request these +lazily. + +### Protocol + +1. Requesting Validator + + - Requests are queued up with `RequestManager::get_or_insert`. + - Done as needed, when handling incoming manifests/statements. + - `RequestManager::dispatch_requests` sends any queued-up requests. + - Calls `RequestManager::next_request` to completion. + - Creates the `OutgoingRequest`, saves the receiver in + `RequestManager::pending_responses`. + - Does nothing if we have more responses pending than the limit of parallel + requests. + +2. Peer + + - Requests come in on a peer on the `IncomingRequestReceiver`. + - Runs in a background responder task which feeds requests to `answer_request` + through `MuxedMessage`. + - This responder task has a limit on the number of parallel requests. + - `answer_request` on the peer takes the request and sends a response. + - Does this using the response sender on the request. + +3. Requesting Validator + + - `receive_response` on the original validator yields a response. + - Response was sent on the request's response sender. + - Uses `RequestManager::await_incoming` to await on pending responses in an + unordered fashion. + - Runs on the `MuxedMessage` receiver. + - `handle_response` handles the response. + +### API + +- `dispatch_requests` + - Dispatches pending requests for candidate data & statements. +- `answer_request` + - Answers an incoming request for a candidate. + - Takes an incoming `AttestedCandidateRequest`. +- `receive_response` + - Wait on the next incoming response. + - If there are no requests pending, this future never resolves. + - Returns `UnhandledResponse` +- `handle_response` + - Handles an incoming response. + - Takes `UnhandledResponse` + +## Manifests + +A manifest is a message about a known backed candidate, along with a description +of the statements backing it. It can be one of two kinds: + +- `Full`: Contains information about the candidate and should be sent to peers + who may not have the candidate yet. This is also called an `Announcement`. +- `Acknowledgement`: Omits information implicit in the candidate, and should be + sent to peers which are guaranteed to have the candidate already. + +### Manifest Exchange + +Manifest exchange is when a receiving node received a `Full` manifest and +replied with an `Acknowledgement`. It indicates that both nodes know the +candidate as valid and backed. This allows the nodes to send `Statement` +messages directly to each other for any new statements. + +Why? This limits the amount of statements we'd have to deal with w.r.t. +candidates that don't really exist. Limiting out-of-group statement distribution +between peers to only candidates that both peers agree are backed and exist +ensures we only have to store statements about real candidates. + +In practice, manifest exchange means that one of three things have happened: + +- They announced, we acknowledged. +- We announced, they acknowledged. +- We announced, they announced. + +Concerning the last case, note that it is possible for two nodes to have each +other in their sending set. Consider: + +``` +1 2 +3 4 +``` + +If validators 2 and 4 are in group B, then there is a path `2->1->3` and +`4->3->1`. Therefore, 1 and 3 might send each other manifests for the same +candidate at the same time, without having seen the other's yet. This also +counts as a manifest exchange, but is only allowed to occur in this way. + +After the exchange is complete, we update pending statements. Pending statements +are those we know locally that the remote node does not. + +#### Alternative Paths Through The Topology + +Nodes should send a `BackedCandidateAcknowledgement(CandidateHash, +StatementFilter)` notification to any peer which has sent a manifest, and the +candidate has been acquired by other means. This keeps alternative paths through +the topology open, which allows nodes to receive additional statements that come +later, but not after the candidate has been posted on-chain. + +This is mostly about the limitation that the runtime has no way for block +authors to post statements that come after the parablock is posted on-chain and +ensure those validators still get rewarded. Technically, we only need enough +statements to back the candidate and the manifest + request will provide that. +But more statements might come shortly afterwards, and we want those to end up +on-chain as well to ensure all validators in the group are rewarded. + +For clarity, here is the full timeline: + +1. candidate seconded +1. backable in cluster +1. distributed along grid +1. latecomers issue statements +1. candidate posted on chain +1. really latecomers issue statements + +## Cluster Module + +The cluster module provides direct distribution of unbacked candidates within a +group. By utilizing this initial phase of propagating only within +clusters/groups, we bound the number of `Seconded` messages per validator per +relay-parent, helping us prevent spam. Validators can try to circumvent this, +but they would only consume a few KB of memory and it is trivially slashable on +chain. + +The cluster module determines whether to accept/reject messages from other +validators in the same group. It keeps track of what we have sent to other +validators in the group, and pending statements. For the full protocol, see +"Protocol". + +## Grid Module + +The grid module provides distribution of backed candidates and late statements +outside the backing group. For the full protocol, see the "Protocol" section. + +### Grid Topology + +For distributing outside our cluster (aka backing group) we use a 2D grid +topology. This limits the amount of peers we send messages to, and handles +view updates. + +The basic operation of the grid topology is that: + +- A validator producing a message sends it to its row-neighbors and its + column-neighbors. +- A validator receiving a message originating from one of its row-neighbors + sends it to its column-neighbors. +- A validator receiving a message originating from one of its column-neighbors + sends it to its row-neighbors. + +This grid approach defines 2 unique paths for every validator to reach every +other validator in at most 2 hops, providing redundancy. + +Propagation follows these rules: + +- Each node has a receiving set and a sending set. These are different for each + group. That is, if a node receives a candidate from group A, it checks if it + is allowed to receive from that node for candidates from group A. +- For groups that we are in, receive from nobody and send to our X/Y peers. +- For groups that we are not part of: + - We receive from any validator in the group we share a slice with and send to + the corresponding X/Y slice in the other dimension. + - For any validators we don't share a slice with, we receive from the nodes + which share a slice with them. + +### Example + +For size 11, the matrix would be: + +``` +0 1 2 +3 4 5 +6 7 8 +9 10 +``` + +e.g. for index 10, the neighbors would be 1, 4, 7, 9 -- these are the nodes we +could directly communicate with (e.g. either send to or receive from). + +Now, which of these neighbors can 10 receive from? Recall that the +sending/receiving sets for 10 would be different for different groups. Here are +some hypothetical scenarios: + +- **Scenario 1:** 9 belongs to group A but not 10. Here, 10 can directly receive + candidates from group A from 9. 10 would propagate them to the nodes in {1, 4, + 7} that are not in A. +- **Scenario 2:** 6 is in group A instead of 9, and 7 is not in group A. 10 can + receive group A messages from 7 or 9. 10 will try to relay these messages, but + 7 and 9 together should have already propagated the message to all x/y + peers of 10. If so, then 10 will just receive acknowledgements in reply rather + than requests. +- **Scenario 3:** 10 itself is in group A. 10 would not receive candidates from + this group from any other nodes through the grid. It would itself send such + candidates to all its neighbors that are not in A. + +### Seconding Limit + +The seconding limit is a per-validator limit. Before asynchronous backing, we +had a rule that every validator was only allowed to second one candidate per +relay parent. With asynchronous backing, we have a 'maximum depth' which makes +it possible to second multiple candidates per relay parent. The seconding limit +is set to `max depth + 1` to set an upper bound on candidates entering the +system. + +## Candidates Module + +The candidates module provides a tracker for all known candidates in the view, +whether they are confirmed or not, and how peers have advertised the candidates. +What is a confirmed candidate? It is a candidate for which we have the full +receipt and the persisted validation data. This module gets confirmed candidates +from two sources: + +- It can be that a validator fetched a collation directly from the collator and + validated it. +- The first time a validator gets an announcement for an unknown candidate, it + will send a request for the candidate. Upon receiving a response and + validating it (see `UnhandledResponse::validate_response`), it will mark the + candidate as confirmed. + +## Requests Module + +The requests module provides a manager for pending requests for candidate data, +as well as pending responses. See "Request/Response Protocol" for a high-level +description of the flow. See module-docs for full details. + +## Glossary + +- **Acknowledgement:** A partial manifest sent to a validator that already has the + candidate to inform them that the sending node also knows the candidate. + Concludes a manifest exchange. +- **Announcement:** A full manifest indicating that a backed candidate is known by + the sending node. Initiates a manifest exchange. +- **Attestation:** See "Statement". +- **Backable vs. Backed:** + - Note that we sometimes use "backed" to refer to candidates that are + "backable", but not yet backed on chain. + - **Backed** should technically mean that the parablock candidate and its + backing statements have been added to a relay chain block. + - **Backable** is when the necessary backing statements have been acquired but + those statements and the parablock candidate haven't been backed in a relay + chain block yet. +- **Fragment tree:** A parachain fragment not referenced by the relay-chain. + It is a tree of prospective parachain blocks. +- **Manifest:** A message about a known backed candidate, along with a + description of the statements backing it. There are two kinds of manifest, + `Acknowledgement` and `Announcement`. See "Manifests" section. +- **Peer:** Another validator that a validator is connected to. +- **Request/response:** A protocol used to lazily request and receive heavy + candidate data when needed. +- **Reputation:** Tracks reputation of peers. Applies annoyance cost and good + behavior benefits. +- **Statement:** Signed statements that can be made about parachain candidates. + - **Seconded:** Proposal of a parachain candidate. Implicit validity vote. + - **Valid:** States that a parachain candidate is valid. +- **Target:** Target validator to send a statement to. +- **View:** Current knowledge of the chain state. + - **Explicit view** / **immediate view** + - The view a peer has of the relay chain heads and highest finalized block. + - **Implicit view** + - Derived from the immediate view. Composed of active leaves and minimum + relay-parents allowed for candidates of various parachains at those + leaves. diff --git a/roadmap/implementers-guide/src/node/collators/collation-generation.md b/roadmap/implementers-guide/src/node/collators/collation-generation.md index 2f0d4742496d..9053ea40f89e 100644 --- a/roadmap/implementers-guide/src/node/collators/collation-generation.md +++ b/roadmap/implementers-guide/src/node/collators/collation-generation.md @@ -9,7 +9,7 @@ Collation generation for Parachains currently works in the following way: 1. A new relay chain block is imported. 2. The collation generation subsystem checks if the core associated to the parachain is free and if yes, continues. -3. Collation generation calls our collator callback to generate a PoV. +3. Collation generation calls our collator callback, if present, to generate a PoV. If none exists, do nothing. 4. Authoring logic determines if the current node should build a PoV. 5. Build new PoV and give it back to collation generation. @@ -25,6 +25,10 @@ Collation generation for Parachains currently works in the following way: - No more than one initialization message should ever be sent to the collation generation subsystem. - Sent by a collator to initialize this subsystem. +- `CollationGenerationMessage::SubmitCollation` + - If the subsystem isn't initialized or the relay-parent is too old to be relevant, ignore the message. + - Otherwise, use the provided parameters to generate a [`CommittedCandidateReceipt`] + - Submit the collation to the collator-protocol with `CollatorProtocolMessage::DistributeCollation`. ### Outgoing @@ -101,7 +105,7 @@ pub struct CollationGenerationConfig { /// Collator's authentication key, so it can sign things. pub key: CollatorPair, /// Collation function. See [`CollatorFn`] for more details. - pub collator: CollatorFn, + pub collator: Option, /// The parachain that this collator collates for pub para_id: ParaId, } @@ -136,7 +140,7 @@ The configuration should be optional, to allow for the case where the node is no - **Collation generation config** - - Contains collator's authentication key, collator function, and + - Contains collator's authentication key, optional collator function, and parachain ID. [CP]: collator-protocol.md diff --git a/roadmap/implementers-guide/src/node/utility/provisioner.md b/roadmap/implementers-guide/src/node/utility/provisioner.md index 36747678106e..a3998cabba6c 100644 --- a/roadmap/implementers-guide/src/node/utility/provisioner.md +++ b/roadmap/implementers-guide/src/node/utility/provisioner.md @@ -1,8 +1,6 @@ # Provisioner -Relay chain block authorship authority is governed by BABE and is beyond the scope of the Overseer and the rest of the subsystems. That said, ultimately the block author needs to select a set of backable parachain candidates and other consensus data, and assemble a block from them. This subsystem is responsible for providing the necessary data to all potential block authors. - -A major feature of the provisioner: this subsystem is responsible for ensuring that parachain block candidates are sufficiently available before sending them to potential block authors. +Relay chain block authorship authority is governed by BABE and is beyond the scope of the Overseer and the rest of the subsystems. That said, ultimately the block author needs to select a set of backable parachain candidates and other consensus data, and assemble a block from them. This subsystem is responsible for providing the necessary data to all potential block authors. ## Provisionable Data @@ -10,7 +8,7 @@ There are several distinct types of provisionable data, but they share this prop ### Backed Candidates -The block author can choose 0 or 1 backed parachain candidates per parachain; the only constraint is that each backed candidate has the appropriate relay parent. However, the choice of a backed candidate must be the block author's; the provisioner must ensure that block authors are aware of all available [`BackedCandidate`s](../../types/backing.md#backed-candidate). +The block author can choose 0 or 1 backed parachain candidates per parachain; the only constraint is that each backable candidate has the appropriate relay parent. However, the choice of a backed candidate must be the block author's. The provisioner subsystem is how those block authors make this choice in practice. ### Signed Bitfields @@ -30,6 +28,23 @@ Dispute resolution is complex and is explained in substantially more detail [her ## Protocol +The subsystem should maintain a set of handles to Block Authorship Provisioning iterations that are currently live. + +### On Overseer Signal + +- `ActiveLeavesUpdate`: + - For each `activated` head: + - spawn a Block Authorship Provisioning iteration with the given relay parent, storing a bidirectional channel with that iteration. + - For each `deactivated` head: + - terminate the Block Authorship Provisioning iteration for the given relay parent, if any. +- `Conclude`: Forward `Conclude` to all iterations, waiting a small amount of time for them to join, and then hard-exiting. + +### On `ProvisionerMessage` + +Forward the message to the appropriate Block Authorship Provisioning iteration, or discard if no appropriate iteration is currently active. + +### Per Provisioning Iteration + Input: [`ProvisionerMessage`](../../types/overseer-protocol.md#provisioner-message). Backed candidates come from the [Candidate Backing subsystem](../backing/candidate-backing.md), signed bitfields come from the [Bitfield Distribution subsystem](../availability/bitfield-distribution.md), and disputes come from the [Disputes Subsystem](../disputes/dispute-coordinator.md). Misbehavior reports are currently sent from the [Candidate Backing subsystem](../backing/candidate-backing.md) and contain the following misbehaviors: 1. `Misbehavior::ValidityDoubleVote` @@ -45,37 +60,17 @@ Block authors request the inherent data they should use for constructing the inh ## Block Production -When a validator is selected by BABE to author a block, it becomes a block producer. The provisioner is the subsystem best suited to choosing which specific backed candidates and availability bitfields should be assembled into the block. To engage this functionality, a `ProvisionerMessage::RequestInherentData` is sent; the response is a [`ParaInherentData`](../../types/runtime.md#parainherentdata). There are never two distinct parachain candidates included for the same parachain and that new parachain candidates cannot be backed until the previous one either gets declared available or expired. Appropriate bitfields, as outlined in the section on [bitfield selection](#bitfield-selection), and any dispute statements should be attached as well. +When a validator is selected by BABE to author a block, it becomes a block producer. The provisioner is the subsystem best suited to choosing which specific backed candidates and availability bitfields should be assembled into the block. To engage this functionality, a `ProvisionerMessage::RequestInherentData` is sent; the response is a [`ParaInherentData`](../../types/runtime.md#parainherentdata). Each relay chain block backs at most one backable parachain block candidate per parachain. Additionally no further block candidate can be backed until the previous one either gets declared available or expired. If bitfields indicate that candidate A, predecessor of B, should be declared available, then B can be backed in the same relay block. Appropriate bitfields, as outlined in the section on [bitfield selection](#bitfield-selection), and any dispute statements should be attached as well. ### Bitfield Selection Our goal with respect to bitfields is simple: maximize availability. However, it's not quite as simple as always including all bitfields; there are constraints which still need to be met: -- We cannot choose more than one bitfield per validator. -- Each bitfield must correspond to an occupied core. +- not more than one bitfield per validator +- each 1 bit must correspond to an occupied core Beyond that, a semi-arbitrary selection policy is fine. In order to meet the goal of maximizing availability, a heuristic of picking the bitfield with the greatest number of 1 bits set in the event of conflict is useful. -### Candidate Selection - -The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate appropriate to each free core. - -To determine availability: - -- Get the list of core states from the runtime API -- For each core state: - - On `CoreState::Scheduled`, then we can make an `OccupiedCoreAssumption::Free`. - - On `CoreState::Occupied`, then we may be able to make an assumption: - - If the bitfields indicate availability and there is a scheduled `next_up_on_available`, then we can make an `OccupiedCoreAssumption::Included`. - - If the bitfields do not indicate availability, and there is a scheduled `next_up_on_time_out`, and `occupied_core.time_out_at == block_number_under_production`, then we can make an `OccupiedCoreAssumption::TimedOut`. - - If we did not make an `OccupiedCoreAssumption`, then continue on to the next core. - - Now compute the core's `validation_data_hash`: get the `PersistedValidationData` from the runtime, given the known `ParaId` and `OccupiedCoreAssumption`; - - Find an appropriate candidate for the core. - - There are two constraints: `backed_candidate.candidate.descriptor.para_id == scheduled_core.para_id && candidate.candidate.descriptor.validation_data_hash == computed_validation_data_hash`. - - In the event that more than one candidate meets the constraints, selection between the candidates is arbitrary. However, not more than one candidate can be selected per core. - -The end result of this process is a vector of `BackedCandidate`s, sorted in order of their core index. Furthermore, this process should select at maximum one candidate which upgrades the runtime validation code. - ### Dispute Statement Selection This is the point at which the block author provides further votes to active disputes or initiates new disputes in the runtime state. @@ -100,27 +95,92 @@ To compute bitfield availability, then: - Update the availability. Conceptually, assuming bit vectors: `availability[validator_index] |= bitfield[core_idx]` - Availability has a 2/3 threshold. Therefore: `3 * availability.count_ones() >= 2 * availability.len()` -### Notes +### Candidate Selection: Prospective Parachains Mode -See also: [Scheduler Module: Availability Cores](../../runtime/scheduler.md#availability-cores). +The state of the provisioner `PerRelayParent` tracks an important setting, `ProspectiveParachainsMode`. This setting determines which backable candidate selection method the provisioner uses. -## Functionality +`ProspectiveParachainsMode::Disabled` - The provisioner uses its own internal legacy candidate selection. +`ProspectiveParachainsMode::Enabled` - The provisioner requests that [prospective parachains](../backing/prospective-parachains.md) provide selected candidates. -The subsystem should maintain a set of handles to Block Authorship Provisioning Jobs that are currently live. +Candidates selected with `ProspectiveParachainsMode::Enabled` are able to benefit from the increased block production time asynchronous backing allows. For this reason all Polkadot protocol networks will eventually use prospective parachains candidate selection. Then legacy candidate selection will be removed as obsolete. -### On Overseer Signal +### Prospective Parachains Candidate Selection -- `ActiveLeavesUpdate`: - - For each `activated` head: - - spawn a Block Authorship Provisioning Job with the given relay parent, storing a bidirectional channel with that job. - - For each `deactivated` head: - - terminate the Block Authorship Provisioning Job for the given relay parent, if any. -- `Conclude`: Forward `Conclude` to all jobs, waiting a small amount of time for them to join, and then hard-exiting. +The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate appropriate to each free core. In prospective parachains candidate selection the provisioner handles the former process while [prospective parachains](../backing/prospective-parachains.md) handles the latter. -### On `ProvisionerMessage` +To select backable candidates: + +- Get the list of core states from the runtime API +- For each core state: + - On `CoreState::Free` + - The core is unscheduled and doesn’t need to be provisioned with a candidate + - On `CoreState::Scheduled` + - The core is unoccupied and scheduled to accept a backed block for a particular `para_id`. + - The provisioner requests a backable candidate from [prospective parachains](../backing/prospective-parachains.md) with the desired relay parent, the core’s scheduled `para_id`, and an empty required path. + - On `CoreState::Occupied` + - The availability core is occupied by a parachain block candidate pending availability. A further candidate need not be provided by the provisioner unless the core will be vacated this block. This is the case when either bitfields indicate the current core occupant has been made available or a timeout is reached. + - If `bitfields_indicate_availability` + - If `Some(scheduled_core) = occupied_core.next_up_on_available`, the core will be vacated and in need of a provisioned candidate. The provisioner requests a backable candidate from [prospective parachains](../backing/prospective-parachains.md) with the core’s scheduled `para_id` and a required path with one entry. This entry corresponds to the parablock candidate previously occupying this core, which was made available and can be built upon even though it hasn’t been seen as included in a relay chain block yet. See the Required Path section below for more detail. + - If `occupied_core.next_up_on_available` is `None`, then the core being vacated is unscheduled and doesn’t need to be provisioned with a candidate. + - Else-if `occupied_core.time_out_at == block_number` + - If `Some(scheduled_core) = occupied_core.next_up_on_timeout`, the core will be vacated and in need of a provisioned candidate. A candidate is requested in exactly the same way as with `CoreState::Scheduled`. + - Else the core being vacated is unscheduled and doesn’t need to be provisioned with a candidate +The end result of this process is a vector of `CandidateHash`s, sorted in order of their core index. -Forward the message to the appropriate Block Authorship Provisioning Job, or discard if no appropriate job is currently active. +#### Required Path -## Block Authorship Provisioning Job +Required path is a parameter for `ProspectiveParachainsMessage::GetBackableCandidate`, which the provisioner sends in candidate selection. + +An empty required path indicates that the requested candidate should be a direct child of the most recently included parablock for the given `para_id` as of the given relay parent. + +In contrast, a required path with one or more entries prompts [prospective parachains](../backing/prospective-parachains.md) to step forward through its fragment tree for the given `para_id` and relay parent until the desired parablock is reached. We then select a direct child of that parablock to pass to the provisioner. + +The parablocks making up a required path do not need to have been previously seen as included in relay chain blocks. Thus the ability to provision backable candidates based on a required path effectively decouples backing from inclusion. + +### Legacy Candidate Selection + +Legacy candidate selection takes place in the provisioner. Thus the provisioner needs to keep an up to date record of all [backed_candidates](../../types/backing.md#backed-candidate) `PerRelayParent` to pick from. + +The goal of candidate selection is to determine which cores are free, and then to the degree possible, pick a candidate appropriate to each free core. + +To determine availability: + +- Get the list of core states from the runtime API +- For each core state: + - On `CoreState::Scheduled`, then we can make an `OccupiedCoreAssumption::Free`. + - On `CoreState::Occupied`, then we may be able to make an assumption: + - If the bitfields indicate availability and there is a scheduled `next_up_on_available`, then we can make an `OccupiedCoreAssumption::Included`. + - If the bitfields do not indicate availability, and there is a scheduled `next_up_on_time_out`, and `occupied_core.time_out_at == block_number_under_production`, then we can make an `OccupiedCoreAssumption::TimedOut`. + - If we did not make an `OccupiedCoreAssumption`, then continue on to the next core. + - Now compute the core's `validation_data_hash`: get the `PersistedValidationData` from the runtime, given the known `ParaId` and `OccupiedCoreAssumption`; + - Find an appropriate candidate for the core. + - There are two constraints: `backed_candidate.candidate.descriptor.para_id == scheduled_core.para_id && candidate.candidate.descriptor.validation_data_hash == computed_validation_data_hash`. + - In the event that more than one candidate meets the constraints, selection between the candidates is arbitrary. However, not more than one candidate can be selected per core. -Maintain the set of channels to block authors. On receiving provisionable data, send a copy over each channel. +The end result of this process is a vector of `CandidateHash`s, sorted in order of their core index. + +### Retrieving Full `BackedCandidate`s for Selected Hashes + +Legacy candidate selection and prospective parachains candidate selection both leave us with a vector of `CandidateHash`s. These are passed to the backing subsystem with `CandidateBackingMessage::GetBackedCandidates`. + +The response is a vector of `BackedCandidate`s, sorted in order of their core index and ready to be provisioned to block authoring. The candidate selection and retrieval process should select at maximum one candidate which upgrades the runtime validation code. + +## Glossary + +- **Relay-parent:** + - A particular relay-chain block which serves as an anchor and reference point for processes and data which depend on relay-chain state. +- **Active Leaf:** + - A relay chain block which is the head of an active fork of the relay chain. + - Block authorship provisioning jobs are spawned per active leaf and concluded for any leaves which become inactive. +- **Candidate Selection:** + - The process by which the provisioner selects backable parachain block candidates to pass to block authoring. + - Two versions, prospective parachains candidate selection and legacy candidate selection. See their respective protocol sections for details. +- **Availability Core:** + - Often referred to simply as "cores", availability cores are an abstraction used for resource management. For the provisioner, availability cores are most relevant in that core states determine which `para_id`s to provision backable candidates for. + - For more on availability cores see [Scheduler Module: Availability Cores](../../runtime/scheduler.md#availability-cores) +- **Availability Bitfield:** + - Often referred to simply as a "bitfield", an availability bitfield represents the view of parablock candidate availability from a particular validator's perspective. Each bit in the bitfield corresponds to a single [availability core](../../runtime-api/availability-cores.md). + - For more on availability bitfields see [availability](../../types/availability.md) +- **Backable vs. Backed:** + - Note that we sometimes use "backed" to refer to candidates that are "backable", but not yet backed on chain. + - Backable means that a quorum of the candidate's assigned backing group have provided signed affirming statements. \ No newline at end of file diff --git a/roadmap/implementers-guide/src/pvf-prechecking.md b/roadmap/implementers-guide/src/pvf-prechecking.md index aefe0257b05e..91cc8f9b6a20 100644 --- a/roadmap/implementers-guide/src/pvf-prechecking.md +++ b/roadmap/implementers-guide/src/pvf-prechecking.md @@ -2,7 +2,7 @@ ## Motivation -Parachains' and parathreads' validation function is described by a wasm module that we refer to as a PVF. Since a PVF is a wasm module the typical way of executing it is to compile it to machine code. +Parachains' validation function is described by a wasm module that we refer to as a PVF. Since a PVF is a wasm module the typical way of executing it is to compile it to machine code. Typically an optimizing compiler consists of algorithms that are able to optimize the resulting machine code heavily. However, while those algorithms perform quite well for a typical wasm code produced by standard toolchains (e.g. rustc/LLVM), those algorithms can be abused to consume a lot of resources. Moreover, since those algorithms are rather complex there is a lot of room for a bug that can crash the compiler. @@ -31,8 +31,8 @@ We also have an additional step where we attempt to instantiate the WASM runtime Pre-checking is run when a new validation code is included in the chain. A new PVF can be added in two cases: -- A new parachain or parathread is registered. -- An existing parachain or parathread signalled an upgrade of its validation code. +- A new parachain is registered. +- An existing parachain signalled an upgrade of its validation code. Before any of those operations finish, the PVF pre-checking vote is initiated. The PVF pre-checking vote is identified by the PVF code hash that is being voted on. If there is already PVF pre-checking process running, then no new PVF pre-checking vote will be started. Instead, the operation just subscribes to the existing vote. @@ -58,7 +58,7 @@ On the node-side, there is a PVF pre-checking [subsystem][pvf-prechecker-subsyst ## Summary -Parachains' and parathreads' validation function is described by a wasm module that we refer to as a PVF. +Parachains' validation function is described by a wasm module that we refer to as a PVF. In order to make the PVF usable for candidate validation it has to be registered on-chain. diff --git a/roadmap/implementers-guide/src/runtime-api/availability-cores.md b/roadmap/implementers-guide/src/runtime-api/availability-cores.md index b95af2343b36..9402924f0013 100644 --- a/roadmap/implementers-guide/src/runtime-api/availability-cores.md +++ b/roadmap/implementers-guide/src/runtime-api/availability-cores.md @@ -52,8 +52,8 @@ enum CoreState { /// If a particular Collator is required to author this block, that is also present in this /// variant. Scheduled(ScheduledCore), - /// The core is currently free and there is nothing scheduled. This can be the case for parathread - /// cores when there are no parathread blocks queued. Parachain cores will never be left idle. + /// The core is currently free and there is nothing scheduled. This can be the case for on-demand + /// cores when there are no on-demand parachain blocks queued. Leased cores will never be left idle. Free, } ``` diff --git a/roadmap/implementers-guide/src/runtime/README.md b/roadmap/implementers-guide/src/runtime/README.md index f1f9d6c950e2..995b684b1f06 100644 --- a/roadmap/implementers-guide/src/runtime/README.md +++ b/roadmap/implementers-guide/src/runtime/README.md @@ -6,7 +6,7 @@ Due to the (lack of) guarantees provided by a particular blockchain-runtime fram We also expect, although it's beyond the scope of this guide, that these runtime modules will exist alongside various other modules. This has two facets to consider. First, even if the modules that we describe here don't invoke each others' entry points or routines during initialization, we still have to protect against those other modules doing that. Second, some of those modules are expected to provide governance capabilities for the chain. Configuration exposed by parachain-host modules is mostly for the benefit of these governance modules, to allow the operators or community of the chain to tweak parameters. -The runtime's primary roles to manage scheduling and updating of parachains and parathreads, as well as handling misbehavior reports and slashing. This guide doesn't focus on how parachains or parathreads are registered, only that they are. Also, this runtime description assumes that validator sets are selected somehow, but doesn't assume any other details than a periodic _session change_ event. Session changes give information about the incoming validator set and the validator set of the following session. +The runtime's primary role is to manage scheduling and updating of parachains, as well as handling misbehavior reports and slashing. This guide doesn't focus on how parachains are registered, only that they are. Also, this runtime description assumes that validator sets are selected somehow, but doesn't assume any other details than a periodic _session change_ event. Session changes give information about the incoming validator set and the validator set of the following session. The runtime also serves another role, which is to make data available to the Node-side logic via Runtime APIs. These Runtime APIs should be sufficient for the Node-side code to author blocks correctly. @@ -17,9 +17,9 @@ We will split the logic of the runtime up into these modules: * Initializer: manages initialization order of the other modules. * Shared: manages shared storage and configurations for other modules. * Configuration: manages configuration and configuration updates in a non-racy manner. -* Paras: manages chain-head and validation code for parachains and parathreads. -* Scheduler: manages parachain and parathread scheduling as well as validator assignments. -* Inclusion: handles the inclusion and availability of scheduled parachains and parathreads. +* Paras: manages chain-head and validation code for parachains. +* Scheduler: manages parachain scheduling as well as validator assignments. +* Inclusion: handles the inclusion and availability of scheduled parachains. * SessionInfo: manages various session keys of validators and other params stored per session. * Disputes: handles dispute resolution for included, available parablocks. * Slashing: handles slashing logic for concluded disputes. diff --git a/roadmap/implementers-guide/src/runtime/configuration.md b/roadmap/implementers-guide/src/runtime/configuration.md index 1d619ec26dff..be62ab2d4d5e 100644 --- a/roadmap/implementers-guide/src/runtime/configuration.md +++ b/roadmap/implementers-guide/src/runtime/configuration.md @@ -1,4 +1,4 @@ -# Configuration Module +# Configuration Pallet This module is responsible for managing all configuration of the parachain host in-flight. It provides a central point for configuration updates to prevent races between configuration changes and parachain-processing logic. Configuration can only change during the session change routine, and as this module handles the session change notification first it provides an invariant that the configuration does not change throughout the entire session. Both the [scheduler](scheduler.md) and [inclusion](inclusion.md) modules rely on this invariant to ensure proper behavior of the scheduler. diff --git a/roadmap/implementers-guide/src/runtime/disputes.md b/roadmap/implementers-guide/src/runtime/disputes.md index 1d3e3f62dc01..a2558b74f562 100644 --- a/roadmap/implementers-guide/src/runtime/disputes.md +++ b/roadmap/implementers-guide/src/runtime/disputes.md @@ -1,4 +1,4 @@ -# Disputes Module +# Disputes Pallet After a backed candidate is made available, it is included and proceeds into an acceptance period during which validators are randomly selected to do (secondary) approval checks of the parablock. Any reports disputing the validity of the candidate will cause escalation, where even more validators are requested to check the block, and so on, until either the parablock is determined to be invalid or valid. Those on the wrong side of the dispute are slashed and, if the parablock is deemed invalid, the relay chain is rolled back to a point before that block was included. diff --git a/roadmap/implementers-guide/src/runtime/dmp.md b/roadmap/implementers-guide/src/runtime/dmp.md index df261db94576..f56df31934ef 100644 --- a/roadmap/implementers-guide/src/runtime/dmp.md +++ b/roadmap/implementers-guide/src/runtime/dmp.md @@ -1,4 +1,4 @@ -# DMP Module +# DMP Pallet A module responsible for Downward Message Processing (DMP). See [Messaging Overview](../messaging.md) for more details. @@ -27,9 +27,9 @@ No initialization routine runs for this module. Candidate Acceptance Function: -* `check_processed_downward_messages(P: ParaId, processed_downward_messages: u32)`: +* `check_processed_downward_messages(P: ParaId, relay_parent_number: BlockNumber, processed_downward_messages: u32)`: + 1. Checks that `processed_downward_messages` is at least 1 if `DownwardMessageQueues` for `P` is not empty at the given `relay_parent_number`. 1. Checks that `DownwardMessageQueues` for `P` is at least `processed_downward_messages` long. - 1. Checks that `processed_downward_messages` is at least 1 if `DownwardMessageQueues` for `P` is not empty. Candidate Enactment: diff --git a/roadmap/implementers-guide/src/runtime/hrmp.md b/roadmap/implementers-guide/src/runtime/hrmp.md index 2b0b4751e30a..927c14cd5969 100644 --- a/roadmap/implementers-guide/src/runtime/hrmp.md +++ b/roadmap/implementers-guide/src/runtime/hrmp.md @@ -1,4 +1,4 @@ -# HRMP Module +# HRMP Pallet A module responsible for Horizontally Relay-routed Message Passing (HRMP). See [Messaging Overview](../messaging.md) for more details. diff --git a/roadmap/implementers-guide/src/runtime/inclusion.md b/roadmap/implementers-guide/src/runtime/inclusion.md index db37ae10a198..3fe7711ae2d0 100644 --- a/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/roadmap/implementers-guide/src/runtime/inclusion.md @@ -1,6 +1,6 @@ -# Inclusion Module +# Inclusion Pallet -The inclusion module is responsible for inclusion and availability of scheduled parachains and parathreads. It also manages the UMP dispatch queue of each parachain/thread. +The inclusion module is responsible for inclusion and availability of scheduled parachains. It also manages the UMP dispatch queue of each parachain. ## Storage @@ -61,9 +61,9 @@ No initialization routine runs for this module. However, the initialization of t All failed checks should lead to an unrecoverable error making the block invalid. * `process_bitfields(expected_bits, Bitfields, core_lookup: Fn(CoreIndex) -> Option)`: - 1. call `sanitize_bitfields` and use the sanitized `signed_bitfields` from now on. - 1. call `sanitize_backed_candidates` and use the sanitized `backed_candidates` from now on. - 1. apply each bit of bitfield to the corresponding pending candidate. looking up parathread cores using the `core_lookup`. Disregard bitfields that have a `1` bit for any free cores. + 1. Call `sanitize_bitfields` and use the sanitized `signed_bitfields` from now on. + 1. Call `sanitize_backed_candidates` and use the sanitized `backed_candidates` from now on. + 1. Apply each bit of bitfield to the corresponding pending candidate, looking up on-demand parachain cores using the `core_lookup`. Disregard bitfields that have a `1` bit for any free cores. 1. For each applied bit of each availability-bitfield, set the bit for the validator in the `CandidatePendingAvailability`'s `availability_votes` bitfield. Track all candidates that now have >2/3 of bits set in their `availability_votes`. These candidates are now available and can be enacted. 1. For all now-available candidates, invoke the `enact_candidate` routine with the candidate and relay-parent number. 1. Return a list of `(CoreIndex, CandidateHash)` from freed cores consisting of the cores where candidates have become available. @@ -84,26 +84,26 @@ All failed checks should lead to an unrecoverable error making the block invalid 1. check that the validator bit index is not out of bounds. 1. check the validators signature, iff `full_check=FullCheck::Yes`. -* `sanitize_backed_candidates bool>( - relay_parent: T::Hash, +* `sanitize_backed_candidates) -> bool>( mut backed_candidates: Vec>, candidate_has_concluded_invalid_dispute: F, scheduled: &[CoreAssignment], ) ` 1. filter out any backed candidates that have concluded invalid. - 1. filter out backed candidates that don't have a matching `relay_parent`. 1. filters backed candidates whom's paraid was scheduled by means of the provided `scheduled` parameter. + 1. sorts remaining candidates with respect to the core index assigned to them. -* `process_candidates(parent_storage_root, BackedCandidates, scheduled: Vec, group_validators: Fn(GroupIndex) -> Option>)`: +* `process_candidates(allowed_relay_parents, BackedCandidates, scheduled: Vec, group_validators: Fn(GroupIndex) -> Option>)`: + > For details on `AllowedRelayParentsTracker` see documentation for [Shared](./shared.md) module. 1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores appear in assignments in `scheduled`. 1. check that `scheduled` is sorted ascending by `CoreIndex`, without duplicates. + 1. check that the relay-parent from each candidate receipt is one of the allowed relay-parents. 1. check that there is no candidate pending availability for any scheduled `ParaId`. - 1. check that each candidate's `validation_data_hash` corresponds to a `PersistedValidationData` computed from the current state. - > NOTE: With contextual execution in place, validation data will be obtained as of the state of the context block. However, only the state of the current block can be used for such a query. + 1. check that each candidate's `validation_data_hash` corresponds to a `PersistedValidationData` computed from the state of the context block. 1. If the core assignment includes a specific collator, ensure the backed candidate is issued by that collator. 1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_cooldown` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID. 1. Check the collator's signature on the candidate data. - 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup. + 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup, while group indices are computed by `Scheduler` according to group rotation info. 1. call `check_upward_messages(config, para, commitments.upward_messages)` to check that the upward messages are valid. 1. call `Dmp::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained. 1. call `Hrmp::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark. diff --git a/roadmap/implementers-guide/src/runtime/initializer.md b/roadmap/implementers-guide/src/runtime/initializer.md index ffeacd5cb357..19dfcbde50a9 100644 --- a/roadmap/implementers-guide/src/runtime/initializer.md +++ b/roadmap/implementers-guide/src/runtime/initializer.md @@ -1,4 +1,4 @@ -# Initializer Module +# Initializer Pallet This module is responsible for initializing the other modules in a deterministic order. It also has one other purpose as described in the overview of the runtime: accepting and forwarding session change notifications. diff --git a/roadmap/implementers-guide/src/runtime/paras.md b/roadmap/implementers-guide/src/runtime/paras.md index 2631fcf944ea..b3015bd57290 100644 --- a/roadmap/implementers-guide/src/runtime/paras.md +++ b/roadmap/implementers-guide/src/runtime/paras.md @@ -1,7 +1,7 @@ -# Paras Module +# Paras Pallet -The Paras module is responsible for storing information on parachains and parathreads. Registered -parachains and parathreads cannot change except at session boundaries and after at least a full +The Paras module is responsible for storing information on parachains. Registered +parachains cannot change except at session boundaries and after at least a full session has passed. This is primarily to ensure that the number and meaning of bits required for the availability bitfields does not change except at session boundaries. @@ -54,15 +54,15 @@ struct ParaGenesisArgs { pub enum ParaLifecycle { /// A Para is new and is onboarding. Onboarding, - /// Para is a Parathread. + /// Para is a Parathread (on-demand parachain). Parathread, - /// Para is a Parachain. + /// Para is a lease holding Parachain. Parachain, - /// Para is a Parathread which is upgrading to a Parachain. + /// Para is a Parathread (on-demand Parachain) which is upgrading to a lease holding Parachain. UpgradingParathread, - /// Para is a Parachain which is downgrading to a Parathread. + /// Para is a lease holding Parachain which is downgrading to an on-demand parachain. DowngradingParachain, - /// Parathread is being offboarded. + /// Parathread (on-demand parachain) is being offboarded. OutgoingParathread, /// Parachain is being offboarded. OutgoingParachain, @@ -102,11 +102,11 @@ struct PvfCheckActiveVoteState { #### Para Lifecycle -Because the state changes of parachains and parathreads are delayed, we track the specific state of +Because the state changes of parachains are delayed, we track the specific state of the para using the `ParaLifecycle` enum. ``` -None Parathread Parachain +None Parathread (on-demand parachain) Parachain + + + | | | | (≈2 Session Delay) | | @@ -148,12 +148,14 @@ use frame_system::pallet_prelude::BlockNumberFor; PvfActiveVoteMap: map ValidationCodeHash => PvfCheckActiveVoteState; /// The list of all currently active PVF votes. Auxiliary to `PvfActiveVoteMap`. PvfActiveVoteList: Vec; -/// All parachains. Ordered ascending by ParaId. Parathreads are not included. +/// All parachains. Ordered ascending by ParaId. On-demand parachains are not included. Parachains: Vec, /// The current lifecycle state of all known Para Ids. ParaLifecycle: map ParaId => Option, /// The head-data of every registered para. Heads: map ParaId => Option; +/// The context (relay-chain block number) of the most recent parachain head. +MostRecentContext: map ParaId => BlockNumber; /// The validation code hash of every live para. CurrentCodeHash: map ParaId => Option; /// Actual past code hash, indicated by the para id as well as the block number at which it became outdated. @@ -221,19 +223,17 @@ CodeByHash: map ValidationCodeHash => Option 1. Execute all queued actions for paralifecycle changes: 1. Clean up outgoing paras. - 1. This means removing the entries under `Heads`, `CurrentCode`, `FutureCodeUpgrades`, and - `FutureCode`. An according entry should be added to `PastCode`, `PastCodeMeta`, and - `PastCodePruning` using the outgoing `ParaId` and removed `CurrentCode` value. This is - because any outdated validation code must remain available on-chain for a determined amount + 1. This means removing the entries under `Heads`, `CurrentCode`, `FutureCodeUpgrades`, + `FutureCode` and `MostRecentContext`. An according entry should be added to `PastCode`, `PastCodeMeta`, and `PastCodePruning` using the outgoing `ParaId` and removed `CurrentCode` value. This is because any outdated validation code must remain available on-chain for a determined amount of blocks, and validation code outdated by de-registering the para is still subject to that invariant. 1. Apply all incoming paras by initializing the `Heads` and `CurrentCode` using the genesis - parameters. + parameters as well as `MostRecentContext` to `0`. 1. Amend the `Parachains` list and `ParaLifecycle` to reflect changes in registered parachains. - 1. Amend the `ParaLifecycle` set to reflect changes in registered parathreads. - 1. Upgrade all parathreads that should become parachains, updating the `Parachains` list and + 1. Amend the `ParaLifecycle` set to reflect changes in registered on-demand parachains. + 1. Upgrade all on-demand parachains that should become lease holding parachains, updating the `Parachains` list and `ParaLifecycle`. - 1. Downgrade all parachains that should become parathreads, updating the `Parachains` list and + 1. Downgrade all lease holding parachains that should become on-demand parachains, updating the `Parachains` list and `ParaLifecycle`. 1. (Deferred) Return list of outgoing paras to the initializer for use by other modules. 1. Go over all active PVF pre-checking votes: @@ -255,22 +255,21 @@ CodeByHash: map ValidationCodeHash => Option * `schedule_para_initialize(ParaId, ParaGenesisArgs)`: Schedule a para to be initialized at the next session. Noop if para is already registered in the system with some `ParaLifecycle`. * `schedule_para_cleanup(ParaId)`: Schedule a para to be cleaned up after the next full session. -* `schedule_parathread_upgrade(ParaId)`: Schedule a parathread to be upgraded to a parachain. -* `schedule_parachain_downgrade(ParaId)`: Schedule a parachain to be downgraded to a parathread. +* `schedule_parathread_upgrade(ParaId)`: Schedule a parathread (on-demand parachain) to be upgraded to a parachain. +* `schedule_parachain_downgrade(ParaId)`: Schedule a parachain to be downgraded from lease holding to on-demand. * `schedule_code_upgrade(ParaId, new_code, relay_parent: BlockNumber, HostConfiguration)`: Schedule a future code upgrade of the given parachain. In case the PVF pre-checking is disabled, or the new code is already present in the storage, the upgrade will be applied after inclusion of a block of the same parachain executed in the context of a relay-chain block with number >= `relay_parent + config.validation_upgrade_delay`. If the upgrade is scheduled `UpgradeRestrictionSignal` is set and it will remain set until `relay_parent + config.validation_upgrade_cooldown`. In case the PVF pre-checking is enabled, or the new code is not already present in the storage, then the PVF pre-checking run will be scheduled for that validation code. If the pre-checking concludes with rejection, then the upgrade is canceled. Otherwise, after pre-checking is concluded the upgrade will be scheduled and be enacted as described above. * `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head, - where the new head was executed in the context of a relay-chain block with given number. This will - apply pending code upgrades based on the block number provided. If an upgrade took place it will clear the `UpgradeGoAheadSignal`. + where the new head was executed in the context of a relay-chain block with given number, the latter value is inserted into the `MostRecentContext` mapping. This will apply pending code upgrades based on the block number provided. If an upgrade took place it will clear the `UpgradeGoAheadSignal`. * `lifecycle(ParaId) -> Option`: Return the `ParaLifecycle` of a para. -* `is_parachain(ParaId) -> bool`: Returns true if the para ID references any live parachain, - including those which may be transitioning to a parathread in the future. -* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread, - including those which may be transitioning to a parachain in the future. -* `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live parathread - or live parachain. +* `is_parachain(ParaId) -> bool`: Returns true if the para ID references any live lease holding parachain, + including those which may be transitioning to an on-demand parachain in the future. +* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread (on-demand parachain), + including those which may be transitioning to a lease holding parachain in the future. +* `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live on-demand parachain + or live lease holding parachain. * `can_upgrade_validation_code(ParaId) -> bool`: Returns true if the given para can signal code upgrade right now. * `pvfs_require_prechecking() -> Vec`: Returns the list of PVF validation code hashes that require PVF pre-checking votes. diff --git a/roadmap/implementers-guide/src/runtime/scheduler.md b/roadmap/implementers-guide/src/runtime/scheduler.md index 16c3280d1808..312ecedcb50f 100644 --- a/roadmap/implementers-guide/src/runtime/scheduler.md +++ b/roadmap/implementers-guide/src/runtime/scheduler.md @@ -1,24 +1,24 @@ -# Scheduler Module +# Scheduler Pallet > TODO: this section is still heavily under construction. key questions about availability cores and validator assignment are still open and the flow of the the section may be contradictory or inconsistent The Scheduler module is responsible for two main tasks: -- Partitioning validators into groups and assigning groups to parachains and parathreads. -- Scheduling parachains and parathreads +- Partitioning validators into groups and assigning groups to parachains. +- Scheduling parachains for each block It aims to achieve these tasks with these goals in mind: - It should be possible to know at least a block ahead-of-time, ideally more, which validators are going to be assigned to which parachains. - Parachains that have a candidate pending availability in this fork of the chain should not be assigned. - Validator assignments should not be gameable. Malicious cartels should not be able to manipulate the scheduler to assign themselves as desired. -- High or close to optimal throughput of parachains and parathreads. Work among validator groups should be balanced. +- High or close to optimal throughput of parachains. Work among validator groups should be balanced. ## Availability Cores -The Scheduler manages resource allocation using the concept of "Availability Cores". There will be one availability core for each parachain, and a fixed number of cores used for multiplexing parathreads. Validators will be partitioned into groups, with the same number of groups as availability cores. Validator groups will be assigned to different availability cores over time. +The Scheduler manages resource allocation using the concept of "Availability Cores". There will be one availability core for each lease holding parachain, and a fixed number of cores used for multiplexing on-demand parachains. Validators will be partitioned into groups, with the same number of groups as availability cores. Validator groups will be assigned to different availability cores over time. -An availability core can exist in either one of two states at the beginning or end of a block: free or occupied. A free availability core can have a parachain or parathread assigned to it for the potential to have a backed candidate included. After backing, the core enters the occupied state as the backed candidate is pending availability. There is an important distinction: a core is not considered occupied until it is in charge of a block pending availability, although the implementation may treat scheduled cores the same as occupied ones for brevity. A core exits the occupied state when the candidate is no longer pending availability - either on timeout or on availability. A core starting in the occupied state can move to the free state and back to occupied all within a single block, as availability bitfields are processed before backed candidates. At the end of the block, there is a possible timeout on availability which can move the core back to the free state if occupied. +An availability core can exist in either one of two states at the beginning or end of a block: free or occupied. A free availability core can have a lease holding or on-demand parachain assigned to it for the potential to have a backed candidate included. After backing, the core enters the occupied state as the backed candidate is pending availability. There is an important distinction: a core is not considered occupied until it is in charge of a block pending availability, although the implementation may treat scheduled cores the same as occupied ones for brevity. A core exits the occupied state when the candidate is no longer pending availability - either on timeout or on availability. A core starting in the occupied state can move to the free state and back to occupied all within a single block, as availability bitfields are processed before backed candidates. At the end of the block, there is a possible timeout on availability which can move the core back to the free state if occupied. Cores are treated as an ordered list and are typically referred to by their index in that list. @@ -82,54 +82,57 @@ digraph { ## Validator Groups -Validator group assignments do not need to change very quickly. The security benefits of fast rotation are redundant with the challenge mechanism in the [Approval process](../protocol-approval.md). Because of this, we only divide validators into groups at the beginning of the session and do not shuffle membership during the session. However, we do take steps to ensure that no particular validator group has dominance over a single parachain or parathread-multiplexer for an entire session to provide better guarantees of live-ness. +Validator group assignments do not need to change very quickly. The security benefits of fast rotation are redundant with the challenge mechanism in the [Approval process](../protocol-approval.md). Because of this, we only divide validators into groups at the beginning of the session and do not shuffle membership during the session. However, we do take steps to ensure that no particular validator group has dominance over a single lease holding parachain or on-demand parachain-multiplexer for an entire session to provide better guarantees of live-ness. Validator groups rotate across availability cores in a round-robin fashion, with rotation occurring at fixed intervals. The i'th group will be assigned to the `(i+k)%n`'th core at any point in time, where `k` is the number of rotations that have occurred in the session, and `n` is the number of cores. This makes upcoming rotations within the same session predictable. -When a rotation occurs, validator groups are still responsible for distributing availability chunks for any previous cores that are still occupied and pending availability. In practice, rotation and availability-timeout frequencies should be set so this will only be the core they have just been rotated from. It is possible that a validator group is rotated onto a core which is currently occupied. In this case, the validator group will have nothing to do until the previously-assigned group finishes their availability work and frees the core or the availability process times out. Depending on if the core is for a parachain or parathread, a different timeout `t` from the [`HostConfiguration`](../types/runtime.md#host-configuration) will apply. Availability timeouts should only be triggered in the first `t-1` blocks after the beginning of a rotation. +When a rotation occurs, validator groups are still responsible for distributing availability chunks for any previous cores that are still occupied and pending availability. In practice, rotation and availability-timeout frequencies should be set so this will only be the core they have just been rotated from. It is possible that a validator group is rotated onto a core which is currently occupied. In this case, the validator group will have nothing to do until the previously-assigned group finishes their availability work and frees the core or the availability process times out. Depending on if the core is for a lease holding parachain or on-demand parachain, a different timeout `t` from the [`HostConfiguration`](../types/runtime.md#host-configuration) will apply. Availability timeouts should only be triggered in the first `t-1` blocks after the beginning of a rotation. ## Claims -Parathreads operate on a system of claims. Collators participate in auctions to stake a claim on authoring the next block of a parathread, although the auction mechanism is beyond the scope of the scheduler. The scheduler guarantees that they'll be given at least a certain number of attempts to author a candidate that is backed. Attempts that fail during the availability phase are not counted, since ensuring availability at that stage is the responsibility of the backing validators, not of the collator. When a claim is accepted, it is placed into a queue of claims, and each claim is assigned to a particular parathread-multiplexing core in advance. Given that the current assignments of validator groups to cores are known, and the upcoming assignments are predictable, it is possible for parathread collators to know who they should be talking to now and how they should begin establishing connections with as a fallback. +On-demand parachains operate on a system of claims. Collators purchase claims on authoring the next block of an on-demand parachain, although the purchase mechanism is beyond the scope of the scheduler. The scheduler guarantees that they'll be given at least a certain number of attempts to author a candidate that is backed. Attempts that fail during the availability phase are not counted, since ensuring availability at that stage is the responsibility of the backing validators, not of the collator. When a claim is accepted, it is placed into a queue of claims, and each claim is assigned to a particular on-demand parachain-multiplexing core in advance. Given that the current assignments of validator groups to cores are known, and the upcoming assignments are predictable, it is possible for on-demand parachain collators to know who they should be talking to now and how they should begin establishing connections with as a fallback. -With this information, the Node-side can be aware of which parathreads have a good chance of being includable within the relay-chain block and can focus any additional resources on backing candidates from those parathreads. Furthermore, Node-side code is aware of which validator group will be responsible for that thread. If the necessary conditions are reached for core reassignment, those candidates can be backed within the same block as the core being freed. +With this information, the Node-side can be aware of which on-demand parachains have a good chance of being includable within the relay-chain block and can focus any additional resources on backing candidates from those on-demand parachains. Furthermore, Node-side code is aware of which validator group will be responsible for that thread. If the necessary conditions are reached for core reassignment, those candidates can be backed within the same block as the core being freed. -Parathread claims, when scheduled onto a free core, may not result in a block pending availability. This may be due to collator error, networking timeout, or censorship by the validator group. In this case, the claims should be retried a certain number of times to give the collator a fair shot. +On-demand claims, when scheduled onto a free core, may not result in a block pending availability. This may be due to collator error, networking timeout, or censorship by the validator group. In this case, the claims should be retried a certain number of times to give the collator a fair shot. ## Storage Utility structs: ```rust -// A claim on authoring the next block for a given parathread. +// A claim on authoring the next block for a given parathread (on-demand parachain). struct ParathreadClaim(ParaId, CollatorId); -// An entry tracking a claim to ensure it does not pass the maximum number of retries. +// An entry tracking a parathread (on-demand parachain) claim to ensure it does not +// pass the maximum number of retries. struct ParathreadEntry { claim: ParathreadClaim, retries: u32, } -// A queued parathread entry, pre-assigned to a core. +// A queued parathread (on-demand parachain) entry, pre-assigned to a core. struct QueuedParathread { claim: ParathreadEntry, - /// offset within the set of para-threads ranged `0..config.parathread_cores`. + /// offset within the set of parathreads (on-demand parachains) ranged `0..config.parathread_cores`. core_offset: u32, } struct ParathreadQueue { queue: Vec, - /// offset within the set of para-threads ranged `0..config.parathread_cores`. + /// offset within the set of parathreads (on-demand parachains) ranged `0..config.parathread_cores`. next_core_offset: u32, } enum CoreOccupied { + // On-demand parachain Parathread(ParathreadEntry), // claim & retries Parachain, } enum AssignmentKind { Parachain, + // On-demand parachain Parathread(CollatorId, u32), } @@ -137,7 +140,6 @@ struct CoreAssignment { core: CoreIndex, para_id: ParaId, kind: AssignmentKind, - group_idx: GroupIndex, } // reasons a core might be freed. enum FreedReason { @@ -151,13 +153,13 @@ Storage layout: ```rust /// All the validator groups. One for each core. Indices are into the `ActiveValidators` storage. ValidatorGroups: Vec>; -/// A queue of upcoming claims and which core they should be mapped onto. +/// A queue of upcoming parathread (on-demand parachain) claims and which core they should be mapped onto. ParathreadQueue: ParathreadQueue; /// One entry for each availability core. Entries are `None` if the core is not currently occupied. -/// The i'th parachain belongs to the i'th core, with the remaining cores all being -/// parathread-multiplexers. +/// The i'th parachain lease belongs to the i'th core, with the remaining cores all being +/// on-demand parachain-multiplexers. AvailabilityCores: Vec>; -/// An index used to ensure that only one claim on a parathread exists in the queue or is +/// An index used to ensure that only one claim on a parathread (on-demand parachain) exists in the queue or is /// currently being handled by an occupied core. ParathreadClaimIndex: Vec; /// The block number where the session start occurred. Used to track how many group rotations have occurred. @@ -187,11 +189,11 @@ Actions: - Note that the total number of validators `V` in AV may not be evenly divided by `n_cores`. - The groups are selected by partitioning AV. The first `V % N` groups will have `(V / n_cores) + 1` members, while the remaining groups will have `(V / N)` members each. - Instead of using the indices within AV, which point to the broader set, indices _into_ AV should be used. This implies that groups should have simply ascending validator indices. -1. Prune the parathread queue to remove all retries beyond `configuration.parathread_retries`. - - Also prune all parathread claims corresponding to de-registered parathreads. - - all pruned claims should have their entry removed from the parathread index. - - assign all non-pruned claims to new cores if the number of parathread cores has changed between the `new_config` and `old_config` of the `SessionChangeNotification`. - - Assign claims in equal balance across all cores if rebalancing, and set the `next_core` of the `ParathreadQueue` by incrementing the relative index of the last assigned core and taking it modulo the number of parathread cores. +1. Prune the parathread (on-demand parachain) queue to remove all retries beyond `configuration.parathread_retries`. + - Also prune all on-demand claims corresponding to de-registered parachains. + - all pruned claims should have their entry removed from the parathread (on-demand parachain) index. + - assign all non-pruned claims to new cores if the number of on-demand parachain cores has changed between the `new_config` and `old_config` of the `SessionChangeNotification`. + - Assign claims in equal balance across all cores if rebalancing, and set the `next_core` of the `ParathreadQueue` (on-demand queue) by incrementing the relative index of the last assigned core and taking it modulo the number of on-demand cores. ## Initialization @@ -203,17 +205,17 @@ No finalization routine runs for this module. ## Routines -- `add_parathread_claim(ParathreadClaim)`: Add a parathread claim to the queue. - - Fails if any parathread claim on the same parathread is currently indexed. +- `add_parathread_claim(ParathreadClaim)`: Add a parathread (on-demand parachain) claim to the queue. + - Fails if any on-demand claim on the same parachain is currently indexed. - Fails if the queue length is >= `config.scheduling_lookahead * config.parathread_cores`. - - The core used for the parathread claim is the `next_core` field of the `ParathreadQueue` and adding `Paras::parachains().len()` to it. + - The core used for the on-demand claim is the `next_core` field of the `ParathreadQueue` (on-demand queue) and adding `Paras::parachains().len()` to it. - `next_core` is then updated by adding 1 and taking it modulo `config.parathread_cores`. - The claim is then added to the claim index. - `free_cores(Vec<(CoreIndex, FreedReason)>)`: indicate previosuly-occupied cores which are to be considered returned and why they are being returned. - - All freed parachain cores should be assigned to their respective parachain - - All freed parathread cores whose reason for freeing was `FreedReason::Concluded` should have the claim removed from the claim index. - - All freed parathread cores whose reason for freeing was `FreedReason::TimedOut` should have the claim added to the parathread queue again without retries incremented - - All freed parathread cores should take the next parathread entry from the queue. + - All freed lease holding parachain cores should be assigned to their respective parachain + - All freed on-demand parachain cores whose reason for freeing was `FreedReason::Concluded` should have the claim removed from the claim index. + - All freed on-demand cores whose reason for freeing was `FreedReason::TimedOut` should have the claim added to the parathread queue (on-demand queue) again without retries incremented + - All freed on-demand cores should take the next on-demand parachain entry from the queue. - `schedule(Vec<(CoreIndex, FreedReason)>, now: BlockNumber)`: schedule new core assignments, with a parameter indicating previously-occupied cores which are to be considered returned and why they are being returned. - Invoke `free_cores(freed_cores)` - The i'th validator group will be assigned to the `(i+k)%n`'th core at any point in time, where `k` is the number of rotations that have occurred in the session, and `n` is the total number of cores. This makes upcoming rotations within the same session predictable. Rotations are based off of `now`. @@ -225,9 +227,9 @@ No finalization routine runs for this module. - Since both the availability cores and the newly-occupied cores lists are sorted ascending, this method can be implemented efficiently. - `core_para(CoreIndex) -> ParaId`: return the currently-scheduled or occupied ParaId for the given core. - `group_validators(GroupIndex) -> Option>`: return all validators in a given group, if the group index is valid for this session. -- `availability_timeout_predicate() -> Option bool>`: returns an optional predicate that should be used for timing out occupied cores. if `None`, no timing-out should be done. The predicate accepts the index of the core, and the block number since which it has been occupied. The predicate should be implemented based on the time since the last validator group rotation, and the respective parachain and parathread timeouts, i.e. only within `max(config.chain_availability_period, config.thread_availability_period)` of the last rotation would this return `Some`. +- `availability_timeout_predicate() -> Option bool>`: returns an optional predicate that should be used for timing out occupied cores. if `None`, no timing-out should be done. The predicate accepts the index of the core, and the block number since which it has been occupied. The predicate should be implemented based on the time since the last validator group rotation, and the respective parachain timeouts, i.e. only within `max(config.chain_availability_period, config.thread_availability_period)` of the last rotation would this return `Some`. - `group_rotation_info(now: BlockNumber) -> GroupRotationInfo`: Returns a helper for determining group rotation. -- `next_up_on_available(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it became available. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the parachain and no specified collator. For parathreads, this is based on the next item in the `ParathreadQueue` assigned to that core, and is `None` if there isn't one. -- `next_up_on_time_out(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it timed out. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the parachain and no specified collator. For parathreads, this is based on the next item in the `ParathreadQueue` assigned to that core, or if there isn't one, the claim that is currently occupying the core. Otherwise `None`. +- `next_up_on_available(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it became available. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For lease holding parachains, this is always the ID of the parachain and no specified collator. For on-demand parachains, this is based on the next item in the `ParathreadQueue` (on-demand queue) assigned to that core, and is `None` if there isn't one. +- `next_up_on_time_out(CoreIndex) -> Option`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it timed out. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the parachain and no specified collator. For on-demand parachains, this is based on the next item in the `ParathreadQueue` (on-demand queue) assigned to that core, or if there isn't one, the claim that is currently occupying the core. Otherwise `None`. - `clear()`: - - Free all scheduled cores and return parathread claims to queue, with retries incremented. Skip parathreads which no longer exist under paras. + - Free all scheduled cores and return on-demand claims to queue, with retries incremented. Skip on-demand parachains which no longer exist under paras. diff --git a/roadmap/implementers-guide/src/runtime/shared.md b/roadmap/implementers-guide/src/runtime/shared.md index ae538928d5fe..0f173134e2a2 100644 --- a/roadmap/implementers-guide/src/runtime/shared.md +++ b/roadmap/implementers-guide/src/runtime/shared.md @@ -1,4 +1,4 @@ -# Shared Module +# Shared Pallet This module is responsible for managing shared storage and configuration for other modules. @@ -19,6 +19,27 @@ pub(crate) const SESSION_DELAY: SessionIndex = 2; ## Storage +Helper structs: + +```rust +struct AllowedRelayParentsTracker { + // The past relay parents, paired with state roots, that are viable to build upon. + // + // They are in ascending chronologic order, so the newest relay parents are at + // the back of the deque. + // + // (relay_parent, state_root) + // + // NOTE: the size limit of look-back is currently defined as a constant in Runtime. + buffer: VecDeque<(Hash, Hash)>, + + // The number of the most recent relay-parent, if any. + latest_number: BlockNumber, +} +``` + +Storage Layout: + ```rust /// The current session index within the Parachains Runtime system. CurrentSessionIndex: SessionIndex; @@ -28,6 +49,8 @@ ActiveValidatorIndices: Vec, /// The parachain attestation keys of the validators actively participating in parachain consensus. /// This should be the same length as `ActiveValidatorIndices`. ActiveValidatorKeys: Vec +/// Relay-parents allowed to build candidates upon. +AllowedRelayParents: AllowedRelayParentsTracker, ``` ## Initialization @@ -51,6 +74,8 @@ This information is used in the: passed. * Paras Module: For delaying updates to paras until at least one full session has passed. +Allowed relay parents buffer, which is maintained by [ParaInherent](./parainherent.md) module, is cleared on every session change. + ## Finalization The Shared Module currently has no finalization routines. diff --git a/roadmap/implementers-guide/src/types/candidate.md b/roadmap/implementers-guide/src/types/candidate.md index 729c72180ee5..a37f98054c5e 100644 --- a/roadmap/implementers-guide/src/types/candidate.md +++ b/roadmap/implementers-guide/src/types/candidate.md @@ -1,7 +1,7 @@ # Candidate Types Para candidates are some of the most common types, both within the runtime and on the Node-side. -Candidates are the fundamental datatype for advancing parachains and parathreads, encapsulating the collator's signature, the context of the parablock, the commitments to the output, and a commitment to the data which proves it valid. +Candidates are the fundamental datatype for advancing parachains, encapsulating the collator's signature, the context of the parablock, the commitments to the output, and a commitment to the data which proves it valid. In a way, this entire guide is about these candidates: how they are scheduled, constructed, backed, included, and challenged. @@ -142,7 +142,7 @@ struct PersistedValidationData { ## `HeadData` -Head data is a type-safe abstraction around bytes (`Vec`) for the purposes of representing heads of parachains or parathreads. +Head data is a type-safe abstraction around bytes (`Vec`) for the purposes of representing heads of parachains. ```rust struct HeadData(Vec); @@ -150,7 +150,7 @@ struct HeadData(Vec); ## Candidate Commitments -The execution and validation of parachain or parathread candidates produces a number of values which either must be committed to on the relay chain or committed to the state of the relay chain. +The execution and validation of parachain candidates produces a number of values which either must be committed to blocks on the relay chain or committed to the state of the relay chain. ```rust /// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation. diff --git a/roadmap/implementers-guide/src/types/overseer-protocol.md b/roadmap/implementers-guide/src/types/overseer-protocol.md index 73c1455e692b..3d9037699da6 100644 --- a/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -345,9 +345,10 @@ enum BitfieldSigningMessage { } ```rust enum CandidateBackingMessage { - /// Requests a set of backable candidates that could be backed in a child of the given - /// relay-parent, referenced by its hash. - GetBackedCandidates(Hash, Vec, ResponseChannel>), + /// Requests a set of backable candidates attested by the subsystem. + /// + /// Each pair is (candidate_hash, candidate_relay_parent). + GetBackedCandidates(Vec<(CandidateHash, Hash)>, oneshot::Sender>), /// Note that the Candidate Backing subsystem should second the given candidate in the context of the /// given relay-parent (ref. by hash). This candidate must be validated using the provided PoV. /// The PoV is expected to match the `pov_hash` in the descriptor. @@ -447,6 +448,57 @@ enum CollatorProtocolMessage { } ``` +## Collation Generation Message + +Messages received by the [Collation Generation subsystem](../node/collators/collation-generation.md) + +This is the core interface by which collators built on top of a Polkadot node submit collations to validators. As such, these messages are not sent by any subsystem but are instead sent from outside of the overseer. + +```rust +/// A function provided to the subsystem which it uses to pull new collations. +/// +/// This mode of querying collations is obsoleted by `CollationGenerationMessages::SubmitCollation` +/// +/// The response channel, if present, is meant to receive a `Seconded` statement as a +/// form of authentication, for collation mechanisms which rely on this for anti-spam. +type CollatorFn = Fn(Hash, PersistedValidationData) -> Future>)>; + +/// Configuration for the collation generator +struct CollationGenerationConfig { + /// Collator's authentication key, so it can sign things. + key: CollatorPair, + /// Collation function. See [`CollatorFn`] for more details. + collator: CollatorFn, + /// The parachain that this collator collates for + para_id: ParaId, +} + +/// Parameters for submitting a collation +struct SubmitCollationParams { + /// The relay-parent the collation is built against. + relay_parent: Hash, + /// The collation itself (PoV and commitments) + collation: Collation, + /// The parent block's head-data. + parent_head: HeadData, + /// The hash of the validation code the collation was created against. + validation_code_hash: ValidationCodeHash, + /// A response channel for receiving a `Seconded` message about the candidate + /// once produced by a validator. This is not guaranteed to provide anything. + result_sender: Option>, +} + +enum CollationGenerationMessage { + /// Initialize the collation generation subsystem + Initialize(CollationGenerationConfig), + /// Submit a collation to the subsystem. This will package it into a signed + /// [`CommittedCandidateReceipt`] and distribute along the network to validators. + /// + /// If sent before `Initialize`, this will be ignored. + SubmitCollation(SubmitCollationParams), +} +``` + ## Dispute Coordinator Message Messages received by the [Dispute Coordinator subsystem](../node/disputes/dispute-coordinator.md) @@ -797,7 +849,7 @@ enum StatementDistributionMessage { /// /// The statement distribution subsystem assumes that the statement should be correctly /// signed. - Share(Hash, SignedFullStatement), + Share(Hash, SignedFullStatementWithPVD), } ``` diff --git a/roadmap/implementers-guide/src/types/runtime.md b/roadmap/implementers-guide/src/types/runtime.md index 55c0a571b6c8..79da899bd35e 100644 --- a/roadmap/implementers-guide/src/types/runtime.md +++ b/roadmap/implementers-guide/src/types/runtime.md @@ -19,9 +19,9 @@ struct HostConfiguration { pub max_code_size: u32, /// The maximum head-data size, in bytes. pub max_head_data_size: u32, - /// The amount of availability cores to dedicate to parathreads. + /// The amount of availability cores to dedicate to parathreads (on-demand parachains). pub parathread_cores: u32, - /// The number of retries that a parathread author has to submit their block. + /// The number of retries that a parathread (on-demand parachain) author has to submit their block. pub parathread_retries: u32, /// How often parachain groups should be rotated across parachains. pub group_rotation_frequency: BlockNumber, @@ -29,10 +29,10 @@ struct HostConfiguration { /// after inclusion that validators have to make the block available and signal its availability to /// the chain. Must be at least 1. pub chain_availability_period: BlockNumber, - /// The availability period, in blocks, for parathreads. Same as the `chain_availability_period`, + /// The availability period, in blocks, for parathreads (on-demand parachains). Same as the `chain_availability_period`, /// but a differing timeout due to differing requirements. Must be at least 1. pub thread_availability_period: BlockNumber, - /// The amount of blocks ahead to schedule parathreads. + /// The amount of blocks ahead to schedule on-demand parachains. pub scheduling_lookahead: u32, /// The maximum number of validators to have per core. `None` means no maximum. pub max_validators_per_core: Option, @@ -88,7 +88,7 @@ struct HostConfiguration { pub hrmp_channel_max_total_size: u32, /// The maximum number of inbound HRMP channels a parachain is allowed to accept. pub hrmp_max_parachain_inbound_channels: u32, - /// The maximum number of inbound HRMP channels a parathread is allowed to accept. + /// The maximum number of inbound HRMP channels a parathread (on-demand parachain) is allowed to accept. pub hrmp_max_parathread_inbound_channels: u32, /// The maximum size of a message that could ever be put into an HRMP channel. /// @@ -96,7 +96,7 @@ struct HostConfiguration { pub hrmp_channel_max_message_size: u32, /// The maximum number of outbound HRMP channels a parachain is allowed to open. pub hrmp_max_parachain_outbound_channels: u32, - /// The maximum number of outbound HRMP channels a parathread is allowed to open. + /// The maximum number of outbound HRMP channels a parathread (on-demand parachain) is allowed to open. pub hrmp_max_parathread_outbound_channels: u32, /// The maximum number of outbound HRMP messages can be sent by a candidate. /// diff --git a/roadmap/parachains.md b/roadmap/parachains.md index 89e8fdaf3892..9d6c014a1c7c 100644 --- a/roadmap/parachains.md +++ b/roadmap/parachains.md @@ -41,13 +41,13 @@ Category: Runtime Auctioning and registration of parachains. This is already implemented and follows the [Parachain Allocation — Research at W3F](https://research.web3.foundation/en/latest/polkadot/Parachain-Allocation.html) document. -#### *Parathread Auctions* +#### *On-demand Blockspace Purchase* Category: Runtime -Parathreads are pay-as-you-go parachains. This consists of an on-chain mechanism for resolving an auction by collators and ensuring that they author a block. +The blockspace purchasing system for on-demand parachains consists of an on-chain mechanism for resolving block space purchases by collators and ensuring that they author a block. -The node-side portion of parathreads is for collators to actually cast bids and to be configured for which conditions to cast bids under. +The node-side portion of on-demand parachains is for collators to actually purchase blockspace and to configure the conditions in which purchases are made. #### *Validator Assignment* @@ -76,11 +76,11 @@ Category: Networking A black-box networking component for validators or fishermen on a parachain to obtain the PoV block referenced by hash in an attestation, for the purpose of validating. When fetching "current" PoV blocks (close to the head of the chain, or relating to the block currently being built), this should be fast. When fetching "old" PoV blocks, it should be possible and fall back on recovering from the availability erasure-coding. -#### *Parathread Auction Voting* +#### *On-demand Blockspace Purchase* Category: Node, Networking -How and when collators are configured to cast votes in parathread auctions. +How and when collators are configured to purchase on-demand blockspace. #### *Collation Loop* @@ -146,7 +146,7 @@ We will need a network where collators of paras can discover and fetch the relev Category: Runtime -Runtime logic for paras to open and close channels by putting down a deposit. The amount of channels a parathread can open will be limited. Channels that are pending close should remain open until the watermark of the recipient has reached the block height of the close request. +Runtime logic for paras to open and close channels by putting down a deposit. The amount of channels an on-demand parachain can open will be limited. Channels that are pending close should remain open until the watermark of the recipient has reached the block height of the close request. --- ### Fishing/Slashing @@ -197,7 +197,7 @@ The very first phase - this is parachains without slashing (full security) or cr ### Assignment: - Auctions - - Parathread Auctions + - On-demand Blockspace purchase - Validator Assignment ### Agreement: diff --git a/runtime/common/src/assigned_slots/mod.rs b/runtime/common/src/assigned_slots/mod.rs index 4763c3e3f0b4..3683cfc210fa 100644 --- a/runtime/common/src/assigned_slots/mod.rs +++ b/runtime/common/src/assigned_slots/mod.rs @@ -217,13 +217,15 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// The specified parachain or parathread is not registered. + /// The specified parachain is not registered. ParaDoesntExist, - /// Not a parathread. + /// Not a parathread (on-demand parachain). NotParathread, - /// Cannot upgrade parathread. + /// Cannot upgrade on-demand parachain to lease holding + /// parachain. CannotUpgrade, - /// Cannot downgrade parachain. + /// Cannot downgrade lease holding parachain to + /// on-demand. CannotDowngrade, /// Permanent or Temporary slot already assigned. SlotAlreadyAssigned, @@ -429,7 +431,7 @@ pub mod pallet { } } - // Force downgrade to parathread (if needed) before end of lease period + // Force downgrade to on-demand parachain (if needed) before end of lease period if is_parachain { if let Err(err) = runtime_parachains::schedule_parachain_downgrade::(id) { // Treat failed downgrade as warning .. slot lease has been cleared, @@ -593,7 +595,7 @@ impl Pallet { TemporarySlots::::contains_key(id) } - /// Returns whether a para is currently a parachain. + /// Returns whether a para is currently a lease holding parachain. fn is_parachain(id: ParaId) -> bool { T::Registrar::is_parachain(id) } @@ -989,7 +991,8 @@ mod tests { ParaId::from(1_u32), )); - // Para is a parachain for PermanentSlotLeasePeriodLength * LeasePeriod blocks + // Para is a lease holding parachain for PermanentSlotLeasePeriodLength * LeasePeriod + // blocks while block < 9 { println!("block #{}", block); @@ -1005,7 +1008,7 @@ mod tests { run_to_block(block); } - // Para lease ended, downgraded back to parathread + // Para lease ended, downgraded back to parathread (on-demand parachain) assert_eq!(TestRegistrar::::is_parathread(ParaId::from(1_u32)), true); assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 5), false); }); @@ -1172,7 +1175,8 @@ mod tests { assert_eq!(AssignedSlots::active_temporary_slot_count(), 1); // Block 1-5 - // Para is a parachain for TemporarySlotLeasePeriodLength * LeasePeriod blocks + // Para is a lease holding parachain for TemporarySlotLeasePeriodLength * LeasePeriod + // blocks while block < 6 { println!("block #{}", block); println!("lease period #{}", AssignedSlots::current_lease_period_index()); @@ -1204,7 +1208,7 @@ mod tests { println!("lease period #{}", AssignedSlots::current_lease_period_index()); println!("lease {:?}", Slots::lease(ParaId::from(1_u32))); - // Para lease ended, downgraded back to parathread + // Para lease ended, downgraded back to on-demand parachain assert_eq!(TestRegistrar::::is_parathread(ParaId::from(1_u32)), true); assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 3), false); assert_eq!(AssignedSlots::active_temporary_slot_count(), 0); diff --git a/runtime/common/src/integration_tests.rs b/runtime/common/src/integration_tests.rs index 34a49bc230b6..f78347dedd8c 100644 --- a/runtime/common/src/integration_tests.rs +++ b/runtime/common/src/integration_tests.rs @@ -377,7 +377,7 @@ fn basic_end_to_end_works() { // User 1 and 2 will own parachains Balances::make_free_balance_be(&account_id(1), 1_000_000_000); Balances::make_free_balance_be(&account_id(2), 1_000_000_000); - // First register 2 parathreads + // First register 2 on-demand parachains let genesis_head = Registrar::worst_head_data(); let validation_code = Registrar::worst_validation_code(); assert_ok!(Registrar::reserve(signed(1))); @@ -409,7 +409,7 @@ fn basic_end_to_end_works() { lease_period_index_start )); - // 2 sessions later they are parathreads + // 2 sessions later they are parathreads (on-demand parachains) run_to_session(START_SESSION_INDEX + 2); assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread)); assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread)); @@ -495,7 +495,7 @@ fn basic_end_to_end_works() { let lease_start_block = start_block + 400 + offset; run_to_block(lease_start_block); - // First slot, Para 1 should be transitioning to Parachain + // First slot, Para 1 should be transitioning to lease holding Parachain assert_eq!( Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::UpgradingParathread) @@ -813,7 +813,8 @@ fn competing_bids() { #[test] fn basic_swap_works() { - // This test will test a swap between a parachain and parathread works successfully. + // This test will test a swap between a lease holding parachain and on-demand parachain works + // successfully. new_test_ext().execute_with(|| { assert!(System::block_number().is_one()); /* So events are emitted */ @@ -823,7 +824,7 @@ fn basic_swap_works() { // User 1 and 2 will own paras Balances::make_free_balance_be(&account_id(1), 1_000_000_000); Balances::make_free_balance_be(&account_id(2), 1_000_000_000); - // First register 2 parathreads with different data + // First register 2 on-demand parachains with different data let validation_code = test_validation_code(10); assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( @@ -857,7 +858,7 @@ fn basic_swap_works() { lease_period_index_start )); - // 2 sessions later they are parathreads + // 2 sessions later they are on-demand parachains run_to_session(START_SESSION_INDEX + 2); assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parathread)); assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parathread)); @@ -930,7 +931,7 @@ fn basic_swap_works() { assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parathread)); assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parachain)); - // Deregister parathread + // Deregister on-demand parachain assert_ok!(Registrar::deregister(para_origin(2000).into(), ParaId::from(2000))); // Correct deposit is unreserved assert_eq!(Balances::reserved_balance(&account_id(1)), 100); // crowdloan deposit left over @@ -985,7 +986,7 @@ fn parachain_swap_works() { // User 1 and 2 will own paras Balances::make_free_balance_be(&account_id(1), 1_000_000_000); Balances::make_free_balance_be(&account_id(2), 1_000_000_000); - // First register 2 parathreads with different data + // First register 2 on-demand parachains with different data let validation_code = test_validation_code(10); assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( @@ -1026,7 +1027,7 @@ fn parachain_swap_works() { lease_period_index_start )); - // 2 sessions later they are parathreads + // 2 sessions later they are on-demand parachains run_to_block(starting_block + 20); assert_eq!(Paras::lifecycle(ParaId::from(winner)), Some(ParaLifecycle::Parathread)); @@ -1163,8 +1164,7 @@ fn crowdloan_ending_period_bid() { // User 1 and 2 will own paras Balances::make_free_balance_be(&account_id(1), 1_000_000_000); Balances::make_free_balance_be(&account_id(2), 1_000_000_000); - - // First register 2 parathreads + // First register 2 on-demand parachains let validation_code = test_validation_code(10); assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( @@ -1199,7 +1199,7 @@ fn crowdloan_ending_period_bid() { lease_period_index_start )); - // 2 sessions later they are parathreads + // 2 sessions later they are on-demand parachains run_to_session(START_SESSION_INDEX + 2); assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parathread)); assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parathread)); @@ -1532,7 +1532,7 @@ fn cant_bid_on_existing_lease_periods() { run_to_session(START_SESSION_INDEX); Balances::make_free_balance_be(&account_id(1), 1_000_000_000); - // First register a parathread + // First register an on-demand parachain let validation_code = test_validation_code(10); assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( @@ -1553,7 +1553,7 @@ fn cant_bid_on_existing_lease_periods() { lease_period_index_start )); - // 2 sessions later they are parathreads + // 2 sessions later they are on-demand parachains run_to_session(START_SESSION_INDEX + 2); // Open a crowdloan for Para 1 for slots 0-3 diff --git a/runtime/common/src/mock.rs b/runtime/common/src/mock.rs index a331ca3968e6..ed25072e246e 100644 --- a/runtime/common/src/mock.rs +++ b/runtime/common/src/mock.rs @@ -32,6 +32,7 @@ use std::{cell::RefCell, collections::HashMap}; thread_local! { static OPERATIONS: RefCell> = RefCell::new(Vec::new()); static PARACHAINS: RefCell> = RefCell::new(Vec::new()); + // On-demand parachains static PARATHREADS: RefCell> = RefCell::new(Vec::new()); static LOCKS: RefCell> = RefCell::new(HashMap::new()); static MANAGERS: RefCell>> = RefCell::new(HashMap::new()); @@ -50,6 +51,7 @@ impl Registrar for TestRegistrar { PARACHAINS.with(|x| x.borrow().clone()) } + // Is on-demand parachain fn is_parathread(id: ParaId) -> bool { PARATHREADS.with(|x| x.borrow().binary_search(&id).is_ok()) } @@ -76,7 +78,7 @@ impl Registrar for TestRegistrar { Err(_) => Ok(()), } })?; - // Should not be parathread, then make it. + // Should not be parathread (on-demand parachain), then make it. PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); match parathreads.binary_search(&id) { @@ -100,7 +102,7 @@ impl Registrar for TestRegistrar { Err(_) => Ok(()), } })?; - // Remove from parathread. + // Remove from parathreads (on-demand parachains). PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); match parathreads.binary_search(&id) { @@ -115,6 +117,8 @@ impl Registrar for TestRegistrar { Ok(()) } + /// If the ParaId corresponds to a parathread (on-demand parachain), + /// then upgrade it to a lease holding parachain fn make_parachain(id: ParaId) -> DispatchResult { PARATHREADS.with(|x| { let mut parathreads = x.borrow_mut(); @@ -145,6 +149,9 @@ impl Registrar for TestRegistrar { }); Ok(()) } + + /// If the ParaId corresponds to a lease holding parachain, then downgrade it to a + /// parathread (on-demand parachain) fn make_parathread(id: ParaId) -> DispatchResult { PARACHAINS.with(|x| { let mut parachains = x.borrow_mut(); diff --git a/runtime/common/src/paras_registrar.rs b/runtime/common/src/paras_registrar.rs index 57d9e21bcf53..3f5a8e1a5f93 100644 --- a/runtime/common/src/paras_registrar.rs +++ b/runtime/common/src/paras_registrar.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Pallet to handle parathread/parachain registration and related fund management. +//! Pallet to handle parachain registration and related fund management. //! In essence this is a simple wrapper around `paras`. use frame_support::{ @@ -113,13 +113,13 @@ pub mod pallet { type RuntimeOrigin: From<::RuntimeOrigin> + Into::RuntimeOrigin>>; - /// The system's currency for parathread payment. + /// The system's currency for on-demand parachain payment. type Currency: ReservableCurrency; - /// Runtime hook for when a parachain and parathread swap. + /// Runtime hook for when a lease holding parachain and on-demand parachain swap. type OnSwap: crate::traits::OnSwap; - /// The deposit to be paid to run a parathread. + /// The deposit to be paid to run a on-demand parachain. /// This should include the cost for storing the genesis head and validation code. #[pallet::constant] type ParaDeposit: Get>; @@ -155,13 +155,13 @@ pub mod pallet { HeadDataTooLarge, /// Para is not a Parachain. NotParachain, - /// Para is not a Parathread. + /// Para is not a Parathread (on-demand parachain). NotParathread, /// Cannot deregister para CannotDeregister, - /// Cannot schedule downgrade of parachain to parathread + /// Cannot schedule downgrade of lease holding parachain to on-demand parachain CannotDowngrade, - /// Cannot schedule upgrade of parathread to parachain + /// Cannot schedule upgrade of on-demand parachain to lease holding parachain CannotUpgrade, /// Para is locked from manipulation by the manager. Must use parachain or relay chain /// governance. @@ -265,8 +265,8 @@ pub mod pallet { /// Deregister a Para Id, freeing all data and returning any deposit. /// - /// The caller must be Root, the `para` owner, or the `para` itself. The para must be a - /// parathread. + /// The caller must be Root, the `para` owner, or the `para` itself. The para must be an + /// on-demand parachain. #[pallet::call_index(2)] #[pallet::weight(::WeightInfo::deregister())] pub fn deregister(origin: OriginFor, id: ParaId) -> DispatchResult { @@ -274,7 +274,8 @@ pub mod pallet { Self::do_deregister(id) } - /// Swap a parachain with another parachain or parathread. + /// Swap a lease holding parachain with another parachain, either on-demand or lease + /// holding. /// /// The origin must be Root, the `para` owner, or the `para` itself. /// @@ -283,8 +284,8 @@ pub mod pallet { /// /// The `ParaId`s remain mapped to the same head data and code so external code can rely on /// `ParaId` to be a long-term identifier of a notional "parachain". However, their - /// scheduling info (i.e. whether they're a parathread or parachain), auction information - /// and the auction deposit are switched. + /// scheduling info (i.e. whether they're an on-demand parachain or lease holding + /// parachain), auction information and the auction deposit are switched. #[pallet::call_index(3)] #[pallet::weight(::WeightInfo::swap())] pub fn swap(origin: OriginFor, id: ParaId, other: ParaId) -> DispatchResult { @@ -304,7 +305,8 @@ pub mod pallet { if PendingSwap::::get(other) == Some(id) { let other_lifecycle = paras::Pallet::::lifecycle(other).ok_or(Error::::NotRegistered)?; - // identify which is a parachain and which is a parathread + // identify which is a lease holding parachain and which is a parathread (on-demand + // parachain) if id_lifecycle == ParaLifecycle::Parachain && other_lifecycle == ParaLifecycle::Parathread { @@ -348,8 +350,8 @@ pub mod pallet { /// /// This function will reserve a new Para Id to be owned/managed by the origin account. /// The origin account is able to register head data and validation code using `register` to - /// create a parathread. Using the Slots pallet, a parathread can then be upgraded to get a - /// parachain slot. + /// create an on-demand parachain. Using the Slots pallet, an on-demand parachain can then + /// be upgraded to a lease holding parachain. /// /// ## Arguments /// - `origin`: Must be called by a `Signed` origin. Becomes the manager/owner of the new @@ -426,17 +428,18 @@ impl Registrar for Pallet { Some(Paras::::get(id)?.manager) } - // All parachains. Ordered ascending by ParaId. Parathreads are not included. + // All lease holding parachains. Ordered ascending by ParaId. On-demand parachains are not + // included. fn parachains() -> Vec { paras::Pallet::::parachains() } - // Return if a para is a parathread + // Return if a para is a parathread (on-demand parachain) fn is_parathread(id: ParaId) -> bool { paras::Pallet::::is_parathread(id) } - // Return if a para is a parachain + // Return if a para is a lease holding parachain fn is_parachain(id: ParaId) -> bool { paras::Pallet::::is_parachain(id) } @@ -469,9 +472,9 @@ impl Registrar for Pallet { Self::do_deregister(id) } - // Upgrade a registered parathread into a parachain. + // Upgrade a registered on-demand parachain into a lease holding parachain. fn make_parachain(id: ParaId) -> DispatchResult { - // Para backend should think this is a parathread... + // Para backend should think this is an on-demand parachain... ensure!( paras::Pallet::::lifecycle(id) == Some(ParaLifecycle::Parathread), Error::::NotParathread @@ -484,7 +487,7 @@ impl Registrar for Pallet { Ok(()) } - // Downgrade a registered para into a parathread. + // Downgrade a registered para into a parathread (on-demand parachain). fn make_parathread(id: ParaId) -> DispatchResult { // Para backend should think this is a parachain... ensure!( @@ -611,7 +614,7 @@ impl Pallet { /// Deregister a Para Id, freeing all data returning any deposit. fn do_deregister(id: ParaId) -> DispatchResult { match paras::Pallet::::lifecycle(id) { - // Para must be a parathread, or not exist at all. + // Para must be a parathread (on-demand parachain), or not exist at all. Some(ParaLifecycle::Parathread) | None => {}, _ => return Err(Error::::NotParathread.into()), } @@ -651,7 +654,8 @@ impl Pallet { Ok((ParaGenesisArgs { genesis_head, validation_code, para_kind }, deposit)) } - /// Swap a parachain and parathread, which involves scheduling an appropriate lifecycle update. + /// Swap a lease holding parachain and parathread (on-demand parachain), which involves + /// scheduling an appropriate lifecycle update. fn do_thread_and_chain_swap(to_downgrade: ParaId, to_upgrade: ParaId) { let res1 = runtime_parachains::schedule_parachain_downgrade::(to_downgrade); debug_assert!(res1.is_ok()); @@ -931,16 +935,16 @@ mod tests { conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); run_to_session(START_SESSION_INDEX + 2); - // It is now a parathread. + // It is now a parathread (on-demand parachain). assert!(Parachains::is_parathread(para_id)); assert!(!Parachains::is_parachain(para_id)); - // Some other external process will elevate parathread to parachain + // Some other external process will elevate on-demand to lease holding parachain assert_ok!(Registrar::make_parachain(para_id)); run_to_session(START_SESSION_INDEX + 4); - // It is now a parachain. + // It is now a lease holding parachain. assert!(!Parachains::is_parathread(para_id)); assert!(Parachains::is_parachain(para_id)); - // Turn it back into a parathread + // Turn it back into a parathread (on-demand parachain) assert_ok!(Registrar::make_parathread(para_id)); run_to_session(START_SESSION_INDEX + 6); assert!(Parachains::is_parathread(para_id)); @@ -1328,7 +1332,7 @@ mod tests { run_to_session(START_SESSION_INDEX + 2); - // They are now a parathread. + // They are now parathreads (on-demand parachains). assert!(Parachains::is_parathread(para_1)); assert!(Parachains::is_parathread(para_2)); @@ -1339,7 +1343,8 @@ mod tests { Error::::CannotSwap ); - // Some other external process will elevate one parathread to parachain + // Some other external process will elevate one on-demand + // parachain to a lease holding parachain assert_ok!(Registrar::make_parachain(para_1)); // Cannot swap @@ -1360,7 +1365,7 @@ mod tests { run_to_session(START_SESSION_INDEX + 4); - // It is now a parachain. + // It is now a lease holding parachain. assert!(Parachains::is_parachain(para_1)); assert!(Parachains::is_parathread(para_2)); @@ -1521,6 +1526,7 @@ mod benchmarking { } swap { + // On demand parachain let parathread = register_para::(LOWEST_PUBLIC_ID.into()); let parachain = register_para::((LOWEST_PUBLIC_ID + 1).into()); diff --git a/runtime/common/src/paras_sudo_wrapper.rs b/runtime/common/src/paras_sudo_wrapper.rs index d18eb8650aaf..0fc2644b2a0b 100644 --- a/runtime/common/src/paras_sudo_wrapper.rs +++ b/runtime/common/src/paras_sudo_wrapper.rs @@ -41,22 +41,22 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// The specified parachain or parathread is not registered. + /// The specified parachain is not registered. ParaDoesntExist, - /// The specified parachain or parathread is already registered. + /// The specified parachain is already registered. ParaAlreadyExists, /// A DMP message couldn't be sent because it exceeds the maximum size allowed for a /// downward message. ExceedsMaxMessageSize, /// Could not schedule para cleanup. CouldntCleanup, - /// Not a parathread. + /// Not a parathread (on-demand parachain). NotParathread, - /// Not a parachain. + /// Not a lease holding parachain. NotParachain, - /// Cannot upgrade parathread. + /// Cannot upgrade on-demand parachain to lease holding parachain. CannotUpgrade, - /// Cannot downgrade parachain. + /// Cannot downgrade lease holding parachain to on-demand. CannotDowngrade, } @@ -89,7 +89,7 @@ pub mod pallet { Ok(()) } - /// Upgrade a parathread to a parachain + /// Upgrade a parathread (on-demand parachain) to a lease holding parachain #[pallet::call_index(2)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_parathread_upgrade( @@ -97,7 +97,7 @@ pub mod pallet { id: ParaId, ) -> DispatchResult { ensure_root(origin)?; - // Para backend should think this is a parathread... + // Para backend should think this is a parathread (on-demand parachain)... ensure!( paras::Pallet::::lifecycle(id) == Some(ParaLifecycle::Parathread), Error::::NotParathread, @@ -107,7 +107,7 @@ pub mod pallet { Ok(()) } - /// Downgrade a parachain to a parathread + /// Downgrade a lease holding parachain to an on-demand parachain #[pallet::call_index(3)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_parachain_downgrade( diff --git a/runtime/common/src/slots/mod.rs b/runtime/common/src/slots/mod.rs index b4e136b1211c..a3efd5bfa30a 100644 --- a/runtime/common/src/slots/mod.rs +++ b/runtime/common/src/slots/mod.rs @@ -245,7 +245,7 @@ impl Pallet { if lease_periods.len() == 1 { // Just one entry, which corresponds to the now-ended lease period. // - // `para` is now just a parathread. + // `para` is now just an on-demand parachain. // // Unreserve whatever is left. if let Some((who, value)) = &lease_periods[0] { @@ -945,7 +945,7 @@ mod tests { Error::::ParaNotOnboarding ); - // Trying Para 2 again should fail cause they are not currently a parathread + // Trying Para 2 again should fail cause they are not currently an on-demand parachain assert!(Slots::trigger_onboard(RuntimeOrigin::signed(1), 2.into()).is_err()); assert_eq!(TestRegistrar::::operations(), vec![(2.into(), 1, true),]); @@ -1004,6 +1004,7 @@ mod benchmarking { assert_eq!(event, &system_event); } + // Registers a parathread (on-demand parachain) fn register_a_parathread(i: u32) -> (ParaId, T::AccountId) { let para = ParaId::from(i); let leaser: T::AccountId = account("leaser", i, 0); @@ -1052,7 +1053,7 @@ mod benchmarking { }.into()); } - // Worst case scenario, T parathreads onboard, and C parachains offboard. + // Worst case scenario, T on-demand parachains onboard, and C lease holding parachains offboard. manage_lease_period_start { // Assume reasonable maximum of 100 paras at any time let c in 0 .. 100; @@ -1064,14 +1065,14 @@ mod benchmarking { // If there is an offset, we need to be on that block to be able to do lease things. frame_system::Pallet::::set_block_number(T::LeaseOffset::get() + One::one()); - // Make T parathreads + // Make T parathreads (on-demand parachains) let paras_info = (0..t).map(|i| { register_a_parathread::(i) }).collect::>(); T::Registrar::execute_pending_transitions(); - // T parathread are upgrading to parachains + // T on-demand parachains are upgrading to lease holding parachains for (para, leaser) in paras_info { let amount = T::Currency::minimum_balance(); let origin = T::ForceOrigin::try_successful_origin() @@ -1081,7 +1082,7 @@ mod benchmarking { T::Registrar::execute_pending_transitions(); - // C parachains are downgrading to parathreads + // C lease holding parachains are downgrading to on-demand parachains for i in 200 .. 200 + c { let (para, leaser) = register_a_parathread::(i); T::Registrar::make_parachain(para)?; diff --git a/runtime/common/src/traits.rs b/runtime/common/src/traits.rs index 940c3dfa2fb3..8f75bf5c2fd8 100644 --- a/runtime/common/src/traits.rs +++ b/runtime/common/src/traits.rs @@ -31,15 +31,16 @@ pub trait Registrar { /// Report the manager (permissioned owner) of a parachain, if there is one. fn manager_of(id: ParaId) -> Option; - /// All parachains. Ordered ascending by `ParaId`. Parathreads are not included. + /// All lease holding parachains. Ordered ascending by `ParaId`. On-demand + /// parachains are not included. fn parachains() -> Vec; - /// Return if a `ParaId` is a Parachain. + /// Return if a `ParaId` is a lease holding Parachain. fn is_parachain(id: ParaId) -> bool { Self::parachains().binary_search(&id).is_ok() } - /// Return if a `ParaId` is a Parathread. + /// Return if a `ParaId` is a Parathread (on-demand parachain). fn is_parathread(id: ParaId) -> bool; /// Return if a `ParaId` is registered in the system. @@ -70,7 +71,7 @@ pub trait Registrar { /// Elevate a para to parachain status. fn make_parachain(id: ParaId) -> DispatchResult; - /// Lower a para back to normal from parachain status. + /// Downgrade lease holding parachain into parathread (on-demand parachain) fn make_parathread(id: ParaId) -> DispatchResult; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -80,7 +81,8 @@ pub trait Registrar { fn worst_validation_code() -> ValidationCode; /// Execute any pending state transitions for paras. - /// For example onboarding to parathread, or parathread to parachain. + /// For example onboarding to on-demand parachain, or upgrading on-demand to + /// lease holding parachain. #[cfg(any(feature = "runtime-benchmarks", test))] fn execute_pending_transitions(); } @@ -253,7 +255,7 @@ pub trait Auctioneer { fn has_won_an_auction(para: ParaId, bidder: &Self::AccountId) -> bool; } -/// Runtime hook for when we swap a parachain and parathread. +/// Runtime hook for when we swap a lease holding parachain and an on-demand parachain. #[impl_trait_for_tuples::impl_for_tuples(30)] pub trait OnSwap { /// Updates any needed state/references to enact a logical swap of two parachains. Identity, diff --git a/runtime/kusama/src/weights/runtime_parachains_paras.rs b/runtime/kusama/src/weights/runtime_parachains_paras.rs index 44db16c4d286..9e66592fbdfa 100644 --- a/runtime/kusama/src/weights/runtime_parachains_paras.rs +++ b/runtime/kusama/src/weights/runtime_parachains_paras.rs @@ -89,6 +89,12 @@ impl runtime_parachains::paras::WeightInfo for WeightIn .saturating_add(Weight::from_parts(992, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: Paras Heads (r:0 w:1) + fn force_set_most_recent_context() -> Weight { + Weight::from_parts(10_155_000, 0) + // Standard Error: 0 + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } /// Storage: Paras FutureCodeHash (r:1 w:1) /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) /// Storage: Paras CurrentCodeHash (r:1 w:0) diff --git a/runtime/parachains/src/configuration/tests.rs b/runtime/parachains/src/configuration/tests.rs index b2a81894a939..83de7db932b4 100644 --- a/runtime/parachains/src/configuration/tests.rs +++ b/runtime/parachains/src/configuration/tests.rs @@ -272,7 +272,7 @@ fn consistency_bypass_works() { fn setting_pending_config_members() { new_test_ext(Default::default()).execute_with(|| { let new_config = HostConfiguration { - async_backing_params: primitives::vstaging::AsyncBackingParams { + async_backing_params: AsyncBackingParams { allowed_ancestry_len: 0, max_candidate_depth: 0, }, diff --git a/runtime/parachains/src/dmp.rs b/runtime/parachains/src/dmp.rs index e4a7d5e17465..490c2fa1cd09 100644 --- a/runtime/parachains/src/dmp.rs +++ b/runtime/parachains/src/dmp.rs @@ -255,13 +255,27 @@ impl Pallet { /// Checks if the number of processed downward messages is valid. pub(crate) fn check_processed_downward_messages( para: ParaId, + relay_parent_number: BlockNumberFor, processed_downward_messages: u32, ) -> Result<(), ProcessedDownwardMessagesAcceptanceErr> { let dmq_length = Self::dmq_length(para); if dmq_length > 0 && processed_downward_messages == 0 { - return Err(ProcessedDownwardMessagesAcceptanceErr::AdvancementRule) + // The advancement rule is for at least one downwards message to be processed + // if the queue is non-empty at the relay-parent. Downwards messages are annotated + // with the block number, so we compare the earliest (first) against the relay parent. + let contents = Self::dmq_contents(para); + + // sanity: if dmq_length is >0 this should always be 'Some'. + if contents.get(0).map_or(false, |msg| msg.sent_at <= relay_parent_number) { + return Err(ProcessedDownwardMessagesAcceptanceErr::AdvancementRule) + } } + + // Note that we might be allowing a parachain to signal that it's processed + // messages that hadn't been placed in the queue at the relay_parent. + // only 'stupid' parachains would do it and we don't (and can't) force anyone + // to act on messages, so the lenient approach is fine here. if dmq_length < processed_downward_messages { return Err(ProcessedDownwardMessagesAcceptanceErr::Underflow { processed_downward_messages, diff --git a/runtime/parachains/src/dmp/tests.rs b/runtime/parachains/src/dmp/tests.rs index 234f5f7e43c7..a65984840da5 100644 --- a/runtime/parachains/src/dmp/tests.rs +++ b/runtime/parachains/src/dmp/tests.rs @@ -125,21 +125,43 @@ fn check_processed_downward_messages() { let a = ParaId::from(1312); new_test_ext(default_genesis_config()).execute_with(|| { + let block_number = System::block_number(); + // processed_downward_messages=0 is allowed when the DMQ is empty. - assert!(Dmp::check_processed_downward_messages(a, 0).is_ok()); + assert!(Dmp::check_processed_downward_messages(a, block_number, 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()); + assert!(Dmp::check_processed_downward_messages(a, block_number, 0).is_err()); // 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()); + assert!(Dmp::check_processed_downward_messages(a, block_number, 1).is_ok()); + assert!(Dmp::check_processed_downward_messages(a, block_number, 2).is_ok()); + assert!(Dmp::check_processed_downward_messages(a, block_number, 3).is_ok()); // there is no 4 messages in the queue - assert!(!Dmp::check_processed_downward_messages(a, 4).is_ok()); + assert!(Dmp::check_processed_downward_messages(a, block_number, 4).is_err()); + }); +} + +#[test] +fn check_processed_downward_messages_advancement_rule() { + let a = ParaId::from(1312); + + new_test_ext(default_genesis_config()).execute_with(|| { + let block_number = System::block_number(); + + run_to_block(block_number + 1, None); + let advanced_block_number = System::block_number(); + + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + queue_downward_message(a, vec![4, 5, 6]).unwrap(); + + // The queue was empty at genesis, 0 is OK despite it being non-empty in the further block. + assert!(Dmp::check_processed_downward_messages(a, block_number, 0).is_ok()); + // For the advanced block number, however, the rule is broken in case of 0. + assert!(Dmp::check_processed_downward_messages(a, advanced_block_number, 0).is_err()); }); } diff --git a/runtime/parachains/src/hrmp.rs b/runtime/parachains/src/hrmp.rs index 27f9fdab7684..a3ce6e2d8a35 100644 --- a/runtime/parachains/src/hrmp.rs +++ b/runtime/parachains/src/hrmp.rs @@ -334,7 +334,7 @@ pub mod pallet { StorageMap<_, Twox64Concat, HrmpChannelId, HrmpOpenChannelRequest>; // NOTE: could become bounded, but we don't have a global maximum for this. - // `HRMP_MAX_INBOUND_CHANNELS_BOUND` are per parachain/parathread, while this storage tracks the + // `HRMP_MAX_INBOUND_CHANNELS_BOUND` are per parachain, while this storage tracks the // global state. #[pallet::storage] pub type HrmpOpenChannelRequestsList = @@ -951,6 +951,14 @@ impl Pallet { Ok(()) } + /// Returns HRMP watermarks of previously sent messages to a given para. + pub(crate) fn valid_watermarks(recipient: ParaId) -> Vec> { + HrmpChannelDigests::::get(&recipient) + .into_iter() + .map(|(block_no, _)| block_no) + .collect() + } + pub(crate) fn check_outbound_hrmp( config: &HostConfiguration>, sender: ParaId, @@ -1015,6 +1023,27 @@ impl Pallet { Ok(()) } + /// Returns remaining outbound channels capacity in messages and in bytes per recipient para. + pub(crate) fn outbound_remaining_capacity(sender: ParaId) -> Vec<(ParaId, (u32, u32))> { + let recipients = HrmpEgressChannelsIndex::::get(&sender); + let mut remaining = Vec::with_capacity(recipients.len()); + + for recipient in recipients { + let Some(channel) = HrmpChannels::::get(&HrmpChannelId { sender, recipient }) else { + continue + }; + remaining.push(( + recipient, + ( + channel.max_capacity - channel.msg_count, + channel.max_total_size - channel.total_size, + ), + )); + } + + remaining + } + pub(crate) fn prune_hrmp(recipient: ParaId, new_hrmp_watermark: BlockNumberFor) -> Weight { let mut weight = Weight::zero(); @@ -1113,12 +1142,12 @@ impl Pallet { HrmpChannels::::insert(&channel_id, channel); HrmpChannelContents::::append(&channel_id, inbound); - // The digests are sorted in ascending by block number order. Assuming absence of - // contextual execution, there are only two possible scenarios here: + // The digests are sorted in ascending by block number order. There are only two + // possible scenarios here ("the current" is the block of candidate's inclusion): // // (a) It's the first time anybody sends a message to this recipient within this block. // In this case, the digest vector would be empty or the block number of the latest - // entry is smaller than the current. + // entry is smaller than the current. // // (b) Somebody has already sent a message within the current block. That means that // the block number of the latest entry is equal to the current. diff --git a/runtime/parachains/src/inclusion/mod.rs b/runtime/parachains/src/inclusion/mod.rs index 9786b87f1162..e60aac0080cf 100644 --- a/runtime/parachains/src/inclusion/mod.rs +++ b/runtime/parachains/src/inclusion/mod.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! The inclusion pallet is responsible for inclusion and availability of scheduled parachains -//! and parathreads. +//! The inclusion pallet is responsible for inclusion and availability of scheduled parachains. //! //! It is responsible for carrying candidates from being backable to being backed, and then from //! backed to included. @@ -23,8 +22,8 @@ use crate::{ configuration::{self, HostConfiguration}, disputes, dmp, hrmp, paras, - scheduler::common::CoreAssignment, - shared, + scheduler::{self, common::CoreAssignment}, + shared::{self, AllowedRelayParentsTracker}, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::{ @@ -140,6 +139,14 @@ impl CandidatePendingAvailability { &self.descriptor } + /// Get the candidate's relay parent's number. + pub(crate) fn relay_parent_number(&self) -> N + where + N: Clone, + { + self.relay_parent_number.clone() + } + #[cfg(any(feature = "runtime-benchmarks", test))] pub(crate) fn new( core: CoreIndex, @@ -194,8 +201,7 @@ impl Default for ProcessedCandidates { /// Number of backing votes we need for a valid backing. /// -/// WARNING: This check has to be kept in sync with the node side check in the backing -/// subsystem. +/// WARNING: This check has to be kept in sync with the node side checks. pub fn minimum_backing_votes(n_validators: usize) -> usize { // For considerations on this value see: // https://github.com/paritytech/polkadot/pull/1656#issuecomment-999734650 @@ -269,6 +275,7 @@ pub mod pallet { + dmp::Config + hrmp::Config + configuration::Config + + scheduler::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; type DisputesHandler: disputes::DisputesHandler>; @@ -330,8 +337,12 @@ pub mod pallet { PrematureCodeUpgrade, /// Output code is too large NewCodeTooLarge, - /// Candidate not in parent context. - CandidateNotInParentContext, + /// The candidate's relay-parent was not allowed. Either it was + /// not recent enough or it didn't advance based on the last parachain block. + DisallowedRelayParent, + /// Failed to compute group index for the core: either it's out of bounds + /// or the relay parent doesn't belong to the current session. + InvalidAssignment, /// Invalid group index in core assignment. InvalidGroupIndex, /// Insufficient (non-majority) backing. @@ -595,7 +606,7 @@ impl Pallet { /// Both should be sorted ascending by core index, and the candidates should be a subset of /// scheduled cores. If these conditions are not met, the execution of the function fails. pub(crate) fn process_candidates( - parent_storage_root: T::Hash, + allowed_relay_parents: &AllowedRelayParentsTracker>, candidates: Vec>, scheduled: Vec>>, group_validators: GV, @@ -603,6 +614,8 @@ impl Pallet { where GV: Fn(GroupIndex) -> Option>, { + let now = >::block_number(); + ensure!(candidates.len() <= scheduled.len(), Error::::UnscheduledCandidate); if scheduled.is_empty() { @@ -610,13 +623,6 @@ impl Pallet { } let validators = shared::Pallet::::active_validator_keys(); - let parent_hash = >::parent_hash(); - - // At the moment we assume (and in fact enforce, below) that the relay-parent is always one - // before of the block where we include a candidate (i.e. this code path). - let now = >::block_number(); - let relay_parent_number = now - One::one(); - let check_ctx = CandidateCheckContext::::new(now, relay_parent_number); // Collect candidate receipts with backers. let mut candidate_receipt_with_backing_validator_indices = @@ -639,9 +645,6 @@ impl Pallet { Ok(()) }; - let signing_context = - SigningContext { parent_hash, session_index: shared::Pallet::::session_index() }; - // We combine an outer loop over candidates with an inner loop over the scheduled, // where each iteration of the outer loop picks up at the position // in scheduled just after the past iteration left off. @@ -655,18 +658,27 @@ impl Pallet { 'next_backed_candidate: for (candidate_idx, backed_candidate) in candidates.iter().enumerate() { - match check_ctx.verify_backed_candidate( - parent_hash, - parent_storage_root, + let relay_parent_hash = backed_candidate.descriptor().relay_parent; + let para_id = backed_candidate.descriptor().para_id; + + let prev_context = >::para_most_recent_context(para_id); + + let check_ctx = CandidateCheckContext::::new(prev_context); + let signing_context = SigningContext { + parent_hash: relay_parent_hash, + session_index: shared::Pallet::::session_index(), + }; + + let relay_parent_number = match check_ctx.verify_backed_candidate( + &allowed_relay_parents, candidate_idx, backed_candidate, )? { Err(FailedToCreatePVD) => { log::debug!( target: LOG_TARGET, - "Failed to create PVD for candidate {} on relay parent {:?}", + "Failed to create PVD for candidate {}", candidate_idx, - parent_hash, ); // We don't want to error out here because it will // brick the relay-chain. So we return early without @@ -674,7 +686,7 @@ impl Pallet { return Ok(ProcessedCandidates::default()) }, Ok(rpn) => rpn, - } + }; let para_id = backed_candidate.descriptor().para_id; let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; @@ -692,7 +704,22 @@ impl Pallet { // account for already skipped, and then skip this one. skip = i + skip + 1; - let group_vals = group_validators(core_assignment.group_idx) + // The candidate based upon relay parent `N` should be backed by a group + // assigned to core at block `N + 1`. Thus, `relay_parent_number + 1` + // will always land in the current session. + let group_idx = >::group_assigned_to_core( + core_assignment.core, + relay_parent_number + One::one(), + ) + .ok_or_else(|| { + log::warn!( + target: LOG_TARGET, + "Failed to compute group index for candidate {}", + candidate_idx + ); + Error::::InvalidAssignment + })?; + let group_vals = group_validators(group_idx) .ok_or_else(|| Error::::InvalidGroupIndex)?; // check the signatures in the backing and that it is a majority. @@ -746,7 +773,8 @@ impl Pallet { core_indices_and_backers.push(( (core_assignment.core, core_assignment.paras_entry.para_id()), backers, - core_assignment.group_idx, + group_idx, + relay_parent_number, )); continue 'next_backed_candidate } @@ -767,8 +795,8 @@ impl Pallet { }; // one more sweep for actually writing to storage. - let core_indices = core_indices_and_backers.iter().map(|(c, _, _)| *c).collect(); - for (candidate, (core, backers, group)) in + let core_indices = core_indices_and_backers.iter().map(|(c, ..)| *c).collect(); + for (candidate, (core, backers, group, relay_parent_number)) in candidates.into_iter().zip(core_indices_and_backers) { let para_id = candidate.descriptor().para_id; @@ -798,7 +826,7 @@ impl Pallet { availability_votes, relay_parent_number, backers: backers.to_bitvec(), - backed_in_number: check_ctx.now, + backed_in_number: now, backing_group: group, }, ); @@ -814,17 +842,16 @@ impl Pallet { /// Run the acceptance criteria checks on the given candidate commitments. pub(crate) fn check_validation_outputs_for_runtime_api( para_id: ParaId, + relay_parent_number: BlockNumberFor, validation_outputs: primitives::CandidateCommitments, ) -> bool { - // This function is meant to be called from the runtime APIs against the relay-parent, hence - // `relay_parent_number` is equal to `now`. - let now = >::block_number(); - let relay_parent_number = now; - let check_ctx = CandidateCheckContext::::new(now, relay_parent_number); + let prev_context = >::para_most_recent_context(para_id); + let check_ctx = CandidateCheckContext::::new(prev_context); if check_ctx .check_validation_outputs( para_id, + relay_parent_number, &validation_outputs.head_data, &validation_outputs.new_validation_code, validation_outputs.processed_downward_messages, @@ -919,6 +946,11 @@ impl Pallet { )) } + pub(crate) fn relay_dispatch_queue_size(para_id: ParaId) -> (u32, u32) { + let fp = T::MessageQueue::footprint(AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id))); + (fp.count as u32, fp.size as u32) + } + /// Check that all the upward messages sent by a candidate pass the acceptance criteria. pub(crate) fn check_upward_messages( config: &HostConfiguration>, @@ -930,46 +962,42 @@ impl Pallet { ensure!(upward_messages.is_empty(), UmpAcceptanceCheckErr::IsOffboarding); } - let additional_msgs = upward_messages.len(); - if additional_msgs > config.max_upward_message_num_per_candidate as usize { + let additional_msgs = upward_messages.len() as u32; + if additional_msgs > config.max_upward_message_num_per_candidate { return Err(UmpAcceptanceCheckErr::MoreMessagesThanPermitted { - sent: additional_msgs as u32, + sent: additional_msgs, permitted: config.max_upward_message_num_per_candidate, }) } - let fp = T::MessageQueue::footprint(AggregateMessageOrigin::Ump(UmpQueueId::Para(para))); - let (para_queue_count, mut para_queue_size) = (fp.count, fp.size); + let (para_queue_count, mut para_queue_size) = Self::relay_dispatch_queue_size(para); - if para_queue_count.saturating_add(additional_msgs as u64) > - config.max_upward_queue_count as u64 - { + if para_queue_count.saturating_add(additional_msgs) > config.max_upward_queue_count { return Err(UmpAcceptanceCheckErr::CapacityExceeded { - count: para_queue_count.saturating_add(additional_msgs as u64), - limit: config.max_upward_queue_count as u64, + count: para_queue_count.saturating_add(additional_msgs).into(), + limit: config.max_upward_queue_count.into(), }) } for (idx, msg) in upward_messages.into_iter().enumerate() { - let msg_size = msg.len(); - if msg_size > config.max_upward_message_size as usize { + let msg_size = msg.len() as u32; + if msg_size > config.max_upward_message_size { return Err(UmpAcceptanceCheckErr::MessageSize { idx: idx as u32, - msg_size: msg_size as u32, + msg_size, max_size: config.max_upward_message_size, }) } // make sure that the queue is not overfilled. // we do it here only once since returning false invalidates the whole relay-chain // block. - if para_queue_size.saturating_add(msg_size as u64) > config.max_upward_queue_size as u64 - { + if para_queue_size.saturating_add(msg_size) > config.max_upward_queue_size { return Err(UmpAcceptanceCheckErr::TotalSizeExceeded { - total_size: para_queue_size.saturating_add(msg_size as u64), - limit: config.max_upward_queue_size as u64, + total_size: para_queue_size.saturating_add(msg_size).into(), + limit: config.max_upward_queue_size.into(), }) } - para_queue_size.saturating_accrue(msg_size as u64); + para_queue_size.saturating_accrue(msg_size); } Ok(()) @@ -1164,8 +1192,7 @@ impl OnQueueChanged for Pallet { /// A collection of data required for checking a candidate. pub(crate) struct CandidateCheckContext { config: configuration::HostConfiguration>, - now: BlockNumberFor, - relay_parent_number: BlockNumberFor, + prev_context: Option>, } /// An error indicating that creating Persisted Validation Data failed @@ -1173,33 +1200,41 @@ pub(crate) struct CandidateCheckContext { pub(crate) struct FailedToCreatePVD; impl CandidateCheckContext { - pub(crate) fn new(now: BlockNumberFor, relay_parent_number: BlockNumberFor) -> Self { - Self { config: >::config(), now, relay_parent_number } + pub(crate) fn new(prev_context: Option>) -> Self { + Self { config: >::config(), prev_context } } /// Execute verification of the candidate. /// /// Assures: - /// * correct expected relay parent reference + /// * relay-parent in-bounds /// * collator signature check passes /// * code hash of commitments matches current code hash /// * para head in the descriptor and commitments match + /// + /// Returns the relay-parent block number. pub(crate) fn verify_backed_candidate( &self, - parent_hash: ::Hash, - parent_storage_root: T::Hash, + allowed_relay_parents: &AllowedRelayParentsTracker>, candidate_idx: usize, backed_candidate: &BackedCandidate<::Hash>, - ) -> Result, Error> { + ) -> Result, FailedToCreatePVD>, Error> { let para_id = backed_candidate.descriptor().para_id; - let now = >::block_number(); - let relay_parent_number = now - One::one(); + let relay_parent = backed_candidate.descriptor().relay_parent; + + // Check that the relay-parent is one of the allowed relay-parents. + let (relay_parent_storage_root, relay_parent_number) = { + match allowed_relay_parents.acquire_info(relay_parent, self.prev_context) { + None => return Err(Error::::DisallowedRelayParent), + Some(info) => info, + } + }; { let persisted_validation_data = match crate::util::make_persisted_validation_data::( para_id, relay_parent_number, - parent_storage_root, + relay_parent_storage_root, ) .defensive_proof("the para is registered") { @@ -1215,11 +1250,6 @@ impl CandidateCheckContext { ); } - // we require that the candidate is in the context of the parent block. - ensure!( - backed_candidate.descriptor().relay_parent == parent_hash, - Error::::CandidateNotInParentContext, - ); ensure!( backed_candidate.descriptor().check_collator_signature().is_ok(), Error::::NotCollatorSigned, @@ -1241,6 +1271,7 @@ impl CandidateCheckContext { if let Err(err) = self.check_validation_outputs( para_id, + relay_parent_number, &backed_candidate.candidate.commitments.head_data, &backed_candidate.candidate.commitments.new_validation_code, backed_candidate.candidate.commitments.processed_downward_messages, @@ -1256,14 +1287,29 @@ impl CandidateCheckContext { ); Err(err.strip_into_dispatch_err::())?; }; - Ok(Ok(())) + Ok(Ok(relay_parent_number)) } /// Check the given outputs after candidate validation on whether it passes the acceptance /// criteria. + /// + /// The things that are checked can be roughly divided into limits and minimums. + /// + /// Limits are things like max message queue sizes and max head data size. + /// + /// Minimums are things like the minimum amount of messages that must be processed + /// by the parachain block. + /// + /// Limits are checked against the current state. The parachain block must be acceptable + /// by the current relay-chain state regardless of whether it was acceptable at some relay-chain + /// state in the past. + /// + /// Minimums are checked against the current state but modulated by + /// considering the information available at the relay-parent of the parachain block. fn check_validation_outputs( &self, para_id: ParaId, + relay_parent_number: BlockNumberFor, head_data: &HeadData, new_validation_code: &Option, processed_downward_messages: u32, @@ -1289,9 +1335,13 @@ impl CandidateCheckContext { } // check if the candidate passes the messaging acceptance criteria - >::check_processed_downward_messages(para_id, processed_downward_messages)?; + >::check_processed_downward_messages( + para_id, + relay_parent_number, + processed_downward_messages, + )?; Pallet::::check_upward_messages(&self.config, para_id, upward_messages)?; - >::check_hrmp_watermark(para_id, self.relay_parent_number, hrmp_watermark)?; + >::check_hrmp_watermark(para_id, relay_parent_number, hrmp_watermark)?; >::check_outbound_hrmp(&self.config, para_id, horizontal_messages)?; Ok(()) diff --git a/runtime/parachains/src/inclusion/tests.rs b/runtime/parachains/src/inclusion/tests.rs index 70179782a53a..7c22ac36a802 100644 --- a/runtime/parachains/src/inclusion/tests.rs +++ b/runtime/parachains/src/inclusion/tests.rs @@ -19,11 +19,12 @@ use crate::{ configuration::HostConfiguration, initializer::SessionChangeNotification, mock::{ - new_test_ext, Configuration, MockGenesisConfig, ParaInclusion, Paras, ParasShared, System, - Test, + new_test_ext, Configuration, MockGenesisConfig, ParaInclusion, Paras, ParasShared, + Scheduler, System, Test, }, paras::{ParaGenesisArgs, ParaKind}, paras_inherent::DisputedBitfield, + shared::AllowedRelayParentsTracker, }; use primitives::{SignedAvailabilityBitfields, UncheckedSignedAvailabilityBitfields}; @@ -47,6 +48,7 @@ fn default_config() -> HostConfiguration { config.on_demand_cores = 1; config.max_code_size = 0b100000; config.max_head_data_size = 0b100000; + config.group_rotation_frequency = u32::MAX; config } @@ -73,6 +75,16 @@ pub(crate) fn genesis_config(paras: Vec<(ParaId, ParaKind)>) -> MockGenesisConfi } } +fn default_allowed_relay_parent_tracker() -> AllowedRelayParentsTracker { + let mut allowed = AllowedRelayParentsTracker::default(); + + let relay_parent = System::parent_hash(); + let parent_number = System::block_number().saturating_sub(1); + + allowed.update(relay_parent, Hash::zero(), parent_number, 1); + allowed +} + #[derive(Debug, Clone, Copy, PartialEq)] pub(crate) enum BackingKind { #[allow(unused)] @@ -301,6 +313,13 @@ impl TestCandidateBuilder { pub(crate) fn make_vdata_hash(para_id: ParaId) -> Option { let relay_parent_number = >::block_number() - 1; + make_vdata_hash_with_block_number(para_id, relay_parent_number) +} + +fn make_vdata_hash_with_block_number( + para_id: ParaId, + relay_parent_number: BlockNumber, +) -> Option { let persisted_validation_data = crate::util::make_persisted_validation_data::( para_id, relay_parent_number, @@ -877,26 +896,33 @@ fn candidate_checks() { .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; + // When processing candidates, we compute the group index from scheduler. + let validator_groups = vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2), ValidatorIndex(3)], + vec![ValidatorIndex(4)], + ]; + Scheduler::set_validator_groups(validator_groups); + let entry_ttl = 10_000; let thread_collator: CollatorId = Sr25519Keyring::Two.public().into(); let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), - group_idx: GroupIndex::from(0), }; let chain_b_assignment = CoreAssignment { core: CoreIndex::from(1), paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl), - group_idx: GroupIndex::from(1), }; let thread_a_assignment = CoreAssignment { core: CoreIndex::from(2), paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl), - group_idx: GroupIndex::from(2), }; + let allowed_relay_parents = default_allowed_relay_parent_tracker(); + // unscheduled candidate. { let mut candidate = TestCandidateBuilder { @@ -921,7 +947,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_b_assignment.clone()], &group_validators, @@ -976,7 +1002,7 @@ fn candidate_checks() { // out-of-order manifests as unscheduled. assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed_b, backed_a], vec![chain_a_assignment.clone(), chain_b_assignment.clone()], &group_validators, @@ -1009,7 +1035,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1018,12 +1044,12 @@ fn candidate_checks() { ); } - // candidate not in parent context. + // one of candidates is not based on allowed relay parent. { let wrong_parent_hash = Hash::repeat_byte(222); assert!(System::parent_hash() != wrong_parent_hash); - let mut candidate = TestCandidateBuilder { + let mut candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: wrong_parent_hash, pov_hash: Hash::repeat_byte(1), @@ -1031,10 +1057,23 @@ fn candidate_checks() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( - candidate, + let mut candidate_b = TestCandidateBuilder { + para_id: chain_b, + relay_parent: System::parent_hash(), + pov_hash: Hash::repeat_byte(2), + persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), + hrmp_watermark: RELAY_PARENT_NUM, + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); + + collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b); + + let backed_a = back_candidate( + candidate_a, &validators, group_validators(GroupIndex::from(0)).unwrap().as_ref(), &keystore, @@ -1042,14 +1081,23 @@ fn candidate_checks() { BackingKind::Threshold, ); + let backed_b = back_candidate( + candidate_b, + &validators, + group_validators(GroupIndex::from(1)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + ); + assert_noop!( ParaInclusion::process_candidates( - Default::default(), - vec![backed], - vec![chain_a_assignment.clone()], + &allowed_relay_parents, + vec![backed_b, backed_a], + vec![chain_a_assignment.clone(), chain_b_assignment.clone()], &group_validators, ), - Error::::CandidateNotInParentContext + Error::::DisallowedRelayParent ); } @@ -1082,7 +1130,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![thread_a_assignment.clone()], &group_validators, @@ -1132,7 +1180,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1172,7 +1220,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1216,7 +1264,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1250,7 +1298,7 @@ fn candidate_checks() { assert_eq!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1285,7 +1333,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1320,7 +1368,7 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed], vec![chain_a_assignment.clone()], &group_validators, @@ -1382,24 +1430,30 @@ fn backing_works() { .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) }; - let entry_ttl = 10_000; + // When processing candidates, we compute the group index from scheduler. + let validator_groups = vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2), ValidatorIndex(3)], + vec![ValidatorIndex(4)], + ]; + Scheduler::set_validator_groups(validator_groups); + let allowed_relay_parents = default_allowed_relay_parent_tracker(); + + let entry_ttl = 10_000; let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), - group_idx: GroupIndex::from(0), }; let chain_b_assignment = CoreAssignment { core: CoreIndex::from(1), paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl), - group_idx: GroupIndex::from(1), }; let thread_a_assignment = CoreAssignment { core: CoreIndex::from(2), paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl), - group_idx: GroupIndex::from(2), }; let mut candidate_a = TestCandidateBuilder { @@ -1486,7 +1540,7 @@ fn backing_works() { core_indices: occupied_cores, candidate_receipt_with_backing_validator_indices, } = ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, backed_candidates.clone(), vec![ chain_a_assignment.clone(), @@ -1661,12 +1715,21 @@ fn can_include_candidate_with_ok_code_upgrade() { .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) }; + // When processing candidates, we compute the group index from scheduler. + let validator_groups = vec![vec![ + ValidatorIndex(0), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(4), + ]]; + Scheduler::set_validator_groups(validator_groups); + + let allowed_relay_parents = default_allowed_relay_parent_tracker(); let entry_ttl = 10_000; - let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl), - group_idx: GroupIndex::from(0), }; let mut candidate_a = TestCandidateBuilder { @@ -1692,7 +1755,7 @@ fn can_include_candidate_with_ok_code_upgrade() { let ProcessedCandidates { core_indices: occupied_cores, .. } = ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed_a], vec![chain_a_assignment.clone()], &group_validators, @@ -1725,6 +1788,212 @@ fn can_include_candidate_with_ok_code_upgrade() { }); } +#[test] +fn check_allowed_relay_parents() { + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + let thread_a = ParaId::from(3); + + let paras = vec![ + (chain_a, ParaKind::Parachain), + (chain_b, ParaKind::Parachain), + (thread_a, ParaKind::Parathread), + ]; + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Ferdie, + ]; + let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*keystore, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); + } + let validator_public = validator_pubkeys(&validators); + let mut config = genesis_config(paras); + config.configuration.config.group_rotation_frequency = 1; + + new_test_ext(config).execute_with(|| { + shared::Pallet::::set_active_validators_ascending(validator_public.clone()); + shared::Pallet::::set_session_index(5); + + run_to_block(5, |_| None); + + let group_validators = |group_index: GroupIndex| { + match group_index { + group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), + group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), + group_index if group_index == GroupIndex::from(2) => Some(vec![4]), + _ => panic!("Group index out of bounds for 2 parachains and 1 parathread core"), + } + .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) + }; + + // When processing candidates, we compute the group index from scheduler. + let validator_groups = vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2), ValidatorIndex(3)], + vec![ValidatorIndex(4)], + ]; + Scheduler::set_validator_groups(validator_groups); + + // Base each candidate on one of allowed relay parents. + // + // Note that the group rotation frequency is set to 1 above, + // which means groups shift at each relay parent. + // + // For example, candidate `a` is based on block 1, + // thus it will be included in block 2, its group index is + // core = 0 shifted 2 times: one for group rotation and one for + // fetching the group assigned to the next block. + // + // Candidates `b` and `c` are constructed accordingly. + + let relay_parent_a = (1, Hash::repeat_byte(0x1)); + let relay_parent_b = (2, Hash::repeat_byte(0x2)); + let relay_parent_c = (3, Hash::repeat_byte(0x3)); + + let mut allowed_relay_parents = AllowedRelayParentsTracker::default(); + let max_ancestry_len = 3; + allowed_relay_parents.update( + relay_parent_a.1, + Hash::zero(), + relay_parent_a.0, + max_ancestry_len, + ); + allowed_relay_parents.update( + relay_parent_b.1, + Hash::zero(), + relay_parent_b.0, + max_ancestry_len, + ); + allowed_relay_parents.update( + relay_parent_c.1, + Hash::zero(), + relay_parent_c.0, + max_ancestry_len, + ); + + let chain_a_assignment = CoreAssignment { + core: CoreIndex::from(0), + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_a }, + availability_timeouts: 0, + ttl: 5, + }, + }; + + let chain_b_assignment = CoreAssignment { + core: CoreIndex::from(1), + paras_entry: ParasEntry { + assignment: Assignment { para_id: chain_b }, + availability_timeouts: 0, + ttl: 5, + }, + }; + + let thread_a_assignment = CoreAssignment { + core: CoreIndex::from(2), + paras_entry: ParasEntry::new(Assignment::new(thread_a), 5), + }; + + let mut candidate_a = TestCandidateBuilder { + para_id: chain_a, + relay_parent: relay_parent_a.1, + pov_hash: Hash::repeat_byte(1), + persisted_validation_data_hash: make_vdata_hash_with_block_number( + chain_a, + relay_parent_a.0, + ) + .unwrap(), + hrmp_watermark: relay_parent_a.0, + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); + let signing_context_a = SigningContext { parent_hash: relay_parent_a.1, session_index: 5 }; + + let mut candidate_b = TestCandidateBuilder { + para_id: chain_b, + relay_parent: relay_parent_b.1, + pov_hash: Hash::repeat_byte(2), + persisted_validation_data_hash: make_vdata_hash_with_block_number( + chain_b, + relay_parent_b.0, + ) + .unwrap(), + hrmp_watermark: relay_parent_b.0, + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b); + let signing_context_b = SigningContext { parent_hash: relay_parent_b.1, session_index: 5 }; + + let mut candidate_c = TestCandidateBuilder { + para_id: thread_a, + relay_parent: relay_parent_c.1, + pov_hash: Hash::repeat_byte(3), + persisted_validation_data_hash: make_vdata_hash_with_block_number( + thread_a, + relay_parent_c.0, + ) + .unwrap(), + hrmp_watermark: relay_parent_c.0, + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_c); + let signing_context_c = SigningContext { parent_hash: relay_parent_c.1, session_index: 5 }; + + let backed_a = back_candidate( + candidate_a.clone(), + &validators, + group_validators(GroupIndex::from(2)).unwrap().as_ref(), + &keystore, + &signing_context_a, + BackingKind::Threshold, + ); + + let backed_b = back_candidate( + candidate_b.clone(), + &validators, + group_validators(GroupIndex::from(1)).unwrap().as_ref(), + &keystore, + &signing_context_b, + BackingKind::Threshold, + ); + + let backed_c = back_candidate( + candidate_c.clone(), + &validators, + group_validators(GroupIndex::from(0)).unwrap().as_ref(), + &keystore, + &signing_context_c, + BackingKind::Threshold, + ); + + let backed_candidates = vec![backed_a, backed_b, backed_c]; + + ParaInclusion::process_candidates( + &allowed_relay_parents, + backed_candidates.clone(), + vec![ + chain_a_assignment.clone(), + chain_b_assignment.clone(), + thread_a_assignment.clone(), + ], + &group_validators, + ) + .expect("candidates scheduled, in order, and backed"); + }); +} + #[test] fn session_change_wipes() { let chain_a = ParaId::from(1_u32); @@ -1911,11 +2180,23 @@ fn para_upgrade_delay_scheduled_from_inclusion() { .map(|vs| vs.into_iter().map(ValidatorIndex).collect::>()) }; + // When processing candidates, we compute the group index from scheduler. + let validator_groups = vec![vec![ + ValidatorIndex(0), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(4), + ]]; + Scheduler::set_validator_groups(validator_groups); + let core_lookup = |core| match core { core if core == CoreIndex::from(0) => Some(chain_a), _ => None, }; + let allowed_relay_parents = default_allowed_relay_parent_tracker(); + let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), paras_entry: ParasEntry { @@ -1923,7 +2204,6 @@ fn para_upgrade_delay_scheduled_from_inclusion() { availability_timeouts: 0, ttl: 5, }, - group_idx: GroupIndex::from(0), }; let mut candidate_a = TestCandidateBuilder { @@ -1949,7 +2229,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let ProcessedCandidates { core_indices: occupied_cores, .. } = ParaInclusion::process_candidates( - Default::default(), + &allowed_relay_parents, vec![backed_a], vec![chain_a_assignment.clone()], &group_validators, diff --git a/runtime/parachains/src/lib.rs b/runtime/parachains/src/lib.rs index a9348ebd2f41..056eef354260 100644 --- a/runtime/parachains/src/lib.rs +++ b/runtime/parachains/src/lib.rs @@ -79,12 +79,12 @@ pub fn schedule_para_cleanup(id: primitives::Id) -> Result<(), >::schedule_para_cleanup(id).map_err(|_| ()) } -/// Schedule a parathread to be upgraded to a parachain. +/// Schedule a parathread (on-demand parachain) to be upgraded to a lease holding parachain. pub fn schedule_parathread_upgrade(id: ParaId) -> Result<(), ()> { paras::Pallet::::schedule_parathread_upgrade(id).map_err(|_| ()) } -/// Schedule a parachain to be downgraded to a parathread. +/// Schedule a lease holding parachain to be downgraded to an on-demand parachain. pub fn schedule_parachain_downgrade(id: ParaId) -> Result<(), ()> { paras::Pallet::::schedule_parachain_downgrade(id).map_err(|_| ()) } diff --git a/runtime/parachains/src/paras/benchmarking.rs b/runtime/parachains/src/paras/benchmarking.rs index 9dfb8a4b37d7..5c060547601f 100644 --- a/runtime/parachains/src/paras/benchmarking.rs +++ b/runtime/parachains/src/paras/benchmarking.rs @@ -99,6 +99,10 @@ benchmarks! { verify { assert_last_event::(Event::CurrentHeadUpdated(para_id).into()); } + force_set_most_recent_context { + let para_id = ParaId::from(1000); + let context = BlockNumberFor::::from(1000u32); + }: _(RawOrigin::Root, para_id, context) force_schedule_code_upgrade { let c in 1 .. MAX_CODE_SIZE; let new_code = ValidationCode(vec![0; c as usize]); diff --git a/runtime/parachains/src/paras/mod.rs b/runtime/parachains/src/paras/mod.rs index 6089fe2ba3b8..95b89a1ca2c3 100644 --- a/runtime/parachains/src/paras/mod.rs +++ b/runtime/parachains/src/paras/mod.rs @@ -18,15 +18,15 @@ //! //! # Tracking State of Paras //! -//! The most important responsibility of this module is to track which parachains and parathreads +//! The most important responsibility of this module is to track which parachains //! are active and what their current state is. The current state of a para consists of the current //! head data and the current validation code (AKA Parachain Validation Function (PVF)). //! //! A para is not considered live until it is registered and activated in this pallet. //! -//! The set of parachains and parathreads cannot change except at session boundaries. This is -//! primarily to ensure that the number and meaning of bits required for the availability bitfields -//! does not change except at session boundaries. +//! The set of parachains cannot change except at session boundaries. This is primarily to ensure +//! that the number and meaning of bits required for the availability bitfields does not change +//! except at session boundaries. //! //! # Validation Code Upgrades //! @@ -61,7 +61,8 @@ //! //! # Para Lifecycle Management //! -//! A para can be in one of the two stable states: it is either a parachain or a parathread. +//! A para can be in one of the two stable states: it is either a lease holding parachain or an +//! on-demand parachain. //! //! However, in order to get into one of those two states, it must first be onboarded. Onboarding //! can be only enacted at session boundaries. Onboarding must take at least one full session. @@ -179,17 +180,17 @@ pub struct ParaPastCodeMeta { /// state will be used to determine the state transition to apply to the para. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum ParaLifecycle { - /// Para is new and is onboarding as a Parathread or Parachain. + /// Para is new and is onboarding as an on-demand or lease holding Parachain. Onboarding, - /// Para is a Parathread. + /// Para is a Parathread (on-demand parachain). Parathread, - /// Para is a Parachain. + /// Para is a lease holding Parachain. Parachain, - /// Para is a Parathread which is upgrading to a Parachain. + /// Para is a Parathread (on-demand parachain) which is upgrading to a lease holding Parachain. UpgradingParathread, - /// Para is a Parachain which is downgrading to a Parathread. + /// Para is a lease holding Parachain which is downgrading to an on-demand parachain. DowngradingParachain, - /// Parathread is queued to be offboarded. + /// Parathread (on-demand parachain) is queued to be offboarded. OffboardingParathread, /// Parachain is queued to be offboarded. OffboardingParachain, @@ -197,14 +198,14 @@ pub enum ParaLifecycle { impl ParaLifecycle { /// Returns true if parachain is currently onboarding. To learn if the - /// parachain is onboarding as a parachain or parathread, look at the + /// parachain is onboarding as a lease holding or on-demand parachain, look at the /// `UpcomingGenesis` storage item. pub fn is_onboarding(&self) -> bool { matches!(self, ParaLifecycle::Onboarding) } /// Returns true if para is in a stable state, i.e. it is currently - /// a parachain or parathread, and not in any transition state. + /// a lease holding or on-demand parachain, and not in any transition state. pub fn is_stable(&self) -> bool { matches!(self, ParaLifecycle::Parathread | ParaLifecycle::Parachain) } @@ -221,7 +222,7 @@ impl ParaLifecycle { ) } - /// Returns true if para is currently treated as a parathread. + /// Returns true if para is currently treated as a parathread (on-demand parachain). /// This also includes transitioning states, so you may want to combine /// this check with `is_stable` if you specifically want `Paralifecycle::Parathread`. pub fn is_parathread(&self) -> bool { @@ -294,12 +295,12 @@ pub struct ParaGenesisArgs { pub genesis_head: HeadData, /// The initial validation code to use. pub validation_code: ValidationCode, - /// Parachain or Parathread. + /// Lease holding or on-demand parachain. #[serde(rename = "parachain")] pub para_kind: ParaKind, } -/// Distinguishes between Parachain and Parathread +/// Distinguishes between lease holding Parachain and Parathread (on-demand parachain) #[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub enum ParaKind { Parathread, @@ -483,6 +484,7 @@ impl PvfCheckActiveVoteState { pub trait WeightInfo { fn force_set_current_code(c: u32) -> Weight; fn force_set_current_head(s: u32) -> Weight; + fn force_set_most_recent_context() -> Weight; fn force_schedule_code_upgrade(c: u32) -> Weight; fn force_note_new_head(s: u32) -> Weight; fn force_queue_action() -> Weight; @@ -504,6 +506,9 @@ impl WeightInfo for TestWeightInfo { fn force_set_current_head(_s: u32) -> Weight { Weight::MAX } + fn force_set_most_recent_context() -> Weight { + Weight::MAX + } fn force_schedule_code_upgrade(_c: u32) -> Weight { Weight::MAX } @@ -606,9 +611,9 @@ pub mod pallet { CannotOnboard, /// Para cannot be offboarded at this time. CannotOffboard, - /// Para cannot be upgraded to a parachain. + /// Para cannot be upgraded to a lease holding parachain. CannotUpgrade, - /// Para cannot be downgraded to a parathread. + /// Para cannot be downgraded to an on-demand parachain. CannotDowngrade, /// The statement for PVF pre-checking is stale. PvfCheckStatementStale, @@ -644,7 +649,8 @@ pub mod pallet { pub(super) type PvfActiveVoteList = StorageValue<_, Vec, ValueQuery>; - /// All parachains. Ordered ascending by `ParaId`. Parathreads are not included. + /// All lease holding parachains. Ordered ascending by `ParaId`. On demand parachains are not + /// included. /// /// Consider using the [`ParachainsCache`] type of modifying. #[pallet::storage] @@ -660,6 +666,12 @@ pub mod pallet { #[pallet::getter(fn para_head)] pub(super) type Heads = StorageMap<_, Twox64Concat, ParaId, HeadData>; + /// The context (relay-chain block number) of the most recent parachain head. + #[pallet::storage] + #[pallet::getter(fn para_most_recent_context)] + pub(super) type MostRecentContext = + StorageMap<_, Twox64Concat, ParaId, BlockNumberFor>; + /// The validation code hash of every live para. /// /// Corresponding code can be retrieved with [`CodeByHash`]. @@ -706,6 +718,7 @@ pub mod pallet { /// /// Corresponding code can be retrieved with [`CodeByHash`]. #[pallet::storage] + #[pallet::getter(fn future_code_hash)] pub(super) type FutureCodeHash = StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>; @@ -733,6 +746,7 @@ pub mod pallet { /// NOTE that this field is used by parachains via merkle storage proofs, therefore changing /// the format will require migration of parachains. #[pallet::storage] + #[pallet::getter(fn upgrade_restriction_signal)] pub(super) type UpgradeRestrictionSignal = StorageMap<_, Twox64Concat, ParaId, UpgradeRestriction>; @@ -1059,6 +1073,19 @@ pub mod pallet { Ok(Some(::WeightInfo::include_pvf_check_statement()).into()) } } + + /// Set the storage for the current parachain head data immediately. + #[pallet::call_index(8)] + #[pallet::weight(::WeightInfo::force_set_most_recent_context())] + pub fn force_set_most_recent_context( + origin: OriginFor, + para: ParaId, + context: BlockNumberFor, + ) -> DispatchResult { + ensure_root(origin)?; + MostRecentContext::::insert(¶, context); + Ok(()) + } } #[pallet::validate_unsigned] @@ -1200,7 +1227,7 @@ impl Pallet { // The actions to take are based on the lifecycle of of the paras. // // The final state of any para after the actions queue should be as a - // parachain, parathread, or not registered. (stable states) + // lease holding parachain, on-demand parachain, or not registered. (stable states) // // Returns the list of outgoing paras from the actions queue. fn apply_actions_queue(session: SessionIndex) -> Vec { @@ -1219,22 +1246,23 @@ impl Pallet { Self::initialize_para_now(&mut parachains, para, &genesis_data); } }, - // Upgrade a parathread to a parachain + // Upgrade an on-demand parachain to a lease holding parachain Some(ParaLifecycle::UpgradingParathread) => { parachains.add(para); ParaLifecycles::::insert(¶, ParaLifecycle::Parachain); }, - // Downgrade a parachain to a parathread + // Downgrade a lease holding parachain to an on-demand parachain Some(ParaLifecycle::DowngradingParachain) => { parachains.remove(para); ParaLifecycles::::insert(¶, ParaLifecycle::Parathread); }, - // Offboard a parathread or parachain from the system + // Offboard a lease holding or on-demand parachain from the system Some(ParaLifecycle::OffboardingParachain) | Some(ParaLifecycle::OffboardingParathread) => { parachains.remove(para); Heads::::remove(¶); + MostRecentContext::::remove(¶); FutureCodeUpgrades::::remove(¶); UpgradeGoAheadSignal::::remove(¶); UpgradeRestrictionSignal::::remove(¶); @@ -1676,8 +1704,7 @@ impl Pallet { /// /// Will return error if either is true: /// - /// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is - /// `false`) + /// - para is not a stable parachain (i.e. [`ParaLifecycle::is_stable`] is `false`) /// - para has a pending upgrade. /// - para has unprocessed messages in its UMP queue. /// @@ -1728,7 +1755,7 @@ impl Pallet { Ok(()) } - /// Schedule a parathread to be upgraded to a parachain. + /// Schedule a parathread (on-demand parachain) to be upgraded to a lease holding parachain. /// /// Will return error if `ParaLifecycle` is not `Parathread`. pub(crate) fn schedule_parathread_upgrade(id: ParaId) -> DispatchResult { @@ -1747,7 +1774,7 @@ impl Pallet { Ok(()) } - /// Schedule a parachain to be downgraded to a parathread. + /// Schedule a lease holding parachain to be downgraded to an on-demand parachain. /// /// Noop if `ParaLifecycle` is not `Parachain`. pub(crate) fn schedule_parachain_downgrade(id: ParaId) -> DispatchResult { @@ -1936,6 +1963,7 @@ impl Pallet { execution_context: BlockNumberFor, ) -> Weight { Heads::::insert(&id, new_head); + MostRecentContext::::insert(&id, execution_context); if let Some(expected_at) = FutureCodeUpgrades::::get(&id) { if expected_at <= execution_context { @@ -2028,9 +2056,10 @@ impl Pallet { ParaLifecycles::::get(&id).map_or(false, |state| state.is_offboarding()) } - /// Whether a para ID corresponds to any live parachain. + /// Whether a para ID corresponds to any live lease holding parachain. /// - /// Includes parachains which will downgrade to a parathread in the future. + /// Includes lease holding parachains which will downgrade to a on-demand parachains in the + /// future. pub fn is_parachain(id: ParaId) -> bool { if let Some(state) = ParaLifecycles::::get(&id) { state.is_parachain() @@ -2039,9 +2068,9 @@ impl Pallet { } } - /// Whether a para ID corresponds to any live parathread. + /// Whether a para ID corresponds to any live parathread (on-demand parachain). /// - /// Includes parathreads which will upgrade to parachains in the future. + /// Includes on-demand parachains which will upgrade to lease holding parachains in the future. pub fn is_parathread(id: ParaId) -> bool { if let Some(state) = ParaLifecycles::::get(&id) { state.is_parathread() @@ -2138,6 +2167,7 @@ impl Pallet { } Heads::::insert(&id, &genesis_data.genesis_head); + MostRecentContext::::insert(&id, BlockNumberFor::::from(0u32)); } #[cfg(test)] diff --git a/runtime/parachains/src/paras/tests.rs b/runtime/parachains/src/paras/tests.rs index e2067448b288..a024525c817a 100644 --- a/runtime/parachains/src/paras/tests.rs +++ b/runtime/parachains/src/paras/tests.rs @@ -1669,6 +1669,50 @@ fn verify_para_head_is_externally_accessible() { }); } +#[test] +fn most_recent_context() { + let validation_code: ValidationCode = vec![1, 2, 3].into(); + + let genesis_config = MockGenesisConfig::default(); + + new_test_ext(genesis_config).execute_with(|| { + const EXPECTED_SESSION: SessionIndex = 1; + run_to_block(1, Some(vec![1])); + + let para_id = ParaId::from(111); + + assert_eq!(Paras::para_most_recent_context(para_id), None); + + assert_ok!(Paras::schedule_para_initialize( + para_id, + ParaGenesisArgs { + para_kind: ParaKind::Parachain, + genesis_head: vec![1].into(), + validation_code: validation_code.clone(), + }, + )); + submit_super_majority_pvf_votes(&validation_code, EXPECTED_SESSION, true); + + assert_eq!(ParaLifecycles::::get(¶_id), Some(ParaLifecycle::Onboarding)); + + // Two sessions pass, so action queue is triggered. + run_to_block(4, Some(vec![3, 4])); + + // Double-check the para is onboarded, the context is set to the recent block. + assert_eq!(ParaLifecycles::::get(¶_id), Some(ParaLifecycle::Parachain)); + assert_eq!(Paras::para_most_recent_context(para_id), Some(0)); + + // Progress para to the new head and check that the recent context is updated. + Paras::note_new_head(para_id, vec![4, 5, 6].into(), 3); + assert_eq!(Paras::para_most_recent_context(para_id), Some(3)); + + // Finally, offboard the para and expect the context to be cleared. + assert_ok!(Paras::schedule_para_cleanup(para_id)); + run_to_block(6, Some(vec![5, 6])); + assert_eq!(Paras::para_most_recent_context(para_id), None); + }) +} + #[test] fn parakind_encodes_decodes_to_bool_scale() { let chain_kind = ParaKind::Parachain.encode(); diff --git a/runtime/parachains/src/paras_inherent/mod.rs b/runtime/parachains/src/paras_inherent/mod.rs index 0ace3c312269..6244f44e434b 100644 --- a/runtime/parachains/src/paras_inherent/mod.rs +++ b/runtime/parachains/src/paras_inherent/mod.rs @@ -28,8 +28,11 @@ use crate::{ inclusion::CandidateCheckContext, initializer, metrics::METRICS, - scheduler, - scheduler::common::{CoreAssignment, FreedReason}, + paras, + scheduler::{ + self, + common::{CoreAssignment, FreedReason}, + }, shared, ParaId, }; use bitvec::prelude::BitVec; @@ -356,6 +359,23 @@ impl Pallet { ); let now = >::block_number(); + let config = >::config(); + + // Before anything else, update the allowed relay-parents. + { + let parent_number = now - One::one(); + let parent_storage_root = *parent_header.state_root(); + + shared::AllowedRelayParents::::mutate(|tracker| { + tracker.update( + parent_hash, + parent_storage_root, + parent_number, + config.async_backing_params.allowed_ancestry_len, + ); + }); + } + let allowed_relay_parents = >::allowed_relay_parents(); let candidates_weight = backed_candidates_weight::(&backed_candidates); let bitfields_weight = signed_bitfields_weight::(&bitfields); @@ -407,7 +427,6 @@ impl Pallet { log::debug!(target: LOG_TARGET, "Found duplicate statement sets, retaining the first"); } - let config = >::config(); let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; let dispute_statement_set_valid = move |set: DisputeStatementSet| { @@ -566,28 +585,28 @@ impl Pallet { let scheduled = >::update_claimqueue(freed, now); - let relay_parent_number = now - One::one(); - let parent_storage_root = *parent_header.state_root(); - - let check_ctx = CandidateCheckContext::::new(now, relay_parent_number); - METRICS.on_candidates_processed_total(backed_candidates.len() as u64); let backed_candidates = sanitize_backed_candidates::( - parent_hash, backed_candidates, - move |candidate_idx: usize, - backed_candidate: &BackedCandidate<::Hash>| - -> bool { + |candidate_idx: usize, + backed_candidate: &BackedCandidate<::Hash>| + -> bool { + let para_id = backed_candidate.descriptor().para_id; + let prev_context = >::para_most_recent_context(para_id); + let check_ctx = CandidateCheckContext::::new(prev_context); + // never include a concluded-invalid candidate current_concluded_invalid_disputes.contains(&backed_candidate.hash()) || // Instead of checking the candidates with code upgrades twice // move the checking up here and skip it in the training wheels fallback. // That way we avoid possible duplicate checks while assuring all // backed candidates fine to pass on. + // + // NOTE: this is the only place where we check the relay-parent. check_ctx - .verify_backed_candidate(parent_hash, parent_storage_root, candidate_idx, backed_candidate) - .is_err() + .verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate) + .is_err() }, &scheduled[..], ); @@ -595,12 +614,11 @@ impl Pallet { METRICS.on_candidates_sanitized(backed_candidates.len() as u64); // Process backed candidates according to scheduled cores. - let parent_storage_root = *parent_header.state_root(); let inclusion::ProcessedCandidates::< as HeaderT>::Hash> { core_indices: occupied, candidate_receipt_with_backing_validator_indices, } = >::process_candidates( - parent_storage_root, + &allowed_relay_parents, backed_candidates.clone(), scheduled, >::group_validators, @@ -897,7 +915,6 @@ fn sanitize_backed_candidates< T: crate::inclusion::Config, F: FnMut(usize, &BackedCandidate) -> bool, >( - relay_parent: T::Hash, mut backed_candidates: Vec>, mut candidate_has_concluded_invalid_dispute_or_is_invalid: F, scheduled: &[CoreAssignment>], @@ -915,12 +932,13 @@ fn sanitize_backed_candidates< // Assure the backed candidate's `ParaId`'s core is free. // This holds under the assumption that `Scheduler::schedule` is called _before_. - // Also checks the candidate references the correct relay parent. + // We don't check the relay-parent because this is done in the closure when + // constructing the inherent and during actual processing otherwise. backed_candidates.retain(|backed_candidate| { let desc = backed_candidate.descriptor(); - desc.relay_parent == relay_parent && - scheduled_paras_to_core_idx.get(&desc.para_id).is_some() + + scheduled_paras_to_core_idx.get(&desc.para_id).is_some() }); // Sort the `Vec` last, once there is a guarantee that these diff --git a/runtime/parachains/src/paras_inherent/tests.rs b/runtime/parachains/src/paras_inherent/tests.rs index 4636200b762b..1e5271909664 100644 --- a/runtime/parachains/src/paras_inherent/tests.rs +++ b/runtime/parachains/src/paras_inherent/tests.rs @@ -601,8 +601,8 @@ mod enter { sum } - #[test] // Ensure that when a block is over weight due to disputes and bitfields, we filter. + #[test] fn limit_candidates_over_weight_1() { let config = MockGenesisConfig::default(); assert!(config.configuration.config.scheduling_lookahead > 0); @@ -671,6 +671,7 @@ mod enter { limit_inherent_data, )); + // TODO [now]: this assertion fails with async backing runtime. assert_eq!( // The length of this vec is equal to the number of candidates, so we know our 2 // backed candidates did not get filtered out @@ -1244,7 +1245,6 @@ mod sanitizers { Assignment::new(ParaId::from(1_u32 + idx as u32)), entry_ttl, ), - group_idx: GroupIndex::from(idx as u32), core: core_idx, }; ca @@ -1291,7 +1291,6 @@ mod sanitizers { // happy path assert_eq!( sanitize_backed_candidates::( - relay_parent, backed_candidates.clone(), has_concluded_invalid, &scheduled @@ -1303,19 +1302,6 @@ mod sanitizers { { let scheduled = &Vec::new(); assert!(sanitize_backed_candidates::( - relay_parent, - backed_candidates.clone(), - has_concluded_invalid, - scheduled - ) - .is_empty()); - } - - // relay parent mismatch - { - let relay_parent = Hash::repeat_byte(0xFA); - assert!(sanitize_backed_candidates::( - relay_parent, backed_candidates.clone(), has_concluded_invalid, &scheduled @@ -1339,7 +1325,6 @@ mod sanitizers { |_idx: usize, candidate: &BackedCandidate| set.contains(&candidate.hash()); assert_eq!( sanitize_backed_candidates::( - relay_parent, backed_candidates.clone(), has_concluded_invalid, &scheduled diff --git a/runtime/parachains/src/runtime_api_impl/v5.rs b/runtime/parachains/src/runtime_api_impl/v5.rs index 36b93a70a9f2..cd1579689733 100644 --- a/runtime/parachains/src/runtime_api_impl/v5.rs +++ b/runtime/parachains/src/runtime_api_impl/v5.rs @@ -126,7 +126,7 @@ pub fn availability_cores() -> Vec>::scheduled_claimqueue(now) { + for scheduled in >::scheduled_claimqueue() { core_states[scheduled.core.0 as usize] = CoreState::Scheduled(primitives::ScheduledCore { para_id: scheduled.paras_entry.para_id(), collator: None, @@ -221,7 +221,12 @@ pub fn check_validation_outputs( para_id: ParaId, outputs: primitives::CandidateCommitments, ) -> bool { - >::check_validation_outputs_for_runtime_api(para_id, outputs) + let relay_parent_number = >::block_number(); + >::check_validation_outputs_for_runtime_api( + para_id, + relay_parent_number, + outputs, + ) } /// Implementation for the `session_index_for_child` function of the runtime API. diff --git a/runtime/parachains/src/runtime_api_impl/vstaging.rs b/runtime/parachains/src/runtime_api_impl/vstaging.rs index d01b543630c3..5406428377d0 100644 --- a/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -15,3 +15,106 @@ // along with Polkadot. If not, see . //! Put implementations of functions from staging APIs here. + +use crate::{configuration, dmp, hrmp, inclusion, initializer, paras, shared}; +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::{ + vstaging::{ + AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints, + InboundHrmpLimitations, OutboundHrmpChannelLimitations, + }, + Id as ParaId, +}; +use sp_std::prelude::*; + +/// Implementation for `StagingParaBackingState` function from the runtime API +pub fn backing_state( + para_id: ParaId, +) -> Option>> { + let config = >::config(); + // Async backing is only expected to be enabled with a tracker capacity of 1. + // Subsequent configuration update gets applied on new session, which always + // clears the buffer. + // + // Thus, minimum relay parent is ensured to have asynchronous backing enabled. + let now = >::block_number(); + let min_relay_parent_number = >::allowed_relay_parents() + .hypothetical_earliest_block_number(now, config.async_backing_params.allowed_ancestry_len); + + let required_parent = >::para_head(para_id)?; + let validation_code_hash = >::current_code_hash(para_id)?; + + let upgrade_restriction = >::upgrade_restriction_signal(para_id); + let future_validation_code = + >::future_code_upgrade_at(para_id).and_then(|block_num| { + // Only read the storage if there's a pending upgrade. + Some(block_num).zip(>::future_code_hash(para_id)) + }); + + let (ump_msg_count, ump_total_bytes) = + >::relay_dispatch_queue_size(para_id); + let ump_remaining = config.max_upward_queue_count - ump_msg_count; + let ump_remaining_bytes = config.max_upward_queue_size - ump_total_bytes; + + let dmp_remaining_messages = >::dmq_contents(para_id) + .into_iter() + .map(|msg| msg.sent_at) + .collect(); + + let valid_watermarks = >::valid_watermarks(para_id); + let hrmp_inbound = InboundHrmpLimitations { valid_watermarks }; + let hrmp_channels_out = >::outbound_remaining_capacity(para_id) + .into_iter() + .map(|(para, (messages_remaining, bytes_remaining))| { + (para, OutboundHrmpChannelLimitations { messages_remaining, bytes_remaining }) + }) + .collect(); + + let constraints = Constraints { + min_relay_parent_number, + max_pov_size: config.max_pov_size, + max_code_size: config.max_code_size, + ump_remaining, + ump_remaining_bytes, + max_ump_num_per_candidate: config.max_upward_message_num_per_candidate, + dmp_remaining_messages, + hrmp_inbound, + hrmp_channels_out, + max_hrmp_num_per_candidate: config.hrmp_max_message_num_per_candidate, + required_parent, + validation_code_hash, + upgrade_restriction, + future_validation_code, + }; + + let pending_availability = { + // Note: the API deals with a `Vec` as it is future-proof for cases + // where there may be multiple candidates pending availability at a time. + // But at the moment only one candidate can be pending availability per + // parachain. + crate::inclusion::PendingAvailability::::get(¶_id) + .and_then(|pending| { + let commitments = + crate::inclusion::PendingAvailabilityCommitments::::get(¶_id); + commitments.map(move |c| (pending, c)) + }) + .map(|(pending, commitments)| { + CandidatePendingAvailability { + candidate_hash: pending.candidate_hash(), + descriptor: pending.candidate_descriptor().clone(), + commitments, + relay_parent_number: pending.relay_parent_number(), + max_pov_size: constraints.max_pov_size, // assume always same in session. + } + }) + .into_iter() + .collect() + }; + + Some(BackingState { constraints, pending_availability }) +} + +/// Implementation for `StagingAsyncBackingParams` function from the runtime API +pub fn async_backing_params() -> AsyncBackingParams { + >::config().async_backing_params +} diff --git a/runtime/parachains/src/scheduler.rs b/runtime/parachains/src/scheduler.rs index 81a8bfc535e0..577bcd153b5b 100644 --- a/runtime/parachains/src/scheduler.rs +++ b/runtime/parachains/src/scheduler.rs @@ -587,7 +587,7 @@ impl Pallet { debug_assert!(timedout_paras.is_empty()); debug_assert!(concluded_paras.is_empty()); - Self::scheduled_claimqueue(now) + Self::scheduled_claimqueue() } } @@ -634,9 +634,7 @@ impl Pallet { // TODO: Temporary to imitate the old schedule() call. Will be adjusted when we make the // scheduler AB ready - pub(crate) fn scheduled_claimqueue( - now: BlockNumberFor, - ) -> Vec>> { + pub(crate) fn scheduled_claimqueue() -> Vec>> { let claimqueue = ClaimQueue::::get(); claimqueue @@ -645,20 +643,11 @@ impl Pallet { v.front() .cloned() .flatten() - .and_then(|pe| Self::paras_entry_to_core_assignment(now, core_idx, pe)) + .map(|pe| CoreAssignment { core: core_idx, paras_entry: pe }) }) .collect() } - fn paras_entry_to_core_assignment( - now: BlockNumberFor, - core_idx: CoreIndex, - pe: ParasEntry>, - ) -> Option>> { - let group_idx = Self::group_assigned_to_core(core_idx, now)?; - Some(CoreAssignment { core: core_idx, group_idx, paras_entry: pe }) - } - #[cfg(any(feature = "runtime-benchmarks", test))] pub(crate) fn assignment_provider_config( core_idx: CoreIndex, @@ -675,4 +664,9 @@ impl Pallet { pub(crate) fn claimqueue_is_empty() -> bool { Self::claimqueue_len() == 0 } + + #[cfg(test)] + pub(crate) fn set_validator_groups(validator_groups: Vec>) { + ValidatorGroups::::set(validator_groups); + } } diff --git a/runtime/parachains/src/scheduler/common.rs b/runtime/parachains/src/scheduler/common.rs index c0404a875f33..0e8e8338b17b 100644 --- a/runtime/parachains/src/scheduler/common.rs +++ b/runtime/parachains/src/scheduler/common.rs @@ -19,7 +19,7 @@ use frame_support::pallet_prelude::*; use primitives::{ v5::{Assignment, ParasEntry}, - CoreIndex, GroupIndex, Id as ParaId, + CoreIndex, Id as ParaId, }; use scale_info::TypeInfo; use sp_std::prelude::*; @@ -81,8 +81,6 @@ pub struct CoreAssignment { pub core: CoreIndex, /// The para id and accompanying information needed to collate and back a parablock. pub paras_entry: ParasEntry, - /// The index of the validator group assigned to the core. - pub group_idx: GroupIndex, } impl CoreAssignment { diff --git a/runtime/parachains/src/scheduler/tests.rs b/runtime/parachains/src/scheduler/tests.rs index 0f64432c5f3a..e203531ca49d 100644 --- a/runtime/parachains/src/scheduler/tests.rs +++ b/runtime/parachains/src/scheduler/tests.rs @@ -400,11 +400,11 @@ fn fill_claimqueue_fills() { new_test_ext(genesis_config).execute_with(|| { assert_eq!(default_config().on_demand_cores, 3); - // register 2 parachains + // register 2 lease holding parachains schedule_blank_para(chain_a, ParaKind::Parachain); schedule_blank_para(chain_b, ParaKind::Parachain); - // and 3 parathreads + // and 3 parathreads (on-demand parachains) schedule_blank_para(thread_a, ParaKind::Parathread); schedule_blank_para(thread_b, ParaKind::Parathread); schedule_blank_para(thread_c, ParaKind::Parathread); @@ -427,7 +427,7 @@ fn fill_claimqueue_fills() { { assert_eq!(Scheduler::claimqueue_len(), 2 * lookahead); - let scheduled = Scheduler::scheduled_claimqueue(1); + let scheduled = Scheduler::scheduled_claimqueue(); // Cannot assert on indices anymore as they depend on the assignment providers assert!(claimqueue_contains_para_ids::(vec![chain_a, chain_b])); @@ -441,7 +441,6 @@ fn fill_claimqueue_fills() { availability_timeouts: 0, ttl: 6 }, - group_idx: GroupIndex(0), } ); @@ -454,7 +453,6 @@ fn fill_claimqueue_fills() { availability_timeouts: 0, ttl: 6 }, - group_idx: GroupIndex(1), } ); } @@ -483,7 +481,7 @@ fn fill_claimqueue_fills() { { assert_eq!(Scheduler::claimqueue_len(), 5); - let scheduled = Scheduler::scheduled_claimqueue(3); + let scheduled = Scheduler::scheduled_claimqueue(); assert_eq!( scheduled[0], @@ -494,7 +492,6 @@ fn fill_claimqueue_fills() { availability_timeouts: 0, ttl: 6 }, - group_idx: GroupIndex(0), } ); assert_eq!( @@ -506,7 +503,6 @@ fn fill_claimqueue_fills() { availability_timeouts: 0, ttl: 6 }, - group_idx: GroupIndex(1), } ); @@ -520,7 +516,6 @@ fn fill_claimqueue_fills() { availability_timeouts: 0, ttl: 7 }, - group_idx: GroupIndex(2), } ); // Sits on the same core as `thread_a` @@ -541,7 +536,6 @@ fn fill_claimqueue_fills() { availability_timeouts: 0, ttl: 7 }, - group_idx: GroupIndex(3), } ); } @@ -574,11 +568,11 @@ fn schedule_schedules_including_just_freed() { new_test_ext(genesis_config).execute_with(|| { assert_eq!(default_config().on_demand_cores, 3); - // register 2 parachains + // register 2 lease holding parachains schedule_blank_para(chain_a, ParaKind::Parachain); schedule_blank_para(chain_b, ParaKind::Parachain); - // and 5 parathreads + // and 5 parathreads (on-demand parachains) schedule_blank_para(thread_a, ParaKind::Parathread); schedule_blank_para(thread_b, ParaKind::Parathread); schedule_blank_para(thread_c, ParaKind::Parathread); @@ -614,7 +608,7 @@ fn schedule_schedules_including_just_freed() { let mut now = 2; run_to_block(now, |_| None); - assert_eq!(Scheduler::scheduled_claimqueue(now).len(), 4); + assert_eq!(Scheduler::scheduled_claimqueue().len(), 4); // cores 0, 1, 2, and 3 should be occupied. mark them as such. let mut occupied_map: BTreeMap = BTreeMap::new(); @@ -636,7 +630,7 @@ fn schedule_schedules_including_just_freed() { // core 4 is free assert!(cores[4] == CoreOccupied::Free); - assert!(Scheduler::scheduled_claimqueue(now).is_empty()); + assert!(Scheduler::scheduled_claimqueue().is_empty()); // All core index entries in the claimqueue should have `None` in them. Scheduler::claimqueue().iter().for_each(|(_core_idx, core_queue)| { @@ -663,10 +657,10 @@ fn schedule_schedules_including_just_freed() { run_to_block(now, |_| None); { - let scheduled = Scheduler::scheduled_claimqueue(now); + let scheduled = Scheduler::scheduled_claimqueue(); - // cores 0 and 1 are occupied by parachains. cores 2 and 3 are occupied by parathread - // claims. core 4 was free. + // cores 0 and 1 are occupied by lease holding parachains. cores 2 and 3 are occupied by + // on-demand parachain claims. core 4 was free. assert_eq!(scheduled.len(), 1); assert_eq!( scheduled[0], @@ -677,7 +671,6 @@ fn schedule_schedules_including_just_freed() { availability_timeouts: 0, ttl: 8 }, - group_idx: GroupIndex(4), } ); } @@ -693,7 +686,7 @@ fn schedule_schedules_including_just_freed() { Scheduler::update_claimqueue(just_updated, now); { - let scheduled = Scheduler::scheduled_claimqueue(now); + let scheduled = Scheduler::scheduled_claimqueue(); // 1 thing scheduled before, + 3 cores freed. assert_eq!(scheduled.len(), 4); @@ -706,7 +699,6 @@ fn schedule_schedules_including_just_freed() { availability_timeouts: 0, ttl: 8 }, - group_idx: GroupIndex(0), } ); assert_eq!( @@ -718,7 +710,6 @@ fn schedule_schedules_including_just_freed() { availability_timeouts: 0, ttl: 8 }, - group_idx: GroupIndex(2), } ); // Although C was descheduled, the core `4` was occupied so C goes back to the queue. @@ -731,7 +722,6 @@ fn schedule_schedules_including_just_freed() { availability_timeouts: 1, ttl: 8 }, - group_idx: GroupIndex(3), } ); assert_eq!( @@ -743,7 +733,6 @@ fn schedule_schedules_including_just_freed() { availability_timeouts: 0, ttl: 8 }, - group_idx: GroupIndex(4), } ); @@ -911,10 +900,16 @@ fn schedule_rotates_groups() { run_to_block(now, |_| None); let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor| { - let scheduled = Scheduler::scheduled_claimqueue(*now); + let scheduled = Scheduler::scheduled_claimqueue(); assert_eq!(scheduled.len(), 2); - assert_eq!(scheduled[0].group_idx, GroupIndex((0u32 + rotations) % on_demand_cores)); - assert_eq!(scheduled[1].group_idx, GroupIndex((1u32 + rotations) % on_demand_cores)); + assert_eq!( + Scheduler::group_assigned_to_core(scheduled[0].core, *now).unwrap(), + GroupIndex((0u32 + rotations) % on_demand_cores) + ); + assert_eq!( + Scheduler::group_assigned_to_core(scheduled[1].core, *now).unwrap(), + GroupIndex((1u32 + rotations) % on_demand_cores) + ); }; assert_groups_rotated(0, &now); diff --git a/runtime/parachains/src/shared.rs b/runtime/parachains/src/shared.rs index 6b50bcce4054..ad13c9e48448 100644 --- a/runtime/parachains/src/shared.rs +++ b/runtime/parachains/src/shared.rs @@ -22,7 +22,8 @@ use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{SessionIndex, ValidatorId, ValidatorIndex}; -use sp_std::vec::Vec; +use sp_runtime::traits::AtLeast32BitUnsigned; +use sp_std::{collections::vec_deque::VecDeque, vec::Vec}; use rand::{seq::SliceRandom, SeedableRng}; use rand_chacha::ChaCha20Rng; @@ -39,6 +40,86 @@ pub(crate) const SESSION_DELAY: SessionIndex = 2; #[cfg(test)] mod tests; +/// Information about past relay-parents. +#[derive(Encode, Decode, Default, TypeInfo)] +pub struct AllowedRelayParentsTracker { + // The past relay parents, paired with state roots, that are viable to build upon. + // + // They are in ascending chronologic order, so the newest relay parents are at + // the back of the deque. + // + // (relay_parent, state_root) + buffer: VecDeque<(Hash, Hash)>, + + // The number of the most recent relay-parent, if any. + // If the buffer is empty, this value has no meaning and may + // be nonsensical. + latest_number: BlockNumber, +} + +impl + AllowedRelayParentsTracker +{ + /// Add a new relay-parent to the allowed relay parents, along with info about the header. + /// Provide a maximum ancestry length for the buffer, which will cause old relay-parents to be + /// pruned. + pub(crate) fn update( + &mut self, + relay_parent: Hash, + state_root: Hash, + number: BlockNumber, + max_ancestry_len: u32, + ) { + // + 1 for the most recent block, which is always allowed. + let buffer_size_limit = max_ancestry_len as usize + 1; + + self.buffer.push_back((relay_parent, state_root)); + self.latest_number = number; + while self.buffer.len() > buffer_size_limit { + let _ = self.buffer.pop_front(); + } + + // We only allow relay parents within the same sessions, the buffer + // gets cleared on session changes. + } + + /// Attempt to acquire the state root and block number to be used when building + /// upon the given relay-parent. + /// + /// This only succeeds if the relay-parent is one of the allowed relay-parents. + /// If a previous relay-parent number is passed, then this only passes if the new relay-parent + /// is more recent than the previous. + pub(crate) fn acquire_info( + &self, + relay_parent: Hash, + prev: Option, + ) -> Option<(Hash, BlockNumber)> { + let pos = self.buffer.iter().position(|(rp, _)| rp == &relay_parent)?; + let age = (self.buffer.len() - 1) - pos; + let number = self.latest_number - BlockNumber::from(age as u32); + + if let Some(prev) = prev { + if prev > number { + return None + } + } + + Some((self.buffer[pos].1, number)) + } + + /// Returns block number of the earliest block the buffer would contain if + /// `now` is pushed into it. + pub(crate) fn hypothetical_earliest_block_number( + &self, + now: BlockNumber, + max_ancestry_len: u32, + ) -> BlockNumber { + let allowed_ancestry_len = max_ancestry_len.min(self.buffer.len() as u32); + + now - allowed_ancestry_len.into() + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -68,6 +149,12 @@ pub mod pallet { #[pallet::getter(fn active_validator_keys)] pub(super) type ActiveValidatorKeys = StorageValue<_, Vec, ValueQuery>; + /// All allowed relay-parents. + #[pallet::storage] + #[pallet::getter(fn allowed_relay_parents)] + pub(crate) type AllowedRelayParents = + StorageValue<_, AllowedRelayParentsTracker>, ValueQuery>; + #[pallet::call] impl Pallet {} } @@ -90,6 +177,17 @@ impl Pallet { new_config: &HostConfiguration>, all_validators: Vec, ) -> Vec { + // Drop allowed relay parents buffer on a session change. + // + // During the initialization of the next block we always add its parent + // to the tracker. + // + // With asynchronous backing candidates built on top of relay + // parent `R` are still restricted by the runtime to be backed + // by the group assigned at `number(R) + 1`, which is guaranteed + // to be in the current session. + AllowedRelayParents::::mutate(|tracker| tracker.buffer.clear()); + CurrentSessionIndex::::set(session_index); let mut rng: ChaCha20Rng = SeedableRng::from_seed(random_seed); diff --git a/runtime/parachains/src/shared/tests.rs b/runtime/parachains/src/shared/tests.rs index cf787f6b8a01..91891ba8d75b 100644 --- a/runtime/parachains/src/shared/tests.rs +++ b/runtime/parachains/src/shared/tests.rs @@ -19,12 +19,81 @@ use crate::{ configuration::HostConfiguration, mock::{new_test_ext, MockGenesisConfig, ParasShared}, }; +use assert_matches::assert_matches; use keyring::Sr25519Keyring; +use primitives::Hash; fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { val_ids.iter().map(|v| v.public().into()).collect() } +#[test] +fn tracker_earliest_block_number() { + let mut tracker = AllowedRelayParentsTracker::default(); + + // Test it on an empty tracker. + let now: u32 = 1; + let max_ancestry_len = 5; + assert_eq!(tracker.hypothetical_earliest_block_number(now, max_ancestry_len), now); + + // Push a single block into the tracker, suppose max capacity is 1. + let max_ancestry_len = 0; + tracker.update(Hash::zero(), Hash::zero(), 0, max_ancestry_len); + assert_eq!(tracker.hypothetical_earliest_block_number(now, max_ancestry_len), now); + + // Test a greater capacity. + let max_ancestry_len = 4; + let now = 4; + for i in 1..now { + tracker.update(Hash::zero(), Hash::zero(), i, max_ancestry_len); + assert_eq!(tracker.hypothetical_earliest_block_number(i + 1, max_ancestry_len), 0); + } + + // Capacity exceeded. + tracker.update(Hash::zero(), Hash::zero(), now, max_ancestry_len); + assert_eq!(tracker.hypothetical_earliest_block_number(now + 1, max_ancestry_len), 1); +} + +#[test] +fn tracker_acquire_info() { + let mut tracker = AllowedRelayParentsTracker::::default(); + let max_ancestry_len = 2; + + // (relay_parent, state_root) pairs. + let blocks = &[ + (Hash::repeat_byte(0), Hash::repeat_byte(10)), + (Hash::repeat_byte(1), Hash::repeat_byte(11)), + (Hash::repeat_byte(2), Hash::repeat_byte(12)), + ]; + + let (relay_parent, state_root) = blocks[0]; + tracker.update(relay_parent, state_root, 0, max_ancestry_len); + assert_matches!( + tracker.acquire_info(relay_parent, None), + Some((s, b)) if s == state_root && b == 0 + ); + + let (relay_parent, state_root) = blocks[1]; + tracker.update(relay_parent, state_root, 1u32, max_ancestry_len); + let (relay_parent, state_root) = blocks[2]; + tracker.update(relay_parent, state_root, 2u32, max_ancestry_len); + for (block_num, (rp, state_root)) in blocks.iter().enumerate().take(2) { + assert_matches!( + tracker.acquire_info(*rp, None), + Some((s, b)) if &s == state_root && b == block_num as u32 + ); + + assert!(tracker.acquire_info(*rp, Some(2)).is_none()); + } + + for (block_num, (rp, state_root)) in blocks.iter().enumerate().skip(1) { + assert_matches!( + tracker.acquire_info(*rp, Some(block_num as u32 - 1)), + Some((s, b)) if &s == state_root && b == block_num as u32 + ); + } +} + #[test] fn sets_and_shuffles_validators() { let validators = vec![ diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index e03b2b673706..ad10de445ab3 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -821,6 +821,7 @@ where } parameter_types! { + // Deposit for a parathread (on-demand parachain) pub const ParathreadDeposit: Balance = 500 * DOLLARS; pub const MaxRetries: u32 = 3; } diff --git a/runtime/polkadot/src/weights/runtime_parachains_paras.rs b/runtime/polkadot/src/weights/runtime_parachains_paras.rs index c8c35f5e7167..06f67211eade 100644 --- a/runtime/polkadot/src/weights/runtime_parachains_paras.rs +++ b/runtime/polkadot/src/weights/runtime_parachains_paras.rs @@ -89,6 +89,12 @@ impl runtime_parachains::paras::WeightInfo for WeightIn .saturating_add(Weight::from_parts(1_040, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: Paras Heads (r:0 w:1) + fn force_set_most_recent_context() -> Weight { + Weight::from_parts(10_155_000, 0) + // Standard Error: 0 + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } /// Storage: Configuration ActiveConfig (r:1 w:0) /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Paras FutureCodeHash (r:1 w:1) diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index a9811872b6af..fb2a56c8100c 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -1715,7 +1715,6 @@ sp_api::impl_runtime_apis! { } } - #[api_version(5)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() diff --git a/runtime/rococo/src/weights/runtime_parachains_paras.rs b/runtime/rococo/src/weights/runtime_parachains_paras.rs index 17958b957f37..dfd95006dc7d 100644 --- a/runtime/rococo/src/weights/runtime_parachains_paras.rs +++ b/runtime/rococo/src/weights/runtime_parachains_paras.rs @@ -86,6 +86,12 @@ impl runtime_parachains::paras::WeightInfo for WeightIn .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: Paras Heads (r:0 w:1) + fn force_set_most_recent_context() -> Weight { + Weight::from_parts(10_155_000, 0) + // Standard Error: 0 + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } /// Storage: Configuration ActiveConfig (r:1 w:0) /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Paras FutureCodeHash (r:1 w:1) diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index e6fa4afc9388..3ade28c51fba 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -1427,7 +1427,6 @@ sp_api::impl_runtime_apis! { } } - #[api_version(5)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() diff --git a/runtime/westend/src/weights/runtime_parachains_paras.rs b/runtime/westend/src/weights/runtime_parachains_paras.rs index dd1cea3e729b..07623f60b012 100644 --- a/runtime/westend/src/weights/runtime_parachains_paras.rs +++ b/runtime/westend/src/weights/runtime_parachains_paras.rs @@ -89,6 +89,12 @@ impl runtime_parachains::paras::WeightInfo for WeightIn .saturating_add(Weight::from_parts(1_025, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: Paras Heads (r:0 w:1) + fn force_set_most_recent_context() -> Weight { + Weight::from_parts(10_155_000, 0) + // Standard Error: 0 + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } /// Storage: Paras FutureCodeHash (r:1 w:1) /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) /// Storage: Paras CurrentCodeHash (r:1 w:0) diff --git a/scripts/ci/gitlab/lingua.dic b/scripts/ci/gitlab/lingua.dic index d9dad4540277..5bf272231fab 100644 --- a/scripts/ci/gitlab/lingua.dic +++ b/scripts/ci/gitlab/lingua.dic @@ -304,6 +304,7 @@ unreserve unreserving unroutable unservable/B +unshare/D untrusted untyped unvested @@ -320,10 +321,11 @@ verify/R versa Versi version/DMSG -versioned VMP/SM VPS VRF/SM +vstaging +VStaging w3f/MS wakeup wakeups diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml index 6d023489c073..62e081d1de0e 100644 --- a/scripts/ci/gitlab/pipeline/zombienet.yml +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -342,3 +342,103 @@ zombienet-tests-beefy-and-mmr: retry: 2 tags: - zombienet-polkadot-integration-test + +zombienet-tests-async-backing-compatibility: + stage: zombienet + extends: + - .kubernetes-env + - .zombienet-refs + image: "${ZOMBIENET_IMAGE}" + needs: + - job: publish-polkadot-debug-image + - job: publish-test-collators-image + - job: build-linux-stable + artifacts: true + variables: + RUN_IN_CONTAINER: "1" + GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/async_backing" + before_script: + - echo "Zombie-net Tests Config" + - echo "${ZOMBIENET_IMAGE_NAME}" + - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" + - echo "${GH_DIR}" + - export DEBUG=zombie,zombie::network-node + - BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" + - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} + - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" + - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}" + --test="001-async-backing-compatibility.zndsl" + allow_failure: false + retry: 2 + tags: + - zombienet-polkadot-integration-test + +zombienet-tests-async-backing-runtime-upgrade: + stage: zombienet + extends: + - .kubernetes-env + - .zombienet-refs + image: "${ZOMBIENET_IMAGE}" + needs: + - job: publish-polkadot-debug-image + - job: publish-test-collators-image + - job: build-linux-stable + artifacts: true + variables: + RUN_IN_CONTAINER: "1" + GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/async_backing" + before_script: + - echo "Zombie-net Tests Config" + - echo "${ZOMBIENET_IMAGE_NAME}" + - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" + - echo "${GH_DIR}" + - export DEBUG=zombie,zombie::network-node + - BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" + - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} + - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" + - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} + - export POLKADOT_PR_BIN_URL="https://gitlab.parity.io/parity/mirrors/polkadot/-/jobs/${BUILD_LINUX_JOB_ID}/artifacts/raw/artifacts/polkadot" + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}" + --test="002-async-backing-runtime-upgrade.zndsl" + allow_failure: false + retry: 2 + tags: + - zombienet-polkadot-integration-test + +zombienet-tests-async-backing-collator-mix: + stage: zombienet + extends: + - .kubernetes-env + - .zombienet-refs + image: "${ZOMBIENET_IMAGE}" + needs: + - job: publish-polkadot-debug-image + - job: publish-test-collators-image + - job: build-linux-stable + artifacts: true + variables: + RUN_IN_CONTAINER: "1" + GH_DIR: "https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/async_backing" + before_script: + - echo "Zombie-net Tests Config" + - echo "${ZOMBIENET_IMAGE_NAME}" + - echo "${PARACHAINS_IMAGE_NAME} ${PARACHAINS_IMAGE_TAG}" + - echo "${GH_DIR}" + - export DEBUG=zombie,zombie::network-node + - BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" + - export ZOMBIENET_INTEGRATION_TEST_IMAGE=${PARACHAINS_IMAGE_NAME}:${PARACHAINS_IMAGE_TAG} + - export ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE="docker.io/parity/polkadot:${BUILD_RELEASE_VERSION}" + - export COL_IMAGE=${COLLATOR_IMAGE_NAME}:${COLLATOR_IMAGE_TAG} + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}" + --test="003-async-backing-collator-mix.zndsl" + allow_failure: false + retry: 2 + tags: + - zombienet-polkadot-integration-test diff --git a/statement-table/src/generic.rs b/statement-table/src/generic.rs index 161a06ef161a..a427aae42fb9 100644 --- a/statement-table/src/generic.rs +++ b/statement-table/src/generic.rs @@ -61,6 +61,14 @@ pub trait Context { fn requisite_votes(&self, group: &Self::GroupId) -> usize; } +/// Table configuration. +pub struct Config { + /// When this is true, the table will allow multiple seconded candidates + /// per authority. This flag means that higher-level code is responsible for + /// bounding the number of candidates. + pub allow_multiple_seconded: bool, +} + /// Statements circulated among peers. #[derive(PartialEq, Eq, Debug, Clone, Encode, Decode)] pub enum Statement { @@ -270,12 +278,12 @@ impl CandidateData { // authority metadata struct AuthorityData { - proposal: Option<(Ctx::Digest, Ctx::Signature)>, + proposals: Vec<(Ctx::Digest, Ctx::Signature)>, } impl Default for AuthorityData { fn default() -> Self { - AuthorityData { proposal: None } + AuthorityData { proposals: Vec::new() } } } @@ -290,19 +298,20 @@ pub struct Table { authority_data: HashMap>, detected_misbehavior: HashMap>>, candidate_votes: HashMap>, + config: Config, } -impl Default for Table { - fn default() -> Self { +impl Table { + /// Create a new `Table` from a `Config`. + pub fn new(config: Config) -> Self { Table { - authority_data: HashMap::new(), - detected_misbehavior: HashMap::new(), - candidate_votes: HashMap::new(), + authority_data: HashMap::default(), + detected_misbehavior: HashMap::default(), + candidate_votes: HashMap::default(), + config, } } -} -impl Table { /// Get the attested candidate for `digest`. /// /// Returns `Some(_)` if the candidate exists and is includable. @@ -393,7 +402,9 @@ impl Table { // note misbehavior. let existing = occ.get_mut(); - if let Some((ref old_digest, ref old_sig)) = existing.proposal { + if !self.config.allow_multiple_seconded && existing.proposals.len() == 1 { + let (old_digest, old_sig) = &existing.proposals[0]; + if old_digest != &digest { const EXISTENCE_PROOF: &str = "when proposal first received from authority, candidate \ @@ -413,15 +424,19 @@ impl Table { })) } + false + } else if self.config.allow_multiple_seconded && + existing.proposals.iter().any(|(ref od, _)| od == &digest) + { false } else { - existing.proposal = Some((digest.clone(), signature.clone())); + existing.proposals.push((digest.clone(), signature.clone())); true } }, Entry::Vacant(vacant) => { vacant - .insert(AuthorityData { proposal: Some((digest.clone(), signature.clone())) }); + .insert(AuthorityData { proposals: vec![(digest.clone(), signature.clone())] }); true }, }; @@ -572,8 +587,12 @@ mod tests { use super::*; use std::collections::HashMap; - fn create() -> Table { - Table::default() + fn create_single_seconded() -> Table { + Table::new(Config { allow_multiple_seconded: false }) + } + + fn create_many_seconded() -> Table { + Table::new(Config { allow_multiple_seconded: true }) } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -631,7 +650,7 @@ mod tests { } #[test] - fn submitting_two_candidates_is_misbehavior() { + fn submitting_two_candidates_can_be_misbehavior() { let context = TestContext { authorities: { let mut map = HashMap::new(); @@ -640,7 +659,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let statement_a = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -666,6 +685,36 @@ mod tests { ); } + #[test] + fn submitting_two_candidates_can_be_allowed() { + let context = TestContext { + authorities: { + let mut map = HashMap::new(); + map.insert(AuthorityId(1), GroupId(2)); + map + }, + }; + + let mut table = create_many_seconded(); + let statement_a = SignedStatement { + statement: Statement::Seconded(Candidate(2, 100)), + signature: Signature(1), + sender: AuthorityId(1), + }; + + let statement_b = SignedStatement { + statement: Statement::Seconded(Candidate(2, 999)), + signature: Signature(1), + sender: AuthorityId(1), + }; + + table.import_statement(&context, statement_a); + assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); + + table.import_statement(&context, statement_b); + assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); + } + #[test] fn submitting_candidate_from_wrong_group_is_misbehavior() { let context = TestContext { @@ -676,7 +725,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -708,7 +757,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let candidate_a = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), @@ -752,7 +801,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -782,7 +831,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -850,7 +899,7 @@ mod tests { }; // have 2/3 validity guarantors note validity. - let mut table = create(); + let mut table = create_single_seconded(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -884,7 +933,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -911,7 +960,7 @@ mod tests { }, }; - let mut table = create(); + let mut table = create_single_seconded(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), diff --git a/statement-table/src/lib.rs b/statement-table/src/lib.rs index 0388c069f646..d4629330ac01 100644 --- a/statement-table/src/lib.rs +++ b/statement-table/src/lib.rs @@ -29,7 +29,7 @@ pub mod generic; -pub use generic::{Context, Table}; +pub use generic::{Config, Context, Table}; /// Concrete instantiations suitable for v2 primitives. pub mod v2 { diff --git a/zombienet_tests/async_backing/001-async-backing-compatibility.toml b/zombienet_tests/async_backing/001-async-backing-compatibility.toml new file mode 100644 index 000000000000..918fb5bf4f62 --- /dev/null +++ b/zombienet_tests/async_backing/001-async-backing-compatibility.toml @@ -0,0 +1,34 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + + [relaychain.default_resources] + limits = { memory = "4G", cpu = "2" } + requests = { memory = "2G", cpu = "1" } + + [[relaychain.nodes]] + name = "alice" + args = [ "-lparachain=debug,runtime=debug"] + + [[relaychain.nodes]] + name = "bob" + image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" + args = [ "-lparachain=debug,runtime=debug"] + +[[parachains]] +id = 100 + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl b/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl new file mode 100644 index 000000000000..46c1d77acf46 --- /dev/null +++ b/zombienet_tests/async_backing/001-async-backing-compatibility.zndsl @@ -0,0 +1,23 @@ +Description: Async Backing Compatibility Test +Network: ./001-async-backing-compatibility.toml +Creds: config + +# General +alice: is up +bob: is up + +# Check authority status +alice: reports node_roles is 4 +bob: reports node_roles is 4 + +# Check peers +alice: reports peers count is at least 2 within 20 seconds +bob: reports peers count is at least 2 within 20 seconds + +# Parachain registration +alice: parachain 100 is registered within 225 seconds +bob: parachain 100 is registered within 225 seconds + +# Ensure parachain progress +alice: parachain 100 block height is at least 10 within 250 seconds +bob: parachain 100 block height is at least 10 within 250 seconds diff --git a/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml b/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml new file mode 100644 index 000000000000..e61f7dd47ef6 --- /dev/null +++ b/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.toml @@ -0,0 +1,54 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + + [relaychain.default_resources] + limits = { memory = "4G", cpu = "2" } + requests = { memory = "2G", cpu = "1" } + + [[relaychain.nodes]] + name = "alice" + args = [ "-lparachain=debug,runtime=debug"] + + [[relaychain.nodes]] + name = "bob" + args = [ "-lparachain=debug,runtime=debug"] + + [[relaychain.nodes]] + name = "charlie" + image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" + args = [ "-lparachain=debug,runtime=debug"] + + [[relaychain.nodes]] + name = "dave" + image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" + args = [ "-lparachain=debug,runtime=debug"] + +[[parachains]] +id = 100 +addToGenesis = true + + [parachains.collator] + name = "collator02" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug"] + +[[parachains]] +id = 101 +addToGenesis = true + + [parachains.collator] + name = "collator02" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl b/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl new file mode 100644 index 000000000000..6213d1afb81e --- /dev/null +++ b/zombienet_tests/async_backing/002-async-backing-runtime-upgrade.zndsl @@ -0,0 +1,34 @@ +Description: Async Backing Runtime Upgrade Test +Network: ./002-async-backing-runtime-upgrade.toml +Creds: config + +# General +alice: is up +bob: is up +charlie: is up +dave: is up + +# Check peers +alice: reports peers count is at least 3 within 20 seconds +bob: reports peers count is at least 3 within 20 seconds + +# Parachain registration +alice: parachain 100 is registered within 225 seconds +bob: parachain 100 is registered within 225 seconds +charlie: parachain 100 is registered within 225 seconds +dave: parachain 100 is registered within 225 seconds +alice: parachain 101 is registered within 225 seconds +bob: parachain 101 is registered within 225 seconds +charlie: parachain 101 is registered within 225 seconds +dave: parachain 101 is registered within 225 seconds + +# Ensure parachain progress +alice: parachain 100 block height is at least 10 within 250 seconds +bob: parachain 100 block height is at least 10 within 250 seconds + +# Runtime upgrade (according to previous runtime tests, avg. is 30s) +alice: run ../misc/0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_BIN_URL}}" within 40 seconds +bob: run ../misc/0002-download-polkadot-from-pr.sh with "{{POLKADOT_PR_BIN_URL}}" within 40 seconds + +# Bootstrap the runtime upgrade +sleep 30 seconds diff --git a/zombienet_tests/async_backing/003-async-backing-collator-mix.toml b/zombienet_tests/async_backing/003-async-backing-collator-mix.toml new file mode 100644 index 000000000000..4dca4d3d5312 --- /dev/null +++ b/zombienet_tests/async_backing/003-async-backing-collator-mix.toml @@ -0,0 +1,40 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +default_command = "polkadot" + + [relaychain.default_resources] + limits = { memory = "4G", cpu = "2" } + requests = { memory = "2G", cpu = "1" } + + [[relaychain.nodes]] + name = "alice" + args = [ "-lparachain=debug"] + + [[relaychain.nodes]] + name = "bob" + image = "{{ZOMBIENET_INTEGRATION_TEST_SECONDARY_IMAGE}}" + args = [ "-lparachain=debug"] + +[[parachains]] +id = 100 + + [[parachains.collators]] + name = "collator01" + image = "docker.io/paritypr/colander:master" + command = "undying-collator" + args = ["-lparachain=debug"] + + [[parachains.collators]] + name = "collator02" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl b/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl new file mode 100644 index 000000000000..98436b0459cf --- /dev/null +++ b/zombienet_tests/async_backing/003-async-backing-collator-mix.zndsl @@ -0,0 +1,19 @@ +Description: Async Backing Collator Mix Test +Network: ./003-async-backing-collator-mix.toml +Creds: config + +# General +alice: is up +bob: is up + +# Check peers +alice: reports peers count is at least 3 within 20 seconds +bob: reports peers count is at least 3 within 20 seconds + +# Parachain registration +alice: parachain 100 is registered within 225 seconds +bob: parachain 100 is registered within 225 seconds + +# Ensure parachain progress +alice: parachain 100 block height is at least 10 within 250 seconds +bob: parachain 100 block height is at least 10 within 250 seconds diff --git a/zombienet_tests/async_backing/README.md b/zombienet_tests/async_backing/README.md new file mode 100644 index 000000000000..9774ea3c25c9 --- /dev/null +++ b/zombienet_tests/async_backing/README.md @@ -0,0 +1,9 @@ +# async-backing zombienet tests + +This directory contains zombienet tests made explicitly for the async-backing feature branch. + +## coverage + +- Network protocol upgrade deploying both master and async branch (compatibility). +- Runtime ugprade while running both master and async backing branch nodes. +- Async backing test with a mix of collators collating via async backing and sync backing. diff --git a/zombienet_tests/functional/0002-parachains-disputes.zndsl b/zombienet_tests/functional/0002-parachains-disputes.zndsl index 31f2b372f894..b7d797a496bb 100644 --- a/zombienet_tests/functional/0002-parachains-disputes.zndsl +++ b/zombienet_tests/functional/0002-parachains-disputes.zndsl @@ -26,9 +26,9 @@ alice: parachain 2003 block height is at least 10 within 200 seconds # Check if disputes are initiated and concluded. # TODO: check if disputes are concluded faster than initiated. -eve: reports parachain_candidate_disputes_total is at least 10 within 15 seconds -eve: reports parachain_candidate_dispute_concluded{validity="valid"} is at least 10 within 15 seconds -eve: reports parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 15 seconds +eve: reports polkadot_parachain_candidate_disputes_total is at least 10 within 15 seconds +eve: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is at least 10 within 15 seconds +eve: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 15 seconds # As of , we don't slash on disputes # with `valid` outcome, so there is no offence reported. diff --git a/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl b/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl index 50fff9e3d597..c4fd3ee7c55a 100644 --- a/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl +++ b/zombienet_tests/functional/0003-parachains-garbage-candidate.zndsl @@ -32,13 +32,13 @@ honest-validator-2: reports polkadot_parachain_disputes_finality_lag is lower th sleep 30 seconds # Check that garbage parachain blocks included by malicious validators are being disputed. -honest-validator-0: reports parachain_candidate_disputes_total is at least 2 within 15 seconds -honest-validator-1: reports parachain_candidate_disputes_total is at least 2 within 15 seconds -honest-validator-2: reports parachain_candidate_disputes_total is at least 2 within 15 seconds +honest-validator-0: reports polkadot_parachain_candidate_disputes_total is at least 2 within 15 seconds +honest-validator-1: reports polkadot_parachain_candidate_disputes_total is at least 2 within 15 seconds +honest-validator-2: reports polkadot_parachain_candidate_disputes_total is at least 2 within 15 seconds # Disputes should always end as "invalid" -honest-validator-0: reports parachain_candidate_dispute_concluded{validity="invalid"} is at least 2 within 15 seconds -honest-validator-1: reports parachain_candidate_dispute_concluded{validity="valid"} is 0 within 15 seconds +honest-validator-0: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is at least 2 within 15 seconds +honest-validator-1: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is 0 within 15 seconds # Check participating in the losing side of a dispute logged malus-validator: log line contains "Voted for a candidate that was concluded invalid." within 180 seconds diff --git a/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl b/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl index e86cbb398357..8e792f974fe3 100644 --- a/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl +++ b/zombienet_tests/functional/0004-parachains-disputes-past-session.zndsl @@ -14,7 +14,7 @@ honest-validator-0: parachain 1000 is registered within 100 seconds honest-validator-0: parachain 1000 block height is at least 1 within 300 seconds # There should be disputes initiated -honest-validator-0: reports parachain_candidate_disputes_total is at least 2 within 200 seconds +honest-validator-0: reports polkadot_parachain_candidate_disputes_total is at least 2 within 200 seconds # Stop issuing disputes malus-validator-0: pause @@ -29,9 +29,9 @@ honest-validator-0: reports block height minus finalised block is at least 10 wi alice: resume # Disputes should start concluding now -honest-validator-0: reports parachain_candidate_dispute_concluded{validity="invalid"} is at least 1 within 200 seconds +honest-validator-0: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is at least 1 within 200 seconds # Disputes should always end as "invalid" -honest-validator-0: reports parachain_candidate_dispute_concluded{validity="valid"} is 0 +honest-validator-0: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is 0 # Check an unsigned extrinsic is submitted honest-validator: log line contains "Successfully reported pending slash" within 180 seconds diff --git a/zombienet_tests/misc/0001-paritydb.zndsl b/zombienet_tests/misc/0001-paritydb.zndsl index eede8bc11142..4a22311de764 100644 --- a/zombienet_tests/misc/0001-paritydb.zndsl +++ b/zombienet_tests/misc/0001-paritydb.zndsl @@ -55,14 +55,14 @@ validator-8: reports polkadot_parachain_approval_checking_finality_lag is 0 validator-9: reports polkadot_parachain_approval_checking_finality_lag is 0 # Check lag - dispute conclusion -validator-0: reports parachain_candidate_disputes_total is 0 -validator-1: reports parachain_candidate_disputes_total is 0 -validator-2: reports parachain_candidate_disputes_total is 0 -validator-3: reports parachain_candidate_disputes_total is 0 -validator-4: reports parachain_candidate_disputes_total is 0 -validator-5: reports parachain_candidate_disputes_total is 0 -validator-6: reports parachain_candidate_disputes_total is 0 -validator-7: reports parachain_candidate_disputes_total is 0 -validator-8: reports parachain_candidate_disputes_total is 0 -validator-9: reports parachain_candidate_disputes_total is 0 +validator-0: reports polkadot_parachain_candidate_disputes_total is 0 +validator-1: reports polkadot_parachain_candidate_disputes_total is 0 +validator-2: reports polkadot_parachain_candidate_disputes_total is 0 +validator-3: reports polkadot_parachain_candidate_disputes_total is 0 +validator-4: reports polkadot_parachain_candidate_disputes_total is 0 +validator-5: reports polkadot_parachain_candidate_disputes_total is 0 +validator-6: reports polkadot_parachain_candidate_disputes_total is 0 +validator-7: reports polkadot_parachain_candidate_disputes_total is 0 +validator-8: reports polkadot_parachain_candidate_disputes_total is 0 +validator-9: reports polkadot_parachain_candidate_disputes_total is 0 From 47e58acc16f6aadde3e7a56770a4462215cf6263 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Sat, 19 Aug 2023 10:39:43 -0300 Subject: [PATCH 36/45] Add tests for PayOverXcm (#7319) * PayOverXcm: Add test skeleton * PayOverXcm: Add tests checking PayOverXcm generates correct message * Add PayOverXcm and salary pallet integration test * Fix XCM execution issue * Fix documentation issues * Add missing period at the end of comment * Fix mock problems * Add missing licenses * Fix lints * Fix more lints * Add docs to mock * Add transfer assertions * Remove magic numbers --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 21 ++ xcm/xcm-builder/Cargo.toml | 3 + xcm/xcm-builder/src/tests/mock.rs | 61 ++++- xcm/xcm-builder/src/tests/mod.rs | 1 + xcm/xcm-builder/src/tests/pay/mock.rs | 334 ++++++++++++++++++++++++ xcm/xcm-builder/src/tests/pay/mod.rs | 21 ++ xcm/xcm-builder/src/tests/pay/pay.rs | 158 +++++++++++ xcm/xcm-builder/src/tests/pay/salary.rs | 172 ++++++++++++ 8 files changed, 770 insertions(+), 1 deletion(-) create mode 100644 xcm/xcm-builder/src/tests/pay/mock.rs create mode 100644 xcm/xcm-builder/src/tests/pay/mod.rs create mode 100644 xcm/xcm-builder/src/tests/pay/pay.rs create mode 100644 xcm/xcm-builder/src/tests/pay/salary.rs diff --git a/Cargo.lock b/Cargo.lock index c2f31fe36efd..be03ec3daa41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6584,6 +6584,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-salary" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#96f8c97dff7f419a349ee01d02613445ba4a41f8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-scheduler" version = "4.0.0-dev" @@ -15130,11 +15148,14 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "log", + "pallet-assets", "pallet-balances", + "pallet-salary", "pallet-transaction-payment", "pallet-xcm", "parity-scale-codec 3.6.4", "polkadot-parachain", + "polkadot-primitives", "polkadot-runtime-parachains", "polkadot-test-runtime", "primitive-types", diff --git a/xcm/xcm-builder/Cargo.toml b/xcm/xcm-builder/Cargo.toml index fec354d0caea..702d5bd7fa06 100644 --- a/xcm/xcm-builder/Cargo.toml +++ b/xcm/xcm-builder/Cargo.toml @@ -29,6 +29,9 @@ polkadot-parachain = { path = "../../parachain", default-features = false } primitive-types = "0.12.1" pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-xcm = { path = "../pallet-xcm" } +pallet-salary = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-assets = { git = "https://github.com/paritytech/substrate", branch = "master" } +primitives = { package = "polkadot-primitives", path = "../../primitives" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } assert_matches = "1.5.0" polkadot-test-runtime = { path = "../../runtime/test-runtime" } diff --git a/xcm/xcm-builder/src/tests/mock.rs b/xcm/xcm-builder/src/tests/mock.rs index 9be034596f43..0e7b748106ef 100644 --- a/xcm/xcm-builder/src/tests/mock.rs +++ b/xcm/xcm-builder/src/tests/mock.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +//! Mock implementations to test XCM builder configuration types. + use crate::{ barriers::{AllowSubscriptionsFrom, RespectSuspension, TrailingSetTopicAsId}, test_utils::*, @@ -42,7 +44,7 @@ pub use sp_std::{ marker::PhantomData, }; pub use xcm::latest::{prelude::*, Weight}; -use xcm_executor::traits::Properties; +use xcm_executor::traits::{Properties, QueryHandler, QueryResponseStatus}; pub use xcm_executor::{ traits::{ AssetExchange, AssetLock, CheckSuspension, ConvertOrigin, Enact, ExportXcm, FeeManager, @@ -410,6 +412,63 @@ pub fn response(query_id: u64) -> Option { }) } +/// Mock implementation of the [`QueryHandler`] trait for creating XCM success queries and expecting +/// responses. +pub struct TestQueryHandler(core::marker::PhantomData<(T, BlockNumber)>); +impl QueryHandler + for TestQueryHandler +{ + type QueryId = u64; + type BlockNumber = BlockNumber; + type Error = XcmError; + type UniversalLocation = T::UniversalLocation; + + fn new_query( + responder: impl Into, + _timeout: Self::BlockNumber, + _match_querier: impl Into, + ) -> Self::QueryId { + let query_id = 1; + expect_response(query_id, responder.into()); + query_id + } + + fn report_outcome( + message: &mut Xcm<()>, + responder: impl Into, + timeout: Self::BlockNumber, + ) -> Result { + let responder = responder.into(); + let destination = Self::UniversalLocation::get() + .invert_target(&responder) + .map_err(|()| XcmError::LocationNotInvertible)?; + let query_id = Self::new_query(responder, timeout, Here); + let response_info = QueryResponseInfo { destination, query_id, max_weight: Weight::zero() }; + let report_error = Xcm(vec![ReportError(response_info)]); + message.0.insert(0, SetAppendix(report_error)); + Ok(query_id) + } + + fn take_response(query_id: Self::QueryId) -> QueryResponseStatus { + QUERIES + .with(|q| { + q.borrow().get(&query_id).and_then(|v| match v { + ResponseSlot::Received(r) => Some(QueryResponseStatus::Ready { + response: r.clone(), + at: Self::BlockNumber::zero(), + }), + _ => Some(QueryResponseStatus::NotFound), + }) + }) + .unwrap_or(QueryResponseStatus::NotFound) + } + + #[cfg(feature = "runtime-benchmarks")] + fn expect_response(_id: Self::QueryId, _response: xcm::latest::Response) { + // Unnecessary since it's only a test implementation + } +} + parameter_types! { pub static ExecutorUniversalLocation: InteriorMultiLocation = (ByGenesis([0; 32]), Parachain(42)).into(); diff --git a/xcm/xcm-builder/src/tests/mod.rs b/xcm/xcm-builder/src/tests/mod.rs index 6daf1872f055..e11caf6282be 100644 --- a/xcm/xcm-builder/src/tests/mod.rs +++ b/xcm/xcm-builder/src/tests/mod.rs @@ -34,6 +34,7 @@ mod bridging; mod expecting; mod locking; mod origins; +mod pay; mod querying; mod transacting; mod version_subscriptions; diff --git a/xcm/xcm-builder/src/tests/pay/mock.rs b/xcm/xcm-builder/src/tests/pay/mock.rs new file mode 100644 index 000000000000..3231611d3dd8 --- /dev/null +++ b/xcm/xcm-builder/src/tests/pay/mock.rs @@ -0,0 +1,334 @@ +// Copyright (C) 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::traits::{AsEnsureOriginWithArg, Nothing}; + +use frame_support::derive_impl; + +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU32, Everything}, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +use polkadot_test_runtime::SignedExtra; +use primitives::{AccountIndex, BlakeTwo256, Signature}; +use sp_runtime::{generic, traits::MaybeEquivalence, AccountId32, BuildStorage}; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; + +pub type Address = sp_runtime::MultiAddress; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +pub type Header = generic::Header; +pub type Block = generic::Block; + +pub type BlockNumber = u32; +pub type AccountId = AccountId32; + +construct_runtime!( + pub struct Test { + System: frame_system, + Balances: pallet_balances, + Assets: pallet_assets, + Salary: pallet_salary, + XcmPallet: pallet_xcm, + } +); + +parameter_types! { + pub const BlockHashCount: BlockNumber = 250; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; + type BlockHashCount = BlockHashCount; + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type OnSetCode = (); + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; +} + +pub type Balance = u128; + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Test { + type MaxLocks = ConstU32<0>; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const AssetDeposit: u128 = 1_000_000; + pub const MetadataDepositBase: u128 = 1_000_000; + pub const MetadataDepositPerByte: u128 = 100_000; + pub const AssetAccountDeposit: u128 = 1_000_000; + pub const ApprovalDeposit: u128 = 1_000_000; + pub const AssetsStringLimit: u32 = 50; + pub const RemoveItemsLimit: u32 = 50; +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetIdForAssets; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type AssetAccountDeposit = AssetAccountDeposit; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = (); + type RemoveItemsLimit = RemoveItemsLimit; + type AssetIdParameter = AssetIdForAssets; + type CallbackHandle = (); +} + +parameter_types! { + pub const RelayLocation: MultiLocation = Here.into_location(); + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorMultiLocation = (ByGenesis([0; 32]), Parachain(42)).into(); + pub UnitWeightCost: u64 = 1_000; + pub static AdvertisedXcmVersion: u32 = 3; + pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); + pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); + pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub CheckingAccount: AccountId = XcmPallet::check_account(); +} + +type AssetIdForAssets = u128; + +pub struct FromMultiLocationToAsset( + core::marker::PhantomData<(MultiLocation, AssetId)>, +); +impl MaybeEquivalence + for FromMultiLocationToAsset +{ + fn convert(value: &MultiLocation) -> Option { + match value { + MultiLocation { parents: 0, interior: Here } => Some(0 as AssetIdForAssets), + MultiLocation { parents: 1, interior: Here } => Some(1 as AssetIdForAssets), + MultiLocation { parents: 0, interior: X2(PalletInstance(1), GeneralIndex(index)) } + if ![0, 1].contains(index) => + Some(*index as AssetIdForAssets), + _ => None, + } + } + + fn convert_back(value: &AssetIdForAssets) -> Option { + match value { + 0u128 => Some(MultiLocation { parents: 1, interior: Here }), + para_id @ 1..=1000 => + Some(MultiLocation { parents: 1, interior: X1(Parachain(*para_id as u32)) }), + _ => None, + } + } +} + +pub type LocalOriginToLocation = SignedToAccountId32; +pub type LocalAssetsTransactor = FungiblesAdapter< + Assets, + ConvertedConcreteId< + AssetIdForAssets, + Balance, + FromMultiLocationToAsset, + JustTry, + >, + SovereignAccountOf, + AccountId, + NoChecking, + CheckingAccount, +>; + +type OriginConverter = ( + pallet_xcm::XcmPassthrough, + SignedAccountId32AsNative, +); +type Barrier = AllowUnpaidExecutionFrom; + +pub struct DummyWeightTrader; +impl WeightTrader for DummyWeightTrader { + fn new() -> Self { + DummyWeightTrader + } + + fn buy_weight( + &mut self, + _weight: Weight, + _payment: xcm_executor::Assets, + _context: &XcmContext, + ) -> Result { + Ok(xcm_executor::Assets::default()) + } +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = TestMessageSender; + type AssetTransactor = LocalAssetsTransactor; + type OriginConverter = OriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = DummyWeightTrader; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; +} + +parameter_types! { + pub TreasuryAccountId: AccountId = AccountId::new([42u8; 32]); +} + +pub struct TreasuryToAccount; +impl ConvertLocation for TreasuryToAccount { + fn convert_location(location: &MultiLocation) -> Option { + match location { + MultiLocation { + parents: 1, + interior: + X2(Parachain(42), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }), + } => Some(TreasuryAccountId::get()), // Hardcoded test treasury account id + _ => None, + } + } +} + +type SovereignAccountOf = ( + AccountId32Aliases, + TreasuryToAccount, + HashedDescription>, +); + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = Some(Parachain(1000).into()); +} + +impl pallet_xcm::Config for Test { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = TestMessageSender; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = AdvertisedXcmVersion; + type TrustedLockers = (); + type SovereignAccountOf = SovereignAccountOf; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type MaxLockers = frame_support::traits::ConstU32<8>; + type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = EnsureRoot; +} + +pub const UNITS: Balance = 1_000_000_000_000; +pub const INITIAL_BALANCE: Balance = 100 * UNITS; +pub const MINIMUM_BALANCE: Balance = 1 * UNITS; + +pub fn sibling_chain_account_id(para_id: u32, account: [u8; 32]) -> AccountId { + let location: MultiLocation = + (Parent, Parachain(para_id), Junction::AccountId32 { id: account, network: None }).into(); + SovereignAccountOf::convert_location(&location).unwrap() +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let admin_account: AccountId = AccountId::new([0u8; 32]); + pallet_assets::GenesisConfig:: { + assets: vec![ + (0, admin_account.clone(), true, MINIMUM_BALANCE), + (1, admin_account.clone(), true, MINIMUM_BALANCE), + (100, admin_account.clone(), true, MINIMUM_BALANCE), + ], + metadata: vec![ + (0, "Native token".encode(), "NTV".encode(), 12), + (1, "Relay token".encode(), "RLY".encode(), 12), + (100, "Test token".encode(), "TST".encode(), 12), + ], + accounts: vec![ + (0, sibling_chain_account_id(42, [3u8; 32]), INITIAL_BALANCE), + (1, TreasuryAccountId::get(), INITIAL_BALANCE), + (100, TreasuryAccountId::get(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub fn next_block() { + System::set_block_number(System::block_number() + 1); +} + +pub fn run_to(block_number: BlockNumber) { + while System::block_number() < block_number { + next_block(); + } +} diff --git a/xcm/xcm-builder/src/tests/pay/mod.rs b/xcm/xcm-builder/src/tests/pay/mod.rs new file mode 100644 index 000000000000..8adf1ad2f5e1 --- /dev/null +++ b/xcm/xcm-builder/src/tests/pay/mod.rs @@ -0,0 +1,21 @@ +// Copyright (C) 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::*; + +mod mock; +mod pay; +mod salary; diff --git a/xcm/xcm-builder/src/tests/pay/pay.rs b/xcm/xcm-builder/src/tests/pay/pay.rs new file mode 100644 index 000000000000..28b2feec0c23 --- /dev/null +++ b/xcm/xcm-builder/src/tests/pay/pay.rs @@ -0,0 +1,158 @@ +// Copyright (C) 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 . + +//! Tests for making sure `PayOverXcm::pay` generates the correct message and sends it to the +//! correct destination + +use super::{mock::*, *}; +use frame_support::{assert_ok, traits::tokens::Pay}; + +/// Type representing both a location and an asset that is held at that location. +/// The id of the held asset is relative to the location where it is being held. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)] +pub struct AssetKind { + destination: MultiLocation, + asset_id: AssetId, +} + +pub struct LocatableAssetKindConverter; +impl sp_runtime::traits::Convert for LocatableAssetKindConverter { + fn convert(value: AssetKind) -> LocatableAssetId { + LocatableAssetId { asset_id: value.asset_id, location: value.destination } + } +} + +parameter_types! { + pub SenderAccount: AccountId = AccountId::new([3u8; 32]); + pub InteriorAccount: InteriorMultiLocation = AccountId32 { id: SenderAccount::get().into(), network: None }.into(); + pub InteriorBody: InteriorMultiLocation = Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into(); + pub Timeout: BlockNumber = 5; // 5 blocks +} + +/// Scenario: +/// Account #3 on the local chain, parachain 42, controls an amount of funds on parachain 2. +/// [`PayOverXcm::pay`] creates the correct message for account #3 to pay another account, account +/// #5, on parachain 2, remotely, in its native token. +#[test] +fn pay_over_xcm_works() { + let recipient = AccountId::new([5u8; 32]); + let asset_kind = + AssetKind { destination: (Parent, Parachain(2)).into(), asset_id: Here.into() }; + let amount = 10 * UNITS; + + new_test_ext().execute_with(|| { + // Check starting balance + assert_eq!(mock::Assets::balance(0, &recipient), 0); + + assert_ok!(PayOverXcm::< + InteriorAccount, + TestMessageSender, + TestQueryHandler, + Timeout, + AccountId, + AssetKind, + LocatableAssetKindConverter, + AliasesIntoAccountId32, + >::pay(&recipient, asset_kind, amount)); + + let expected_message = Xcm(vec![ + DescendOrigin(AccountId32 { id: SenderAccount::get().into(), network: None }.into()), + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { + destination: (Parent, Parachain(42)).into(), + query_id: 1, + max_weight: Weight::zero(), + })])), + TransferAsset { + assets: (Here, amount).into(), + beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), + }, + ]); + let expected_hash = fake_message_hash(&expected_message); + + assert_eq!( + sent_xcm(), + vec![((Parent, Parachain(2)).into(), expected_message, expected_hash)] + ); + + let (_, message, hash) = sent_xcm()[0].clone(); + let message = + Xcm::<::RuntimeCall>::from(message.clone()); + + // Execute message in parachain 2 with parachain 42's origin + let origin = (Parent, Parachain(42)); + XcmExecutor::::execute_xcm(origin, message, hash, Weight::MAX); + assert_eq!(mock::Assets::balance(0, &recipient), amount); + }); +} + +/// Scenario: +/// A pluralistic body, a Treasury, on the local chain, parachain 42, controls an amount of funds +/// on parachain 2. [`PayOverXcm::pay`] creates the correct message for the treasury to pay +/// another account, account #7, on parachain 2, remotely, in the relay's token. +#[test] +fn pay_over_xcm_governance_body() { + let recipient = AccountId::new([7u8; 32]); + let asset_kind = + AssetKind { destination: (Parent, Parachain(2)).into(), asset_id: Parent.into() }; + let amount = 10 * UNITS; + + let relay_asset_index = 1; + + new_test_ext().execute_with(|| { + // Check starting balance + assert_eq!(mock::Assets::balance(relay_asset_index, &recipient), 0); + + assert_ok!(PayOverXcm::< + InteriorBody, + TestMessageSender, + TestQueryHandler, + Timeout, + AccountId, + AssetKind, + LocatableAssetKindConverter, + AliasesIntoAccountId32, + >::pay(&recipient, asset_kind, amount)); + + let expected_message = Xcm(vec![ + DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()), + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { + destination: (Parent, Parachain(42)).into(), + query_id: 1, + max_weight: Weight::zero(), + })])), + TransferAsset { + assets: (Parent, amount).into(), + beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), + }, + ]); + let expected_hash = fake_message_hash(&expected_message); + assert_eq!( + sent_xcm(), + vec![((Parent, Parachain(2)).into(), expected_message, expected_hash)] + ); + + let (_, message, hash) = sent_xcm()[0].clone(); + let message = + Xcm::<::RuntimeCall>::from(message.clone()); + + // Execute message in parachain 2 with parachain 42's origin + let origin = (Parent, Parachain(42)); + XcmExecutor::::execute_xcm(origin, message, hash, Weight::MAX); + assert_eq!(mock::Assets::balance(relay_asset_index, &recipient), amount); + }); +} diff --git a/xcm/xcm-builder/src/tests/pay/salary.rs b/xcm/xcm-builder/src/tests/pay/salary.rs new file mode 100644 index 000000000000..1d40345f302a --- /dev/null +++ b/xcm/xcm-builder/src/tests/pay/salary.rs @@ -0,0 +1,172 @@ +// Copyright (C) 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 . + +//! Tests for the integration between `PayOverXcm` and the salary pallet + +use super::{mock::*, *}; + +use frame_support::{ + assert_ok, + traits::{tokens::GetSalary, RankedMembers}, +}; +use sp_runtime::{traits::ConvertToValue, DispatchResult}; + +parameter_types! { + pub Interior: InteriorMultiLocation = Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into(); + pub Timeout: BlockNumber = 5; + pub AssetHub: MultiLocation = (Parent, Parachain(1)).into(); + pub AssetIdGeneralIndex: u128 = 100; + pub AssetHubAssetId: AssetId = (PalletInstance(1), GeneralIndex(AssetIdGeneralIndex::get())).into(); + pub LocatableAsset: LocatableAssetId = LocatableAssetId { asset_id: AssetHubAssetId::get(), location: AssetHub::get() }; +} + +type SalaryPayOverXcm = PayOverXcm< + Interior, + TestMessageSender, + TestQueryHandler, + Timeout, + AccountId, + (), + ConvertToValue, + AliasesIntoAccountId32, +>; + +type Rank = u128; + +thread_local! { + pub static CLUB: RefCell> = RefCell::new(BTreeMap::new()); +} + +pub struct TestClub; +impl RankedMembers for TestClub { + type AccountId = AccountId; + type Rank = Rank; + + fn min_rank() -> Self::Rank { + 0 + } + fn rank_of(who: &Self::AccountId) -> Option { + CLUB.with(|club| club.borrow().get(who).cloned()) + } + fn induct(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| club.borrow_mut().insert(who.clone(), 0)); + Ok(()) + } + fn promote(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| { + club.borrow_mut().entry(who.clone()).and_modify(|rank| *rank += 1); + }); + Ok(()) + } + fn demote(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| match club.borrow().get(who) { + None => Err(sp_runtime::DispatchError::Unavailable), + Some(&0) => { + club.borrow_mut().remove(&who); + Ok(()) + }, + Some(_) => { + club.borrow_mut().entry(who.clone()).and_modify(|rank| *rank += 1); + Ok(()) + }, + }) + } +} + +fn set_rank(who: AccountId, rank: u128) { + CLUB.with(|club| club.borrow_mut().insert(who, rank)); +} + +parameter_types! { + pub const RegistrationPeriod: BlockNumber = 2; + pub const PayoutPeriod: BlockNumber = 2; + pub const FixedSalaryAmount: Balance = 10 * UNITS; + pub static Budget: Balance = FixedSalaryAmount::get(); +} + +pub struct FixedSalary; +impl GetSalary for FixedSalary { + fn get_salary(_rank: Rank, _who: &AccountId) -> Balance { + FixedSalaryAmount::get() + } +} + +impl pallet_salary::Config for Test { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Paymaster = SalaryPayOverXcm; + type Members = TestClub; + type Salary = FixedSalary; + type RegistrationPeriod = RegistrationPeriod; + type PayoutPeriod = PayoutPeriod; + type Budget = Budget; +} + +/// Scenario: +/// The salary pallet is used to pay a member over XCM. +/// The correct XCM message is generated and when executed in the remote chain, +/// the member receives the salary. +#[test] +fn salary_pay_over_xcm_works() { + let recipient = AccountId::new([1u8; 32]); + + new_test_ext().execute_with(|| { + // Set the recipient as a member of a ranked collective + set_rank(recipient.clone(), 1); + + // Check starting balance + assert_eq!(mock::Assets::balance(AssetIdGeneralIndex::get(), &recipient.clone()), 0); + + // Use salary pallet to call `PayOverXcm::pay` + assert_ok!(Salary::init(RuntimeOrigin::signed(recipient.clone()))); + run_to(5); + assert_ok!(Salary::induct(RuntimeOrigin::signed(recipient.clone()))); + assert_ok!(Salary::bump(RuntimeOrigin::signed(recipient.clone()))); + assert_ok!(Salary::register(RuntimeOrigin::signed(recipient.clone()))); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(recipient.clone()))); + + // Get message from mock transport layer + let (_, message, hash) = sent_xcm()[0].clone(); + // Change type from `Xcm<()>` to `Xcm` to be able to execute later + let message = + Xcm::<::RuntimeCall>::from(message.clone()); + + let expected_message: Xcm = Xcm::(vec![ + DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()), + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { + destination: (Parent, Parachain(42)).into(), + query_id: 1, + max_weight: Weight::zero(), + })])), + TransferAsset { + assets: (AssetHubAssetId::get(), FixedSalaryAmount::get()).into(), + beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), + }, + ]); + assert_eq!(message, expected_message); + + // Execute message as the asset hub + XcmExecutor::::execute_xcm((Parent, Parachain(42)), message, hash, Weight::MAX); + + // Recipient receives the payment + assert_eq!( + mock::Assets::balance(AssetIdGeneralIndex::get(), &recipient), + FixedSalaryAmount::get() + ); + }); +} From 53957c4ff16728cb89e7e8a7bb009d61387b9657 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Mon, 21 Aug 2023 08:49:29 +1200 Subject: [PATCH 37/45] Fix cargo.toml (#7645) * fix cargo.toml * update arrayvec --- Cargo.lock | 843 +++++++++--------- node/core/prospective-parachains/Cargo.toml | 9 +- .../network/statement-distribution/Cargo.toml | 2 +- .../src/legacy_v1/mod.rs | 6 +- 4 files changed, 409 insertions(+), 451 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be03ec3daa41..c963a3f5eef1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -778,7 +778,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "hash-db", "log", @@ -826,28 +826,16 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", -] - [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty 2.0.0", - "radium 0.7.0", + "funty", + "radium", "tap", - "wyz 0.5.1", + "wyz", ] [[package]] @@ -957,7 +945,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6" dependencies = [ "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", ] @@ -2779,7 +2767,7 @@ dependencies = [ "futures-timer", "log", "num-traits", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "scale-info", ] @@ -2843,9 +2831,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", ] [[package]] @@ -2866,14 +2854,14 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-support-procedural", "frame-system", "linregress", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "paste", "scale-info", "serde", @@ -2891,7 +2879,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "Inflector", "array-bytes", @@ -2907,7 +2895,7 @@ dependencies = [ "lazy_static", "linked-hash-map", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rand 0.8.5", "rand_pcg", "sc-block-builder", @@ -2939,7 +2927,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2950,12 +2938,12 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-election-provider-solution-type", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-core", @@ -2967,12 +2955,12 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "frame-try-runtime", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -2988,7 +2976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692" dependencies = [ "cfg-if", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", ] @@ -2996,14 +2984,14 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-recursion", "futures", "indicatif", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "serde", "sp-core", "sp-io", @@ -3018,7 +3006,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "aquamarine", "bitflags 1.3.2", @@ -3030,7 +3018,7 @@ dependencies = [ "k256", "log", "macro_magic", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "paste", "scale-info", "serde", @@ -3056,7 +3044,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "Inflector", "cfg-expr", @@ -3074,7 +3062,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3086,7 +3074,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro2", "quote", @@ -3096,14 +3084,14 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-executive", "frame-support", "frame-support-test-pallet", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "pretty_assertions", "rustversion", "scale-info", @@ -3123,11 +3111,11 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-runtime", @@ -3136,12 +3124,12 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "cfg-if", "frame-support", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -3155,12 +3143,12 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", @@ -3170,19 +3158,19 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-api", ] [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-api", "sp-runtime", "sp-std", @@ -3214,12 +3202,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "funty" version = "2.0.0" @@ -3360,7 +3342,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "chrono", "frame-election-provider-support", @@ -3875,7 +3857,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", ] [[package]] @@ -4273,7 +4255,7 @@ dependencies = [ name = "kusama-runtime" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -4335,7 +4317,7 @@ dependencies = [ "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", @@ -5364,11 +5346,11 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sc-offchain", "sp-api", @@ -5383,11 +5365,11 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "anyhow", "jsonrpsee", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "serde", "sp-api", "sp-blockchain", @@ -5920,12 +5902,12 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", @@ -5935,12 +5917,12 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "pallet-session", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-authority-discovery", @@ -5951,12 +5933,12 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -5965,7 +5947,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", @@ -5974,7 +5956,7 @@ dependencies = [ "pallet-authorship", "pallet-session", "pallet-timestamp", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-consensus-babe", @@ -5989,7 +5971,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "aquamarine", "docify", @@ -5999,7 +5981,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6011,7 +5993,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -6030,13 +6012,13 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -6045,13 +6027,13 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "pallet-authorship", "pallet-session", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-consensus-beefy", @@ -6064,7 +6046,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -6074,7 +6056,7 @@ dependencies = [ "pallet-beefy", "pallet-mmr", "pallet-session", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -6088,14 +6070,14 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-treasury", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6106,7 +6088,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6114,7 +6096,7 @@ dependencies = [ "log", "pallet-bounties", "pallet-treasury", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6125,13 +6107,13 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6142,13 +6124,13 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "assert_matches", "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-io", @@ -6159,13 +6141,13 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -6177,7 +6159,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6185,7 +6167,7 @@ dependencies = [ "frame-system", "log", "pallet-election-provider-support-benchmarking", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rand 0.8.5", "scale-info", "sp-arithmetic", @@ -6200,12 +6182,12 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-npos-elections", "sp-runtime", ] @@ -6213,13 +6195,13 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6232,7 +6214,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "docify", "frame-benchmarking", @@ -6240,7 +6222,7 @@ dependencies = [ "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6251,7 +6233,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6259,7 +6241,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-consensus-grandpa", @@ -6274,13 +6256,13 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "enumflags2", "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6290,14 +6272,14 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-authorship", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-application-crypto", "sp-core", @@ -6310,12 +6292,12 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6327,13 +6309,13 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6344,13 +6326,13 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-core", @@ -6363,12 +6345,12 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6380,13 +6362,13 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6396,12 +6378,12 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-core", @@ -6412,13 +6394,13 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6431,7 +6413,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6440,7 +6422,7 @@ dependencies = [ "pallet-bags-list", "pallet-nomination-pools", "pallet-staking", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-runtime-interface", @@ -6451,10 +6433,10 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "pallet-nomination-pools", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-api", "sp-std", ] @@ -6462,13 +6444,13 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-runtime", @@ -6479,7 +6461,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6493,7 +6475,7 @@ dependencies = [ "pallet-offences", "pallet-session", "pallet-staking", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-staking", @@ -6503,13 +6485,13 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6520,12 +6502,12 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6535,13 +6517,13 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-arithmetic", "sp-core", @@ -6553,12 +6535,12 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6568,14 +6550,14 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "assert_matches", "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-arithmetic", @@ -6587,7 +6569,7 @@ dependencies = [ [[package]] name = "pallet-salary" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#96f8c97dff7f419a349ee01d02613445ba4a41f8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6605,14 +6587,14 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "docify", "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6623,14 +6605,14 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", "log", "pallet-timestamp", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6644,7 +6626,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6660,13 +6642,13 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rand_chacha 0.2.2", "scale-info", "sp-arithmetic", @@ -6678,7 +6660,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6687,7 +6669,7 @@ dependencies = [ "log", "pallet-authorship", "pallet-session", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rand_chacha 0.2.2", "scale-info", "serde", @@ -6701,7 +6683,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6712,7 +6694,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "log", "sp-arithmetic", @@ -6721,22 +6703,22 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-api", ] [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6747,12 +6729,12 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-io", "sp-runtime", @@ -6762,13 +6744,13 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-inherents", "sp-io", @@ -6780,14 +6762,14 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-treasury", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -6799,11 +6781,11 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -6815,11 +6797,11 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-api", "sp-blockchain", "sp-core", @@ -6831,10 +6813,10 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "pallet-transaction-payment", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-api", "sp-runtime", "sp-weights", @@ -6843,14 +6825,14 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "impl-trait-for-tuples", "pallet-balances", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-runtime", @@ -6860,13 +6842,13 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -6875,12 +6857,12 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-io", @@ -6891,13 +6873,13 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -6906,12 +6888,12 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-api", "sp-runtime", @@ -6928,7 +6910,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-runtime-parachains", "scale-info", @@ -6953,7 +6935,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-xcm", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", "scale-info", @@ -6987,19 +6969,6 @@ dependencies = [ "snap", ] -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.4", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "serde", -] - [[package]] name = "parity-scale-codec" version = "3.6.4" @@ -7007,7 +6976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" dependencies = [ "arrayvec 0.7.4", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "bytes", "impl-trait-for-tuples", @@ -7331,7 +7300,7 @@ version = "0.9.43" dependencies = [ "always-assert", "assert_matches", - "bitvec 1.0.1", + "bitvec", "env_logger 0.9.3", "futures", "futures-timer", @@ -7362,7 +7331,7 @@ dependencies = [ "futures", "futures-timer", "lru 0.11.0", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7392,7 +7361,7 @@ dependencies = [ "futures-timer", "log", "lru 0.11.0", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7443,13 +7412,13 @@ name = "polkadot-collator-protocol" version = "0.9.43" dependencies = [ "assert_matches", - "bitvec 1.0.1", + "bitvec", "env_logger 0.9.3", "fatality", "futures", "futures-timer", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7472,7 +7441,7 @@ dependencies = [ name = "polkadot-core-primitives" version = "0.9.43" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-runtime", @@ -7493,7 +7462,7 @@ dependencies = [ "indexmap 1.9.3", "lazy_static", "lru 0.11.0", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7517,7 +7486,7 @@ name = "polkadot-erasure-coding" version = "0.9.43" dependencies = [ "criterion", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-primitives", "polkadot-primitives", "reed-solomon-novelpoly", @@ -7565,7 +7534,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-metrics", "polkadot-node-network-protocol", @@ -7589,7 +7558,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "futures", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7610,7 +7579,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "async-trait", - "bitvec 1.0.1", + "bitvec", "derive_more", "futures", "futures-timer", @@ -7618,7 +7587,7 @@ dependencies = [ "kvdb-memorydb", "lru 0.11.0", "merlin 2.0.1", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -7648,14 +7617,14 @@ name = "polkadot-node-core-av-store" version = "0.9.43" dependencies = [ "assert_matches", - "bitvec 1.0.1", + "bitvec", "env_logger 0.9.3", "futures", "futures-timer", "kvdb", "kvdb-memorydb", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "polkadot-erasure-coding", "polkadot-node-jaeger", @@ -7678,7 +7647,7 @@ name = "polkadot-node-core-backing" version = "0.9.43" dependencies = [ "assert_matches", - "bitvec 1.0.1", + "bitvec", "fatality", "futures", "polkadot-erasure-coding", @@ -7723,7 +7692,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-core-pvf", "polkadot-node-metrics", "polkadot-node-primitives", @@ -7746,7 +7715,7 @@ version = "0.9.43" dependencies = [ "futures", "maplit", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-metrics", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7768,7 +7737,7 @@ dependencies = [ "futures-timer", "kvdb", "kvdb-memorydb", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7791,7 +7760,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "lru 0.11.0", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -7826,13 +7795,13 @@ dependencies = [ [[package]] name = "polkadot-node-core-prospective-parachains" -version = "0.9.16" +version = "0.9.43" dependencies = [ "assert_matches", - "bitvec 1.0.1", + "bitvec", "fatality", "futures", - "parity-scale-codec 2.3.1", + "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -7853,7 +7822,7 @@ dependencies = [ name = "polkadot-node-core-provisioner" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "fatality", "futures", "futures-timer", @@ -7879,7 +7848,7 @@ dependencies = [ "futures-timer", "hex-literal 0.3.4", "libc", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "pin-project", "polkadot-core-primitives", "polkadot-node-core-pvf", @@ -7936,7 +7905,7 @@ dependencies = [ "futures", "landlock", "libc", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "sc-executor", @@ -7957,7 +7926,7 @@ version = "0.9.43" dependencies = [ "cpu-time", "futures", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-parachain", "polkadot-primitives", @@ -7976,7 +7945,7 @@ version = "0.9.43" dependencies = [ "futures", "libc", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-parachain", "polkadot-primitives", @@ -8020,7 +7989,7 @@ dependencies = [ "lazy_static", "log", "mick-jaeger", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-primitives", @@ -8040,7 +8009,7 @@ dependencies = [ "futures-timer", "hyper", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "polkadot-test-service", "prioritized-metered-channel", @@ -8062,12 +8031,12 @@ version = "0.9.43" dependencies = [ "async-channel", "async-trait", - "bitvec 1.0.1", + "bitvec", "derive_more", "fatality", "futures", "hex", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", @@ -8086,7 +8055,7 @@ version = "0.9.43" dependencies = [ "bounded-vec", "futures", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-erasure-coding", "polkadot-parachain", "polkadot-primitives", @@ -8171,7 +8140,7 @@ dependencies = [ "log", "lru 0.11.0", "parity-db", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.11.2", "pin-project", "polkadot-node-jaeger", @@ -8226,7 +8195,7 @@ dependencies = [ "bounded-collections", "derive_more", "frame-support", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-core-primitives", "scale-info", "serde", @@ -8256,9 +8225,9 @@ dependencies = [ name = "polkadot-primitives" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "hex-literal 0.4.1", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "scale-info", @@ -8324,7 +8293,7 @@ dependencies = [ name = "polkadot-runtime" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -8381,7 +8350,7 @@ dependencies = [ "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-constants", @@ -8427,7 +8396,7 @@ dependencies = [ name = "polkadot-runtime-common" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -8449,7 +8418,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-treasury", "pallet-vesting", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-runtime-parachains", @@ -8493,7 +8462,7 @@ version = "0.9.43" dependencies = [ "bs58", "frame-benchmarking", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "sp-std", "sp-tracing", @@ -8505,7 +8474,7 @@ version = "0.9.43" dependencies = [ "assert_matches", "bitflags 1.3.2", - "bitvec 1.0.1", + "bitvec", "derive_more", "frame-benchmarking", "frame-support", @@ -8523,7 +8492,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "pallet-vesting", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-primitives-test-helpers", @@ -8581,7 +8550,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-db", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -8685,15 +8654,15 @@ dependencies = [ name = "polkadot-statement-distribution" version = "0.9.43" dependencies = [ - "arrayvec 0.5.2", + "arrayvec 0.7.4", "assert_matches", "async-channel", - "bitvec 1.0.1", + "bitvec", "fatality", "futures", "futures-timer", "indexmap 1.9.3", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -8720,7 +8689,7 @@ dependencies = [ name = "polkadot-statement-table" version = "0.9.43" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-primitives", "sp-core", ] @@ -8731,7 +8700,7 @@ version = "0.9.43" dependencies = [ "frame-benchmarking", "futures", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-node-subsystem", "polkadot-primitives", "polkadot-test-runtime", @@ -8789,7 +8758,7 @@ dependencies = [ name = "polkadot-test-runtime" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "frame-election-provider-support", "frame-executive", "frame-support", @@ -8813,7 +8782,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-vesting", "pallet-xcm", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -9366,12 +9335,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -9818,7 +9781,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -10121,7 +10084,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "log", "sp-core", @@ -10132,7 +10095,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "futures", @@ -10141,7 +10104,7 @@ dependencies = [ "libp2p", "log", "multihash", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "prost", "prost-build", "rand 0.8.5", @@ -10160,12 +10123,12 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -10183,9 +10146,9 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sp-api", "sp-block-builder", @@ -10198,7 +10161,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10217,7 +10180,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10228,7 +10191,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "chrono", @@ -10238,7 +10201,7 @@ dependencies = [ "libp2p-identity", "log", "names 0.13.0", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rand 0.8.5", "regex", "rpassword", @@ -10267,12 +10230,12 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "fnv", "futures", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-executor", "sc-transaction-pool-api", @@ -10293,7 +10256,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "hash-db", "kvdb", @@ -10302,7 +10265,7 @@ dependencies = [ "linked-hash-map", "log", "parity-db", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-client-api", "sc-state-db", @@ -10319,7 +10282,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "futures", @@ -10344,7 +10307,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "fork-tree", @@ -10353,7 +10316,7 @@ dependencies = [ "num-bigint", "num-rational", "num-traits", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-client-api", "sc-consensus", @@ -10380,7 +10343,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "jsonrpsee", @@ -10402,7 +10365,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "async-channel", @@ -10410,7 +10373,7 @@ dependencies = [ "fnv", "futures", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-client-api", "sc-consensus", @@ -10436,12 +10399,12 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-consensus-beefy", "sc-rpc", @@ -10455,10 +10418,10 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "fork-tree", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sc-consensus", "sp-blockchain", @@ -10468,7 +10431,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ahash 0.8.3", "array-bytes", @@ -10479,7 +10442,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", "sc-block-builder", @@ -10509,13 +10472,13 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "finality-grandpa", "futures", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sc-consensus-grandpa", "sc-rpc", @@ -10529,13 +10492,13 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "futures", "futures-timer", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sc-consensus", "sc-telemetry", @@ -10552,9 +10515,9 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-executor-common", "sc-executor-wasmtime", @@ -10574,7 +10537,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10586,7 +10549,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "anyhow", "cfg-if", @@ -10603,7 +10566,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ansi_term", "futures", @@ -10619,7 +10582,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -10633,7 +10596,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "async-channel", @@ -10649,7 +10612,7 @@ dependencies = [ "linked_hash_set", "log", "mockall", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "partial_sort", "pin-project", @@ -10674,7 +10637,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-channel", "cid", @@ -10694,13 +10657,13 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "bitflags 1.3.2", "futures", "libp2p-identity", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "prost-build", "sc-consensus", "sp-consensus", @@ -10711,7 +10674,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ahash 0.8.3", "futures", @@ -10729,14 +10692,14 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "async-channel", "futures", "libp2p-identity", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "prost", "prost-build", "sc-client-api", @@ -10750,7 +10713,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "async-channel", @@ -10761,7 +10724,7 @@ dependencies = [ "libp2p", "log", "mockall", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "prost", "prost-build", "sc-client-api", @@ -10784,13 +10747,13 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "futures", "libp2p", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-network", "sc-network-common", "sc-utils", @@ -10802,7 +10765,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "bytes", @@ -10815,7 +10778,7 @@ dependencies = [ "log", "num_cpus", "once_cell", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", "sc-client-api", @@ -10836,7 +10799,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10845,12 +10808,12 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-block-builder", "sc-chain-spec", @@ -10876,10 +10839,10 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "jsonrpsee", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-chain-spec", "sc-transaction-pool-api", "scale-info", @@ -10895,7 +10858,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "http", "jsonrpsee", @@ -10910,7 +10873,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "futures", @@ -10918,7 +10881,7 @@ dependencies = [ "hex", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-chain-spec", "sc-client-api", @@ -10938,7 +10901,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "directories", @@ -10947,7 +10910,7 @@ dependencies = [ "futures-timer", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "pin-project", "rand 0.8.5", @@ -11002,10 +10965,10 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sp-core", ] @@ -11013,7 +10976,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "clap 4.3.19", "fs4", @@ -11027,10 +10990,10 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "jsonrpsee", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-chain-spec", "sc-client-api", "sc-consensus-babe", @@ -11046,7 +11009,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "libc", @@ -11065,7 +11028,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "chrono", "futures", @@ -11084,7 +11047,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ansi_term", "atty", @@ -11113,7 +11076,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11124,14 +11087,14 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "futures", "futures-timer", "linked-hash-map", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sc-client-api", "sc-transaction-pool-api", @@ -11150,12 +11113,12 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "futures", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "serde", "sp-blockchain", "sp-core", @@ -11166,7 +11129,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-channel", "futures", @@ -11184,10 +11147,10 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ - "bitvec 1.0.1", + "bitvec", "cfg-if", "derive_more", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info-derive", "serde", ] @@ -11666,7 +11629,7 @@ name = "slot-range-helper" version = "0.9.43" dependencies = [ "enumn", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "paste", "sp-runtime", "sp-std", @@ -11750,11 +11713,11 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "hash-db", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-api-proc-macro", "sp-core", @@ -11771,7 +11734,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "Inflector", "blake2", @@ -11785,9 +11748,9 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -11798,11 +11761,11 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "integer-sqrt", "num-traits", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-std", @@ -11812,9 +11775,9 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-api", "sp-application-crypto", @@ -11825,7 +11788,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "sp-api", "sp-inherents", @@ -11836,11 +11799,11 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "schnellru", "sp-api", @@ -11854,7 +11817,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "futures", @@ -11869,10 +11832,10 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-api", "sp-application-crypto", @@ -11886,10 +11849,10 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -11905,10 +11868,10 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "lazy_static", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -11924,11 +11887,11 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "finality-grandpa", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -11942,9 +11905,9 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-std", @@ -11954,7 +11917,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11973,7 +11936,7 @@ dependencies = [ "libsecp256k1", "log", "merlin 2.0.1", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "paste", "primitive-types", @@ -12001,7 +11964,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "blake2b_simd", "byteorder", @@ -12014,7 +11977,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "quote", "sp-core-hashing", @@ -12024,7 +11987,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12033,7 +11996,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro2", "quote", @@ -12043,10 +12006,10 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "environmental", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-std", "sp-storage", ] @@ -12054,7 +12017,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "serde_json", "sp-api", @@ -12065,11 +12028,11 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "impl-trait-for-tuples", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-runtime", "sp-std", @@ -12079,14 +12042,14 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "bytes", "ed25519", "ed25519-dalek", "libsecp256k1", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rustversion", "secp256k1", "sp-core", @@ -12104,7 +12067,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "lazy_static", "sp-core", @@ -12115,9 +12078,9 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "sp-core", "sp-externalities", @@ -12127,7 +12090,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "thiserror", "zstd 0.12.4", @@ -12136,10 +12099,10 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-metadata", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-std", ] @@ -12147,11 +12110,11 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ckb-merkle-mountain-range", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-api", @@ -12165,9 +12128,9 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-arithmetic", @@ -12179,7 +12142,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "sp-api", "sp-core", @@ -12189,7 +12152,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "backtrace", "lazy_static", @@ -12199,7 +12162,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "rustc-hash", "serde", @@ -12209,13 +12172,13 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "either", "hash256-std-hasher", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "paste", "rand 0.8.5", "scale-info", @@ -12231,11 +12194,11 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "bytes", "impl-trait-for-tuples", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "primitive-types", "sp-externalities", "sp-runtime-interface-proc-macro", @@ -12249,7 +12212,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "Inflector", "proc-macro-crate", @@ -12261,9 +12224,9 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-api", "sp-core", @@ -12276,10 +12239,10 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "impl-trait-for-tuples", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-core", @@ -12290,11 +12253,11 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "hash-db", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", "smallvec", @@ -12311,13 +12274,13 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "aes-gcm 0.10.2", "curve25519-dalek 3.2.0", "ed25519-dalek", "hkdf", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "rand 0.8.5", "scale-info", "sha2 0.10.7", @@ -12335,15 +12298,15 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "impl-serde", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "ref-cast", "serde", "sp-debug-derive", @@ -12353,10 +12316,10 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-inherents", "sp-runtime", "sp-std", @@ -12366,9 +12329,9 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-std", "tracing", "tracing-core", @@ -12378,7 +12341,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "sp-api", "sp-runtime", @@ -12387,10 +12350,10 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "sp-core", "sp-inherents", @@ -12402,7 +12365,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ahash 0.8.3", "hash-db", @@ -12410,7 +12373,7 @@ dependencies = [ "lazy_static", "memory-db", "nohash-hasher", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parking_lot 0.12.1", "scale-info", "schnellru", @@ -12425,10 +12388,10 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "impl-serde", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "parity-wasm", "scale-info", "serde", @@ -12442,9 +12405,9 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "proc-macro2", "quote", "syn 2.0.28", @@ -12453,12 +12416,12 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-std", "wasmtime", ] @@ -12466,9 +12429,9 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "smallvec", @@ -12555,7 +12518,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-staking", "pallet-transaction-payment", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "paste", "polkadot-core-primitives", "polkadot-runtime", @@ -12707,18 +12670,18 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "frame-system-rpc-runtime-api", "futures", "jsonrpsee", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-rpc-api", "sc-transaction-pool-api", "sp-api", @@ -12731,7 +12694,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "hyper", "log", @@ -12743,7 +12706,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "jsonrpsee", @@ -12756,10 +12719,10 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "jsonrpsee", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sc-rpc-api", "serde", @@ -12773,12 +12736,12 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "array-bytes", "async-trait", "futures", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-client-api", "sc-client-db", "sc-consensus", @@ -12799,7 +12762,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12809,7 +12772,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12820,7 +12783,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "ansi_term", "build-helper", @@ -13041,7 +13004,7 @@ name = "test-parachain-adder" version = "0.9.43" dependencies = [ "dlmalloc", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "sp-io", "sp-std", @@ -13057,7 +13020,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -13090,7 +13053,7 @@ version = "0.9.43" dependencies = [ "dlmalloc", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "sp-io", "sp-std", @@ -13106,7 +13069,7 @@ dependencies = [ "futures", "futures-timer", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-cli", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -13129,7 +13092,7 @@ dependencies = [ name = "test-parachains" version = "0.9.43" dependencies = [ - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-core", "test-parachain-adder", "test-parachain-halt", @@ -13728,7 +13691,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#ecd503d49029236cc43d6de8c5068188c0fc1ef8" +source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" dependencies = [ "async-trait", "clap 4.3.19", @@ -13736,7 +13699,7 @@ dependencies = [ "frame-try-runtime", "hex", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sc-cli", "sc-executor", "serde", @@ -14670,7 +14633,7 @@ dependencies = [ name = "westend-runtime" version = "0.9.43" dependencies = [ - "bitvec 1.0.1", + "bitvec", "frame-benchmarking", "frame-election-provider-support", "frame-executive", @@ -14725,7 +14688,7 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "pallet-xcm-benchmarks", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", @@ -15047,12 +15010,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "wyz" version = "0.5.1" @@ -15131,7 +15088,7 @@ dependencies = [ "hex-literal 0.4.1", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "scale-info", "serde", "sp-io", @@ -15153,7 +15110,7 @@ dependencies = [ "pallet-salary", "pallet-transaction-payment", "pallet-xcm", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-parachains", @@ -15178,7 +15135,7 @@ dependencies = [ "frame-support", "impl-trait-for-tuples", "log", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "sp-arithmetic", "sp-core", "sp-io", @@ -15223,7 +15180,7 @@ name = "xcm-simulator" version = "0.9.43" dependencies = [ "frame-support", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "paste", "polkadot-core-primitives", "polkadot-parachain", @@ -15246,7 +15203,7 @@ dependencies = [ "pallet-message-queue", "pallet-uniques", "pallet-xcm", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -15273,7 +15230,7 @@ dependencies = [ "pallet-balances", "pallet-message-queue", "pallet-xcm", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime-parachains", @@ -15343,7 +15300,7 @@ version = "0.9.43" dependencies = [ "futures-util", "lazy_static", - "parity-scale-codec 3.6.4", + "parity-scale-codec", "reqwest", "serde", "serde_json", diff --git a/node/core/prospective-parachains/Cargo.toml b/node/core/prospective-parachains/Cargo.toml index b088202d3736..8afd0e4e8d17 100644 --- a/node/core/prospective-parachains/Cargo.toml +++ b/node/core/prospective-parachains/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "polkadot-node-core-prospective-parachains" -version = "0.9.16" -authors = ["Parity Technologies "] -edition = "2018" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true [dependencies] futures = "0.3.19" gum = { package = "tracing-gum", path = "../../gum" } -parity-scale-codec = "2" +parity-scale-codec = "3.6.4" thiserror = "1.0.30" fatality = "0.0.6" bitvec = "1" diff --git a/node/network/statement-distribution/Cargo.toml b/node/network/statement-distribution/Cargo.toml index dadd07613713..b9d52bda5706 100644 --- a/node/network/statement-distribution/Cargo.toml +++ b/node/network/statement-distribution/Cargo.toml @@ -17,7 +17,7 @@ polkadot-node-subsystem = {path = "../../subsystem" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-network-protocol = { path = "../../network/protocol" } -arrayvec = "0.5.2" +arrayvec = "0.7.4" indexmap = "1.9.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } thiserror = "1.0.31" diff --git a/node/network/statement-distribution/src/legacy_v1/mod.rs b/node/network/statement-distribution/src/legacy_v1/mod.rs index 219151daa020..b5895cb9f65b 100644 --- a/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -160,8 +160,8 @@ impl RecentOutdatedHeads { /// via other means. #[derive(Default)] struct VcPerPeerTracker { - local_observed: arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, - remote_observed: arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, + local_observed: arrayvec::ArrayVec, + remote_observed: arrayvec::ArrayVec, } impl VcPerPeerTracker { @@ -193,7 +193,7 @@ impl VcPerPeerTracker { } fn note_hash( - observed: &mut arrayvec::ArrayVec<[CandidateHash; VC_THRESHOLD]>, + observed: &mut arrayvec::ArrayVec, h: CandidateHash, ) -> bool { if observed.contains(&h) { From aba8beefb557d5a5bcb576b1d85a98108b29cc34 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Mon, 21 Aug 2023 06:55:15 +1000 Subject: [PATCH 38/45] stop scheduler migration pre/post hooks failing after migration (#7638) --- runtime/parachains/src/scheduler/migration.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/runtime/parachains/src/scheduler/migration.rs b/runtime/parachains/src/scheduler/migration.rs index 4284b979264b..32ac9deaf68f 100644 --- a/runtime/parachains/src/scheduler/migration.rs +++ b/runtime/parachains/src/scheduler/migration.rs @@ -109,10 +109,6 @@ pub mod v1 { "Scheduled before migration: {}", v0::Scheduled::::get().len() ); - ensure!( - StorageVersion::get::>() == 0, - "Storage version should be less than `1` before the migration", - ); let bytes = u32::to_be_bytes(v0::Scheduled::::get().len() as u32); @@ -123,8 +119,8 @@ pub mod v1 { fn post_upgrade(state: Vec) -> Result<(), sp_runtime::DispatchError> { log::trace!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); ensure!( - StorageVersion::get::>() == 1, - "Storage version should be `1` after the migration" + StorageVersion::get::>() >= 1, + "Storage version should be at least `1` after the migration" ); ensure!( v0::Scheduled::::get().len() == 0, From 903cef2ae1be9994c9517086b7141be3e4036644 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Mon, 21 Aug 2023 15:18:31 +0200 Subject: [PATCH 39/45] PVF worker: Prevent access to env vars (#7330) --- node/core/pvf/common/src/worker/mod.rs | 10 ++++++++++ .../src/node/utility/pvf-host-and-workers.md | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/node/core/pvf/common/src/worker/mod.rs b/node/core/pvf/common/src/worker/mod.rs index d9a0dff71b24..d249007ec36e 100644 --- a/node/core/pvf/common/src/worker/mod.rs +++ b/node/core/pvf/common/src/worker/mod.rs @@ -128,6 +128,16 @@ pub fn worker_event_loop( } } + // Delete all env vars to prevent malicious code from accessing them. + for (key, _) in std::env::vars() { + // TODO: *theoretically* the value (or mere presence) of `RUST_LOG` can be a source of + // randomness for malicious code. In the future we can remove it also and log in the host; + // see . + if key != "RUST_LOG" { + std::env::remove_var(key); + } + } + // Run the main worker loop. let rt = Runtime::new().expect("Creates tokio runtime. If this panics the worker will die and the host will detect that and deal with it."); let err = rt diff --git a/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md b/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md index 017b7fc025cc..bcf01b61f217 100644 --- a/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md +++ b/roadmap/implementers-guide/src/node/utility/pvf-host-and-workers.md @@ -125,3 +125,10 @@ A basic security mechanism is to make sure that any thread directly interfacing with untrusted code does not have access to the file-system. This provides some protection against attackers accessing sensitive data or modifying data on the host machine. + +### Clearing env vars + +We clear environment variables before handling untrusted code, because why give +attackers potentially sensitive data unnecessarily? And even if everything else +is locked down, env vars can potentially provide a source of randomness (see +point 1, "Consensus faults" above). From ea027a8e3722346b5e29587c2b5370f455c34b90 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 21 Aug 2023 17:02:13 +0200 Subject: [PATCH 40/45] Companion for substrate#14776 (#7648) * Bump dalek * update lockfile for {"substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 457 ++++++++++++++++++++++++++++------------------------- 1 file changed, 239 insertions(+), 218 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c963a3f5eef1..0e72e6aabc57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -778,7 +778,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "hash-db", "log", @@ -1847,18 +1847,32 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.1" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2" dependencies = [ "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", "fiat-crypto", - "packed_simd_2", "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "cxx" version = "1.0.102" @@ -2339,6 +2353,16 @@ dependencies = [ "signature 1.6.4", ] +[[package]] +name = "ed25519" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.1.0", +] + [[package]] name = "ed25519-dalek" version = "1.0.1" @@ -2346,13 +2370,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.2.0", - "ed25519", + "ed25519 1.5.3", "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +dependencies = [ + "curve25519-dalek 4.0.0", + "ed25519 2.2.2", + "serde", + "sha2 0.10.7", + "zeroize", +] + [[package]] name = "ed25519-zebra" version = "3.1.0" @@ -2831,7 +2868,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", ] @@ -2854,7 +2891,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-support-procedural", @@ -2879,7 +2916,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "Inflector", "array-bytes", @@ -2927,7 +2964,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2938,7 +2975,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2955,7 +2992,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -2984,7 +3021,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-recursion", "futures", @@ -3006,7 +3043,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "aquamarine", "bitflags 1.3.2", @@ -3044,7 +3081,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "Inflector", "cfg-expr", @@ -3062,7 +3099,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3074,7 +3111,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro2", "quote", @@ -3084,7 +3121,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-executive", @@ -3111,7 +3148,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -3124,7 +3161,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "cfg-if", "frame-support", @@ -3143,7 +3180,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -3158,7 +3195,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "sp-api", @@ -3167,7 +3204,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "parity-scale-codec", @@ -3342,7 +3379,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "chrono", "frame-election-provider-support", @@ -4472,12 +4509,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "libm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" - [[package]] name = "libp2p" version = "0.51.3" @@ -4607,7 +4638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1" dependencies = [ "bs58", - "ed25519-dalek", + "ed25519-dalek 1.0.1", "log", "multiaddr", "multihash", @@ -5346,7 +5377,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "log", @@ -5365,7 +5396,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "anyhow", "jsonrpsee", @@ -5889,20 +5920,10 @@ dependencies = [ "sha2 0.10.7", ] -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm", -] - [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -5917,7 +5938,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -5933,7 +5954,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -5947,7 +5968,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -5971,7 +5992,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "aquamarine", "docify", @@ -5993,7 +6014,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-election-provider-support", "frame-remote-externalities", @@ -6012,7 +6033,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6027,7 +6048,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -6046,7 +6067,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "binary-merkle-tree", @@ -6070,7 +6091,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6088,7 +6109,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6107,7 +6128,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6124,7 +6145,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6141,7 +6162,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6159,7 +6180,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6182,7 +6203,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6195,7 +6216,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6214,7 +6235,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "docify", "frame-benchmarking", @@ -6233,7 +6254,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6256,7 +6277,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6272,7 +6293,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6292,7 +6313,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6309,7 +6330,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6326,7 +6347,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6345,7 +6366,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6362,7 +6383,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6378,7 +6399,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6394,7 +6415,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -6413,7 +6434,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6433,7 +6454,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6444,7 +6465,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -6461,7 +6482,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6485,7 +6506,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6502,7 +6523,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6517,7 +6538,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6535,7 +6556,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6550,7 +6571,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6569,7 +6590,7 @@ dependencies = [ [[package]] name = "pallet-salary" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6587,7 +6608,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "docify", "frame-benchmarking", @@ -6605,7 +6626,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -6626,7 +6647,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6642,7 +6663,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6660,7 +6681,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6683,7 +6704,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6694,7 +6715,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "log", "sp-arithmetic", @@ -6703,7 +6724,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "sp-api", @@ -6712,7 +6733,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6729,7 +6750,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6744,7 +6765,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6783,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6781,7 +6802,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-support", "frame-system", @@ -6797,7 +6818,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6813,7 +6834,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6825,7 +6846,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6842,7 +6863,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6857,7 +6878,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6873,7 +6894,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -6888,7 +6909,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-benchmarking", "frame-support", @@ -10084,7 +10105,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "log", "sp-core", @@ -10095,7 +10116,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "futures", @@ -10123,7 +10144,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "futures-timer", @@ -10146,7 +10167,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10161,7 +10182,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10180,7 +10201,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10191,7 +10212,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "chrono", @@ -10230,7 +10251,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "fnv", "futures", @@ -10256,7 +10277,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "hash-db", "kvdb", @@ -10282,7 +10303,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "futures", @@ -10307,7 +10328,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "fork-tree", @@ -10343,7 +10364,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "jsonrpsee", @@ -10365,7 +10386,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "async-channel", @@ -10399,7 +10420,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "jsonrpsee", @@ -10418,7 +10439,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10431,7 +10452,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ahash 0.8.3", "array-bytes", @@ -10472,7 +10493,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "finality-grandpa", "futures", @@ -10492,7 +10513,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "futures", @@ -10515,7 +10536,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -10537,7 +10558,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10549,7 +10570,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "anyhow", "cfg-if", @@ -10566,7 +10587,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ansi_term", "futures", @@ -10582,7 +10603,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -10596,7 +10617,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "async-channel", @@ -10637,7 +10658,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-channel", "cid", @@ -10657,7 +10678,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "bitflags 1.3.2", @@ -10674,7 +10695,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ahash 0.8.3", "futures", @@ -10692,7 +10713,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "async-channel", @@ -10713,7 +10734,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "async-channel", @@ -10747,7 +10768,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "futures", @@ -10765,7 +10786,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "bytes", @@ -10799,7 +10820,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10808,7 +10829,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "jsonrpsee", @@ -10839,7 +10860,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10858,7 +10879,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "http", "jsonrpsee", @@ -10873,7 +10894,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "futures", @@ -10901,7 +10922,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "directories", @@ -10965,7 +10986,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "log", "parity-scale-codec", @@ -10976,7 +10997,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "clap 4.3.19", "fs4", @@ -10990,7 +11011,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11009,7 +11030,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "libc", @@ -11028,7 +11049,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "chrono", "futures", @@ -11047,7 +11068,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ansi_term", "atty", @@ -11076,7 +11097,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11087,7 +11108,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "futures", @@ -11113,7 +11134,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "futures", @@ -11129,7 +11150,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-channel", "futures", @@ -11658,14 +11679,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" +checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-rc.1", + "curve25519-dalek 4.0.0", "rand_core 0.6.4", "ring 0.16.20", "rustc_version", @@ -11713,7 +11734,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "hash-db", "log", @@ -11734,7 +11755,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "Inflector", "blake2", @@ -11748,7 +11769,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "scale-info", @@ -11761,7 +11782,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "integer-sqrt", "num-traits", @@ -11775,7 +11796,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "scale-info", @@ -11788,7 +11809,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "sp-api", "sp-inherents", @@ -11799,7 +11820,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "log", @@ -11817,7 +11838,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "futures", @@ -11832,7 +11853,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "parity-scale-codec", @@ -11849,7 +11870,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "parity-scale-codec", @@ -11868,7 +11889,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11887,7 +11908,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "finality-grandpa", "log", @@ -11905,7 +11926,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "scale-info", @@ -11917,7 +11938,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -11964,7 +11985,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "blake2b_simd", "byteorder", @@ -11977,7 +11998,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "quote", "sp-core-hashing", @@ -11987,7 +12008,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11996,7 +12017,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro2", "quote", @@ -12006,7 +12027,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "environmental", "parity-scale-codec", @@ -12017,7 +12038,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "serde_json", "sp-api", @@ -12028,7 +12049,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12042,11 +12063,10 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "bytes", - "ed25519", - "ed25519-dalek", + "ed25519-dalek 2.0.0", "libsecp256k1", "log", "parity-scale-codec", @@ -12067,7 +12087,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "lazy_static", "sp-core", @@ -12078,7 +12098,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -12090,7 +12110,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "thiserror", "zstd 0.12.4", @@ -12099,7 +12119,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -12110,7 +12130,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12128,7 +12148,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "scale-info", @@ -12142,7 +12162,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "sp-api", "sp-core", @@ -12152,7 +12172,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "backtrace", "lazy_static", @@ -12162,7 +12182,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "rustc-hash", "serde", @@ -12172,7 +12192,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "either", "hash256-std-hasher", @@ -12194,7 +12214,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12212,7 +12232,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "Inflector", "proc-macro-crate", @@ -12224,7 +12244,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "scale-info", @@ -12239,7 +12259,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -12253,7 +12273,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "hash-db", "log", @@ -12274,11 +12294,11 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "aes-gcm 0.10.2", - "curve25519-dalek 3.2.0", - "ed25519-dalek", + "curve25519-dalek 4.0.0", + "ed25519-dalek 2.0.0", "hkdf", "parity-scale-codec", "rand 0.8.5", @@ -12292,18 +12312,18 @@ dependencies = [ "sp-runtime-interface", "sp-std", "thiserror", - "x25519-dalek 2.0.0-pre.1", + "x25519-dalek 2.0.0", ] [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12316,7 +12336,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "parity-scale-codec", @@ -12329,7 +12349,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "sp-std", @@ -12341,7 +12361,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "sp-api", "sp-runtime", @@ -12350,7 +12370,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "parity-scale-codec", @@ -12365,7 +12385,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ahash 0.8.3", "hash-db", @@ -12388,7 +12408,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12405,7 +12425,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12416,7 +12436,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12429,7 +12449,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "parity-scale-codec", "scale-info", @@ -12670,12 +12690,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12694,7 +12714,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "hyper", "log", @@ -12706,7 +12726,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "jsonrpsee", @@ -12719,7 +12739,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -12736,7 +12756,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "array-bytes", "async-trait", @@ -12762,7 +12782,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12772,7 +12792,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12783,7 +12803,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "ansi_term", "build-helper", @@ -13691,7 +13711,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#94be94be6d26becd2395b58ae09ca31f596afe7d" +source = "git+https://github.com/paritytech/substrate?branch=master#51695bb7009ea2e0996eb94ab4dfdc643a076702" dependencies = [ "async-trait", "clap 4.3.19", @@ -14513,7 +14533,7 @@ dependencies = [ "tokio", "webpki 0.21.4", "webrtc-util", - "x25519-dalek 2.0.0-pre.1", + "x25519-dalek 2.0.0", "x509-parser 0.13.2", ] @@ -15032,12 +15052,13 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0-pre.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek 3.2.0", + "curve25519-dalek 4.0.0", "rand_core 0.6.4", + "serde", "zeroize", ] From 0bbe0a7621500788dd841be7e4d869cfba5f0676 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Mon, 21 Aug 2023 19:31:02 +0200 Subject: [PATCH 41/45] PVF worker: random fixes (#7649) * PVF worker: random fixes - Fixes possible panic due to non-UTF-8 env vars (https://github.com/paritytech/polkadot/pull/7330#discussion_r1300101716) - Very small refactor of some duplicated code * Don't need `to_str()` for comparison between OsString and str * Check edge cases that can cause env::remove_var to panic In case of a key or value that would cause env::remove_var to panic, we first log a warning and then proceed to attempt to remove the env var. * Make warning message clearer for end users * Backslash was unescaped, but can just remove it from error messages --- node/core/pvf/common/src/worker/mod.rs | 64 ++++++++++++++++++++------ 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/node/core/pvf/common/src/worker/mod.rs b/node/core/pvf/common/src/worker/mod.rs index d249007ec36e..8b41cb82f73b 100644 --- a/node/core/pvf/common/src/worker/mod.rs +++ b/node/core/pvf/common/src/worker/mod.rs @@ -121,22 +121,13 @@ pub fn worker_event_loop( "Node and worker version mismatch, node needs restarting, forcing shutdown", ); kill_parent_node_in_emergency(); - let err: io::Result = - Err(io::Error::new(io::ErrorKind::Unsupported, "Version mismatch")); - gum::debug!(target: LOG_TARGET, %worker_pid, "quitting pvf worker({}): {:?}", debug_id, err); + let err = io::Error::new(io::ErrorKind::Unsupported, "Version mismatch"); + worker_shutdown_message(debug_id, worker_pid, err); return } } - // Delete all env vars to prevent malicious code from accessing them. - for (key, _) in std::env::vars() { - // TODO: *theoretically* the value (or mere presence) of `RUST_LOG` can be a source of - // randomness for malicious code. In the future we can remove it also and log in the host; - // see . - if key != "RUST_LOG" { - std::env::remove_var(key); - } - } + remove_env_vars(debug_id); // Run the main worker loop. let rt = Runtime::new().expect("Creates tokio runtime. If this panics the worker will die and the host will detect that and deal with it."); @@ -152,7 +143,7 @@ pub fn worker_event_loop( // It's never `Ok` because it's `Ok(Never)`. .unwrap_err(); - gum::debug!(target: LOG_TARGET, %worker_pid, "quitting pvf worker ({}): {:?}", debug_id, err); + worker_shutdown_message(debug_id, worker_pid, err); // We don't want tokio to wait for the tasks to finish. We want to bring down the worker as fast // as possible and not wait for stalled validation to finish. This isn't strictly necessary now, @@ -160,6 +151,53 @@ pub fn worker_event_loop( rt.shutdown_background(); } +/// Delete all env vars to prevent malicious code from accessing them. +fn remove_env_vars(debug_id: &'static str) { + for (key, value) in std::env::vars_os() { + // TODO: *theoretically* the value (or mere presence) of `RUST_LOG` can be a source of + // randomness for malicious code. In the future we can remove it also and log in the host; + // see . + if key == "RUST_LOG" { + continue + } + + // In case of a key or value that would cause [`env::remove_var` to + // panic](https://doc.rust-lang.org/std/env/fn.remove_var.html#panics), we first log a + // warning and then proceed to attempt to remove the env var. + let mut err_reasons = vec![]; + let (key_str, value_str) = (key.to_str(), value.to_str()); + if key.is_empty() { + err_reasons.push("key is empty"); + } + if key_str.is_some_and(|s| s.contains('=')) { + err_reasons.push("key contains '='"); + } + if key_str.is_some_and(|s| s.contains('\0')) { + err_reasons.push("key contains null character"); + } + if value_str.is_some_and(|s| s.contains('\0')) { + err_reasons.push("value contains null character"); + } + if !err_reasons.is_empty() { + gum::warn!( + target: LOG_TARGET, + %debug_id, + ?key, + ?value, + "Attempting to remove badly-formatted env var, this may cause the PVF worker to crash. Please remove it yourself. Reasons: {:?}", + err_reasons + ); + } + + std::env::remove_var(key); + } +} + +/// Provide a consistent message on worker shutdown. +fn worker_shutdown_message(debug_id: &'static str, worker_pid: u32, err: io::Error) { + gum::debug!(target: LOG_TARGET, %worker_pid, "quitting pvf worker ({}): {:?}", debug_id, err); +} + /// Loop that runs in the CPU time monitor thread on prepare and execute jobs. Continuously wakes up /// and then either blocks for the remaining CPU time, or returns if we exceed the CPU timeout. /// From e39c00381e8d5e8aa6fe752fc5cf2fcba14c8599 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 22 Aug 2023 12:08:54 +0300 Subject: [PATCH 42/45] Add BEEFY capabilities to Westend and Kusama (#7591) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * runtime: add BEEFY and MMR to Westend Signed-off-by: Adrian Catangiu * runtime: add BEEFY and MMR to Kusama Signed-off-by: Adrian Catangiu * node/service: enable BEEFY for Westend and Kusama Signed-off-by: Adrian Catangiu * node/service: regenerate genesis keys for westend-native and kusama-native Since these keys are only used for development/local chains, also publish the secret seeds used to generate the public keys, so that developers can recover/generate the private key pairs if needed. Signed-off-by: Adrian Catangiu * runtime: add session keys migration to add BEEFY to Westend and Kusama * runtime: fix migration * fix try-runtime build * cargo fmt * fix parachains slashing benchmark * address review comments * Apply suggestions from code review Co-authored-by: Bastian Köcher * runtime: fix session keys migration --------- Signed-off-by: Adrian Catangiu Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- Cargo.lock | 10 + cli/src/command.rs | 5 +- node/service/src/chain_spec.rs | 339 ++++++++++-------- node/service/src/lib.rs | 18 +- runtime/kusama/Cargo.toml | 12 + runtime/kusama/src/lib.rs | 221 ++++++++++-- runtime/kusama/src/tests.rs | 2 +- .../src/disputes/slashing/benchmarking.rs | 11 +- runtime/polkadot/src/lib.rs | 7 +- runtime/rococo/src/lib.rs | 17 +- runtime/westend/Cargo.toml | 12 + runtime/westend/src/lib.rs | 222 ++++++++++-- runtime/westend/src/tests.rs | 7 +- scripts/prepare-test-net.sh | 2 +- 14 files changed, 638 insertions(+), 247 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e72e6aabc57..5b19bc139384 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4292,6 +4292,7 @@ dependencies = [ name = "kusama-runtime" version = "0.9.43" dependencies = [ + "binary-merkle-tree", "bitvec", "frame-benchmarking", "frame-election-provider-support", @@ -4310,6 +4311,8 @@ dependencies = [ "pallet-babe", "pallet-bags-list", "pallet-balances", + "pallet-beefy", + "pallet-beefy-mmr", "pallet-bounties", "pallet-child-bounties", "pallet-collective", @@ -4325,6 +4328,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-message-queue", + "pallet-mmr", "pallet-multisig", "pallet-nis", "pallet-nomination-pools", @@ -4366,6 +4370,7 @@ dependencies = [ "serde_json", "smallvec", "sp-api", + "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", @@ -14653,6 +14658,7 @@ dependencies = [ name = "westend-runtime" version = "0.9.43" dependencies = [ + "binary-merkle-tree", "bitvec", "frame-benchmarking", "frame-election-provider-support", @@ -14670,6 +14676,8 @@ dependencies = [ "pallet-babe", "pallet-bags-list", "pallet-balances", + "pallet-beefy", + "pallet-beefy-mmr", "pallet-collective", "pallet-democracy", "pallet-election-provider-multi-phase", @@ -14682,6 +14690,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-message-queue", + "pallet-mmr", "pallet-multisig", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", @@ -14720,6 +14729,7 @@ dependencies = [ "serde_json", "smallvec", "sp-api", + "sp-application-crypto", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", diff --git a/cli/src/command.rs b/cli/src/command.rs index 0fbeafb99a07..6b36e6895b6e 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -240,9 +240,8 @@ where .map_err(Error::from)?; let chain_spec = &runner.config().chain_spec; - // By default, enable BEEFY on test networks. - let enable_beefy = (chain_spec.is_rococo() || chain_spec.is_wococo() || chain_spec.is_versi()) && - !cli.run.no_beefy; + // By default, enable BEEFY on all networks except Polkadot (for now). + let enable_beefy = !chain_spec.is_polkadot() && !cli.run.no_beefy; set_default_ss58_version(chain_spec); diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index 4d0d11ba436e..1e5aaa807b81 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -274,6 +274,7 @@ fn kusama_session_keys( para_validator: ValidatorId, para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, + beefy: BeefyId, ) -> kusama::SessionKeys { kusama::SessionKeys { babe, @@ -282,6 +283,7 @@ fn kusama_session_keys( para_validator, para_assignment, authority_discovery, + beefy, } } @@ -293,6 +295,7 @@ fn westend_session_keys( para_validator: ValidatorId, para_assignment: AssignmentId, authority_discovery: AuthorityDiscoveryId, + beefy: BeefyId, ) -> westend::SessionKeys { westend::SessionKeys { babe, @@ -301,6 +304,7 @@ fn westend_session_keys( para_validator, para_assignment, authority_discovery, + beefy, } } @@ -330,12 +334,16 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim use hex_literal::hex; use sp_core::crypto::UncheckedInto; - // subkey inspect "$SECRET" + // Following keys are used in genesis config for development chains. + // DO NOT use them in production chains as the secret seed is public. + // + // SECRET_SEED="slow awkward present example safe bundle science ocean cradle word tennis earn" + // subkey inspect -n polkadot "$SECRET_SEED" let endowed_accounts = vec![ - // 5DaVh5WRfazkGaKhx1jUu6hjz7EmRe4dtW6PKeVLim84KLe8 - hex!["42f4a4b3e0a89c835ee696205caa90dd85c8ea1d7364b646328ee919a6b2fc1e"].into(), + // 15S75FkhCWEowEGfxWwVfrW3LQuy8w8PNhVmrzfsVhCMjUh1 + hex!["c416837e232d9603e83162ef4bda08e61580eeefe60fe92fc044aa508559ae42"].into(), ]; - // SECRET='...' ./scripts/prepare-test-net.sh 4 + // SECRET=$SECRET_SEED ./scripts/prepare-test-net.sh 4 let initial_authorities: Vec<( AccountId, AccountId, @@ -345,101 +353,114 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim ValidatorId, AssignmentId, AuthorityDiscoveryId, + BeefyId, )> = vec![ ( - //5ERCqy118nnXDai8g4t3MjdX7ZC5PrQzQpe9vwex5cELWqbt - hex!["681af4f93073484e1acd6b27395d0d258f1a6b158c808846c8fd05ee2435056e"].into(), - //5GTS114cfQNBgpQULhMaNCPXGds6NokegCnikxDe1vqANhtn - hex!["c2463372598ebabd21ee5bc33e1d7e77f391d2df29ce2fbe6bed0d13be629a45"].into(), - //5FhGbceKeH7fuGogcBwd28ZCkAwDGYBADCTeHiYrvx2ztyRd - hex!["a097bfc6a33499ed843b711f52f523f8a7174f798a9f98620e52f4170dbe2948"] + //5EvydUTtHvt39Khac3mMxNPgzcfu49uPDzUs3TL7KEzyrwbw + hex!["7ecfd50629cdd246649959d88d490b31508db511487e111a52a392e6e458f518"].into(), + //5HQyX5gyy77m9QLXguAhiwjTArHYjYspeY98dYDu1JDetfZg + hex!["eca2cca09bdc66a7e6d8c3d9499a0be2ad4690061be8a9834972e17d13d2fe7e"].into(), + //5G13qYRudTyttwTJvHvnwp8StFtcfigyPnwfD4v7LNopsnX4 + hex!["ae27367cb77850fb195fe1f9c60b73210409e68c5ad953088070f7d8513d464c"] + .unchecked_into(), + //5Eb7wM65PNgtY6e33FEAzYtU5cRTXt6WQvZTnzaKQwkVcABk + hex!["6faae44b21c6f2681a7f60df708e9f79d340f7d441d28bd987fab8d05c6487e8"] .unchecked_into(), - //5Es7nDkJt2by5qVCCD7PZJdp76KJw1LdRCiNst5S5f4eecnz - hex!["7bde49dda82c2c9f082b807ef3ceebff96437d67b3e630c584db7a220ecafacf"] + //5CdS2wGo4qdTQceVfEnbZH8vULeBrnGYCxSCxDna4tQSMV6y + hex!["18f5d55f138bfa8e0ea26ed6fa56817b247de3c2e2030a908c63fb37c146473f"] .unchecked_into(), - //5D4e8zRjaYzFamqChGPPtu26PcKbKgUrhb7WqcNbKa2RDFUR - hex!["2c2fb730a7d9138e6d62fcf516f9ecc2d712af3f2f03ca330c9564b8c0c1bb33"] + //5FqMLAgygdX9UqzukDp15Uid9PAKdFAR621U7xtp5ut2NfrW + hex!["a6c1a5b501985a83cb1c37630c5b41e6b0a15b3675b2fd94694758e6cfa6794d"] .unchecked_into(), - //5DD3JY5ENkjcgVFbVSgUbZv7WmrnyJ8bxxu56ee6hZFiRdnh - hex!["3297a8622988cc23dd9c131e3fb8746d49e007f6e58a81d43420cd539e250e4c"] + //5DhXAV75BKvF9o447ikWqLttyL2wHtLMFSX7GrsKF9Ny61Ta + hex!["485051748ab9c15732f19f3fbcf1fd00a6d9709635f084505107fbb059c33d2f"] .unchecked_into(), - //5Gpodowhud8FG9xENXR5YwTFbUAWyoEtw7sYFytFsG4z7SU6 - hex!["d2932edf775088bd088dc5a112ad867c24cc95858f77f8a1ab014de8d4f96a3f"] + //5GNHfmrtWLTawnGCmc39rjAEiW97vKvE7DGePYe4am5JtE4i + hex!["be59ed75a72f7b47221ce081ba4262cf2e1ea7867e30e0b3781822f942b97677"] .unchecked_into(), - //5GUMj8tnjL3PJZgXoiWtgLCaMVNHBNeSeTqDsvcxmaVAjKn9 - hex!["c2fb0f74591a00555a292bc4882d3158bafc4c632124cb60681f164ef81bcf72"] + //5DA6Z8RUF626stn94aTRBCeobDCYcFbU7Pdk4Tz1R9vA8B8F + hex!["0207e43990799e1d02b0507451e342a1240ff836ea769c57297589a5fd072ad8f4"] .unchecked_into(), ), ( - //5HgDCznTkHKUjzPkQoTZGWbvbyqB7sqHDBPDKdF1FyVYM7Er - hex!["f8418f189f84814fd40cc1b2e90873e72ea789487f3b98ed42811ba76d10fc37"].into(), - //5GQTryeFwuvgmZ2tH5ZeAKZHRM9ch5WGVGo6ND9P8f9uMsNY - hex!["c002bb4af4a1bd2f33d104aef8a41878fe1ac94ba007029c4dfdefa8b698d043"].into(), - //5C7YkWSVH1zrpsE5KwW1ua1qatyphzYxiZrL24mjkxz7mUbn - hex!["022b14fbcf65a93b81f453105b9892c3fc4aa74c22c53b4abab019e1d58fbd41"] + //5DFpvDUdCgw54E3E357GR1PyJe3Ft9s7Qyp7wbELAoJH9RQa + hex!["34b7b3efd35fcc3c1926ca065381682b1af29b57dabbcd091042c6de1d541b7d"].into(), + //5DZSSsND5wCjngvyXv27qvF3yPzt3MCU8rWnqNy4imqZmjT8 + hex!["4226796fa792ac78875e023ff2e30e3c2cf79f0b7b3431254cd0f14a3007bc0e"].into(), + //5CPrgfRNDQvQSnLRdeCphP3ibj5PJW9ESbqj2fw29vBMNQNn + hex!["0e9b60f04be3bffe362eb2212ea99d2b909b052f4bff7c714e13c2416a797f5d"] + .unchecked_into(), + //5FXFsPReTUEYPRNKhbTdUathcWBsxTNsLbk2mTpYdKCJewjA + hex!["98f4d81cb383898c2c3d54dab28698c0f717c81b509cb32dc6905af3cc697b18"] .unchecked_into(), - //5GwFC6Tmg4fhj4PxSqHycgJxi3PDfnC9RGDsNHoRwAvXvpnZ - hex!["d77cafd3b32c8b52b0e2780a586a6e527c94f1bdec117c4e4acb0a491461ffa3"] + //5CDYSCJK91r8y2r1V4Ddrit4PFMEkwZXJe8mNBqGXJ4xWCWq + hex!["06bd7dd4ab4c808c7d09d9cb6bd27fbcd99ad8400e99212b335056c475c24031"] .unchecked_into(), - //5DSVrGURuDuh8Luzo8FYq7o2NWiUSLSN6QAVNrj9BtswWH6R - hex!["3cdb36a5a14715999faffd06c5b9e5dcdc24d4b46bc3e4df1aaad266112a7b49"] + //5CZjurB78XbSHf6SLkLhCdkqw52Zm7aBYUDdfkLqEDWJ9Zhj + hex!["162508accd470e379b04cb0c7c60b35a7d5357e84407a89ed2dd48db4b726960"] .unchecked_into(), - //5DLEG2AupawCXGwhJtrzBRc3zAhuP8V662dDrUTzAsCiB9Ec - hex!["38134245c9919ecb20bf2eedbe943b69ba92ceb9eb5477b92b0afd3cb6ce2858"] + //5DkAqCtSjUMVoJFauuGoAbSEgn2aFCRGziKJiLGpPwYgE1pS + hex!["4a559c028b69a7f784ce553393e547bec0aa530352157603396d515f9c83463b"] .unchecked_into(), - //5D83o9fDgnHxaKPkSx59hk8zYzqcgzN2mrf7cp8fiVEi7V4E - hex!["2ec917690dc1d676002e3504c530b2595490aa5a4603d9cc579b9485b8d0d854"] + //5GsBt9MhGwkg8Jfb1F9LAy2kcr88WNyNy4L5ezwbCr8NWKQU + hex!["d464908266c878acbf181bf8fda398b3aa3fd2d05508013e414aaece4cf0d702"] .unchecked_into(), - //5DwBJquZgncRWXFxj2ydbF8LBUPPUbiq86sXWXgm8Z38m8L2 - hex!["52bae9b8dedb8058dda93ec6f57d7e5a517c4c9f002a4636fada70fed0acf376"] + //5DtJVkz8AHevEnpszy3X4dUcPvACW6x1qBMQZtFxjexLr5bq + hex!["02fdf30222d2cb88f2376d558d3de9cb83f9fde3aa4b2dd40c93e3104e3488bcd2"] .unchecked_into(), ), ( - //5DMHpkRpQV7NWJFfn2zQxCLiAKv7R12PWFRPHKKk5X3JkYfP - hex!["38e280b35d08db46019a210a944e4b7177665232ab679df12d6a8bbb317a2276"].into(), - //5FbJpSHmFDe5FN3DVGe1R345ZePL9nhcC9V2Cczxo7q8q6rN - hex!["9c0bc0e2469924d718ae683737f818a47c46b0612376ecca06a2ac059fe1f870"].into(), - //5E5Pm3Udzxy26KGkLE5pc8JPfQrvkYHiaXWtuEfmQsBSgep9 - hex!["58fecadc2df8182a27e999e7e1fd7c99f8ec18f2a81f9a0db38b3653613f3f4d"] + //5E2cob2jrXsBkTih56pizwSqENjE4siaVdXhaD6akLdDyVq7 + hex!["56e0f73c563d49ee4a3971c393e17c44eaa313dabad7fcf297dc3271d803f303"].into(), + //5D4rNYgP9uFNi5GMyDEXTfiaFLjXyDEEX2VvuqBVi3f1qgCh + hex!["2c58e5e1d5aef77774480cead4f6876b1a1a6261170166995184d7f86140572b"].into(), + //5Ea2D65KXqe625sz4uV1jjhSfuigVnkezC8VgEj9LXN7ERAk + hex!["6ed45cb7af613be5d88a2622921e18d147225165f24538af03b93f2a03ce6e13"] .unchecked_into(), - //5FxcystSLHtaWoy2HEgRNerj9PrUs452B6AvHVnQZm5ZQmqE - hex!["ac4d0c5e8f8486de05135c10a707f58aa29126d5eb28fdaaba00f9a505f5249d"] + //5G4kCbgqUhEyrRHCyFwFEkgBZXoYA8sbgsRxT9rY8Tp5Jj5F + hex!["b0f8d2b9e4e1eafd4dab6358e0b9d5380d78af27c094e69ae9d6d30ca300fd86"] .unchecked_into(), - //5E7KqVXaVGuAqiqMigpuH8oXHLVh4tmijmpJABLYANpjMkem - hex!["5a781385a0235fe8594dd101ec55ef9ba01883f8563a0cdd37b89e0303f6a578"] + //5HVhFBLFTKSZK9fX6RktckWDTgYNoSd33fgonsEC8zfr4ddm + hex!["f03c3e184b2883eec9beaeb97f54321587e7476b228831ea0b5fc6da847ea975"] .unchecked_into(), - //5H9AybjkpyZ79yN5nHuBqs6RKuZPgM7aAVVvTQsDFovgXb2A - hex!["e09570f62a062450d4406b4eb43e7f775ff954e37606646cd590d1818189501f"] + //5CS7thd2n54WfqeKU3cjvZzK4z5p7zku1Zw97mSzXgPioAAs + hex!["1055100a283968271a0781450b389b9093231be809be1e48a305ebad2a90497e"] .unchecked_into(), - //5Ccgs7VwJKBawMbwMENDmj2eFAxhFdGksVHdk8aTAf4w7xox - hex!["1864832dae34df30846d5cc65973f58a2d01b337d094b1284ec3466ecc90251d"] + //5DSaL4ZmSYarZSazhL5NQh7LT6pWhNRDcefk2QS9RxEXfsJe + hex!["3cea4ab74bab4adf176cf05a6e18c1599a7bc217d4c6c217275bfbe3b037a527"] .unchecked_into(), - //5EsSaZZ7niJs7hmAtp4QeK19AcAuTp7WXB7N7gRipVooerq4 - hex!["7c1d92535e6d94e21cffea6633a855a7e3c9684cd2f209e5ddbdeaf5111e395b"] + //5CaNLkYEbFYXZodXhd3UjV6RNLjFGNLiYafc8X5NooMkZiAq + hex!["169faa81aebfe74533518bda28567f2e2664014c8905aa07ea003336afda5a58"] + .unchecked_into(), + //5ERwhKiePayukzZStMuzGzRJGxGRFpwxYUXVarQpMSMrXzDS + hex!["03429d0d20f6ac5ca8b349f04d014f7b5b864acf382a744104d5d9a51108156c0f"] .unchecked_into(), ), ( - //5Ea11qhmGRntQ7pyEkEydbwxvfrYwGMKW6rPERU4UiSBB6rd - hex!["6ed057d2c833c45629de2f14b9f6ce6df1edbf9421b7a638e1fb4828c2bd2651"].into(), - //5CZomCZwPB78BZMZsCiy7WSpkpHhdrN8QTSyjcK3FFEZHBor - hex!["1631ff446b3534d031adfc37b7f7aed26d2a6b3938d10496aab3345c54707429"].into(), - //5CSM6vppouFHzAVPkVFWN76DPRUG7B9qwJe892ccfSfJ8M5f - hex!["108188c43a7521e1abe737b343341c2179a3a89626c7b017c09a5b10df6f1c42"] + //5H6j9ovzYk9opckVjvM9SvVfaK37ASTtPTzWeRfqk1tgLJUN + hex!["deb804ed2ed2bb696a3dd4ed7de4cd5c496528a2b204051c6ace385bacd66a3a"].into(), + //5DJ51tMW916mGwjMpfS1o9skcNt6Sb28YnZQXaKVg4h89agE + hex!["366da6a748afedb31f07902f2de36ab265beccee37762d3ae1f237de234d9c36"].into(), + //5CSPYDYoCDGSoSLgSp4EHkJ52YasZLHG2woqhPZkdbtNQpke + hex!["1089bc0cd60237d061872925e81d36c9d9205d250d5d8b542c8e08a8ecf1b911"] + .unchecked_into(), + //5ChfdrAqmLjCeDJvynbMjcxYLHYzPe8UWXd3HnX9JDThUMbn + hex!["1c309a70b4e274314b84c9a0a1f973c9c4fc084df5479ef686c54b1ae4950424"] .unchecked_into(), - //5GwkG4std9KcjYi3ThSC7QWfhqokmYVvWEqTU9h7iswjhLnr - hex!["d7de8a43f7ee49fa3b3aaf32fb12617ec9ff7b246a46ab14e9c9d259261117fa"] + //5DnsMm24575xK2b2aGfmafiDxwCet6Mr4iiZQeDdWvi8CzuF + hex!["4c64868ba6d8ace235d3efb4c10d745a67cf3bdfeae23b264d7ea2f3439dec42"] .unchecked_into(), - //5CoUk3wrCGJAWbiJEcsVjYhnd2JAHvR59jBRbSw77YrBtRL1 - hex!["209f680bc501f9b59358efe3636c51fd61238a8659bac146db909aea2595284b"] + //5D8C3HHEp5E8fJsXRD56494F413CdRSR9QKGXe7v5ZEfymdj + hex!["2ee4d78f328db178c54f205ac809da12e291a33bcbd4f29f081ce7e74bdc5044"] .unchecked_into(), - //5EcSu96wprFM7G2HfJTjYu8kMParnYGznSUNTsoEKXywEsgG - hex!["70adf80395b3f59e4cab5d9da66d5a286a0b6e138652a06f72542e46912df922"] + //5GxeTYCGmp1C3ZRLDkRWqJc6gB2GYmuqnygweuH3vsivMQq6 + hex!["d88e40e3c2c7a7c5abf96ffdd8f7b7bec8798cc277bc97e255881871ab73b529"] .unchecked_into(), - //5Ge3sjpD43Cuy7rNoJQmE9WctgCn6Faw89Pe7xPs3i55eHwJ - hex!["ca5f6b970b373b303f64801a0c2cadc4fc05272c6047a2560a27d0c65589ca1d"] + //5DoGpsgSLcJsHa9B8V4PKjxegWAqDZttWfxicAd68prUX654 + hex!["4cb3863271b70daa38612acd5dae4f5afcb7c165fa277629e5150d2214df322a"] .unchecked_into(), - //5EFcjHLvB2z5vd5g63n4gABmhzP5iPsKvTwd8sjfvTehNNrk - hex!["60cae7fa5a079d9fc8061d715fbcc35ef57c3b00005694c2badce22dcc5a9f1b"] + //5G1KLjqFyMsPAodnjSRkwRFJztTTEzmZWxow2Q3ZSRCPdthM + hex!["03be5ec86d10a94db89c9b7a396d3c7742e3bec5f85159d4cf308cef505966ddf5"] .unchecked_into(), ), ]; @@ -456,6 +477,7 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) .collect(), }, + beefy: Default::default(), indices: westend::IndicesConfig { indices: vec![] }, session: westend::SessionConfig { keys: initial_authorities @@ -471,6 +493,7 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim x.5.clone(), x.6.clone(), x.7.clone(), + x.8.clone(), ), ) }) @@ -521,18 +544,17 @@ fn kusama_staging_testnet_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeG use hex_literal::hex; use sp_core::crypto::UncheckedInto; - // subkey inspect "$SECRET" + // Following keys are used in genesis config for development chains. + // DO NOT use them in production chains as the secret seed is public. + // + // SECRET_SEED="explain impose opinion genius bar parrot erupt panther surround best expire + // album" subkey inspect -n kusama "$SECRET_SEED" let endowed_accounts = vec![ - // 5CVFESwfkk7NmhQ6FwHCM9roBvr9BGa4vJHFYU8DnGQxrXvz - hex!["12b782529c22032ed4694e0f6e7d486be7daa6d12088f6bc74d593b3900b8438"].into(), + // FLN5cfhF7VCGJYefjPQJR2V6WwbfRmb9ozTwLAzBNeQQG6y + hex!["7a0fe424217ed176da7abf12e08198db0d0949298e1372c80a1930cb6dc21d3e"].into(), ]; - // for i in 1 2 3 4; do for j in stash controller; do subkey inspect "$SECRET//$i//$j"; done; - // done for i in 1 2 3 4; do for j in babe; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; - // done for i in 1 2 3 4; do for j in grandpa; do subkey --ed25519 inspect "$SECRET//$i//$j"; - // done; done for i in 1 2 3 4; do for j in im_online; do subkey --sr25519 inspect - // "$SECRET//$i//$j"; done; done for i in 1 2 3 4; do for j in para_validator para_assignment; - // do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done + // SECRET=$SECRET_SEED ./scripts/prepare-test-net.sh 4 let initial_authorities: Vec<( AccountId, AccountId, @@ -542,101 +564,114 @@ fn kusama_staging_testnet_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeG ValidatorId, AssignmentId, AuthorityDiscoveryId, + BeefyId, )> = vec![ ( - // 5DD7Q4VEfPTLEdn11CnThoHT5f9xKCrnofWJL5SsvpTghaAT - hex!["32a5718e87d16071756d4b1370c411bbbb947eb62f0e6e0b937d5cbfc0ea633b"].into(), - // 5GNzaEqhrZAtUQhbMe2gn9jBuNWfamWFZHULryFwBUXyd1cG - hex!["bee39fe862c85c91aaf343e130d30b643c6ea0b4406a980206f1df8331f7093b"].into(), - // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 - hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"] + //5D5EsvSJf3KR3WHeZNG8rETdW6homig1cGHezspFt1P4o7sL + hex!["2ca4a9582244a3356a0d96e59d71f7e4d12aa88bca6d46f360ef11f6487cab1f"].into(), + //5Ev6RixvmK62UQE2PW19MPdLsYT4Nomwj85HKPdbnRECbDYh + hex!["7e237806f642b7f45f70ec45fbc41034516c8e5561bae2a62cd287129e1d0712"].into(), + //5GbjzK1uYVo6v1SaYhTeK3dbYy2GN9X4K5iwRkHEQ9eLS3We + hex!["c89cb7afc47ec0b5aac5824e5338a62959c92978167d3f841491836746e70b3d"] + .unchecked_into(), + //5GFz3YFW8QzEUsWhRjJzvDP7e5X5tPf5U12vUw32R8oJVgqb + hex!["b98b200021a608148f9817aeb553596b6968a5aa61b6d320c522f520ecc9cf9c"] .unchecked_into(), - // 5EjvdwATjyFFikdZibVvx1q5uBHhphS2Mnsq5c7yfaYK25vm - hex!["76620f7c98bce8619979c2b58cf2b0aff71824126d2b039358729dad993223db"] + //5GzaFD8YsqnP5FYe5ijA9M4LQvzU9TPJmnBGdpuoqEvR1gQC + hex!["da0690438c0dd7a9aa26e03c9f1deaa58ba2b88d0bec0954b06478632164a401"] .unchecked_into(), - // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 - hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"] + //5CkZPtNy61PtbJpLqnjNFmbi1qukGkFdqFr5GKduSEthJ1cd + hex!["1e6554d35f6f17a37176c71801426204d6df400a1869114e4f00564b35d31150"] .unchecked_into(), - // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 - hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"] + //5CodnwweaYA1zB4QhdP4YVYFWnuZHY6W7zkN1NCRqJ9wZhap + hex!["20bddf09b1d0a2d93bafeb87fe19eb5bd59950c174f23a141a6d99736a5e700d"] .unchecked_into(), - // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 - hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"] + //5E7TSvNAP6QeJNeckdvYvADpHsx7v6aHXtGoQv5R2N1V3hEB + hex!["5a91b2546f1aac1c388eb0739c83e42d9972884d74360200ce32b7595bc65a04"] .unchecked_into(), - // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 - hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"] + //5GsoKeoM2HmjXPsdCua4oPu3Ms1Jgu4HbSnB81Lisa2tBFZp + hex!["02fd1e7e8455ab888ad054bbec7bc19409e6b1a5bb0300feefc6b58e60efae7e85"] .unchecked_into(), ), ( - // 5G9VGb8ESBeS8Ca4or43RfhShzk9y7T5iTmxHk5RJsjZwsRx - hex!["b496c98a405ceab59b9e970e59ef61acd7765a19b704e02ab06c1cdfe171e40f"].into(), - // 5F7V9Y5FcxKXe1aroqvPeRiUmmeQwTFcL3u9rrPXcMuMiCNx - hex!["86d3a7571dd60139d297e55d8238d0c977b2e208c5af088f7f0136b565b0c103"].into(), - // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY - hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"] + //5HMtKQuL2GQ7YvLBTh3vqFJEpkZW19sQh2X2mcUzAwBAe885 + hex!["ea478deab0ebfbeab7342febc236a9f1af5129ca0083fa25e6b0cf6a998d8354"].into(), + //5EFD5pLC3w5NFEcmQ6rGw9dUZ6fTSjWJemsvJZuaj7Qmq2WT + hex!["607b4e88129804eca8cd6fa26cbe2dd36667130e2a061050b08d9015871f4263"].into(), + //5DFztsnvC9hN85j5AP116atcnzFhAxnbzPodEp1AsYq1LYXu + hex!["34d949c39fae5801ba328ac6d0ddc76e469b7d5a4372a4a0d94f6aad6f9c1600"] .unchecked_into(), - // 5HBDAaybNqjmY7ww8ZcZZY1L5LHxvpnyfqJwoB7HhR6raTmG - hex!["e2234d661bee4a04c38392c75d1566200aa9e6ae44dd98ee8765e4cc9af63cb7"] + //5EZJNJ4j1eEEwCWusg7nYsZxTYBwoTH2drszxRqgMBTgNxMW + hex!["6e47830dcfc1f2b53a1b5db3f76702fc2760c1cc119119aceb00a57ec6658465"] .unchecked_into(), - // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY - hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"] + //5Dts3SrgDQMY9XCzKeQrxYSTh5MphPek994qkDCDk5c4neeF + hex!["50f6ef6326cd61ac500f167493e435f1204ce1d66ad18024bc5810d09673785e"] .unchecked_into(), - // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY - hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"] + //5DMKT99825TvA8F1yCQvE1ZcKTqg8T8Ad1KEjN6EuVpz4E6w + hex!["38e7fb2f6a1dcec73d93b07a0dc7cff1f9a9cc32cde8eb1e6ea1782f5316b431"] .unchecked_into(), - // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY - hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"] + //5EestuSehdMsWsBZ1hXCVo5YQiYiTPJwtV281x5fjUVtaqtP + hex!["72889a7b6ada28c3bd05a5a7298437f01d6d3270559768d16275efaf11864c0a"] .unchecked_into(), - // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY - hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"] + //5FNd5EabUbcReXEPwY9aASJMwSqyiic9w1Qt23YxNXj3dzbi + hex!["925f03f6211c68377987b0f78cd02aa882ad1fa9cc00c01fe6ce68e14c23340d"] + .unchecked_into(), + //5DxhuqfovpooTn8yH7WJGFjYw3pQxSEN9y9kvYUiGguHAj9D + hex!["030e77039e470ccdec7fe23dbc41c66f1c187ec8345e8919d3dc1250d975c3ce82"] .unchecked_into(), ), ( - // 5FzwpgGvk2kk9agow6KsywLYcPzjYc8suKej2bne5G5b9YU3 - hex!["ae12f70078a22882bf5135d134468f77301927aa67c376e8c55b7ff127ace115"].into(), - // 5EqoZhVC2BcsM4WjvZNidu2muKAbu5THQTBKe3EjvxXkdP7A - hex!["7addb914ec8486bbc60643d2647685dcc06373401fa80e09813b630c5831d54b"].into(), - // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 - hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"] + //5DAiYTKQ5KxwLncfNoTAH58dXBk2oDcQxtAXyDwMdKGLpGeY + hex!["30d203d942c1d056245b51e466a50b684f172a37c1cdde678f5346a0b3dbcd52"].into(), + //5Dq778qqNiAsjdF4qLVdkSBR8SftJKU35nyeBnkztRgniVhV + hex!["4e194bbafeec45647b2679e6b615b2a879d2e74fe706921930509ab3c9dbb22d"].into(), + //5E6iENoE1tXJUd7PkopQ8uqejg6xhPpqAnsVjS3hAQHWK1tm + hex!["5a0037b6bfc5e879ba5ef480ac29c59a12873854159686899082f41950ffd472"] + .unchecked_into(), + //5F8Dtgoc5dCaLAGYtaDqQUDg91fPQUynd497Fvhor8SYMdXp + hex!["87638aef8ab75db093150a6677c0919292ff66fc17f9f006a71fd0618415e164"] .unchecked_into(), - // 5E8ULLQrDAtWhfnVfZmX41Yux86zNAwVJYguWJZVWrJvdhBe - hex!["5b57ed1443c8967f461db1f6eb2ada24794d163a668f1cf9d9ce3235dfad8799"] + //5EKsYx6Wj1Qg7LLc12U2YRjRUFmHa4Q3rNSoGZaP1ofS54km + hex!["6409c85a1125fa456b9dc6e85408a6d931aa8e04f48511c87fc147d1c103e902"] .unchecked_into(), - // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 - hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"] + //5H3UQy1NhCUUq3getmSEG8R1capY7Uy8JtKJz68UABmD9UxS + hex!["dc3cab0f94fa974cba826984f23dd4dc77ade20f25d935af5f07b85518da8044"] .unchecked_into(), - // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 - hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"] + //5DstCjokShCt9NppNnAcjg2nS4M5PKY3etn2BoFkZzMhQJ3w + hex!["50379866eb62e5c8aac31133efc4a1723e964a8e30c93c3ce2e7758bd03eb776"] .unchecked_into(), - // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 - hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"] + //5E4SCbSqUWKC4NVRCkMkJEnXCaVRiNQbSHL4upRB1ffd1Mk1 + hex!["5843c339c39d2c308bfb1841cd10beecfa157580492db05b66db8553e8d6512c"] .unchecked_into(), - // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 - hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"] + //5HNoMQ1PL3m7eBhp24FZxZUBtz4eh3AiwWq8i8jXLCRpJHsu + hex!["03c81d4e72cbdb96a7e6aad76830ae783b0b4650dc19703dde96866d8894dc921f"] .unchecked_into(), ), ( - // 5CFj6Kg9rmVn1vrqpyjau2ztyBzKeVdRKwNPiA3tqhB5HPqq - hex!["0867dbb49721126df589db100dda728dc3b475cbf414dad8f72a1d5e84897252"].into(), - // 5CwQXP6nvWzigFqNhh2jvCaW9zWVzkdveCJY3tz2MhXMjTon - hex!["26ab2b4b2eba2263b1e55ceb48f687bb0018130a88df0712fbdaf6a347d50e2a"].into(), - // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd - hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"] + //5FNnjg8hXcPVLKASA69bPbooatacxcWNqkQAyXZfFiXi7T8r + hex!["927f8b12a0fa7185077353d9f6b4fe6bc6cd9682bd498642fa3801280909711a"].into(), + //5GipjBdL3rbex9qyxMinZpJYQbobbwk1ctbZp6B2mh3H25c6 + hex!["ce03638cd1e8496793b0540ba23370034511ea5d08837deb17f6c4d905b8d017"].into(), + //5GByn4uRpwmPe4i4MA4PjTQ8HXuycdue8HMWDhZ7vbU4WR9R + hex!["b67d3ed42ab1fcf3fcd7dee99bd6963bc22058ee22bcfddddb776492e85bd76e"] + .unchecked_into(), + //5GnZZ1rs7RE1jwPiyw1kts4JqaxnML5SdsWMuHV9TqCcuPWj + hex!["d0dd492b1a33d2f06a9aa7213e1aaa41d8820a6b56e95cd2462129b446574014"] .unchecked_into(), - // 5HGLmrZsiTFTPp3QoS1W8w9NxByt8PVq79reqvdxNcQkByqK - hex!["e60d23f49e93c1c1f2d7c115957df5bbd7faf5ebf138d1e9d02e8b39a1f63df0"] + //5GKEKSAa3gbitHhvu5gm4f7q942azCVGDNhrw3hnsGPEMzyg + hex!["bc04e9764e23330b9f4e6922aa6437f87f3dd17b8590825e824724ae89d4ac51"] .unchecked_into(), - // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd - hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"] + //5H6QLnsfU7sAQ5ZACs9bPivsn9CXrqqwxhq4KKyoquZb5mVW + hex!["de78b26966c08357d66f7f56e7dcac7e4beb16aa0b74939290a42b3f5949bc36"] .unchecked_into(), - // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd - hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"] + //5FUUeYiAvFfXfB5yZLNkis2ZDy9T3CBLBPC6SwXFriGEjH5f + hex!["96d61fe92a50a79944ea93e3afc0a95a328773878e774cf8c8fbe8eba81cd95c"] .unchecked_into(), - // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd - hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"] + //5DLkWtgJahWG99cMcQxtftW9W14oduySyQi6hdhav7w3BiKq + hex!["38791c68ee472b94105c66cf150387979c49175062a687d1a1509119cfdc9e0c"] .unchecked_into(), - // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd - hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"] + //5Cjm1c3Jwt5jp6AaN2XfnncgZcswAmyfJn1buHEUaPauXAKK + hex!["025185a88886008267d27797fc74e34241e3aa8da767fafc9dd3ae5a59546802bb"] .unchecked_into(), ), ]; @@ -653,6 +688,7 @@ fn kusama_staging_testnet_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeG .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) .collect(), }, + beefy: Default::default(), indices: kusama::IndicesConfig { indices: vec![] }, session: kusama::SessionConfig { keys: initial_authorities @@ -668,6 +704,7 @@ fn kusama_staging_testnet_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeG x.5.clone(), x.6.clone(), x.7.clone(), + x.8.clone(), ), ) }) @@ -1321,6 +1358,7 @@ pub fn kusama_testnet_genesis( ValidatorId, AssignmentId, AuthorityDiscoveryId, + BeefyId, )>, _root_key: AccountId, endowed_accounts: Option>, @@ -1336,6 +1374,7 @@ pub fn kusama_testnet_genesis( balances: kusama::BalancesConfig { balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), }, + beefy: Default::default(), session: kusama::SessionConfig { keys: initial_authorities .iter() @@ -1350,6 +1389,7 @@ pub fn kusama_testnet_genesis( x.5.clone(), x.6.clone(), x.7.clone(), + x.8.clone(), ), ) }) @@ -1405,6 +1445,7 @@ pub fn westend_testnet_genesis( ValidatorId, AssignmentId, AuthorityDiscoveryId, + BeefyId, )>, root_key: AccountId, endowed_accounts: Option>, @@ -1420,6 +1461,7 @@ pub fn westend_testnet_genesis( balances: westend::BalancesConfig { balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), }, + beefy: Default::default(), session: westend::SessionConfig { keys: initial_authorities .iter() @@ -1434,6 +1476,7 @@ pub fn westend_testnet_genesis( x.5.clone(), x.6.clone(), x.7.clone(), + x.8.clone(), ), ) }) @@ -1583,7 +1626,7 @@ fn polkadot_development_config_genesis(wasm_binary: &[u8]) -> polkadot::RuntimeG fn kusama_development_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeGenesisConfig { kusama_testnet_genesis( wasm_binary, - vec![get_authority_keys_from_seed_no_beefy("Alice")], + vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed::("Alice"), None, ) @@ -1593,7 +1636,7 @@ fn kusama_development_config_genesis(wasm_binary: &[u8]) -> kusama::RuntimeGenes fn westend_development_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { westend_testnet_genesis( wasm_binary, - vec![get_authority_keys_from_seed_no_beefy("Alice")], + vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed::("Alice"), None, ) @@ -1772,10 +1815,7 @@ pub fn polkadot_local_testnet_config() -> Result { fn kusama_local_testnet_genesis(wasm_binary: &[u8]) -> kusama::RuntimeGenesisConfig { kusama_testnet_genesis( wasm_binary, - vec![ - get_authority_keys_from_seed_no_beefy("Alice"), - get_authority_keys_from_seed_no_beefy("Bob"), - ], + vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], get_account_id_from_seed::("Alice"), None, ) @@ -1804,10 +1844,7 @@ pub fn kusama_local_testnet_config() -> Result { fn westend_local_testnet_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig { westend_testnet_genesis( wasm_binary, - vec![ - get_authority_keys_from_seed_no_beefy("Alice"), - get_authority_keys_from_seed_no_beefy("Bob"), - ], + vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], get_account_id_from_seed::("Alice"), None, ) diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 3d9486ccc87b..95c887947c98 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -753,13 +753,9 @@ pub fn new_full( Some(backoff) }; - // If not on a known test network, warn the user that BEEFY is still experimental. - if enable_beefy && - !config.chain_spec.is_rococo() && - !config.chain_spec.is_wococo() && - !config.chain_spec.is_versi() - { - gum::warn!("BEEFY is still experimental, usage on a production network is discouraged."); + // Warn the user that BEEFY is still experimental for Polkadot. + if enable_beefy && config.chain_spec.is_polkadot() { + gum::warn!("BEEFY is still experimental, usage on Polkadot network is discouraged."); } let disable_grandpa = config.disable_grandpa; @@ -1204,14 +1200,14 @@ pub fn new_full( let gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); - // BEEFY currently only runs on testnets, if it fails we'll - // bring the node down with it to make sure it is noticed. + // BEEFY is part of consensus, if it fails we'll bring the node down with it to make sure it + // is noticed. task_manager .spawn_essential_handle() .spawn_blocking("beefy-gadget", None, gadget); - + // When offchain indexing is enabled, MMR gadget should also run. if is_offchain_indexing_enabled { - task_manager.spawn_handle().spawn_blocking( + task_manager.spawn_essential_handle().spawn_blocking( "mmr-gadget", None, MmrGadget::start( diff --git a/runtime/kusama/Cargo.toml b/runtime/kusama/Cargo.toml index 28598bde9443..a88654d26121 100644 --- a/runtime/kusama/Cargo.toml +++ b/runtime/kusama/Cargo.toml @@ -20,11 +20,13 @@ smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } beefy-primitives = { package = "sp-consensus-beefy", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +binary-merkle-tree = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } kusama-runtime-constants = { package = "kusama-runtime-constants", path = "./constants", default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } offchain-primitives = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -42,6 +44,8 @@ pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-bags-list = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-bounties = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-child-bounties = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -61,6 +65,7 @@ pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = " pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -144,6 +149,8 @@ std = [ "pallet-authorship/std", "pallet-bags-list/std", "pallet-balances/std", + "pallet-beefy/std", + "pallet-beefy-mmr/std", "pallet-bounties/std", "pallet-child-bounties/std", "pallet-transaction-payment/std", @@ -161,6 +168,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-mmr/std", "pallet-multisig/std", "pallet-nomination-pools/std", "pallet-nomination-pools-runtime-api/std", @@ -184,6 +192,7 @@ std = [ "pallet-whitelist/std", "pallet-babe/std", "pallet-xcm/std", + "sp-application-crypto/std", "sp-mmr-primitives/std", "sp-runtime/std", "sp-staking/std", @@ -265,6 +274,8 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", + "pallet-beefy/try-runtime", + "pallet-beefy-mmr/try-runtime", "pallet-bounties/try-runtime", "pallet-child-bounties/try-runtime", "pallet-transaction-payment/try-runtime", @@ -281,6 +292,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-offences/try-runtime", diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index c7077e38a653..3d6a56cfecbd 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -52,7 +52,10 @@ use runtime_parachains::{ }; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; -use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; +use beefy_primitives::{ + ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}, + mmr::{BeefyDataProvider, MmrLeafVersion}, +}; use frame_election_provider_support::{ bounds::ElectionBoundsBuilder, generate_solution_type, onchain, NposSolution, SequentialPhragmen, @@ -71,13 +74,12 @@ use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; -use sp_core::{ConstU128, OpaqueMetadata}; -use sp_mmr_primitives as mmr; +use sp_core::{ConstU128, OpaqueMetadata, H256}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, - OpaqueKeys, SaturatedConversion, Verify, + Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, @@ -316,6 +318,81 @@ impl pallet_balances::Config for Runtime { type MaxHolds = ConstU32<1>; } +parameter_types! { + pub BeefySetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); +} + +impl pallet_beefy::Config for Runtime { + type BeefyId = BeefyId; + type MaxAuthorities = MaxAuthorities; + type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxSetIdSessionEntries = BeefySetIdSessionEntries; + type OnNewValidatorSet = BeefyMmrLeaf; + type WeightInfo = (); + type KeyOwnerProof = >::Proof; + type EquivocationReportSystem = + pallet_beefy::EquivocationReportSystem; +} + +impl pallet_mmr::Config for Runtime { + const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; + type Hashing = Keccak256; + type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; + type WeightInfo = (); + type LeafData = pallet_beefy_mmr::Pallet; +} + +/// MMR helper types. +mod mmr { + use super::Runtime; + pub use pallet_mmr::primitives::*; + + pub type Leaf = <::LeafData as LeafDataProvider>::LeafData; + pub type Hashing = ::Hashing; + pub type Hash = ::Output; +} + +parameter_types! { + /// Version of the produced MMR leaf. + /// + /// The version consists of two parts; + /// - `major` (3 bits) + /// - `minor` (5 bits) + /// + /// `major` should be updated only if decoding the previous MMR Leaf format from the payload + /// is not possible (i.e. backward incompatible change). + /// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE + /// encoding does not prevent old leafs from being decoded. + /// + /// Hence we expect `major` to be changed really rarely (think never). + /// See [`MmrLeafVersion`] type documentation for more details. + pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0); +} + +/// A BEEFY data provider that merkelizes all the parachain heads at the current block +/// (sorted by their parachain id). +pub struct ParaHeadsRootProvider; +impl BeefyDataProvider for ParaHeadsRootProvider { + fn extra_data() -> H256 { + let mut para_heads: Vec<(u32, Vec)> = Paras::parachains() + .into_iter() + .filter_map(|id| Paras::para_head(&id).map(|head| (id.into(), head.0))) + .collect(); + para_heads.sort_by_key(|k| k.0); + binary_merkle_tree::merkle_root::( + para_heads.into_iter().map(|pair| pair.encode()), + ) + .into() + } +} + +impl pallet_beefy_mmr::Config for Runtime { + type LeafVersion = LeafVersion; + type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; + type LeafExtra = H256; + type BeefyDataProvider = ParaHeadsRootProvider; +} + parameter_types! { pub const TransactionByteFee: Balance = 10 * MILLICENTS; /// This value increases the priority of `Operational` transactions by adding @@ -347,6 +424,17 @@ impl pallet_authorship::Config for Runtime { type EventHandler = (Staking, ImOnline); } +impl_opaque_keys! { + pub struct OldSessionKeys { + pub grandpa: Grandpa, + pub babe: Babe, + pub im_online: ImOnline, + pub para_validator: Initializer, + pub para_assignment: ParaSessionInfo, + pub authority_discovery: AuthorityDiscovery, + } +} + impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, @@ -355,6 +443,33 @@ impl_opaque_keys! { pub para_validator: Initializer, pub para_assignment: ParaSessionInfo, pub authority_discovery: AuthorityDiscovery, + pub beefy: Beefy, + } +} + +// remove this when removing `OldSessionKeys` +fn transform_session_keys(v: AccountId, old: OldSessionKeys) -> SessionKeys { + SessionKeys { + grandpa: old.grandpa, + babe: old.babe, + im_online: old.im_online, + para_validator: old.para_validator, + para_assignment: old.para_assignment, + authority_discovery: old.authority_discovery, + beefy: { + // From Session::upgrade_keys(): + // + // Care should be taken that the raw versions of the + // added keys are unique for every `ValidatorId, KeyTypeId` combination. + // This is an invariant that the session pallet typically maintains internally. + // + // So, produce a dummy value that's unique for the `ValidatorId, KeyTypeId` combination. + let mut id: BeefyId = sp_application_crypto::ecdsa::Public::from_raw([0u8; 33]).into(); + let id_raw: &mut [u8] = id.as_mut(); + id_raw[1..33].copy_from_slice(v.as_ref()); + id_raw[0..4].copy_from_slice(b"beef"); + id + }, } } @@ -1390,6 +1505,14 @@ construct_runtime! { Staking: pallet_staking::{Pallet, Call, Storage, Config, Event} = 6, Offences: pallet_offences::{Pallet, Storage, Event} = 7, Historical: session_historical::{Pallet} = 34, + + // BEEFY Bridges support. + Beefy: pallet_beefy::{Pallet, Call, Storage, Config, ValidateUnsigned} = 200, + // MMR leaf construction must be before session in order to have leaf contents + // refer to block consistently. see substrate issue #11797 for details. + Mmr: pallet_mmr::{Pallet, Storage} = 201, + BeefyMmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 202, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 8, Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 10, ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config} = 11, @@ -1527,7 +1650,7 @@ impl Get for NominationPoolsMigrationV4OldPallet { /// /// This contains the combined migrations of the last 10 releases. It allows to skip runtime /// upgrades in case governance decides to do so. THE ORDER IS IMPORTANT. -pub type Migrations = (migrations::Unreleased,); +pub type Migrations = migrations::Unreleased; /// The runtime migrations per release. #[allow(deprecated, missing_docs)] @@ -1579,6 +1702,16 @@ pub mod migrations { type PalletName = TipsPalletName; } + /// Upgrade Session keys to include BEEFY key. + /// When this is removed, should also remove `OldSessionKeys`. + pub struct UpgradeSessionKeys; + impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { + fn on_runtime_upgrade() -> Weight { + Session::upgrade_keys::(transform_session_keys); + Perbill::from_percent(50) * BlockWeights::get().max_block + } + } + /// Unreleased migrations. Add new ones here: pub type Unreleased = ( init_state_migration::InitMigrate, @@ -1606,6 +1739,8 @@ pub mod migrations { frame_support::migrations::RemovePallet::DbWeight>, frame_support::migrations::RemovePallet::DbWeight>, + // Upgrade SessionKeys to include BEEFY key + UpgradeSessionKeys, ); } @@ -1886,62 +2021,94 @@ sp_api::impl_runtime_apis! { impl beefy_primitives::BeefyApi for Runtime { fn beefy_genesis() -> Option { - // dummy implementation due to lack of BEEFY pallet. - None + Beefy::genesis_block() } fn validator_set() -> Option> { - // dummy implementation due to lack of BEEFY pallet. - None + Beefy::validator_set() } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: beefy_primitives::EquivocationProof< + equivocation_proof: beefy_primitives::EquivocationProof< BlockNumber, BeefyId, BeefySignature, >, - _key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, + key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, ) -> Option<()> { - None + let key_owner_proof = key_owner_proof.decode()?; + + Beefy::submit_unsigned_equivocation_report( + equivocation_proof, + key_owner_proof, + ) } fn generate_key_ownership_proof( _set_id: beefy_primitives::ValidatorSetId, - _authority_id: BeefyId, + authority_id: BeefyId, ) -> Option { - None + use parity_scale_codec::Encode; + + Historical::prove((beefy_primitives::KEY_TYPE, authority_id)) + .map(|p| p.encode()) + .map(beefy_primitives::OpaqueKeyOwnershipProof::new) } } impl mmr::MmrApi for Runtime { - fn mmr_root() -> Result { - Err(mmr::Error::PalletNotIncluded) + fn mmr_root() -> Result { + Ok(Mmr::mmr_root()) } fn mmr_leaf_count() -> Result { - Err(mmr::Error::PalletNotIncluded) + Ok(Mmr::mmr_leaves()) } fn generate_proof( - _block_numbers: Vec, - _best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { - Err(mmr::Error::PalletNotIncluded) + block_numbers: Vec, + best_known_block_number: Option, + ) -> Result<(Vec, mmr::Proof), mmr::Error> { + Mmr::generate_proof(block_numbers, best_known_block_number).map( + |(leaves, proof)| { + ( + leaves + .into_iter() + .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) + .collect(), + proof, + ) + }, + ) } - fn verify_proof(_leaves: Vec, _proof: mmr::Proof) + fn verify_proof(leaves: Vec, proof: mmr::Proof) -> Result<(), mmr::Error> { - Err(mmr::Error::PalletNotIncluded) + let leaves = leaves.into_iter().map(|leaf| + leaf.into_opaque_leaf() + .try_decode() + .ok_or(mmr::Error::Verify)).collect::, mmr::Error>>()?; + Mmr::verify_leaves(leaves, proof) } fn verify_proof_stateless( - _root: Hash, - _leaves: Vec, - _proof: mmr::Proof + root: mmr::Hash, + leaves: Vec, + proof: mmr::Proof ) -> Result<(), mmr::Error> { - Err(mmr::Error::PalletNotIncluded) + let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); + pallet_mmr::verify_leaves_proof::(root, nodes, proof) + } + } + + impl pallet_beefy_mmr::BeefyMmrApi for RuntimeApi { + fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { + BeefyMmrLeaf::authority_set_proof() + } + + fn next_authority_set_proof() -> beefy_primitives::mmr::BeefyNextAuthoritySet { + BeefyMmrLeaf::next_authority_set_proof() } } diff --git a/runtime/kusama/src/tests.rs b/runtime/kusama/src/tests.rs index 5383e2824687..053c3054ab46 100644 --- a/runtime/kusama/src/tests.rs +++ b/runtime/kusama/src/tests.rs @@ -148,7 +148,7 @@ fn nominator_limit() { #[test] fn call_size() { - RuntimeCall::assert_size_under(230); + RuntimeCall::assert_size_under(256); } #[test] diff --git a/runtime/parachains/src/disputes/slashing/benchmarking.rs b/runtime/parachains/src/disputes/slashing/benchmarking.rs index 271da6d58437..3ede1c908802 100644 --- a/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -23,7 +23,7 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_staking::testing_utils::create_validators; use parity_scale_codec::Decode; use primitives::{Hash, PARACHAIN_KEY_TYPE_ID}; -use sp_runtime::traits::{One, StaticLookup}; +use sp_runtime::traits::{One, OpaqueKeys, StaticLookup}; use sp_session::MembershipProof; // Candidate hash of the disputed candidate. @@ -54,9 +54,14 @@ where let controller = pallet_staking::Pallet::::bonded(validator).unwrap(); let keys = { - const NUM_SESSION_KEYS: usize = 6; const SESSION_KEY_LEN: usize = 32; - let mut keys = [0u8; NUM_SESSION_KEYS * SESSION_KEY_LEN]; + let key_ids = T::Keys::key_ids(); + let mut keys_len = key_ids.len() * SESSION_KEY_LEN; + if key_ids.contains(&sp_core::crypto::key_types::BEEFY) { + // BEEFY key is 33 bytes long, not 32. + keys_len += 1; + } + let mut keys = vec![0u8; keys_len]; let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(n as u64); rng.fill_bytes(&mut keys); keys diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index ad10de445ab3..dca0d0d986da 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -2346,12 +2346,7 @@ mod test { #[test] fn call_size() { - assert!( - core::mem::size_of::() <= 230, - "size of RuntimeCall is more than 230 bytes: some calls have too big arguments, use Box to \ - reduce the size of RuntimeCall. - If the limit is too strong, maybe consider increase the limit", - ); + RuntimeCall::assert_size_under(230); } #[test] diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index fb2a56c8100c..145b25d8aa9a 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -1331,8 +1331,8 @@ parameter_types! { pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0); } -pub struct ParasProvider; -impl BeefyDataProvider for ParasProvider { +pub struct ParaHeadsRootProvider; +impl BeefyDataProvider for ParaHeadsRootProvider { fn extra_data() -> H256 { let mut para_heads: Vec<(u32, Vec)> = Paras::parachains() .into_iter() @@ -1350,7 +1350,7 @@ impl pallet_beefy_mmr::Config for Runtime { type LeafVersion = LeafVersion; type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; type LeafExtra = H256; - type BeefyDataProvider = ParasProvider; + type BeefyDataProvider = ParaHeadsRootProvider; } impl paras_sudo_wrapper::Config for Runtime {} @@ -1402,9 +1402,14 @@ construct_runtime! { Authorship: pallet_authorship::{Pallet, Storage} = 5, Offences: pallet_offences::{Pallet, Storage, Event} = 7, Historical: session_historical::{Pallet} = 34, + + // BEEFY Bridges support. + Beefy: pallet_beefy::{Pallet, Call, Storage, Config, ValidateUnsigned} = 240, // MMR leaf construction must be before session in order to have leaf contents // refer to block consistently. see substrate issue #11797 for details. Mmr: pallet_mmr::{Pallet, Storage} = 241, + MmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 242, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 8, Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 10, ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config} = 11, @@ -1488,12 +1493,6 @@ construct_runtime! { // Pallet for sending XCM. XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, - // Rococo specific pallets (not included in Kusama). Start indices at 240 - // - // BEEFY Bridges support. - Beefy: pallet_beefy::{Pallet, Call, Storage, Config, ValidateUnsigned} = 240, - MmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 242, - ParasSudoWrapper: paras_sudo_wrapper::{Pallet, Call} = 250, AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event, Config} = 251, diff --git a/runtime/westend/Cargo.toml b/runtime/westend/Cargo.toml index 79583fc2fb1e..a0b13145578d 100644 --- a/runtime/westend/Cargo.toml +++ b/runtime/westend/Cargo.toml @@ -19,9 +19,11 @@ smallvec = "1.8.0" authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } beefy-primitives = { package = "sp-consensus-beefy", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +binary-merkle-tree = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } offchain-primitives = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -45,6 +47,8 @@ pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-bags-list = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-collective = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-democracy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-elections-phragmen = { package = "pallet-elections-phragmen", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -56,6 +60,7 @@ pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = " pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -134,6 +139,8 @@ std = [ "pallet-authority-discovery/std", "pallet-authorship/std", "pallet-balances/std", + "pallet-beefy/std", + "pallet-beefy-mmr/std", "pallet-transaction-payment/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-collective/std", @@ -147,6 +154,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-mmr/std", "beefy-primitives/std", "pallet-multisig/std", "pallet-nomination-pools/std", @@ -170,6 +178,7 @@ std = [ "pallet-babe/std", "pallet-bags-list/std", "frame-executive/std", + "sp-application-crypto/std", "sp-mmr-primitives/std", "sp-runtime/std", "sp-staking/std", @@ -243,6 +252,8 @@ try-runtime = [ "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", + "pallet-beefy/try-runtime", + "pallet-beefy-mmr/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-collective/try-runtime", "pallet-elections-phragmen/try-runtime", @@ -255,6 +266,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-offences/try-runtime", diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 3ade28c51fba..62770e0992fb 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -17,11 +17,14 @@ //! The Westend runtime. This can be compiled with `#[no_std]`, ready for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512. +#![recursion_limit = "512"] use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; -use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; +use beefy_primitives::{ + ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}, + mmr::{BeefyDataProvider, MmrLeafVersion}, +}; use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, SequentialPhragmen}; use frame_support::{ construct_runtime, parameter_types, @@ -64,15 +67,14 @@ use runtime_parachains::{ shared as parachains_shared, }; use scale_info::TypeInfo; -use sp_core::{OpaqueMetadata, RuntimeDebug}; -use sp_mmr_primitives as mmr; +use sp_core::{OpaqueMetadata, RuntimeDebug, H256}; use sp_runtime::{ create_runtime_str, curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, - OpaqueKeys, SaturatedConversion, Verify, + Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, @@ -271,6 +273,81 @@ impl pallet_balances::Config for Runtime { type MaxFreezes = ConstU32<0>; } +parameter_types! { + pub const BeefySetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); +} + +impl pallet_beefy::Config for Runtime { + type BeefyId = BeefyId; + type MaxAuthorities = MaxAuthorities; + type MaxNominators = MaxNominatorRewardedPerValidator; + type MaxSetIdSessionEntries = BeefySetIdSessionEntries; + type OnNewValidatorSet = BeefyMmrLeaf; + type WeightInfo = (); + type KeyOwnerProof = >::Proof; + type EquivocationReportSystem = + pallet_beefy::EquivocationReportSystem; +} + +impl pallet_mmr::Config for Runtime { + const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; + type Hashing = Keccak256; + type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; + type WeightInfo = (); + type LeafData = pallet_beefy_mmr::Pallet; +} + +/// MMR helper types. +mod mmr { + use super::Runtime; + pub use pallet_mmr::primitives::*; + + pub type Leaf = <::LeafData as LeafDataProvider>::LeafData; + pub type Hashing = ::Hashing; + pub type Hash = ::Output; +} + +parameter_types! { + /// Version of the produced MMR leaf. + /// + /// The version consists of two parts; + /// - `major` (3 bits) + /// - `minor` (5 bits) + /// + /// `major` should be updated only if decoding the previous MMR Leaf format from the payload + /// is not possible (i.e. backward incompatible change). + /// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE + /// encoding does not prevent old leafs from being decoded. + /// + /// Hence we expect `major` to be changed really rarely (think never). + /// See [`MmrLeafVersion`] type documentation for more details. + pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0); +} + +/// A BEEFY data provider that merkelizes all the parachain heads at the current block +/// (sorted by their parachain id). +pub struct ParaHeadsRootProvider; +impl BeefyDataProvider for ParaHeadsRootProvider { + fn extra_data() -> H256 { + let mut para_heads: Vec<(u32, Vec)> = Paras::parachains() + .into_iter() + .filter_map(|id| Paras::para_head(&id).map(|head| (id.into(), head.0))) + .collect(); + para_heads.sort_by_key(|k| k.0); + binary_merkle_tree::merkle_root::( + para_heads.into_iter().map(|pair| pair.encode()), + ) + .into() + } +} + +impl pallet_beefy_mmr::Config for Runtime { + type LeafVersion = LeafVersion; + type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; + type LeafExtra = H256; + type BeefyDataProvider = ParaHeadsRootProvider; +} + parameter_types! { pub const TransactionByteFee: Balance = 10 * MILLICENTS; /// This value increases the priority of `Operational` transactions by adding @@ -307,6 +384,17 @@ parameter_types! { pub const Offset: BlockNumber = 0; } +impl_opaque_keys! { + pub struct OldSessionKeys { + pub grandpa: Grandpa, + pub babe: Babe, + pub im_online: ImOnline, + pub para_validator: Initializer, + pub para_assignment: ParaSessionInfo, + pub authority_discovery: AuthorityDiscovery, + } +} + impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, @@ -315,6 +403,33 @@ impl_opaque_keys! { pub para_validator: Initializer, pub para_assignment: ParaSessionInfo, pub authority_discovery: AuthorityDiscovery, + pub beefy: Beefy, + } +} + +// remove this when removing `OldSessionKeys` +fn transform_session_keys(v: AccountId, old: OldSessionKeys) -> SessionKeys { + SessionKeys { + grandpa: old.grandpa, + babe: old.babe, + im_online: old.im_online, + para_validator: old.para_validator, + para_assignment: old.para_assignment, + authority_discovery: old.authority_discovery, + beefy: { + // From Session::upgrade_keys(): + // + // Care should be taken that the raw versions of the + // added keys are unique for every `ValidatorId, KeyTypeId` combination. + // This is an invariant that the session pallet typically maintains internally. + // + // So, produce a dummy value that's unique for the `ValidatorId, KeyTypeId` combination. + let mut id: BeefyId = sp_application_crypto::ecdsa::Public::from_raw([0u8; 33]).into(); + let id_raw: &mut [u8] = id.as_mut(); + id_raw[1..33].copy_from_slice(v.as_ref()); + id_raw[0..4].copy_from_slice(b"beef"); + id + }, } } @@ -1167,6 +1282,14 @@ construct_runtime! { Staking: pallet_staking::{Pallet, Call, Storage, Config, Event} = 6, Offences: pallet_offences::{Pallet, Storage, Event} = 7, Historical: session_historical::{Pallet} = 27, + + // BEEFY Bridges support. + Beefy: pallet_beefy::{Pallet, Call, Storage, Config, ValidateUnsigned} = 200, + // MMR leaf construction must be before session in order to have leaf contents + // refer to block consistently. see substrate issue #11797 for details. + Mmr: pallet_mmr::{Pallet, Storage} = 201, + BeefyMmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 202, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 8, Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 10, ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config} = 11, @@ -1284,6 +1407,16 @@ pub type Migrations = migrations::Unreleased; pub mod migrations { use super::*; + /// Upgrade Session keys to include BEEFY key. + /// When this is removed, should also remove `OldSessionKeys`. + pub struct UpgradeSessionKeys; + impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { + fn on_runtime_upgrade() -> Weight { + Session::upgrade_keys::(transform_session_keys); + Perbill::from_percent(50) * BlockWeights::get().max_block + } + } + /// Unreleased migrations. Add new ones here: pub type Unreleased = ( pallet_im_online::migration::v1::Migration, @@ -1291,6 +1424,7 @@ pub mod migrations { assigned_slots::migration::v1::VersionCheckedMigrateToV1, parachains_scheduler::migration::v1::MigrateToV1, parachains_configuration::migration::v8::MigrateToV8, + UpgradeSessionKeys, ); } @@ -1561,64 +1695,94 @@ sp_api::impl_runtime_apis! { impl beefy_primitives::BeefyApi for Runtime { fn beefy_genesis() -> Option { - // dummy implementation due to lack of BEEFY pallet. - None + Beefy::genesis_block() } fn validator_set() -> Option> { - // dummy implementation due to lack of BEEFY pallet. - None + Beefy::validator_set() } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: beefy_primitives::EquivocationProof< + equivocation_proof: beefy_primitives::EquivocationProof< BlockNumber, BeefyId, BeefySignature, >, - _key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, + key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, ) -> Option<()> { - None + let key_owner_proof = key_owner_proof.decode()?; + + Beefy::submit_unsigned_equivocation_report( + equivocation_proof, + key_owner_proof, + ) } fn generate_key_ownership_proof( _set_id: beefy_primitives::ValidatorSetId, - _authority_id: BeefyId, + authority_id: BeefyId, ) -> Option { - None + use parity_scale_codec::Encode; + + Historical::prove((beefy_primitives::KEY_TYPE, authority_id)) + .map(|p| p.encode()) + .map(beefy_primitives::OpaqueKeyOwnershipProof::new) } } impl mmr::MmrApi for Runtime { - fn mmr_root() -> Result { - Err(mmr::Error::PalletNotIncluded) + fn mmr_root() -> Result { + Ok(Mmr::mmr_root()) } fn mmr_leaf_count() -> Result { - Err(mmr::Error::PalletNotIncluded) + Ok(Mmr::mmr_leaves()) } fn generate_proof( - _block_numbers: Vec, - _best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { - Err(mmr::Error::PalletNotIncluded) + block_numbers: Vec, + best_known_block_number: Option, + ) -> Result<(Vec, mmr::Proof), mmr::Error> { + Mmr::generate_proof(block_numbers, best_known_block_number).map( + |(leaves, proof)| { + ( + leaves + .into_iter() + .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) + .collect(), + proof, + ) + }, + ) } - fn verify_proof(_leaves: Vec, _proof: mmr::Proof) + fn verify_proof(leaves: Vec, proof: mmr::Proof) -> Result<(), mmr::Error> { - - Err(mmr::Error::PalletNotIncluded) + let leaves = leaves.into_iter().map(|leaf| + leaf.into_opaque_leaf() + .try_decode() + .ok_or(mmr::Error::Verify)).collect::, mmr::Error>>()?; + Mmr::verify_leaves(leaves, proof) } fn verify_proof_stateless( - _root: Hash, - _leaves: Vec, - _proof: mmr::Proof + root: mmr::Hash, + leaves: Vec, + proof: mmr::Proof ) -> Result<(), mmr::Error> { + let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); + pallet_mmr::verify_leaves_proof::(root, nodes, proof) + } + } + + impl pallet_beefy_mmr::BeefyMmrApi for RuntimeApi { + fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { + BeefyMmrLeaf::authority_set_proof() + } - Err(mmr::Error::PalletNotIncluded) + fn next_authority_set_proof() -> beefy_primitives::mmr::BeefyNextAuthoritySet { + BeefyMmrLeaf::next_authority_set_proof() } } diff --git a/runtime/westend/src/tests.rs b/runtime/westend/src/tests.rs index 9e8acb67c36a..78062662fee0 100644 --- a/runtime/westend/src/tests.rs +++ b/runtime/westend/src/tests.rs @@ -46,12 +46,7 @@ fn sample_size_is_sensible() { #[test] fn call_size() { - assert!( - core::mem::size_of::() <= 230, - "size of RuntimeCall is more than 230 bytes: some calls have too big arguments, use Box to reduce \ - the size of RuntimeCall. - If the limit is too strong, maybe consider increase the limit to 300.", - ); + RuntimeCall::assert_size_under(256); } #[test] diff --git a/scripts/prepare-test-net.sh b/scripts/prepare-test-net.sh index 14bbd680d6ef..c908aba308a3 100755 --- a/scripts/prepare-test-net.sh +++ b/scripts/prepare-test-net.sh @@ -15,7 +15,7 @@ generate_address() { } generate_public_key() { - subkey inspect ${3:-} ${4:-} "$SECRET//$1//$2" | grep "Public" | awk '{ print $4 }' + subkey inspect ${3:-} ${4:-} "$SECRET//$1//$2" | grep "Public key (hex)" | awk '{ print $4 }' } generate_address_and_public_key() { From 8ce17160bf6e281ec4d54557c937fc9db510d987 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 10:28:19 +0000 Subject: [PATCH 43/45] Bump actions/setup-node from 3.8.0 to 3.8.1 (#7639) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3.8.0 to 3.8.1. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3.8.0...v3.8.1) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/check-licenses.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index b61005649eec..1e654f7b3070 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -9,7 +9,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v3 - - uses: actions/setup-node@v3.8.0 + - uses: actions/setup-node@v3.8.1 with: node-version: '18.x' registry-url: 'https://npm.pkg.github.com' From 9f1e9ea531687397ec68b74cb7abb1dc647c0f6a Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 22 Aug 2023 13:19:05 +0200 Subject: [PATCH 44/45] Bound number of assets which can be withdrawn to pay for execution. (#7641) * Bound number of assets which can be withdrawn to pay for execution. * ".git/.scripts/commands/fmt/fmt.sh" * Include ClaimAsset in limiting the assets * Change max assets to constant --------- Co-authored-by: command-bot <> Co-authored-by: Francisco Aguirre --- xcm/xcm-builder/src/barriers.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 6996c7145528..353e111b813b 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -52,6 +52,8 @@ impl ShouldExecute for TakeWeightCredit { } } +const MAX_ASSETS_FOR_BUY_EXECUTION: usize = 1; + /// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking /// payments into account. /// @@ -79,10 +81,10 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFro instructions[..end] .matcher() .match_next_inst(|inst| match inst { - ReceiveTeleportedAsset(..) | - WithdrawAsset(..) | - ReserveAssetDeposited(..) | - ClaimAsset { .. } => Ok(()), + ReceiveTeleportedAsset(..) | ReserveAssetDeposited(..) => Ok(()), + WithdrawAsset(ref assets) if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => Ok(()), + ClaimAsset { ref assets, .. } if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => + Ok(()), _ => Err(ProcessMessageError::BadFormat), })? .skip_inst_while(|inst| matches!(inst, ClearOrigin))? From 759fe213acd6071b4a2bfebcef08be8a5f2ecc15 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 22 Aug 2023 17:12:13 +0200 Subject: [PATCH 45/45] Fix xcm-builder mock (#7652) * Fix xcm-builder mock (preparation for monorepo) The CI fails here when the runtime-benchmarks feature is enabled in the workspace. Signed-off-by: Oliver Tale-Yazdi * Update xcm/xcm-builder/Cargo.toml --------- Signed-off-by: Oliver Tale-Yazdi --- xcm/xcm-builder/Cargo.toml | 1 + xcm/xcm-builder/src/tests/pay/mock.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/xcm/xcm-builder/Cargo.toml b/xcm/xcm-builder/Cargo.toml index 702d5bd7fa06..6e4db1016864 100644 --- a/xcm/xcm-builder/Cargo.toml +++ b/xcm/xcm-builder/Cargo.toml @@ -42,6 +42,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", ] std = [ "log/std", diff --git a/xcm/xcm-builder/src/tests/pay/mock.rs b/xcm/xcm-builder/src/tests/pay/mock.rs index 3231611d3dd8..c663b0a4d76f 100644 --- a/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/xcm/xcm-builder/src/tests/pay/mock.rs @@ -119,6 +119,8 @@ impl pallet_assets::Config for Test { type RemoveItemsLimit = RemoveItemsLimit; type AssetIdParameter = AssetIdForAssets; type CallbackHandle = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! {