From 710bab9ca9389e9cbcc6c2e59e92d0e482b08f0e Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 10 Jan 2023 15:42:51 +0100 Subject: [PATCH 01/24] Adds StakingAPI_nominations_quota and NominationPoolsApi_balanceToPoint and NominationPoolsApi_pointsToBalance runtime APIs --- Cargo.lock | 9 ++++++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 1 + bin/node/runtime/src/lib.rs | 16 ++++++++++- frame/nomination-pools/runtime-api/src/lib.rs | 11 +++++++- frame/nomination-pools/src/lib.rs | 28 +++++++++++++++++-- frame/staking/runtime-api/Cargo.toml | 24 ++++++++++++++++ frame/staking/runtime-api/README.md | 3 ++ frame/staking/runtime-api/src/lib.rs | 28 +++++++++++++++++++ frame/staking/src/pallet/impls.rs | 7 +++++ 10 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 frame/staking/runtime-api/Cargo.toml create mode 100644 frame/staking/runtime-api/README.md create mode 100644 frame/staking/runtime-api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index eb644202ae382..83d3b0c8b4cdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3479,6 +3479,7 @@ dependencies = [ "pallet-society", "pallet-staking", "pallet-staking-reward-curve", + "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-sudo", "pallet-timestamp", @@ -6395,6 +6396,14 @@ dependencies = [ "sp-arithmetic", ] +[[package]] +name = "pallet-staking-runtime-api" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 8f55d8e527ecd..53d0c590e241f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,6 +141,7 @@ members = [ "frame/staking", "frame/staking/reward-curve", "frame/staking/reward-fn", + "frame/staking/runtime-api", "frame/state-trie-migration", "frame/sudo", "frame/root-offences", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 7037be9d7c54d..4b8d498481fa3 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -96,6 +96,7 @@ pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = ". pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true } pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" } pallet-staking-reward-curve = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/reward-curve" } +pallet-staking-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/runtime-api" } pallet-state-trie-migration = { version = "4.0.0-dev", default-features = false, path = "../../../frame/state-trie-migration" } pallet-scheduler = { version = "4.0.0-dev", default-features = false, path = "../../../frame/scheduler" } pallet-society = { version = "4.0.0-dev", default-features = false, path = "../../../frame/society" } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a9e93a16f0713..3f58bb3edd228 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1972,7 +1972,21 @@ impl_runtime_apis! { impl pallet_nomination_pools_runtime_api::NominationPoolsApi for Runtime { fn pending_rewards(member_account: AccountId) -> Balance { - NominationPools::pending_rewards(member_account).unwrap_or_default() + NominationPools::api_pending_rewards(member_account).unwrap_or_default() + } + + fn points_to_balance(pool_id: u32) -> Result { + NominationPools::api_points_to_balance(pool_id) + } + + fn balance_to_point(pool_id: u32, new_funds: Balance) -> Result { + NominationPools::api_balance_to_point(pool_id, new_funds) + } + } + + impl pallet_staking_runtime_api::StakingApi for Runtime { + fn nominations_quota() -> u32 { + Staking::api_nominations_quota() } } diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index aa3ca57ca5b8b..4bc3f8d097181 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -24,10 +24,19 @@ use codec::Codec; sp_api::decl_runtime_apis! { /// Runtime api for accessing information about nomination pools. + #[api_version(1)] pub trait NominationPoolsApi - where AccountId: Codec, Balance: Codec + where + AccountId: Codec, + Balance: Codec, { /// Returns the pending rewards for the member that the AccountId was given for. fn pending_rewards(member: AccountId) -> Balance; + + /// Returns the points to balance conversion for a given pool. + fn points_to_balance(pool_id: u32) -> Result; + + /// Returns the equivalent points of `new_funds` for a given pool + fn balance_to_point(pool_id: u32, new_funds: Balance) -> Result; } } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 3cb8abedda2fb..ebc65ae9e9085 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2144,8 +2144,8 @@ pub mod pallet { impl Pallet { /// Returns the pending rewards for the specified `member_account`. /// - /// In the case of error, `None` is returned. - pub fn pending_rewards(member_account: T::AccountId) -> Option> { + /// In the case of error, `None` is returned. Used by runtime API. + pub fn api_pending_rewards(member_account: T::AccountId) -> Option> { if let Some(pool_member) = PoolMembers::::get(member_account) { if let Some((reward_pool, bonded_pool)) = RewardPools::::get(pool_member.pool_id) .zip(BondedPools::::get(pool_member.pool_id)) @@ -2160,6 +2160,30 @@ impl Pallet { None } + /// Returns the points to balance conversion for a specified pool. + /// + /// If the pool ID does not exist, return an error. Used by runtime API. + pub fn api_points_to_balance(pool_id: u32) -> Result, ()> { + if let Some(pool) = BondedPool::::get(pool_id) { + Ok(pool.points_to_balance(pool.points)) + } else { + Err(()) + } + } + + /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. + /// + /// If the pool ID does not exist, return an error. Used by runtime API. + pub fn api_balance_to_point(pool_id: u32, new_funds: BalanceOf) -> Result, ()> { + if let Some(pool) = BondedPool::::get(pool_id) { + let bonded_balance = + T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); + Ok(Pallet::::balance_to_point(bonded_balance, pool.points, new_funds)) + } else { + Err(()) + } + } + /// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS. /// /// It is the responsibility of the depositor to put these funds into the pool initially. Upon diff --git a/frame/staking/runtime-api/Cargo.toml b/frame/staking/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..9923b881c38d8 --- /dev/null +++ b/frame/staking/runtime-api/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pallet-staking-runtime-api" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "RPC runtime API for transaction payment FRAME pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", +] diff --git a/frame/staking/runtime-api/README.md b/frame/staking/runtime-api/README.md new file mode 100644 index 0000000000000..a999e519f8cbf --- /dev/null +++ b/frame/staking/runtime-api/README.md @@ -0,0 +1,3 @@ +Runtime API definition for the staking pallet. + +License: Apache-2.0 diff --git a/frame/staking/runtime-api/src/lib.rs b/frame/staking/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..2b78e94fc4817 --- /dev/null +++ b/frame/staking/runtime-api/src/lib.rs @@ -0,0 +1,28 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime API definition for the staking pallet. + +#![cfg_attr(not(feature = "std"), no_std)] + +sp_api::decl_runtime_apis! { + #[api_version(1)] + pub trait StakingApi { + /// Returns the current nominations quota for nominators. + fn nominations_quota() -> u32; + } +} diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7af9b0aaaa04a..7b3ebaa2d1bed 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -59,6 +59,13 @@ use super::{pallet::*, STAKING_ID}; const NPOS_MAX_ITERATIONS_COEFFICIENT: u32 = 2; impl Pallet { + /// Returns the current nominations quota for nominators. + /// + /// Used by runtime API. + pub fn api_nominations_quota() -> u32 { + T::MaxNominations::get() + } + /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. From 11c4f61bd0a90ebd54a96796100899418221d9fc Mon Sep 17 00:00:00 2001 From: gpestana Date: Wed, 11 Jan 2023 12:08:36 +0100 Subject: [PATCH 02/24] Adds balance param to api_nominations_quota --- bin/node/runtime/src/lib.rs | 6 +++--- frame/staking/runtime-api/src/lib.rs | 11 ++++++++--- frame/staking/src/pallet/impls.rs | 6 +++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3f58bb3edd228..4d7cd7a64b5a2 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1984,9 +1984,9 @@ impl_runtime_apis! { } } - impl pallet_staking_runtime_api::StakingApi for Runtime { - fn nominations_quota() -> u32 { - Staking::api_nominations_quota() + impl pallet_staking_runtime_api::StakingApi for Runtime { + fn nominations_quota(balance: Balance) -> u32 { + Staking::api_nominations_quota(balance) } } diff --git a/frame/staking/runtime-api/src/lib.rs b/frame/staking/runtime-api/src/lib.rs index 2b78e94fc4817..dece7d4de71e3 100644 --- a/frame/staking/runtime-api/src/lib.rs +++ b/frame/staking/runtime-api/src/lib.rs @@ -19,10 +19,15 @@ #![cfg_attr(not(feature = "std"), no_std)] +use codec::Codec; + sp_api::decl_runtime_apis! { #[api_version(1)] - pub trait StakingApi { - /// Returns the current nominations quota for nominators. - fn nominations_quota() -> u32; + pub trait StakingApi + where + Balance: Codec, + { + /// Returns the nominations quota for a nominator with a given balance. + fn nominations_quota(balance: Balance) -> u32; } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7b3ebaa2d1bed..5f59d54f591e8 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -62,7 +62,11 @@ impl Pallet { /// Returns the current nominations quota for nominators. /// /// Used by runtime API. - pub fn api_nominations_quota() -> u32 { + /// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it + /// is redundant. However, with the upcoming changes in https://github.com/paritytech/substrate/pull/12970 + /// the nominations quota will change depending on the nominators balance. We're introducing + /// this runtime API now to prepare the community to use it before rolling out PR#12970. + pub fn api_nominations_quota(_balance: BalanceOf) -> u32 { T::MaxNominations::get() } From 326808816ca8c3623cbdc676c271436176f67408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 13 Jan 2023 15:31:42 +0000 Subject: [PATCH 03/24] Update frame/nomination-pools/src/lib.rs Co-authored-by: Anton --- frame/nomination-pools/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index ebc65ae9e9085..077a6849f7070 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2173,7 +2173,7 @@ impl Pallet { /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. /// - /// If the pool ID does not exist, return an error. Used by runtime API. + /// If the pool ID does not exist, it returns an error. Used by runtime API. pub fn api_balance_to_point(pool_id: u32, new_funds: BalanceOf) -> Result, ()> { if let Some(pool) = BondedPool::::get(pool_id) { let bonded_balance = From ca2ed2f8839f5930e1d5d1f808dc9fd3df66e39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 13 Jan 2023 15:32:34 +0000 Subject: [PATCH 04/24] Update frame/nomination-pools/src/lib.rs Co-authored-by: Anton --- frame/nomination-pools/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 077a6849f7070..8ee415ebddb88 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2162,7 +2162,7 @@ impl Pallet { /// Returns the points to balance conversion for a specified pool. /// - /// If the pool ID does not exist, return an error. Used by runtime API. + /// If the pool ID does not exist, it returns an error. Used by runtime API. pub fn api_points_to_balance(pool_id: u32) -> Result, ()> { if let Some(pool) = BondedPool::::get(pool_id) { Ok(pool.points_to_balance(pool.points)) From a31efce63af8a6c101b61ad1a091ea62697ec3ff Mon Sep 17 00:00:00 2001 From: gpestana Date: Fri, 13 Jan 2023 18:13:57 +0100 Subject: [PATCH 05/24] Addresses comments - returns zero instead of error in runtime api --- bin/node/runtime/src/lib.rs | 6 +++--- frame/nomination-pools/runtime-api/src/lib.rs | 4 ++-- frame/nomination-pools/src/lib.rs | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4d7cd7a64b5a2..146d77cab3256 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1975,12 +1975,12 @@ impl_runtime_apis! { NominationPools::api_pending_rewards(member_account).unwrap_or_default() } - fn points_to_balance(pool_id: u32) -> Result { + fn points_to_balance(pool_id: u32) -> Balance { NominationPools::api_points_to_balance(pool_id) } - fn balance_to_point(pool_id: u32, new_funds: Balance) -> Result { - NominationPools::api_balance_to_point(pool_id, new_funds) + fn balance_to_points(pool_id: u32, new_funds: Balance) -> Balance { + NominationPools::api_balance_to_points(pool_id, new_funds) } } diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index 4bc3f8d097181..b98c42f5b8bb1 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -34,9 +34,9 @@ sp_api::decl_runtime_apis! { fn pending_rewards(member: AccountId) -> Balance; /// Returns the points to balance conversion for a given pool. - fn points_to_balance(pool_id: u32) -> Result; + fn points_to_balance(pool_id: u32) -> Balance; /// Returns the equivalent points of `new_funds` for a given pool - fn balance_to_point(pool_id: u32, new_funds: Balance) -> Result; + fn balance_to_points(pool_id: u32, new_funds: Balance) -> Balance; } } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 8ee415ebddb88..7ab03b9142b84 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2163,24 +2163,24 @@ impl Pallet { /// Returns the points to balance conversion for a specified pool. /// /// If the pool ID does not exist, it returns an error. Used by runtime API. - pub fn api_points_to_balance(pool_id: u32) -> Result, ()> { + pub fn api_points_to_balance(pool_id: u32) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { - Ok(pool.points_to_balance(pool.points)) + pool.points_to_balance(pool.points) } else { - Err(()) + Zero::zero() } } /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. /// /// If the pool ID does not exist, it returns an error. Used by runtime API. - pub fn api_balance_to_point(pool_id: u32, new_funds: BalanceOf) -> Result, ()> { + pub fn api_balance_to_points(pool_id: u32, new_funds: BalanceOf) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { let bonded_balance = T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); - Ok(Pallet::::balance_to_point(bonded_balance, pool.points, new_funds)) + Pallet::::balance_to_point(bonded_balance, pool.points, new_funds) } else { - Err(()) + Zero::zero() } } From 5dfae89057705c9bdf0f3954304f9854c4c40702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 14 Jan 2023 11:49:22 +0000 Subject: [PATCH 06/24] Update frame/staking/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/staking/runtime-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/runtime-api/src/lib.rs b/frame/staking/runtime-api/src/lib.rs index dece7d4de71e3..431b0c74c67a3 100644 --- a/frame/staking/runtime-api/src/lib.rs +++ b/frame/staking/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From 9e9e79302e48c0c513911e1f961c7f41ee97f9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 14 Jan 2023 11:49:29 +0000 Subject: [PATCH 07/24] Update frame/staking/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/staking/runtime-api/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/staking/runtime-api/src/lib.rs b/frame/staking/runtime-api/src/lib.rs index 431b0c74c67a3..378599c665506 100644 --- a/frame/staking/runtime-api/src/lib.rs +++ b/frame/staking/runtime-api/src/lib.rs @@ -22,7 +22,6 @@ use codec::Codec; sp_api::decl_runtime_apis! { - #[api_version(1)] pub trait StakingApi where Balance: Codec, From 0a8059a1c474842f9395dc95dc4743d9d8b5a973 Mon Sep 17 00:00:00 2001 From: gpestana Date: Sat, 14 Jan 2023 13:32:13 +0100 Subject: [PATCH 08/24] Addresses PR comments --- Cargo.lock | 1 + bin/node/runtime/src/lib.rs | 8 ++-- frame/nomination-pools/runtime-api/Cargo.toml | 2 + frame/nomination-pools/runtime-api/src/lib.rs | 8 ++-- frame/nomination-pools/src/lib.rs | 10 ++-- frame/nomination-pools/src/tests.rs | 46 +++++++++---------- 6 files changed, 39 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83d3b0c8b4cdf..7a1f789f29735 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6025,6 +6025,7 @@ dependencies = [ name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" dependencies = [ + "pallet-nomination-pools", "parity-scale-codec", "sp-api", "sp-std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 146d77cab3256..bab985c38af54 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1971,15 +1971,15 @@ impl_runtime_apis! { } impl pallet_nomination_pools_runtime_api::NominationPoolsApi for Runtime { - fn pending_rewards(member_account: AccountId) -> Balance { - NominationPools::api_pending_rewards(member_account).unwrap_or_default() + fn pending_rewards(who: AccountId) -> Balance { + NominationPools::api_pending_rewards(who).unwrap_or_default() } - fn points_to_balance(pool_id: u32) -> Balance { + fn points_to_balance(pool_id: pallet_nomination_pools::PoolId) -> Balance { NominationPools::api_points_to_balance(pool_id) } - fn balance_to_points(pool_id: u32, new_funds: Balance) -> Balance { + fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { NominationPools::api_balance_to_points(pool_id, new_funds) } } diff --git a/frame/nomination-pools/runtime-api/Cargo.toml b/frame/nomination-pools/runtime-api/Cargo.toml index cf72d795c9faa..689c3e835ba1f 100644 --- a/frame/nomination-pools/runtime-api/Cargo.toml +++ b/frame/nomination-pools/runtime-api/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../"} [features] default = ["std"] @@ -23,4 +24,5 @@ std = [ "codec/std", "sp-api/std", "sp-std/std", + "pallet-nomination-pools/std", ] diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index b98c42f5b8bb1..e4cbf149d0e64 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -21,22 +21,22 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Codec; +use pallet_nomination_pools::PoolId; sp_api::decl_runtime_apis! { /// Runtime api for accessing information about nomination pools. - #[api_version(1)] pub trait NominationPoolsApi where AccountId: Codec, Balance: Codec, { /// Returns the pending rewards for the member that the AccountId was given for. - fn pending_rewards(member: AccountId) -> Balance; + fn pending_rewards(who: AccountId) -> Balance; /// Returns the points to balance conversion for a given pool. - fn points_to_balance(pool_id: u32) -> Balance; + fn points_to_balance(pool_id: PoolId) -> Balance; /// Returns the equivalent points of `new_funds` for a given pool - fn balance_to_points(pool_id: u32, new_funds: Balance) -> Balance; + fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance; } } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 7ab03b9142b84..b0d3035a0010b 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2142,11 +2142,11 @@ pub mod pallet { } impl Pallet { - /// Returns the pending rewards for the specified `member_account`. + /// Returns the pending rewards for the specified `who` account. /// /// In the case of error, `None` is returned. Used by runtime API. - pub fn api_pending_rewards(member_account: T::AccountId) -> Option> { - if let Some(pool_member) = PoolMembers::::get(member_account) { + pub fn api_pending_rewards(who: T::AccountId) -> Option> { + if let Some(pool_member) = PoolMembers::::get(who) { if let Some((reward_pool, bonded_pool)) = RewardPools::::get(pool_member.pool_id) .zip(BondedPools::::get(pool_member.pool_id)) { @@ -2163,7 +2163,7 @@ impl Pallet { /// Returns the points to balance conversion for a specified pool. /// /// If the pool ID does not exist, it returns an error. Used by runtime API. - pub fn api_points_to_balance(pool_id: u32) -> BalanceOf { + pub fn api_points_to_balance(pool_id: PoolId) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { pool.points_to_balance(pool.points) } else { @@ -2174,7 +2174,7 @@ impl Pallet { /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. /// /// If the pool ID does not exist, it returns an error. Used by runtime API. - pub fn api_balance_to_points(pool_id: u32, new_funds: BalanceOf) -> BalanceOf { + pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { let bonded_balance = T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 7d5d418bbf2c8..d4ad844296f71 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -1305,51 +1305,51 @@ mod claim_payout { ExtBuilder::default().build_and_execute(|| { let ed = Balances::minimum_balance(); - assert_eq!(Pools::pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(10), Some(0)); Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); - assert_eq!(Pools::pending_rewards(10), Some(30)); - assert_eq!(Pools::pending_rewards(20), None); + assert_eq!(Pools::api_pending_rewards(10), Some(30)); + assert_eq!(Pools::api_pending_rewards(20), None); Balances::make_free_balance_be(&20, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_eq!(Pools::pending_rewards(10), Some(30)); - assert_eq!(Pools::pending_rewards(20), Some(0)); + assert_eq!(Pools::api_pending_rewards(10), Some(30)); + assert_eq!(Pools::api_pending_rewards(20), Some(0)); Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); - assert_eq!(Pools::pending_rewards(10), Some(30 + 50)); - assert_eq!(Pools::pending_rewards(20), Some(50)); - assert_eq!(Pools::pending_rewards(30), None); + assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50)); + assert_eq!(Pools::api_pending_rewards(20), Some(50)); + assert_eq!(Pools::api_pending_rewards(30), None); Balances::make_free_balance_be(&30, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); - assert_eq!(Pools::pending_rewards(10), Some(30 + 50)); - assert_eq!(Pools::pending_rewards(20), Some(50)); - assert_eq!(Pools::pending_rewards(30), Some(0)); + assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50)); + assert_eq!(Pools::api_pending_rewards(20), Some(50)); + assert_eq!(Pools::api_pending_rewards(30), Some(0)); Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); - assert_eq!(Pools::pending_rewards(10), Some(30 + 50 + 20)); - assert_eq!(Pools::pending_rewards(20), Some(50 + 20)); - assert_eq!(Pools::pending_rewards(30), Some(20)); + assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50 + 20)); + assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20)); + assert_eq!(Pools::api_pending_rewards(30), Some(20)); // 10 should claim 10, 20 should claim nothing. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); - assert_eq!(Pools::pending_rewards(10), Some(0)); - assert_eq!(Pools::pending_rewards(20), Some(50 + 20)); - assert_eq!(Pools::pending_rewards(30), Some(20)); + assert_eq!(Pools::api_pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20)); + assert_eq!(Pools::api_pending_rewards(30), Some(20)); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); - assert_eq!(Pools::pending_rewards(10), Some(0)); - assert_eq!(Pools::pending_rewards(20), Some(0)); - assert_eq!(Pools::pending_rewards(30), Some(20)); + assert_eq!(Pools::api_pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(20), Some(0)); + assert_eq!(Pools::api_pending_rewards(30), Some(20)); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); - assert_eq!(Pools::pending_rewards(10), Some(0)); - assert_eq!(Pools::pending_rewards(20), Some(0)); - assert_eq!(Pools::pending_rewards(30), Some(0)); + assert_eq!(Pools::api_pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(20), Some(0)); + assert_eq!(Pools::api_pending_rewards(30), Some(0)); }); } From 8b848fd62ec9e6163379ccb544b8f7f7d8c2ac85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 7 Feb 2023 16:15:27 +0000 Subject: [PATCH 09/24] Update frame/nomination-pools/runtime-api/Cargo.toml Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/nomination-pools/runtime-api/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/runtime-api/Cargo.toml b/frame/nomination-pools/runtime-api/Cargo.toml index 689c3e835ba1f..70794be264726 100644 --- a/frame/nomination-pools/runtime-api/Cargo.toml +++ b/frame/nomination-pools/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } -pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../"} +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" } [features] default = ["std"] From 825f3125f1ea7417e4a579bb5ebde3c83ae2524e Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 7 Feb 2023 13:17:38 -0300 Subject: [PATCH 10/24] Fixes points_to_balance logic; adds tests --- bin/node/runtime/src/lib.rs | 4 +- frame/nomination-pools/runtime-api/src/lib.rs | 2 +- frame/nomination-pools/src/lib.rs | 8 ++-- frame/nomination-pools/src/tests.rs | 40 +++++++++++++++++++ 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bab985c38af54..5d29f175d46da 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1975,8 +1975,8 @@ impl_runtime_apis! { NominationPools::api_pending_rewards(who).unwrap_or_default() } - fn points_to_balance(pool_id: pallet_nomination_pools::PoolId) -> Balance { - NominationPools::api_points_to_balance(pool_id) + fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { + NominationPools::api_points_to_balance(pool_id, points) } fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index e4cbf149d0e64..c9149c29497b4 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -34,7 +34,7 @@ sp_api::decl_runtime_apis! { fn pending_rewards(who: AccountId) -> Balance; /// Returns the points to balance conversion for a given pool. - fn points_to_balance(pool_id: PoolId) -> Balance; + fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance; /// Returns the equivalent points of `new_funds` for a given pool fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance; diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index b0d3035a0010b..bb7061a1406ff 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2162,10 +2162,10 @@ impl Pallet { /// Returns the points to balance conversion for a specified pool. /// - /// If the pool ID does not exist, it returns an error. Used by runtime API. - pub fn api_points_to_balance(pool_id: PoolId) -> BalanceOf { + /// If the pool ID does not exist, it returns 0 ratio points to balance. Used by runtime API. + pub fn api_points_to_balance(pool_id: PoolId, points: BalanceOf) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { - pool.points_to_balance(pool.points) + pool.points_to_balance(points) } else { Zero::zero() } @@ -2173,7 +2173,7 @@ impl Pallet { /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. /// - /// If the pool ID does not exist, it returns an error. Used by runtime API. + /// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API. pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { let bonded_balance = diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index d4ad844296f71..6f3a699316bbb 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -195,6 +195,46 @@ mod bonded_pool { }) } + #[test] + fn api_points_to_balance_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(BondedPool::::get(1).is_some()); + assert_eq!(Pallet::::api_points_to_balance(1, 10), 10); + + // slash half of the pool's balance. expected result of `fn api_points_to_balance` + // to be 1/2 of the pool's balance. + StakingMock::set_bonded_balance( + default_bonded_account(), + Pools::depositor_min_bond() / 2, + ); + assert_eq!(Pallet::::api_points_to_balance(1, 10), 5); + + // if pool does not exist, points to balance ratio is 0. + assert_eq!(BondedPool::::get(2), None); + assert_eq!(Pallet::::api_points_to_balance(2, 10), 0); + }) + } + + #[test] + fn api_balance_to_points_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Pallet::::api_balance_to_points(1, 0), 0); + assert_eq!(Pallet::::api_balance_to_points(1, 10), 10); + + // slash half of the pool's balance. expect result of `fn api_balance_to_points` + // to be 2 * of the balance to add to the pool. + StakingMock::set_bonded_balance( + default_bonded_account(), + Pools::depositor_min_bond() / 2, + ); + assert_eq!(Pallet::::api_balance_to_points(1, 10), 20); + + // if pool does not exist, points to balance ratio is 0. + assert_eq!(BondedPool::::get(2), None); + assert_eq!(Pallet::::api_points_to_balance(2, 10), 0); + }) + } + #[test] fn ok_to_join_with_works() { ExtBuilder::default().build_and_execute(|| { From 62aa1a2e65c8bf3d0f0b1cbf187bd51c09df77df Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 7 Feb 2023 13:20:43 -0300 Subject: [PATCH 11/24] test comment fix --- frame/nomination-pools/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 6f3a699316bbb..be52996a587f7 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -229,7 +229,7 @@ mod bonded_pool { ); assert_eq!(Pallet::::api_balance_to_points(1, 10), 20); - // if pool does not exist, points to balance ratio is 0. + // if pool does not exist, balance to points ratio is 0. assert_eq!(BondedPool::::get(2), None); assert_eq!(Pallet::::api_points_to_balance(2, 10), 0); }) From 137a35553837004dce0e9abd05b66c7396d49ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 14 Feb 2023 21:19:25 +0000 Subject: [PATCH 12/24] Update frame/nomination-pools/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/nomination-pools/runtime-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index c9149c29497b4..427fe1f927f15 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -36,7 +36,7 @@ sp_api::decl_runtime_apis! { /// Returns the points to balance conversion for a given pool. fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance; - /// Returns the equivalent points of `new_funds` for a given pool + /// Returns the equivalent points of `new_funds` for a given pool. fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance; } } From cfea646bc4854004a8887474a7a10c1409aa1987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 14 Feb 2023 21:19:32 +0000 Subject: [PATCH 13/24] Update frame/nomination-pools/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/nomination-pools/runtime-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index 427fe1f927f15..94573bfdb2e33 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -33,7 +33,7 @@ sp_api::decl_runtime_apis! { /// Returns the pending rewards for the member that the AccountId was given for. fn pending_rewards(who: AccountId) -> Balance; - /// Returns the points to balance conversion for a given pool. + /// Returns the equivalent balance of `points` for a given pool. fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance; /// Returns the equivalent points of `new_funds` for a given pool. From bf944a4a344769419da5a134d60525e497895745 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 7 Feb 2023 19:15:01 +0100 Subject: [PATCH 14/24] Fix block pruning (#13323) --- client/db/src/lib.rs | 84 +++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index f217eb6480abc..f54f1bdb131c7 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1806,7 +1806,13 @@ impl Backend { } let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); - self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?; + self.prune_blocks( + transaction, + f_num, + f_hash, + &new_displaced, + current_transaction_justifications, + )?; Ok(()) } @@ -1815,6 +1821,7 @@ impl Backend { &self, transaction: &mut Transaction, finalized_number: NumberFor, + finalized_hash: Block::Hash, displaced: &FinalizationOutcome>, current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { @@ -1843,10 +1850,10 @@ impl Backend { self.prune_block(transaction, BlockId::::number(number))?; } - self.prune_displaced_branches(transaction, finalized_number, displaced)?; + self.prune_displaced_branches(transaction, finalized_hash, displaced)?; }, BlocksPruning::KeepFinalized => { - self.prune_displaced_branches(transaction, finalized_number, displaced)?; + self.prune_displaced_branches(transaction, finalized_hash, displaced)?; }, } Ok(()) @@ -1855,28 +1862,21 @@ impl Backend { fn prune_displaced_branches( &self, transaction: &mut Transaction, - finalized: NumberFor, + finalized: Block::Hash, displaced: &FinalizationOutcome>, ) -> ClientResult<()> { // Discard all blocks from displaced branches for h in displaced.leaves() { - let mut number = finalized; - let mut hash = *h; - // Follow displaced chains back until we reach a finalized block. - // Since leaves are discarded due to finality, they can't have parents - // that are canonical, but not yet finalized. So we stop deleting as soon as - // we reach canonical chain. - while self.blockchain.hash(number)? != Some(hash) { - match self.blockchain.header(hash)? { - Some(header) => { - self.blockchain.insert_persisted_body_if_pinned(hash)?; - - self.prune_block(transaction, BlockId::::hash(hash))?; - number = header.number().saturating_sub(One::one()); - hash = *header.parent_hash(); + match sp_blockchain::tree_route(&self.blockchain, *h, finalized) { + Ok(tree_route) => + for r in tree_route.retracted() { + self.blockchain.insert_persisted_body_if_pinned(r.hash)?; + self.prune_block(transaction, BlockId::::hash(r.hash))?; }, - None => break, - } + Err(sp_blockchain::Error::UnknownBlock(_)) => { + // Sometimes routes can't be calculated. E.g. after warp sync. + }, + Err(e) => Err(e)?, } } Ok(()) @@ -3569,6 +3569,50 @@ pub(crate) mod tests { assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } + #[test] + fn prune_blocks_on_finalize_and_reorg() { + // 0 - 1b + // \ - 1a - 2a - 3a + // \ - 2b + + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); + + let make_block = |index, parent, val: u64| { + insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) + .unwrap() + }; + + let block_0 = make_block(0, Default::default(), 0x00); + let block_1a = make_block(1, block_0, 0x1a); + let block_1b = make_block(1, block_0, 0x1b); + let block_2a = make_block(2, block_1a, 0x2a); + let block_2b = make_block(2, block_1a, 0x2b); + let block_3a = make_block(3, block_2a, 0x3a); + + // Make sure 1b is head + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block_0).unwrap(); + op.mark_head(block_1b).unwrap(); + backend.commit_operation(op).unwrap(); + + // Finalize 3a + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block_0).unwrap(); + op.mark_head(block_3a).unwrap(); + op.mark_finalized(block_1a, None).unwrap(); + op.mark_finalized(block_2a, None).unwrap(); + op.mark_finalized(block_3a, None).unwrap(); + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(None, bc.body(block_1b).unwrap()); + assert_eq!(None, bc.body(block_2b).unwrap()); + assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); + assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); + assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); + assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); + } + #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); From e8d759055df60677533bae54e5d77413d4928afa Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 8 Feb 2023 09:33:34 +0100 Subject: [PATCH 15/24] Referendum proposal's metadata (#12568) * referenda metadata * todo comment * remove TODO, update rustdocs * referenda clear_metadata origin signed or root * referenda metadata unit tests * drop schema type for referenda metadata * remove metadata type * referenda metadata benches * note different preimages * metadata for democracy pallet * metadata democracy pallet tests and benches * fix cargo clippy * update docs * ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy * ".git/.scripts/bench-bot.sh" pallet dev pallet_referenda * Update the doc frame/democracy/src/lib.rs Co-authored-by: Roman Useinov * Update the doc frame/democracy/src/lib.rs Co-authored-by: Anthony Alaribe * reference instead clone for take Co-authored-by: Anthony Alaribe * error rename BadMetadata to PreimageNotExist * clear metadata within internal_cancel_referendum fn * remove redundant clone * collapse metadata api into one set_metadata method * fmt * review fixes * not request preimage on set_metadata * rename events and update docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_democracy * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_referenda * rename reset_metadata to transfer_metadata --------- Co-authored-by: command-bot <> Co-authored-by: Roman Useinov Co-authored-by: Anthony Alaribe --- frame/democracy/src/benchmarking.rs | 203 +++++- frame/democracy/src/lib.rs | 176 +++++- frame/democracy/src/tests.rs | 15 +- frame/democracy/src/tests/fast_tracking.rs | 11 + frame/democracy/src/tests/metadata.rs | 209 +++++++ frame/democracy/src/tests/public_proposals.rs | 14 +- frame/democracy/src/types.rs | 17 + frame/democracy/src/weights.rs | 581 ++++++++++++------ frame/referenda/src/benchmarking.rs | 26 +- frame/referenda/src/lib.rs | 72 ++- frame/referenda/src/mock.rs | 14 +- frame/referenda/src/tests.rs | 72 +++ frame/referenda/src/weights.rs | 307 +++++---- 13 files changed, 1367 insertions(+), 350 deletions(-) create mode 100644 frame/democracy/src/tests/metadata.rs diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index f2d45b719f678..f376b733aba6b 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -54,19 +54,20 @@ fn add_proposal(n: u32) -> Result { Ok(proposal.hash()) } -fn add_referendum(n: u32) -> (ReferendumIndex, H256) { +// add a referendum with a metadata. +fn add_referendum(n: u32) -> (ReferendumIndex, H256, PreimageHash) { let vote_threshold = VoteThreshold::SimpleMajority; let proposal = make_proposal::(n); let hash = proposal.hash(); - ( - Democracy::::inject_referendum( - T::LaunchPeriod::get(), - proposal, - vote_threshold, - 0u32.into(), - ), - hash, - ) + let index = Democracy::::inject_referendum( + T::LaunchPeriod::get(), + proposal, + vote_threshold, + 0u32.into(), + ); + let preimage_hash = note_preimage::(); + MetadataOf::::insert(crate::MetadataOwner::Referendum(index), preimage_hash.clone()); + (index, hash, preimage_hash) } fn account_vote(b: BalanceOf) -> AccountVote> { @@ -75,6 +76,25 @@ fn account_vote(b: BalanceOf) -> AccountVote> { AccountVote::Standard { vote: v, balance: b } } +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn assert_has_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_has_event(generic_event.into()); +} + +// note a new preimage. +fn note_preimage() -> PreimageHash { + use core::sync::atomic::{AtomicU8, Ordering}; + use sp_std::borrow::Cow; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = Cow::from(vec![COUNTER.fetch_add(1, Ordering::Relaxed)]); + let hash = ::Preimages::note(data).unwrap(); + hash +} + benchmarks! { propose { let p = T::MaxProposals::get(); @@ -179,7 +199,7 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let ref_index = add_referendum::(0).0; + let (ref_index, _, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); }: _(origin, ref_index) verify { @@ -188,6 +208,10 @@ benchmarks! { Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid, ); + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + }.into()); } blacklist { @@ -198,7 +222,7 @@ benchmarks! { // We should really add a lot of seconds here, but we're not doing it elsewhere. // Add a referendum of our proposal. - let (ref_index, hash) = add_referendum::(0); + let (ref_index, hash, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. assert_ok!(Democracy::::external_propose( @@ -215,6 +239,10 @@ benchmarks! { Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid ); + assert_has_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + }.into()); } // Worst case scenario, we external propose a previously blacklisted proposal @@ -262,8 +290,13 @@ benchmarks! { .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); - Democracy::::external_propose_default(origin_propose, proposal)?; - + Democracy::::external_propose_default(origin_propose.clone(), proposal)?; + // Set metadata to the external proposal. + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + origin_propose, + MetadataOwner::External, + Some(preimage_hash))); // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -271,7 +304,12 @@ benchmarks! { let delay = 0u32; }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { - assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") + assert_eq!(Democracy::::referendum_count(), 1, "referendum not created"); + assert_last_event::(crate::Event::MetadataTransferred { + prev_owner: MetadataOwner::External, + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + }.into()); } veto_external { @@ -280,7 +318,14 @@ benchmarks! { let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); - Democracy::::external_propose_default(origin_propose, proposal)?; + Democracy::::external_propose_default(origin_propose.clone(), proposal)?; + + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + origin_propose, + MetadataOwner::External, + Some(preimage_hash)) + ); let mut vetoers: BoundedVec = Default::default(); for i in 0 .. (T::MaxBlacklisted::get() - 1) { @@ -303,13 +348,32 @@ benchmarks! { for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } + // Add metadata to the first proposal. + let proposer = funded_account::("proposer", 0); + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + RawOrigin::Signed(proposer).into(), + MetadataOwner::Proposal(0), + Some(preimage_hash))); let cancel_origin = T::CancelProposalOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; }: _(cancel_origin, 0) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Proposal(0), + hash: preimage_hash, + }.into()); + } cancel_referendum { - let ref_index = add_referendum::(0).0; + let (ref_index, _, preimage_hash) = add_referendum::(0); }: _(RawOrigin::Root, ref_index) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + }.into()); + } #[extra] on_initialize_external { @@ -678,6 +742,111 @@ benchmarks! { assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); } + set_external_metadata { + let origin = T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"); + assert_ok!( + Democracy::::external_propose(origin.clone(), make_proposal::(0)) + ); + let owner = MetadataOwner::External; + let hash = note_preimage::(); + }: set_metadata(origin, owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_external_metadata { + let origin = T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"); + assert_ok!( + Democracy::::external_propose(origin.clone(), make_proposal::(0)) + ); + let owner = MetadataOwner::External; + let proposer = funded_account::("proposer", 0); + let hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata(origin.clone(), owner.clone(), Some(hash))); + }: set_metadata(origin, owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + + set_proposal_metadata { + // Place our proposal at the end to make sure it's worst case. + for i in 0 .. T::MaxProposals::get() { + add_proposal::(i)?; + } + let owner = MetadataOwner::Proposal(0); + let proposer = funded_account::("proposer", 0); + let hash = note_preimage::(); + }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_proposal_metadata { + // Place our proposal at the end to make sure it's worst case. + for i in 0 .. T::MaxProposals::get() { + add_proposal::(i)?; + } + let proposer = funded_account::("proposer", 0); + let owner = MetadataOwner::Proposal(0); + let hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + RawOrigin::Signed(proposer.clone()).into(), + owner.clone(), + Some(hash))); + }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + + set_referendum_metadata { + // create not ongoing referendum. + ReferendumInfoOf::::insert( + 0, + ReferendumInfo::Finished { end: T::BlockNumber::zero(), approved: true }, + ); + let owner = MetadataOwner::Referendum(0); + let caller = funded_account::("caller", 0); + let hash = note_preimage::(); + }: set_metadata(RawOrigin::Root.into(), owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_referendum_metadata { + // create not ongoing referendum. + ReferendumInfoOf::::insert( + 0, + ReferendumInfo::Finished { end: T::BlockNumber::zero(), approved: true }, + ); + let owner = MetadataOwner::Referendum(0); + let hash = note_preimage::(); + MetadataOf::::insert(owner.clone(), hash); + let caller = funded_account::("caller", 0); + }: set_metadata(RawOrigin::Signed(caller).into(), owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + impl_benchmark_test_suite!( Democracy, crate::tests::new_test_ext(), diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 2c65e5d94bc46..3aa8bc0015d38 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -155,14 +155,17 @@ use codec::{Decode, Encode}; use frame_support::{ ensure, + error::BadOrigin, traits::{ defensive_prelude::*, schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, - ReservableCurrency, StorePreimage, WithdrawReasons, + Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, + LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, + WithdrawReasons, }, weights::Weight, }; +use frame_system::pallet_prelude::OriginFor; use sp_runtime::{ traits::{Bounded as ArithBounded, One, Saturating, StaticLookup, Zero}, ArithmeticError, DispatchError, DispatchResult, @@ -176,7 +179,10 @@ mod vote_threshold; pub mod weights; pub use conviction::Conviction; pub use pallet::*; -pub use types::{Delegations, ReferendumInfo, ReferendumStatus, Tally, UnvoteScope}; +pub use types::{ + Delegations, MetadataOwner, PropIndex, ReferendumIndex, ReferendumInfo, ReferendumStatus, + Tally, UnvoteScope, +}; pub use vote::{AccountVote, Vote, Voting}; pub use vote_threshold::{Approved, VoteThreshold}; pub use weights::WeightInfo; @@ -191,12 +197,6 @@ pub mod migrations; const DEMOCRACY_ID: LockIdentifier = *b"democrac"; -/// A proposal index. -pub type PropIndex = u32; - -/// A referendum index. -pub type ReferendumIndex = u32; - type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -425,6 +425,15 @@ pub mod pallet { #[pallet::storage] pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; + /// General information concerning any proposal or referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, PreimageHash>; + #[pallet::genesis_config] pub struct GenesisConfig { _phantom: sp_std::marker::PhantomData, @@ -477,6 +486,29 @@ pub mod pallet { Seconded { seconder: T::AccountId, prop_index: PropIndex }, /// A proposal got canceled. ProposalCanceled { prop_index: PropIndex }, + /// Metadata for a proposal or a referendum has been set. + MetadataSet { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a proposal or a referendum has been cleared. + MetadataCleared { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata has been transferred to new owner. + MetadataTransferred { + /// Previous metadata owner. + prev_owner: MetadataOwner, + /// New metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, } #[pallet::error] @@ -528,6 +560,8 @@ pub mod pallet { TooMany, /// Voting period too low VotingPeriodLow, + /// The preimage does not exist. + PreimageNotExist, } #[pallet::hooks] @@ -773,12 +807,13 @@ pub mod pallet { >::kill(); let now = >::block_number(); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(voting_period), ext_proposal, threshold, delay, ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); Ok(()) } @@ -816,6 +851,7 @@ pub mod pallet { Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); >::kill(); + Self::clear_metadata(MetadataOwner::External); Ok(()) } @@ -1025,12 +1061,14 @@ pub mod pallet { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); } } + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); } }); // Remove the external queued referendum, if it's there. if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { NextExternal::::kill(); + Self::clear_metadata(MetadataOwner::External); } // Remove the referendum, if it's there. @@ -1067,8 +1105,68 @@ pub mod pallet { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); } } - Self::deposit_event(Event::::ProposalCanceled { prop_index }); + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); + Ok(()) + } + + /// Set or clear a metadata of a proposal or a referendum. + /// + /// Parameters: + /// - `origin`: Must correspond to the `MetadataOwner`. + /// - `ExternalOrigin` for an external proposal with the `SuperMajorityApprove` + /// threshold. + /// - `ExternalDefaultOrigin` for an external proposal with the `SuperMajorityAgainst` + /// threshold. + /// - `ExternalMajorityOrigin` for an external proposal with the `SimpleMajority` + /// threshold. + /// - `Signed` by a creator for a public proposal. + /// - `Signed` to clear a metadata for a finished referendum. + /// - `Root` to set a metadata for an ongoing referendum. + /// - `owner`: an identifier of a metadata owner. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(18)] + #[pallet::weight( + match (owner, maybe_hash) { + (MetadataOwner::External, Some(_)) => T::WeightInfo::set_external_metadata(), + (MetadataOwner::External, None) => T::WeightInfo::clear_external_metadata(), + (MetadataOwner::Proposal(_), Some(_)) => T::WeightInfo::set_proposal_metadata(), + (MetadataOwner::Proposal(_), None) => T::WeightInfo::clear_proposal_metadata(), + (MetadataOwner::Referendum(_), Some(_)) => T::WeightInfo::set_referendum_metadata(), + (MetadataOwner::Referendum(_), None) => T::WeightInfo::clear_referendum_metadata(), + } + )] + pub fn set_metadata( + origin: OriginFor, + owner: MetadataOwner, + maybe_hash: Option, + ) -> DispatchResult { + match owner { + MetadataOwner::External => { + let (_, threshold) = >::get().ok_or(Error::::NoProposal)?; + Self::ensure_external_origin(threshold, origin)?; + }, + MetadataOwner::Proposal(index) => { + let who = ensure_signed(origin)?; + let (_, _, proposer) = Self::proposal(index)?; + ensure!(proposer == who, Error::::NoPermission); + }, + MetadataOwner::Referendum(index) => { + let is_root = ensure_signed_or_root(origin)?.is_none(); + ensure!(is_root || maybe_hash.is_none(), Error::::NoPermission); + ensure!( + is_root || Self::referendum_status(index).is_err(), + Error::::NoPermission + ); + }, + } + if let Some(hash) = maybe_hash { + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(owner.clone(), hash); + Self::deposit_event(Event::::MetadataSet { owner, hash }); + } else { + Self::clear_metadata(owner); + } Ok(()) } } @@ -1146,6 +1244,7 @@ impl Pallet { pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { Self::deposit_event(Event::::Cancelled { ref_index }); ReferendumInfoOf::::remove(ref_index); + Self::clear_metadata(MetadataOwner::Referendum(ref_index)); } // private. @@ -1432,12 +1531,13 @@ impl Pallet { if let Some((proposal, threshold)) = >::take() { LastTabledWasExternal::::put(true); Self::deposit_event(Event::::ExternalTabled); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, threshold, T::EnactmentPeriod::get(), ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); Ok(()) } else { return Err(Error::::NoneWaiting.into()) @@ -1460,12 +1560,16 @@ impl Pallet { T::Currency::unreserve(d, deposit); } Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, VoteThreshold::SuperMajorityApprove, T::EnactmentPeriod::get(), ); + Self::transfer_metadata( + MetadataOwner::Proposal(prop_index), + MetadataOwner::Referendum(ref_index), + ) } Ok(()) } else { @@ -1578,6 +1682,52 @@ impl Pallet { // `Compact`. decode_compact_u32_at(&>::hashed_key_for(proposal)) } + + /// Return a proposal of an index. + fn proposal(index: PropIndex) -> Result<(PropIndex, BoundedCallOf, T::AccountId), Error> { + PublicProps::::get() + .into_iter() + .find(|(prop_index, _, _)| prop_index == &index) + .ok_or(Error::::ProposalMissing) + } + + /// Clear metadata if exist for a given owner. + fn clear_metadata(owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + Self::deposit_event(Event::::MetadataCleared { owner, hash }); + } + } + + /// Transfer the metadata of an `owner` to a `new_owner`. + fn transfer_metadata(owner: MetadataOwner, new_owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + MetadataOf::::insert(&new_owner, hash); + Self::deposit_event(Event::::MetadataTransferred { + prev_owner: owner, + owner: new_owner, + hash, + }); + } + } + + /// Ensure external origin for corresponding vote threshold. + fn ensure_external_origin( + threshold: VoteThreshold, + origin: OriginFor, + ) -> Result<(), BadOrigin> { + match threshold { + VoteThreshold::SuperMajorityApprove => { + let _ = T::ExternalOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SuperMajorityAgainst => { + let _ = T::ExternalDefaultOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SimpleMajority => { + let _ = T::ExternalMajorityOrigin::ensure_origin(origin)?; + }, + }; + Ok(()) + } } /// Decode `Compact` from the trie at given key. diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 41b279035028e..9c7ec2906c677 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -32,7 +32,7 @@ use pallet_balances::{BalanceLock, Error as BalancesError}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, Hash, IdentityLookup}, Perbill, }; mod cancellation; @@ -41,6 +41,7 @@ mod delegation; mod external_proposing; mod fast_tracking; mod lock_voting; +mod metadata; mod public_proposals; mod scheduling; mod voting; @@ -276,3 +277,15 @@ fn big_nay(who: u64) -> AccountVote { fn tally(r: ReferendumIndex) -> Tally { Democracy::referendum_status(r).unwrap().tally } + +/// note a new preimage without registering. +fn note_preimage(who: u64) -> PreimageHash { + use std::sync::atomic::{AtomicU8, Ordering}; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = vec![COUNTER.fetch_add(1, Ordering::Relaxed)]; + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(who), data.clone())); + let hash = BlakeTwo256::hash(&data); + assert!(!Preimage::is_requested(&hash)); + hash +} diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 97bb7a63908ab..09af3dbf3b5dd 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -32,6 +32,14 @@ fn fast_track_referendum_works() { RuntimeOrigin::signed(3), set_balance_proposal(2) )); + let hash = note_preimage(1); + assert!(>::get(MetadataOwner::External).is_none()); + assert_ok!(Democracy::set_metadata( + RuntimeOrigin::signed(3), + MetadataOwner::External, + Some(hash), + ),); + assert!(>::get(MetadataOwner::External).is_some()); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); assert_eq!( @@ -44,6 +52,9 @@ fn fast_track_referendum_works() { tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); + // metadata reset from the external proposal to the referendum. + assert!(>::get(MetadataOwner::External).is_none()); + assert!(>::get(MetadataOwner::Referendum(0)).is_some()); }); } diff --git a/frame/democracy/src/tests/metadata.rs b/frame/democracy/src/tests/metadata.rs new file mode 100644 index 0000000000000..95b617e37b199 --- /dev/null +++ b/frame/democracy/src/tests/metadata.rs @@ -0,0 +1,209 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The tests for functionality concerning the metadata. + +use super::*; + +#[test] +fn set_external_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // metadata owner is an external proposal. + let owner = MetadataOwner::External; + // fails to set metadata if an external proposal does not exist. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(invalid_hash)), + Error::::NoProposal, + ); + // create an external proposal. + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert!(>::exists()); + // fails to set metadata with non external origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash)), + BadOrigin, + ); + // fails to set non-existing preimage. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(invalid_hash)), + Error::::PreimageNotExist, + ); + // set metadata successful. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),),); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner, + hash, + })); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + // metadata owner is an external proposal. + let owner = MetadataOwner::External; + // create an external proposal. + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert!(>::exists()); + // set metadata. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),)); + // fails to clear metadata with a wrong origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), + BadOrigin, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn set_proposal_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // create an external proposal. + assert_ok!(propose_set_balance(1, 2, 5)); + // metadata owner is a public proposal. + let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + // fails to set non-existing preimage. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash),), + Error::::PreimageNotExist, + ); + // note preimage. + let hash = note_preimage(1); + // fails to set a preimage if an origin is not a proposer. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Error::::NoPermission, + ); + // set metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),),); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner, + hash, + })); + }); +} + +#[test] +fn clear_proposal_metadata_works() { + new_test_ext().execute_with(|| { + // create an external proposal. + assert_ok!(propose_set_balance(1, 2, 5)); + // metadata owner is a public proposal. + let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + // set metadata. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),)); + // fails to clear metadata with a wrong origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None), + Error::::NoPermission, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn set_referendum_metadata_by_root() { + new_test_ext().execute_with(|| { + let index = Democracy::inject_referendum( + 2, + set_balance_proposal(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + // metadata owner is a referendum. + let owner = MetadataOwner::Referendum(index); + // note preimage. + let hash = note_preimage(1); + // fails to set if not a root. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Error::::NoPermission, + ); + // fails to clear if not a root. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None,), + Error::::NoPermission, + ); + // succeed to set metadata by a root for an ongoing referendum. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), Some(hash),)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner: owner.clone(), + hash, + })); + // succeed to clear metadata by a root for an ongoing referendum. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn clear_referendum_metadata_works() { + new_test_ext().execute_with(|| { + // create a referendum. + let index = Democracy::inject_referendum( + 2, + set_balance_proposal(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + // metadata owner is a referendum. + let owner = MetadataOwner::Referendum(index); + // set metadata. + let hash = note_preimage(1); + // referendum finished. + MetadataOf::::insert(owner.clone(), hash); + // no permission to clear metadata of an ongoing referendum. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), + Error::::NoPermission, + ); + // referendum finished. + ReferendumInfoOf::::insert( + index, + ReferendumInfo::Finished { end: 1, approved: true }, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index f48824dc95c5d..f9471442c6336 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -91,8 +91,20 @@ fn cancel_proposal_should_work() { assert_ok!(propose_set_balance(1, 2, 2)); assert_ok!(propose_set_balance(1, 4, 4)); assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin); + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata( + RuntimeOrigin::signed(1), + MetadataOwner::Proposal(0), + Some(hash) + )); + assert!(>::get(MetadataOwner::Proposal(0)).is_some()); assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); - System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); + // metadata cleared, preimage unrequested. + assert!(>::get(MetadataOwner::Proposal(0)).is_none()); + System::assert_has_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); + System::assert_last_event( + crate::Event::MetadataCleared { owner: MetadataOwner::Proposal(0), hash }.into(), + ); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); }); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 4b7f1a0fac45c..25954e05498a6 100644 --- a/frame/democracy/src/types.rs +++ b/frame/democracy/src/types.rs @@ -25,6 +25,12 @@ use sp_runtime::{ RuntimeDebug, }; +/// A proposal index. +pub type PropIndex = u32; + +/// A referendum index. +pub type ReferendumIndex = u32; + /// Info regarding an ongoing referendum. #[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct Tally { @@ -206,3 +212,14 @@ pub enum UnvoteScope { /// Permitted to do only the changes that do not need the owner's permission. OnlyExpired, } + +/// Identifies an owner of a metadata. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum MetadataOwner { + /// External proposal. + External, + /// Public proposal of the index. + Proposal(PropIndex), + /// Referendum of the index. + Referendum(ReferendumIndex), +} diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 985fe8fbde781..10d0744eac029 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_democracy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/democracy/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_democracy +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/democracy/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,6 +71,12 @@ pub trait WeightInfo { fn unlock_set(r: u32, ) -> Weight; fn remove_vote(r: u32, ) -> Weight; fn remove_other_vote(r: u32, ) -> Weight; + fn set_external_metadata() -> Weight; + fn clear_external_metadata() -> Weight; + fn set_proposal_metadata() -> Weight; + fn clear_proposal_metadata() -> Weight; + fn set_referendum_metadata() -> Weight; + fn clear_referendum_metadata() -> Weight; } /// Weights for pallet_democracy using the Substrate node and recommended hardware. @@ -87,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4864` // Estimated: `23409` - // Minimum execution time: 34_509 nanoseconds. - Weight::from_parts(34_781_000, 23409) + // Minimum execution time: 42_939 nanoseconds. + Weight::from_parts(43_543_000, 23409) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -98,8 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3620` // Estimated: `5705` - // Minimum execution time: 31_151 nanoseconds. - Weight::from_parts(31_566_000, 5705) + // Minimum execution time: 36_475 nanoseconds. + Weight::from_parts(37_863_000, 5705) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -111,10 +118,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3555` + // Measured: `3565` // Estimated: `12720` - // Minimum execution time: 42_618 nanoseconds. - Weight::from_parts(43_231_000, 12720) + // Minimum execution time: 56_372 nanoseconds. + Weight::from_parts(57_483_000, 12720) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -126,10 +133,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3577` + // Measured: `3587` // Estimated: `12720` - // Minimum execution time: 42_875 nanoseconds. - Weight::from_parts(43_338_000, 12720) + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_737_000, 12720) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -137,14 +144,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Democracy Cancellations (r:1 w:1) /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `5184` - // Minimum execution time: 16_543 nanoseconds. - Weight::from_parts(16_762_000, 5184) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `398` + // Estimated: `7712` + // Minimum execution time: 24_379 nanoseconds. + Weight::from_parts(25_302_000, 7712) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -152,6 +161,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -160,12 +171,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5958` - // Estimated: `28808` - // Minimum execution time: 70_135 nanoseconds. - Weight::from_parts(70_616_000, 28808) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `6036` + // Estimated: `36392` + // Minimum execution time: 100_345 nanoseconds. + Weight::from_parts(102_233_000, 36392) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -175,8 +186,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3448` // Estimated: `6340` - // Minimum execution time: 12_580 nanoseconds. - Weight::from_parts(12_987_000, 6340) + // Minimum execution time: 13_155 nanoseconds. + Weight::from_parts(14_158_000, 6340) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_320 nanoseconds. - Weight::from_ref_time(3_513_000) + // Minimum execution time: 2_961 nanoseconds. + Weight::from_ref_time(3_139_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -196,37 +207,41 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_407 nanoseconds. - Weight::from_ref_time(3_565_000) + // Minimum execution time: 3_040 nanoseconds. + Weight::from_ref_time(3_261_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumCount (r:1 w:1) /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `1126` - // Minimum execution time: 16_831 nanoseconds. - Weight::from_parts(17_155_000, 1126) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `286` + // Estimated: `3654` + // Minimum execution time: 26_666 nanoseconds. + Weight::from_parts(28_014_000, 3654) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy Blacklist (r:1 w:1) /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3477` - // Estimated: `6340` - // Minimum execution time: 22_072 nanoseconds. - Weight::from_parts(22_517_000, 6340) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `3551` + // Estimated: `8868` + // Minimum execution time: 30_180 nanoseconds. + Weight::from_parts(31_593_000, 8868) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -234,24 +249,29 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5837` - // Estimated: `25505` - // Minimum execution time: 56_925 nanoseconds. - Weight::from_parts(57_253_000, 25505) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `5915` + // Estimated: `28033` + // Minimum execution time: 80_780 nanoseconds. + Weight::from_parts(82_070_000, 28033) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_582 nanoseconds. - Weight::from_ref_time(8_754_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `271` + // Estimated: `2528` + // Minimum execution time: 18_117 nanoseconds. + Weight::from_parts(19_027_000, 2528) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -262,12 +282,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 6_665 nanoseconds. - Weight::from_parts(9_219_932, 998) - // Standard Error: 4_236 - .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + // Minimum execution time: 7_093 nanoseconds. + Weight::from_parts(8_792_955, 998) + // Standard Error: 6_630 + .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -288,12 +308,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 9_842 nanoseconds. - Weight::from_parts(11_932_535, 19318) - // Standard Error: 4_413 - .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + // Minimum execution time: 10_372 nanoseconds. + Weight::from_parts(10_961_165, 19318) + // Standard Error: 7_284 + .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -308,12 +328,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `948 + r * (139 ±0)` + // Measured: `958 + r * (139 ±0)` // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 34_740 nanoseconds. - Weight::from_parts(38_366_374, 22584) - // Standard Error: 4_868 - .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + // Minimum execution time: 36_618 nanoseconds. + Weight::from_parts(42_803_184, 22584) + // Standard Error: 7_268 + .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -327,12 +347,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `547 + r * (139 ±0)` + // Measured: `557 + r * (139 ±0)` // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_516 nanoseconds. - Weight::from_parts(21_629_605, 12540) - // Standard Error: 4_401 - .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + // Minimum execution time: 19_758 nanoseconds. + Weight::from_parts(21_641_793, 12540) + // Standard Error: 6_889 + .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -345,8 +365,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_ref_time(3_485_000) + // Minimum execution time: 2_844 nanoseconds. + Weight::from_ref_time(3_017_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -358,12 +378,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617` + // Measured: `627` // Estimated: `12647` - // Minimum execution time: 19_357 nanoseconds. - Weight::from_parts(24_014_517, 12647) - // Standard Error: 994 - .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + // Minimum execution time: 20_380 nanoseconds. + Weight::from_parts(28_295_875, 12647) + // Standard Error: 2_331 + .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -376,12 +396,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + r * (22 ±0)` + // Measured: `628 + r * (22 ±0)` // Estimated: `12647` - // Minimum execution time: 22_340 nanoseconds. - Weight::from_parts(23_355_734, 12647) - // Standard Error: 548 - .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + // Minimum execution time: 24_475 nanoseconds. + Weight::from_parts(27_102_576, 12647) + // Standard Error: 1_464 + .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -392,12 +412,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_542 nanoseconds. - Weight::from_parts(16_411_916, 8946) - // Standard Error: 839 - .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + // Minimum execution time: 15_039 nanoseconds. + Weight::from_parts(19_252_498, 8946) + // Standard Error: 1_798 + .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -408,15 +428,97 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_463 nanoseconds. - Weight::from_parts(16_302_901, 8946) - // Standard Error: 809 - .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + // Minimum execution time: 14_837 nanoseconds. + Weight::from_parts(19_144_929, 8946) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3193` + // Minimum execution time: 17_338 nanoseconds. + Weight::from_parts(17_946_000, 3193) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3155` + // Minimum execution time: 15_364 nanoseconds. + Weight::from_parts(15_990_000, 3155) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4919` + // Estimated: `19763` + // Minimum execution time: 37_147 nanoseconds. + Weight::from_parts(37_778_000, 19763) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4853` + // Estimated: `19725` + // Minimum execution time: 34_118 nanoseconds. + Weight::from_parts(34_737_000, 19725) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 12_787 nanoseconds. + Weight::from_parts(13_463_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `5204` + // Minimum execution time: 17_636 nanoseconds. + Weight::from_parts(18_399_000, 5204) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -433,8 +535,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4864` // Estimated: `23409` - // Minimum execution time: 34_509 nanoseconds. - Weight::from_parts(34_781_000, 23409) + // Minimum execution time: 42_939 nanoseconds. + Weight::from_parts(43_543_000, 23409) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -444,8 +546,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3620` // Estimated: `5705` - // Minimum execution time: 31_151 nanoseconds. - Weight::from_parts(31_566_000, 5705) + // Minimum execution time: 36_475 nanoseconds. + Weight::from_parts(37_863_000, 5705) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -457,10 +559,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3555` + // Measured: `3565` // Estimated: `12720` - // Minimum execution time: 42_618 nanoseconds. - Weight::from_parts(43_231_000, 12720) + // Minimum execution time: 56_372 nanoseconds. + Weight::from_parts(57_483_000, 12720) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -472,10 +574,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3577` + // Measured: `3587` // Estimated: `12720` - // Minimum execution time: 42_875 nanoseconds. - Weight::from_parts(43_338_000, 12720) + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_737_000, 12720) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -483,14 +585,16 @@ impl WeightInfo for () { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Democracy Cancellations (r:1 w:1) /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `5184` - // Minimum execution time: 16_543 nanoseconds. - Weight::from_parts(16_762_000, 5184) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `398` + // Estimated: `7712` + // Minimum execution time: 24_379 nanoseconds. + Weight::from_parts(25_302_000, 7712) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -498,6 +602,8 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -506,12 +612,12 @@ impl WeightInfo for () { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5958` - // Estimated: `28808` - // Minimum execution time: 70_135 nanoseconds. - Weight::from_parts(70_616_000, 28808) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `6036` + // Estimated: `36392` + // Minimum execution time: 100_345 nanoseconds. + Weight::from_parts(102_233_000, 36392) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -521,8 +627,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3448` // Estimated: `6340` - // Minimum execution time: 12_580 nanoseconds. - Weight::from_parts(12_987_000, 6340) + // Minimum execution time: 13_155 nanoseconds. + Weight::from_parts(14_158_000, 6340) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -532,8 +638,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_320 nanoseconds. - Weight::from_ref_time(3_513_000) + // Minimum execution time: 2_961 nanoseconds. + Weight::from_ref_time(3_139_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -542,37 +648,41 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_407 nanoseconds. - Weight::from_ref_time(3_565_000) + // Minimum execution time: 3_040 nanoseconds. + Weight::from_ref_time(3_261_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumCount (r:1 w:1) /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `1126` - // Minimum execution time: 16_831 nanoseconds. - Weight::from_parts(17_155_000, 1126) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `286` + // Estimated: `3654` + // Minimum execution time: 26_666 nanoseconds. + Weight::from_parts(28_014_000, 3654) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy Blacklist (r:1 w:1) /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3477` - // Estimated: `6340` - // Minimum execution time: 22_072 nanoseconds. - Weight::from_parts(22_517_000, 6340) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `3551` + // Estimated: `8868` + // Minimum execution time: 30_180 nanoseconds. + Weight::from_parts(31_593_000, 8868) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -580,24 +690,29 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5837` - // Estimated: `25505` - // Minimum execution time: 56_925 nanoseconds. - Weight::from_parts(57_253_000, 25505) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `5915` + // Estimated: `28033` + // Minimum execution time: 80_780 nanoseconds. + Weight::from_parts(82_070_000, 28033) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_582 nanoseconds. - Weight::from_ref_time(8_754_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `271` + // Estimated: `2528` + // Minimum execution time: 18_117 nanoseconds. + Weight::from_parts(19_027_000, 2528) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -608,12 +723,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 6_665 nanoseconds. - Weight::from_parts(9_219_932, 998) - // Standard Error: 4_236 - .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + // Minimum execution time: 7_093 nanoseconds. + Weight::from_parts(8_792_955, 998) + // Standard Error: 6_630 + .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -634,12 +749,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 9_842 nanoseconds. - Weight::from_parts(11_932_535, 19318) - // Standard Error: 4_413 - .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + // Minimum execution time: 10_372 nanoseconds. + Weight::from_parts(10_961_165, 19318) + // Standard Error: 7_284 + .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -654,12 +769,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `948 + r * (139 ±0)` + // Measured: `958 + r * (139 ±0)` // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 34_740 nanoseconds. - Weight::from_parts(38_366_374, 22584) - // Standard Error: 4_868 - .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + // Minimum execution time: 36_618 nanoseconds. + Weight::from_parts(42_803_184, 22584) + // Standard Error: 7_268 + .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -673,12 +788,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `547 + r * (139 ±0)` + // Measured: `557 + r * (139 ±0)` // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_516 nanoseconds. - Weight::from_parts(21_629_605, 12540) - // Standard Error: 4_401 - .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + // Minimum execution time: 19_758 nanoseconds. + Weight::from_parts(21_641_793, 12540) + // Standard Error: 6_889 + .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -691,8 +806,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_ref_time(3_485_000) + // Minimum execution time: 2_844 nanoseconds. + Weight::from_ref_time(3_017_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -704,12 +819,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617` + // Measured: `627` // Estimated: `12647` - // Minimum execution time: 19_357 nanoseconds. - Weight::from_parts(24_014_517, 12647) - // Standard Error: 994 - .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + // Minimum execution time: 20_380 nanoseconds. + Weight::from_parts(28_295_875, 12647) + // Standard Error: 2_331 + .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -722,12 +837,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + r * (22 ±0)` + // Measured: `628 + r * (22 ±0)` // Estimated: `12647` - // Minimum execution time: 22_340 nanoseconds. - Weight::from_parts(23_355_734, 12647) - // Standard Error: 548 - .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + // Minimum execution time: 24_475 nanoseconds. + Weight::from_parts(27_102_576, 12647) + // Standard Error: 1_464 + .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -738,12 +853,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_542 nanoseconds. - Weight::from_parts(16_411_916, 8946) - // Standard Error: 839 - .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + // Minimum execution time: 15_039 nanoseconds. + Weight::from_parts(19_252_498, 8946) + // Standard Error: 1_798 + .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -754,13 +869,95 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_463 nanoseconds. - Weight::from_parts(16_302_901, 8946) - // Standard Error: 809 - .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + // Minimum execution time: 14_837 nanoseconds. + Weight::from_parts(19_144_929, 8946) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3193` + // Minimum execution time: 17_338 nanoseconds. + Weight::from_parts(17_946_000, 3193) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3155` + // Minimum execution time: 15_364 nanoseconds. + Weight::from_parts(15_990_000, 3155) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4919` + // Estimated: `19763` + // Minimum execution time: 37_147 nanoseconds. + Weight::from_parts(37_778_000, 19763) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4853` + // Estimated: `19725` + // Minimum execution time: 34_118 nanoseconds. + Weight::from_parts(34_737_000, 19725) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 12_787 nanoseconds. + Weight::from_parts(13_463_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `5204` + // Minimum execution time: 17_636 nanoseconds. + Weight::from_parts(18_399_000, 5204) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 62b37857f2567..ea44beeb3994f 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -33,7 +33,6 @@ use sp_runtime::traits::Bounded as ArithBounded; const SEED: u32 = 0; -#[allow(dead_code)] fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -631,6 +630,31 @@ benchmarks_instance_pallet! { assert_matches!(info, ReferendumInfo::Rejected(..)); } + set_some_metadata { + use sp_std::borrow::Cow; + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); + let hash = T::Preimages::note(Cow::from(vec![5, 6])).unwrap(); + }: set_metadata(origin, index, Some(hash)) + verify { + assert_last_event::(Event::MetadataSet { index, hash }.into()); + } + + clear_metadata { + use sp_std::borrow::Cow; + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); + let hash = T::Preimages::note(Cow::from(vec![6, 7, 8])).unwrap(); + assert_ok!( + Referenda::::set_metadata(origin.clone(), index, Some(hash)) + ); + }: set_metadata(origin, index, None) + verify { + assert_last_event::(Event::MetadataCleared { index, hash }.into()); + } + impl_benchmark_test_suite!( Referenda, crate::mock::new_test_ext(), diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 0b846faf88558..4491c1b40d197 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -72,8 +72,8 @@ use frame_support::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, }, - Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, - ReservableCurrency, StorePreimage, VoteTally, + Currency, Hash as PreimageHash, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, + Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, }; @@ -251,6 +251,16 @@ pub mod pallet { pub type DecidingCount, I: 'static = ()> = StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; + /// The metadata is a general information concerning the referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, ReferendumIndex, PreimageHash>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -356,6 +366,20 @@ pub mod pallet { /// The amount placed by the account. amount: BalanceOf, }, + /// Metadata for a referendum has been set. + MetadataSet { + /// Index of the referendum. + index: ReferendumIndex, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a referendum has been cleared. + MetadataCleared { + /// Index of the referendum. + index: ReferendumIndex, + /// Preimage hash. + hash: PreimageHash, + }, } #[pallet::error] @@ -384,6 +408,8 @@ pub mod pallet { NoDeposit, /// The referendum status is invalid for this operation. BadStatus, + /// The preimage does not exist. + PreimageNotExist, } #[pallet::call] @@ -540,6 +566,7 @@ pub mod pallet { Self::deposit_event(Event::::Killed { index, tally: status.tally }); Self::slash_deposit(Some(status.submission_deposit.clone())); Self::slash_deposit(status.decision_deposit.clone()); + Self::do_clear_metadata(index); let info = ReferendumInfo::Killed(frame_system::Pallet::::block_number()); ReferendumInfoFor::::insert(index, info); Ok(()) @@ -633,6 +660,40 @@ pub mod pallet { Self::deposit_event(e); Ok(()) } + + /// Set or clear metadata of a referendum. + /// + /// Parameters: + /// - `origin`: Must be `Signed` by a creator of a referendum or by anyone to clear a + /// metadata of a finished referendum. + /// - `index`: The index of a referendum to set or clear metadata for. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(8)] + #[pallet::weight( + maybe_hash.map_or( + T::WeightInfo::clear_metadata(), |_| T::WeightInfo::set_some_metadata()) + )] + pub fn set_metadata( + origin: OriginFor, + index: ReferendumIndex, + maybe_hash: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + if let Some(hash) = maybe_hash { + let status = Self::ensure_ongoing(index)?; + ensure!(status.submission_deposit.who == who, Error::::NoPermission); + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(index, hash); + Self::deposit_event(Event::::MetadataSet { index, hash }); + Ok(()) + } else { + if let Some(status) = Self::ensure_ongoing(index).ok() { + ensure!(status.submission_deposit.who == who, Error::::NoPermission); + } + Self::do_clear_metadata(index); + Ok(()) + } + } } } @@ -1204,4 +1265,11 @@ impl, I: 'static> Pallet { support_needed.passing(x, tally.support(id)) && approval_needed.passing(x, tally.approval(id)) } + + /// Clear metadata if exist for a given referendum index. + fn do_clear_metadata(index: ReferendumIndex) { + if let Some(hash) = MetadataOf::::take(index) { + Self::deposit_event(Event::::MetadataCleared { index, hash }); + } + } } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 82ae508d52b6f..f6e19d06ed5f3 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Hash, IdentityLookup}, DispatchResult, Perbill, }; @@ -470,3 +470,15 @@ impl RefState { index } } + +/// note a new preimage without registering. +pub fn note_preimage(who: u64) -> PreimageHash { + use std::sync::atomic::{AtomicU8, Ordering}; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = vec![COUNTER.fetch_add(1, Ordering::Relaxed)]; + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(who), data.clone())); + let hash = BlakeTwo256::hash(&data); + assert!(!Preimage::is_requested(&hash)); + hash +} diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index c109fafe332e2..034454cfcc265 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -578,3 +578,75 @@ fn curve_handles_all_inputs() { let threshold = test_curve.threshold(Perbill::one()); assert_eq!(threshold, Perbill::zero()); } + +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // fails to set metadata for a finished referendum. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_ok!(Referenda::kill(RuntimeOrigin::root(), index)); + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(invalid_hash)), + Error::::NotOngoing, + ); + // no permission to set metadata. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(2), index, Some(invalid_hash)), + Error::::NoPermission, + ); + // preimage does not exist. + let index = ReferendumCount::::get() - 1; + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(invalid_hash)), + Error::::PreimageNotExist, + ); + // metadata set. + let index = ReferendumCount::::get() - 1; + let hash = note_preimage(1); + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(hash))); + System::assert_last_event(RuntimeEvent::Referenda(crate::Event::MetadataSet { + index, + hash, + })); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let hash = note_preimage(1); + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(hash))); + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(2), index, None), + Error::::NoPermission, + ); + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, None),); + System::assert_last_event(RuntimeEvent::Referenda(crate::Event::MetadataCleared { + index, + hash, + })); + }); +} diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 68b44e8beff90..ab49759516bd9 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/referenda/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/referenda/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,6 +77,8 @@ pub trait WeightInfo { fn nudge_referendum_continue_confirming() -> Weight; fn nudge_referendum_approved() -> Weight; fn nudge_referendum_rejected() -> Weight; + fn set_some_metadata() -> Weight; + fn clear_metadata() -> Weight; } /// Weights for pallet_referenda using the Substrate node and recommended hardware. @@ -91,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `251` // Estimated: `109996` - // Minimum execution time: 32_207 nanoseconds. - Weight::from_parts(32_639_000, 109996) + // Minimum execution time: 34_540 nanoseconds. + Weight::from_parts(36_144_000, 109996) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -104,8 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `221835` - // Minimum execution time: 43_766 nanoseconds. - Weight::from_parts(44_494_000, 221835) + // Minimum execution time: 46_963 nanoseconds. + Weight::from_parts(48_459_000, 221835) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -119,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3203` // Estimated: `9817` - // Minimum execution time: 41_561 nanoseconds. - Weight::from_parts(42_180_000, 9817) + // Minimum execution time: 55_798 nanoseconds. + Weight::from_parts(58_260_000, 9817) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -134,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3223` // Estimated: `9817` - // Minimum execution time: 41_039 nanoseconds. - Weight::from_parts(41_673_000, 9817) + // Minimum execution time: 53_888 nanoseconds. + Weight::from_parts(57_919_000, 9817) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -149,8 +152,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 52_922 nanoseconds. - Weight::from_parts(53_395_000, 224324) + // Minimum execution time: 56_121 nanoseconds. + Weight::from_parts(58_301_000, 224324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -164,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 51_050 nanoseconds. - Weight::from_parts(51_736_000, 224324) + // Minimum execution time: 54_237 nanoseconds. + Weight::from_parts(55_681_000, 224324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -175,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `415` // Estimated: `2841` - // Minimum execution time: 24_102 nanoseconds. - Weight::from_parts(24_372_000, 2841) + // Minimum execution time: 25_734 nanoseconds. + Weight::from_parts(26_429_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,8 +189,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `405` // Estimated: `2841` - // Minimum execution time: 24_162 nanoseconds. - Weight::from_parts(24_547_000, 2841) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_parts(26_786_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,8 +202,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `221835` - // Minimum execution time: 32_247 nanoseconds. - Weight::from_parts(32_731_000, 221835) + // Minimum execution time: 34_567 nanoseconds. + Weight::from_parts(35_939_000, 221835) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -208,13 +211,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `717` - // Estimated: `221835` - // Minimum execution time: 59_900 nanoseconds. - Weight::from_parts(60_659_000, 221835) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `224362` + // Minimum execution time: 67_744 nanoseconds. + Weight::from_parts(70_047_000, 224362) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Referenda TrackQueue (r:1 w:0) @@ -225,8 +230,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6976` - // Minimum execution time: 9_322 nanoseconds. - Weight::from_parts(9_638_000, 6976) + // Minimum execution time: 9_886 nanoseconds. + Weight::from_parts(10_406_000, 6976) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,8 +245,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 76_976 nanoseconds. - Weight::from_parts(77_597_000, 226322) + // Minimum execution time: 100_449 nanoseconds. + Weight::from_parts(101_812_000, 226322) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -255,8 +260,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 78_405 nanoseconds. - Weight::from_parts(78_972_000, 226322) + // Minimum execution time: 101_430 nanoseconds. + Weight::from_parts(103_704_000, 226322) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -270,8 +275,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4682` // Estimated: `116825` - // Minimum execution time: 51_360 nanoseconds. - Weight::from_parts(51_737_000, 116825) + // Minimum execution time: 67_224 nanoseconds. + Weight::from_parts(70_596_000, 116825) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -285,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4668` // Estimated: `116825` - // Minimum execution time: 50_485 nanoseconds. - Weight::from_parts(51_601_000, 116825) + // Minimum execution time: 65_461 nanoseconds. + Weight::from_parts(69_624_000, 116825) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -302,8 +307,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4642` // Estimated: `119314` - // Minimum execution time: 53_075 nanoseconds. - Weight::from_parts(54_014_000, 119314) + // Minimum execution time: 69_848 nanoseconds. + Weight::from_parts(74_480_000, 119314) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -319,8 +324,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4676` // Estimated: `119314` - // Minimum execution time: 52_916 nanoseconds. - Weight::from_parts(53_716_000, 119314) + // Minimum execution time: 70_042 nanoseconds. + Weight::from_parts(72_912_000, 119314) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -332,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `364` // Estimated: `112338` - // Minimum execution time: 21_920 nanoseconds. - Weight::from_parts(22_172_000, 112338) + // Minimum execution time: 23_008 nanoseconds. + Weight::from_parts(23_767_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -345,8 +350,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `112338` - // Minimum execution time: 22_094 nanoseconds. - Weight::from_parts(22_314_000, 112338) + // Minimum execution time: 23_550 nanoseconds. + Weight::from_parts(24_081_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -356,8 +361,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `310` // Estimated: `2841` - // Minimum execution time: 15_696 nanoseconds. - Weight::from_parts(15_964_000, 2841) + // Minimum execution time: 15_850 nanoseconds. + Weight::from_parts(16_773_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -371,8 +376,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_126_000, 114827) + // Minimum execution time: 32_126 nanoseconds. + Weight::from_parts(33_313_000, 114827) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -386,8 +391,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 32_961 nanoseconds. - Weight::from_parts(33_295_000, 114827) + // Minimum execution time: 34_698 nanoseconds. + Weight::from_parts(35_802_000, 114827) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -399,8 +404,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 27_072 nanoseconds. - Weight::from_parts(27_405_000, 112338) + // Minimum execution time: 28_710 nanoseconds. + Weight::from_parts(29_574_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -412,8 +417,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `112338` - // Minimum execution time: 27_056 nanoseconds. - Weight::from_parts(27_768_000, 112338) + // Minimum execution time: 29_030 nanoseconds. + Weight::from_parts(30_308_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -425,8 +430,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(25_170_000, 112338) + // Minimum execution time: 26_382 nanoseconds. + Weight::from_parts(27_219_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -438,8 +443,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `469` // Estimated: `112338` - // Minimum execution time: 23_737 nanoseconds. - Weight::from_parts(24_184_000, 112338) + // Minimum execution time: 25_445 nanoseconds. + Weight::from_parts(26_010_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -453,8 +458,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `469` // Estimated: `224358` - // Minimum execution time: 37_880 nanoseconds. - Weight::from_parts(38_537_000, 224358) + // Minimum execution time: 41_064 nanoseconds. + Weight::from_parts(42_895_000, 224358) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -466,11 +471,39 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 26_898 nanoseconds. - Weight::from_parts(27_496_000, 112338) + // Minimum execution time: 29_472 nanoseconds. + Weight::from_parts(30_011_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `454` + // Estimated: `5407` + // Minimum execution time: 19_389 nanoseconds. + Weight::from_parts(20_490_000, 5407) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `5368` + // Minimum execution time: 18_195 nanoseconds. + Weight::from_parts(19_917_000, 5368) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -485,8 +518,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `251` // Estimated: `109996` - // Minimum execution time: 32_207 nanoseconds. - Weight::from_parts(32_639_000, 109996) + // Minimum execution time: 34_540 nanoseconds. + Weight::from_parts(36_144_000, 109996) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -498,8 +531,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `221835` - // Minimum execution time: 43_766 nanoseconds. - Weight::from_parts(44_494_000, 221835) + // Minimum execution time: 46_963 nanoseconds. + Weight::from_parts(48_459_000, 221835) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -513,8 +546,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3203` // Estimated: `9817` - // Minimum execution time: 41_561 nanoseconds. - Weight::from_parts(42_180_000, 9817) + // Minimum execution time: 55_798 nanoseconds. + Weight::from_parts(58_260_000, 9817) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -528,8 +561,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3223` // Estimated: `9817` - // Minimum execution time: 41_039 nanoseconds. - Weight::from_parts(41_673_000, 9817) + // Minimum execution time: 53_888 nanoseconds. + Weight::from_parts(57_919_000, 9817) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -543,8 +576,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 52_922 nanoseconds. - Weight::from_parts(53_395_000, 224324) + // Minimum execution time: 56_121 nanoseconds. + Weight::from_parts(58_301_000, 224324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -558,8 +591,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 51_050 nanoseconds. - Weight::from_parts(51_736_000, 224324) + // Minimum execution time: 54_237 nanoseconds. + Weight::from_parts(55_681_000, 224324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -569,8 +602,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `415` // Estimated: `2841` - // Minimum execution time: 24_102 nanoseconds. - Weight::from_parts(24_372_000, 2841) + // Minimum execution time: 25_734 nanoseconds. + Weight::from_parts(26_429_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -580,8 +613,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `405` // Estimated: `2841` - // Minimum execution time: 24_162 nanoseconds. - Weight::from_parts(24_547_000, 2841) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_parts(26_786_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -593,8 +626,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `221835` - // Minimum execution time: 32_247 nanoseconds. - Weight::from_parts(32_731_000, 221835) + // Minimum execution time: 34_567 nanoseconds. + Weight::from_parts(35_939_000, 221835) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -602,13 +635,15 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `717` - // Estimated: `221835` - // Minimum execution time: 59_900 nanoseconds. - Weight::from_parts(60_659_000, 221835) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `224362` + // Minimum execution time: 67_744 nanoseconds. + Weight::from_parts(70_047_000, 224362) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Referenda TrackQueue (r:1 w:0) @@ -619,8 +654,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6976` - // Minimum execution time: 9_322 nanoseconds. - Weight::from_parts(9_638_000, 6976) + // Minimum execution time: 9_886 nanoseconds. + Weight::from_parts(10_406_000, 6976) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -634,8 +669,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 76_976 nanoseconds. - Weight::from_parts(77_597_000, 226322) + // Minimum execution time: 100_449 nanoseconds. + Weight::from_parts(101_812_000, 226322) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -649,8 +684,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 78_405 nanoseconds. - Weight::from_parts(78_972_000, 226322) + // Minimum execution time: 101_430 nanoseconds. + Weight::from_parts(103_704_000, 226322) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -664,8 +699,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4682` // Estimated: `116825` - // Minimum execution time: 51_360 nanoseconds. - Weight::from_parts(51_737_000, 116825) + // Minimum execution time: 67_224 nanoseconds. + Weight::from_parts(70_596_000, 116825) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -679,8 +714,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4668` // Estimated: `116825` - // Minimum execution time: 50_485 nanoseconds. - Weight::from_parts(51_601_000, 116825) + // Minimum execution time: 65_461 nanoseconds. + Weight::from_parts(69_624_000, 116825) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -696,8 +731,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4642` // Estimated: `119314` - // Minimum execution time: 53_075 nanoseconds. - Weight::from_parts(54_014_000, 119314) + // Minimum execution time: 69_848 nanoseconds. + Weight::from_parts(74_480_000, 119314) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -713,8 +748,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4676` // Estimated: `119314` - // Minimum execution time: 52_916 nanoseconds. - Weight::from_parts(53_716_000, 119314) + // Minimum execution time: 70_042 nanoseconds. + Weight::from_parts(72_912_000, 119314) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -726,8 +761,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `364` // Estimated: `112338` - // Minimum execution time: 21_920 nanoseconds. - Weight::from_parts(22_172_000, 112338) + // Minimum execution time: 23_008 nanoseconds. + Weight::from_parts(23_767_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -739,8 +774,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `112338` - // Minimum execution time: 22_094 nanoseconds. - Weight::from_parts(22_314_000, 112338) + // Minimum execution time: 23_550 nanoseconds. + Weight::from_parts(24_081_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -750,8 +785,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `310` // Estimated: `2841` - // Minimum execution time: 15_696 nanoseconds. - Weight::from_parts(15_964_000, 2841) + // Minimum execution time: 15_850 nanoseconds. + Weight::from_parts(16_773_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -765,8 +800,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_126_000, 114827) + // Minimum execution time: 32_126 nanoseconds. + Weight::from_parts(33_313_000, 114827) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -780,8 +815,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 32_961 nanoseconds. - Weight::from_parts(33_295_000, 114827) + // Minimum execution time: 34_698 nanoseconds. + Weight::from_parts(35_802_000, 114827) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -793,8 +828,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 27_072 nanoseconds. - Weight::from_parts(27_405_000, 112338) + // Minimum execution time: 28_710 nanoseconds. + Weight::from_parts(29_574_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -806,8 +841,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `112338` - // Minimum execution time: 27_056 nanoseconds. - Weight::from_parts(27_768_000, 112338) + // Minimum execution time: 29_030 nanoseconds. + Weight::from_parts(30_308_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -819,8 +854,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(25_170_000, 112338) + // Minimum execution time: 26_382 nanoseconds. + Weight::from_parts(27_219_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -832,8 +867,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `469` // Estimated: `112338` - // Minimum execution time: 23_737 nanoseconds. - Weight::from_parts(24_184_000, 112338) + // Minimum execution time: 25_445 nanoseconds. + Weight::from_parts(26_010_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -847,8 +882,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `469` // Estimated: `224358` - // Minimum execution time: 37_880 nanoseconds. - Weight::from_parts(38_537_000, 224358) + // Minimum execution time: 41_064 nanoseconds. + Weight::from_parts(42_895_000, 224358) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -860,9 +895,37 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 26_898 nanoseconds. - Weight::from_parts(27_496_000, 112338) + // Minimum execution time: 29_472 nanoseconds. + Weight::from_parts(30_011_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `454` + // Estimated: `5407` + // Minimum execution time: 19_389 nanoseconds. + Weight::from_parts(20_490_000, 5407) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `5368` + // Minimum execution time: 18_195 nanoseconds. + Weight::from_parts(19_917_000, 5368) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } From 51648486b288f0443243eba233074c04cb1227aa Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:04:02 +0200 Subject: [PATCH 16/24] Improve test coverage of the `Notifications` protocol (#13033) * Add handler and upgrade tests * Add tests for `behaviour.rs` * Apply review comments * Update dependencies * Apply suggestions from code review Co-authored-by: Dmitry Markin * Apply review comments * Fix clippy * Update mockall * Apply review comment --------- Co-authored-by: Dmitry Markin --- Cargo.lock | 702 +++-- client/consensus/common/Cargo.toml | 2 +- client/network/Cargo.toml | 4 + .../src/protocol/notifications/behaviour.rs | 2417 +++++++++++++++++ .../src/protocol/notifications/handler.rs | 1015 ++++++- .../src/protocol/notifications/upgrade.rs | 4 +- .../protocol/notifications/upgrade/collec.rs | 80 +- .../notifications/upgrade/notifications.rs | 18 +- client/network/sync/Cargo.toml | 2 +- 9 files changed, 3773 insertions(+), 471 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b89619a511f3..030c88352b8f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.1", ] [[package]] @@ -139,9 +139,9 @@ dependencies = [ [[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", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "approx" @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.2.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" +checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad" [[package]] name = "arc-swap" @@ -308,11 +308,11 @@ checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" [[package]] name = "assert_cmd" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" +checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" dependencies = [ - "bstr 1.1.0", + "bstr", "doc-comment", "predicates", "predicates-core", @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -435,7 +435,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.0", + "object 0.30.3", "rustc-demangle", ] @@ -463,12 +463,27 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "base64ct" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +[[package]] +name = "basic-toml" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4" +dependencies = [ + "serde", +] + [[package]] name = "beef" version = "0.5.2" @@ -546,7 +561,7 @@ name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "hash-db", "log", "sp-core", @@ -718,18 +733,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - -[[package]] -name = "bstr" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" +checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832" dependencies = [ "memchr", "once_cell", @@ -748,9 +754,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -778,9 +784,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2-sys" @@ -795,9 +801,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" +checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" dependencies = [ "serde", ] @@ -813,9 +819,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" dependencies = [ "camino", "cargo-platform", @@ -833,9 +839,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -911,7 +917,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.0.32", + "clap 4.1.4", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -1027,13 +1033,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.32" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.0", + "clap_lex 0.3.1", "is-terminal", "once_cell", "strsim", @@ -1042,18 +1048,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.7" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" +checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" dependencies = [ "heck", "proc-macro-error", @@ -1073,9 +1079,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -1103,9 +1109,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -1278,18 +1284,18 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] name = "crc32fast" @@ -1495,9 +1501,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.5" +version = "4.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" +checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" dependencies = [ "cfg-if", "fiat-crypto", @@ -1509,9 +1515,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" dependencies = [ "cc", "cxxbridge-flags", @@ -1521,9 +1527,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" dependencies = [ "cc", "codespan-reporting", @@ -1536,15 +1542,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" dependencies = [ "proc-macro2", "quote", @@ -1553,9 +1559,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" dependencies = [ "darling_core", "darling_macro", @@ -1563,9 +1569,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" dependencies = [ "fnv", "ident_case", @@ -1577,9 +1583,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" dependencies = [ "darling_core", "quote", @@ -1799,9 +1805,9 @@ dependencies = [ [[package]] name = "dissimilar" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5f0c7e4bd266b8ab2550e6238d2e74977c23c15536ac7be45e9c95e2e3fbbb" +checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" [[package]] name = "doc-comment" @@ -1868,9 +1874,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] @@ -1905,9 +1911,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1976,6 +1982,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "environmental" version = "1.1.4" @@ -2066,11 +2085,11 @@ checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" [[package]] name = "file-per-thread-logger" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger", + "env_logger 0.10.0", "log", ] @@ -2203,7 +2222,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.4", "comfy-table", "frame-benchmarking", "frame-support", @@ -2294,7 +2313,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2539,9 +2558,9 @@ dependencies = [ [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "funty" @@ -2551,9 +2570,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -2566,9 +2585,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -2576,15 +2595,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -2594,9 +2613,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-lite" @@ -2615,9 +2634,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -2631,21 +2650,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.7", + "rustls 0.20.8", "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-timer" @@ -2655,9 +2674,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -2777,15 +2796,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "git2" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ "bitflags", "libc", @@ -2796,18 +2815,18 @@ dependencies = [ [[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.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr", "fnv", "log", "regex", @@ -2895,9 +2914,9 @@ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[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" @@ -2917,6 +2936,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" + [[package]] name = "hex" version = "0.4.3" @@ -3053,9 +3078,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" dependencies = [ "bytes", "futures-channel", @@ -3084,7 +3109,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.20.7", + "rustls 0.20.8", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3255,12 +3280,12 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3283,20 +3308,20 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.0", "io-lifetimes", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3325,9 +3350,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -3644,9 +3669,9 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libgit2-sys" -version = "0.14.1+1.5.0" +version = "0.14.2+1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" dependencies = [ "cc", "libc", @@ -3914,7 +3939,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn-proto", "rand 0.8.5", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "tokio", ] @@ -3997,7 +4022,7 @@ dependencies = [ "libp2p-core", "rcgen 0.10.0", "ring", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "webpki 0.22.0", "x509-parser 0.14.0", @@ -4104,7 +4129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -4306,9 +4331,9 @@ dependencies = [ [[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" @@ -4539,9 +4564,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -4635,9 +4660,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", @@ -4662,9 +4687,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +checksum = "260e21fbb6f3d253a14df90eb0000a6066780a15dd901a7519ce02d77a94985b" dependencies = [ "bytes", "futures", @@ -4687,9 +4712,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags", "cfg-if", @@ -4704,7 +4729,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.0.32", + "clap 4.1.4", "derive_more", "fs_extra", "futures", @@ -4741,7 +4766,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.0.32", + "clap 4.1.4", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4751,7 +4776,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.26.1", + "nix 0.26.2", "node-executor", "node-inspect", "node-primitives", @@ -4860,7 +4885,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4919,7 +4944,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "generate-bags", "kitchensink-runtime", ] @@ -4928,7 +4953,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5047,9 +5072,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.2" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -5084,9 +5109,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -5157,9 +5182,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -5583,7 +5608,7 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -5948,7 +5973,7 @@ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -6797,7 +6822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core 0.9.7", ] [[package]] @@ -6816,15 +6841,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -6859,11 +6884,11 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -6883,9 +6908,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" +checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" dependencies = [ "thiserror", "ucd-trie", @@ -6893,9 +6918,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" dependencies = [ "pest", "pest_generator", @@ -6903,9 +6928,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" +checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" dependencies = [ "pest", "pest_meta", @@ -6916,20 +6941,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" +checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" dependencies = [ "once_cell", "pest", - "sha1", + "sha2 0.10.6", ] [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -7127,9 +7152,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" dependencies = [ "proc-macro2", "syn", @@ -7150,11 +7175,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", "thiserror", "toml", ] @@ -7185,9 +7209,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -7231,9 +7255,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" +checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" dependencies = [ "bytes", "prost-derive", @@ -7241,9 +7265,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" +checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" dependencies = [ "bytes", "heck", @@ -7276,9 +7300,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" +checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" dependencies = [ "anyhow", "itertools", @@ -7289,9 +7313,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" +checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" dependencies = [ "bytes", "prost", @@ -7342,7 +7366,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustc-hash", - "rustls 0.20.7", + "rustls 0.20.8", "slab", "thiserror", "tinyvec", @@ -7473,9 +7497,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -7562,9 +7586,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -7749,16 +7773,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -7767,7 +7791,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", + "base64 0.13.1", "log", "ring", "sct 0.6.1", @@ -7776,9 +7800,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -7800,11 +7824,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] @@ -7978,7 +8002,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.4", "fdlimit", "futures", "futures-timer", @@ -8315,7 +8339,7 @@ dependencies = [ "array-bytes", "assert_matches", "criterion", - "env_logger", + "env_logger 0.9.3", "lru", "num_cpus", "parity-scale-codec", @@ -8399,7 +8423,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "assert_matches", "async-trait", @@ -8512,6 +8536,8 @@ dependencies = [ "libp2p", "log", "lru", + "mockall", + "multistream-select", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", @@ -8540,6 +8566,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-test", "tokio-util", "unsigned-varint", "zeroize", @@ -8599,7 +8626,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "futures", "futures-timer", "libp2p", @@ -8784,7 +8811,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "env_logger", + "env_logger 0.9.3", "futures", "jsonrpsee", "log", @@ -9009,10 +9036,10 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "futures", "log", - "nix 0.26.1", + "nix 0.26.2", "sc-client-db", "sc-utils", "sp-core", @@ -9206,12 +9233,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -9220,7 +9246,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", ] @@ -9303,9 +9329,9 @@ dependencies = [ [[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", ] @@ -9330,9 +9356,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -9343,9 +9369,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -9406,9 +9432,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ "itoa", "ryu", @@ -9428,17 +9454,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", -] - [[package]] name = "sha2" version = "0.8.2" @@ -9561,14 +9576,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" +checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.5", + "curve25519-dalek 4.0.0-rc.0", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -9592,7 +9607,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64", + "base64 0.13.1", "bytes", "flate2", "futures", @@ -10080,7 +10095,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10352,7 +10367,7 @@ dependencies = [ name = "sp-trie" version = "7.0.0" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "criterion", "hash-db", @@ -10453,9 +10468,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.36.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b" dependencies = [ "Inflector", "num-format", @@ -10540,7 +10555,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" dependencies = [ - "base64", + "base64 0.13.1", "crc", "lazy_static", "md-5", @@ -10557,7 +10572,7 @@ dependencies = [ name = "subkey" version = "2.0.2" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "sc-cli", ] @@ -10585,7 +10600,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-support", "frame-system", "sc-cli", @@ -10915,9 +10930,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -10980,12 +10995,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -11076,15 +11090,15 @@ 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" -version = "1.23.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", @@ -11117,7 +11131,7 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.7", + "rustls 0.20.8", "tokio", "webpki 0.22.0", ] @@ -11164,9 +11178,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -11414,15 +11428,15 @@ 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" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11451,10 +11465,11 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.74" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654bfc024d30963fce210f22f98956407fe8c8365eb85a1fa530f6f8844137ed" +checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413" dependencies = [ + "basic-toml", "dissimilar", "glob", "once_cell", @@ -11462,7 +11477,6 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml", ] [[package]] @@ -11478,7 +11492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" dependencies = [ "async-trait", - "base64", + "base64 0.13.1", "futures", "log", "md-5", @@ -11528,9 +11542,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -11600,9 +11614,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" dependencies = [ "getrandom 0.2.8", ] @@ -11696,9 +11710,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -11706,9 +11720,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -11721,9 +11735,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -11733,9 +11747,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11743,9 +11757,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -11756,15 +11770,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.20.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05632e0a66a6ed8cca593c24223aabd6262f256c3693ad9822c315285f010614" +checksum = "9a584273ccc2d9311f1dd19dc3fb26054661fa3e373d53ede5d1144ba07a9acd" dependencies = [ "leb128", ] @@ -11968,7 +11982,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830570847f905b8f6d2ca635c33cf42ce701dd8e4abd7d1806c631f8f06e9e4b" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "bincode", "directories-next", "file-per-thread-logger", @@ -12105,9 +12119,9 @@ dependencies = [ [[package]] name = "wast" -version = "50.0.0" +version = "52.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2cbb59d4ac799842791fe7e806fa5dbbf6b5554d538e51cc8e176db6ff0ae34" +checksum = "15942180f265280eede7bc38b239e9770031d1821c02d905284216c645316430" dependencies = [ "leb128", "memchr", @@ -12117,18 +12131,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.52" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584aaf7a1ecf4d383bbe1a25eeab0cbb8ff96acc6796707ff65cde48f4632f15" +checksum = "37212100d4cbe6f0f6ff6e707f1e5a5b5b675f0451231ed9e4235e234e127ed3" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -12386,9 +12400,9 @@ dependencies = [ [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -12457,37 +12471,48 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 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", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" @@ -12497,15 +12522,9 @@ 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.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" @@ -12515,15 +12534,9 @@ 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.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" @@ -12533,15 +12546,9 @@ 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.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" @@ -12551,21 +12558,15 @@ 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.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" @@ -12575,15 +12576,9 @@ 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.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winreg" @@ -12632,7 +12627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" dependencies = [ "asn1-rs 0.3.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 7.0.0", "lazy_static", @@ -12651,7 +12646,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ "asn1-rs 0.5.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 8.1.0", "lazy_static", @@ -12733,10 +12728,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.4+zstd.1.5.2" +version = "2.0.6+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" dependencies = [ "cc", "libc", + "pkg-config", ] diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 87b052d434e93..d9e80e1e5ce99 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -18,7 +18,7 @@ futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p = "0.50.0" log = "0.4.17" -mockall = "0.11.2" +mockall = "0.11.3" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 44a7973b33659..b6b21247128d7 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -28,6 +28,7 @@ ip_network = "0.4.1" libp2p = { version = "0.50.0", features = ["dns", "identify", "kad", "macros", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } log = "0.4.17" lru = "0.8.1" +mockall = "0.11.3" parking_lot = "0.12.1" pin-project = "1.0.12" rand = "0.8.5" @@ -52,9 +53,12 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" +multistream-select = "0.12.1" +rand = "0.8.5" tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["macros"] } tokio-util = { version = "0.7.4", features = ["compat"] } +tokio-test = "0.4.2" sc-network-light = { version = "0.10.0-dev", path = "./light" } sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 2db46867128ac..c546f6b6f2c44 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -2111,3 +2111,2420 @@ impl NetworkBehaviour for Notifications { Poll::Pending } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::protocol::notifications::handler::tests::*; + use libp2p::{ + core::ConnectedPoint, + swarm::{behaviour::FromSwarm, AddressRecord}, + }; + use std::{collections::HashSet, iter}; + + impl PartialEq for ConnectionState { + fn eq(&self, other: &ConnectionState) -> bool { + match (self, other) { + (ConnectionState::Closed, ConnectionState::Closed) => true, + (ConnectionState::Closing, ConnectionState::Closing) => true, + (ConnectionState::Opening, ConnectionState::Opening) => true, + (ConnectionState::OpeningThenClosing, ConnectionState::OpeningThenClosing) => true, + (ConnectionState::OpenDesiredByRemote, ConnectionState::OpenDesiredByRemote) => + true, + (ConnectionState::Open(_), ConnectionState::Open(_)) => true, + _ => false, + } + } + } + + #[derive(Clone)] + struct MockPollParams { + peer_id: PeerId, + addr: Multiaddr, + } + + impl PollParameters for MockPollParams { + type SupportedProtocolsIter = std::vec::IntoIter>; + type ListenedAddressesIter = std::vec::IntoIter; + type ExternalAddressesIter = std::vec::IntoIter; + + fn supported_protocols(&self) -> Self::SupportedProtocolsIter { + vec![].into_iter() + } + + fn listened_addresses(&self) -> Self::ListenedAddressesIter { + vec![self.addr.clone()].into_iter() + } + + fn external_addresses(&self) -> Self::ExternalAddressesIter { + vec![].into_iter() + } + + fn local_peer_id(&self) -> &PeerId { + &self.peer_id + } + } + + fn development_notifs() -> (Notifications, sc_peerset::PeersetHandle) { + let (peerset, peerset_handle) = { + let mut sets = Vec::with_capacity(1); + + sets.push(sc_peerset::SetConfig { + in_peers: 25, + out_peers: 25, + bootnodes: Vec::new(), + reserved_nodes: HashSet::new(), + reserved_only: false, + }); + + sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) + }; + + ( + Notifications::new( + peerset, + iter::once(ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: vec![1, 2, 3, 4], + max_notification_size: u64::MAX, + }), + ), + peerset_handle, + ) + } + + #[test] + fn update_handshake() { + let (mut notif, _peerset) = development_notifs(); + + let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); + assert_eq!(inner, vec![1, 2, 3, 4]); + + notif.set_notif_protocol_handshake(0.into(), vec![5, 6, 7, 8]); + + let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); + assert_eq!(inner, vec![5, 6, 7, 8]); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn update_unknown_handshake() { + let (mut notif, _peerset) = development_notifs(); + + notif.set_notif_protocol_handshake(1337.into(), vec![5, 6, 7, 8]); + } + + #[test] + fn disconnect_backoff_peer() { + let (mut notif, _peerset) = development_notifs(); + + let peer = PeerId::random(); + notif.peers.insert( + (peer, 0.into()), + PeerState::Backoff { timer: DelayId(0), timer_deadline: Instant::now() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::Backoff { timer: DelayId(0), .. }) + )); + } + + #[test] + fn disconnect_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + + notif.peers.insert( + (peer, 0.into()), + PeerState::PendingRequest { timer: DelayId(0), timer_deadline: Instant::now() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::PendingRequest { timer: DelayId(0), .. }) + )); + } + + #[test] + fn disconnect_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + + let peer = PeerId::random(); + notif.peers.insert((peer, 0.into()), PeerState::Requested); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!(notif.peers.get(&(peer, 0.into())), Some(PeerState::Requested))); + } + + #[test] + fn disconnect_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + notif.peers.insert( + (peer, 0.into()), + PeerState::Disabled { backoff_until: None, connections: SmallVec::new() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::Disabled { backoff_until: None, .. }) + )); + } + + #[test] + fn remote_opens_connection_and_substream() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&PeerState::Disabled { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections[0], (conn, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(&PeerState::Incoming { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + } else { + panic!("invalid state"); + } + + assert!(std::matches!( + notif.incoming.pop(), + Some(IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }), + )); + } + + #[tokio::test] + async fn disconnect_remote_substream_before_handled_by_peerset() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + notif.disconnect_peer(&peer, 0.into()); + + if let Some(&PeerState::Disabled { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::Closing)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_report_connect_backoff() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + // + // there is not straight-forward way of adding backoff to `PeerState::Disabled` + // so manually adjust the value in order to progress on to the next stage. + // This modification together with `ConnectionClosed` will conver the peer + // state into `PeerState::Backoff`. + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + let timer = if let Some(&PeerState::Backoff { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + timer_deadline + } else { + panic!("invalid state"); + }; + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + + if let Some(&PeerState::PendingRequest { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + assert_eq!(timer, timer_deadline); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_connect_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + // attempt to connect to the peer and verify that the peer state is `Enabled` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + } + + #[test] + fn peerset_disconnect_disable_pending_enable() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.peerset_report_disconnect(peer, set_id); + + if let Some(PeerState::Disabled { backoff_until, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(backoff_until.is_some()); + assert!(backoff_until.unwrap() > Instant::now()); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_disconnect_enabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // Set peer into `Enabled` state. + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + // disconnect peer and verify that the state is `Disabled` + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn peerset_disconnect_requested() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + // disconnect peer and verify that the state is `Disabled` + notif.peerset_report_disconnect(peer, set_id); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[test] + fn peerset_disconnect_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + // attempt to disconnect the backed-off peer and verify that the request is pending + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn peerset_accept_peer_not_alive() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.disconnect_peer(&peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: false, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + assert_eq!(notif.incoming.len(), 0); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(PeerState::Disabled { .. }))); + } + + #[test] + fn secondary_connection_peer_state_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + } else { + panic!("invalid state"); + } + + // add another connection + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 2); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn close_connection_for_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[test] + fn close_connection_for_incoming_peer_one_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: false, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + } + + #[test] + fn close_connection_for_incoming_peer_two_connections() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let conn1 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conns = SmallVec::< + [(ConnectionId, ConnectionState); crate::MAX_CONNECTIONS_PER_PEER], + >::from(vec![(conn, ConnectionState::Closed)]); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + conns.push((conn1, ConnectionState::Closed)); + + if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 2); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn1, ConnectionState::Closed)); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn connection_and_substream_open() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + // open new substream + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0].0, conn); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } + + assert!(std::matches!( + notif.events[notif.events.len() - 1], + NetworkBehaviourAction::GenerateEvent(NotificationsOut::CustomProtocolOpen { .. }) + )); + } + + #[test] + fn connection_closed_sink_replaced() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // open substreams on both active connections + notif.peerset_report_connect(peer, set_id); + notif.on_connection_handler_event( + peer, + conn2, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Opening)); + assert_eq!(connections[1], (conn2, ConnectionState::Opening)); + } else { + panic!("invalid state"); + } + + // add two new substreams, one for each connection and verify that both are in open state + for conn in vec![conn1, conn2].iter() { + notif.on_connection_handler_event( + peer, + *conn, + conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + ); + } + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections[0].0, conn1); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + assert_eq!(connections[1].0, conn2); + assert!(std::matches!(connections[1].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + // check peer information + assert_eq!(notif.open_peers().collect::>(), vec![&peer],); + assert_eq!(notif.reserved_peers(set_id).collect::>(), Vec::<&PeerId>::new(),); + assert_eq!(notif.num_discovered_peers(), 0usize); + + // close the other connection and verify that notification replacement event is emitted + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0].0, conn2); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + assert!(std::matches!( + notif.events[notif.events.len() - 1], + NetworkBehaviourAction::GenerateEvent(NotificationsOut::CustomProtocolReplaced { .. }) + )); + } + + #[test] + fn dial_failure_for_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + notif.on_swarm_event(FromSwarm::DialFailure(libp2p::swarm::behaviour::DialFailure { + peer_id: Some(peer), + handler: NotifsHandlerProto::new(vec![]), + error: &libp2p::swarm::DialError::Banned, + })); + + if let Some(PeerState::Backoff { timer_deadline, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(timer_deadline > &Instant::now()); + } else { + panic!("invalid state"); + } + } + + #[tokio::test] + async fn write_notification() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]), + ); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections[0].0, conn); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + notif.write_notification(&peer, set_id, vec![1, 3, 3, 7]); + assert_eq!(conn_yielder.get_next_event(peer, set_id.into()).await, Some(vec![1, 3, 3, 7])); + } + + #[test] + fn peerset_report_connect_backoff_expired() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let backoff_duration = Duration::from_millis(100); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = Some(Instant::now().checked_add(backoff_duration).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + // wait until the backoff time has passed + std::thread::sleep(backoff_duration * 2); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested { .. }))) + } + + #[test] + fn peerset_report_disconnect_disabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn peerset_report_disconnect_backoff() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let backoff_duration = Duration::from_secs(2); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = Some(Instant::now().checked_add(backoff_duration).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn peer_is_backed_off_if_both_connections_get_closed_while_peer_is_disabled_with_back_off() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn inject_connection_closed_incoming_with_backoff() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + // manually add backoff for the entry + if let Some(&mut PeerState::Incoming { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, 0.into())) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn two_connections_inactive_connection_gets_closed_peer_state_is_still_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!( + notif.peers.get_mut(&(peer, 0.into())), + Some(&mut PeerState::Incoming { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + } + + #[test] + fn two_connections_active_connection_gets_closed_peer_state_is_disabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!( + notif.peers.get_mut(&(peer, 0.into())), + Some(PeerState::Incoming { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn inject_connection_closed_for_active_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // open substreams on both active connections + notif.peerset_report_connect(peer, set_id); + + if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Opening)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + notif.on_connection_handler_event( + peer, + conn1, + conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + ); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + assert_eq!(connections[0].0, conn1); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + fn inject_dial_failure_for_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + let now = Instant::now(); + notif.on_swarm_event(FromSwarm::DialFailure(libp2p::swarm::behaviour::DialFailure { + peer_id: Some(peer), + handler: NotifsHandlerProto::new(vec![]), + error: &libp2p::swarm::DialError::Banned, + })); + + if let Some(PeerState::PendingRequest { ref timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + assert!(timer_deadline > &(now + std::time::Duration::from_secs(5))); + } + } + + #[test] + fn peerstate_incoming_open_desired_by_remote() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // add another open event from remote + notif.on_connection_handler_event( + peer, + conn2, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn2, ConnectionState::OpenDesiredByRemote)); + } + } + + #[tokio::test] + async fn remove_backoff_peer_after_timeout() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&mut PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, 0.into())) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_millis(100)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + let until = if let Some(&PeerState::Backoff { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + timer_deadline + } else { + panic!("invalid state"); + }; + + if until > Instant::now() { + std::thread::sleep(until - Instant::now()); + } + + assert!(notif.peers.get(&(peer, set_id)).is_some()); + + if tokio::time::timeout(Duration::from_secs(5), async { + let mut params = MockPollParams { peer_id: PeerId::random(), addr: Multiaddr::empty() }; + + loop { + futures::future::poll_fn(|cx| { + let _ = notif.poll(cx, &mut params); + Poll::Ready(()) + }) + .await; + + if notif.peers.get(&(peer, set_id)).is_none() { + break + } + } + }) + .await + .is_err() + { + panic!("backoff peer was not removed in time"); + } + + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[tokio::test] + async fn reschedule_disabled_pending_enable_when_connection_not_closed() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // open substream + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0], (_, ConnectionState::Open(_)))); + assert_eq!(connections[0].0, conn); + } else { + panic!("invalid state"); + } + + notif.peerset_report_disconnect(peer, set_id); + + if let Some(PeerState::Disabled { ref connections, ref mut backoff_until }) = + notif.peers.get_mut(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + assert_eq!(connections[0].0, conn); + + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(2)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.peerset_report_connect(peer, set_id); + + let prev_instant = + if let Some(PeerState::DisabledPendingEnable { + ref connections, timer_deadline, .. + }) = notif.peers.get(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + assert_eq!(connections[0].0, conn); + + *timer_deadline + } else { + panic!("invalid state"); + }; + + // one of the peers has an active backoff timer so poll the notifications code until + // the timer has expired. Because the connection is still in the state of `Closing`, + // verify that the code continues to keep the peer disabled by resetting the timer + // after the first one expired. + if tokio::time::timeout(Duration::from_secs(5), async { + let mut params = MockPollParams { peer_id: PeerId::random(), addr: Multiaddr::empty() }; + + loop { + futures::future::poll_fn(|cx| { + let _ = notif.poll(cx, &mut params); + Poll::Ready(()) + }) + .await; + + if let Some(PeerState::DisabledPendingEnable { + timer_deadline, connections, .. + }) = notif.peers.get(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + + if timer_deadline != &prev_instant { + break + } + } else { + panic!("invalid state"); + } + } + }) + .await + .is_err() + { + panic!("backoff peer was not removed in time"); + } + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_enabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0], (_, ConnectionState::Open(_)))); + assert_eq!(connections[0].0, conn); + } else { + panic!("invalid state"); + } + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_disabled_pending_enable_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_pending_requested() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_disconnect_with_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_accept_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peers.remove(&(peer, set_id)); + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_accept_not_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + notif.on_connection_handler_event(peer, conn, event); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + notif.incoming[0].alive = true; + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let endpoint = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(0usize), + endpoint: &endpoint, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &endpoint), + remaining_established: 0usize, + }, + )); + } + + #[test] + fn disconnect_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + notif.peerset_report_disconnect(peer, set_id); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn accept_non_existent_connection() { + let (mut notif, _peerset) = development_notifs(); + + notif.peerset_report_accept(0.into()); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn reject_non_existent_connection() { + let (mut notif, _peerset) = development_notifs(); + + notif.peerset_report_reject(0.into()); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn reject_non_active_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.incoming[0].alive = false; + notif.peerset_report_reject(0.into()); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn reject_non_existent_peer_but_alive_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peers.remove(&(peer, set_id)); + notif.peerset_report_reject(0.into()); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_disabled_pending_enable() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_incoming_peer_state_mismatch() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + notif.incoming[0].alive = false; + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_enabled_state_mismatch() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // attempt to connect to the peer and verify that the peer state is `Enabled` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_backoff_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn open_result_ok_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_connection_handler_event( + PeerId::random(), + conn, + conn_yielder.open_substream(PeerId::random(), 0, connected, vec![1, 2, 3, 4]), + ); + } +} diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index ea09cb76edce1..57561c7b9879d 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -58,8 +58,8 @@ //! [`NotifsHandlerIn::Open`] has gotten an answer. use crate::protocol::notifications::upgrade::{ - NotificationsHandshakeError, NotificationsIn, NotificationsInSubstream, NotificationsOut, - NotificationsOutSubstream, UpgradeCollec, + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, + UpgradeCollec, }; use bytes::BytesMut; @@ -69,12 +69,9 @@ use futures::{ prelude::*, }; use libp2p::{ - core::{ - upgrade::{InboundUpgrade, OutboundUpgrade}, - ConnectedPoint, PeerId, - }, + core::{ConnectedPoint, PeerId}, swarm::{ - ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, IntoConnectionHandler, + handler::ConnectionEvent, ConnectionHandler, ConnectionHandlerEvent, IntoConnectionHandler, KeepAlive, NegotiatedSubstream, SubstreamProtocol, }, }; @@ -494,98 +491,128 @@ impl ConnectionHandler for NotifsHandler { SubstreamProtocol::new(protocols, ()) } - fn inject_fully_negotiated_inbound( + fn on_connection_event( &mut self, - (mut in_substream_open, protocol_index): >::Output, - (): (), + event: ConnectionEvent< + '_, + Self::InboundProtocol, + Self::OutboundProtocol, + Self::InboundOpenInfo, + Self::OutboundOpenInfo, + >, ) { - let mut protocol_info = &mut self.protocols[protocol_index]; - match protocol_info.state { - State::Closed { pending_opening } => { - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, - )); + match event { + ConnectionEvent::FullyNegotiatedInbound(inbound) => { + let (mut in_substream_open, protocol_index) = inbound.protocol; + let mut protocol_info = &mut self.protocols[protocol_index]; - protocol_info.state = State::OpenDesiredByRemote { - in_substream: in_substream_open.substream, - pending_opening, - }; - }, - State::OpenDesiredByRemote { .. } => { - // If a substream already exists, silently drop the new one. - // Note that we drop the substream, which will send an equivalent to a - // TCP "RST" to the remote and force-close the substream. It might - // seem like an unclean way to get rid of a substream. However, keep - // in mind that it is invalid for the remote to open multiple such - // substreams, and therefore sending a "RST" is the most correct thing - // to do. - return - }, - State::Opening { ref mut in_substream, .. } | - State::Open { ref mut in_substream, .. } => { - if in_substream.is_some() { - // Same remark as above. - return - } + match protocol_info.state { + State::Closed { pending_opening } => { + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, + )); - // Create `handshake_message` on a separate line to be sure that the - // lock is released as soon as possible. - let handshake_message = protocol_info.config.handshake.read().clone(); - in_substream_open.substream.send_handshake(handshake_message); - *in_substream = Some(in_substream_open.substream); - }, - } - } + protocol_info.state = State::OpenDesiredByRemote { + in_substream: in_substream_open.substream, + pending_opening, + }; + }, + State::OpenDesiredByRemote { .. } => { + // If a substream already exists, silently drop the new one. + // Note that we drop the substream, which will send an equivalent to a + // TCP "RST" to the remote and force-close the substream. It might + // seem like an unclean way to get rid of a substream. However, keep + // in mind that it is invalid for the remote to open multiple such + // substreams, and therefore sending a "RST" is the most correct thing + // to do. + return + }, + State::Opening { ref mut in_substream, .. } | + State::Open { ref mut in_substream, .. } => { + if in_substream.is_some() { + // Same remark as above. + return + } - fn inject_fully_negotiated_outbound( - &mut self, - new_open: >::Output, - protocol_index: Self::OutboundOpenInfo, - ) { - match self.protocols[protocol_index].state { - State::Closed { ref mut pending_opening } | - State::OpenDesiredByRemote { ref mut pending_opening, .. } => { - debug_assert!(*pending_opening); - *pending_opening = false; - }, - State::Open { .. } => { - error!(target: "sub-libp2p", "☎️ State mismatch in notifications handler"); - debug_assert!(false); + // Create `handshake_message` on a separate line to be sure that the + // lock is released as soon as possible. + let handshake_message = protocol_info.config.handshake.read().clone(); + in_substream_open.substream.send_handshake(handshake_message); + *in_substream = Some(in_substream_open.substream); + }, + } }, - State::Opening { ref mut in_substream } => { - let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); - let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); - let notifications_sink = NotificationsSink { - inner: Arc::new(NotificationsSinkInner { - peer_id: self.peer_id, - async_channel: FuturesMutex::new(async_tx), - sync_channel: Mutex::new(Some(sync_tx)), - }), - }; - - self.protocols[protocol_index].state = State::Open { - notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()) - .peekable(), - out_substream: Some(new_open.substream), - in_substream: in_substream.take(), - }; + ConnectionEvent::FullyNegotiatedOutbound(outbound) => { + let (new_open, protocol_index) = (outbound.protocol, outbound.info); - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenResultOk { - protocol_index, - negotiated_fallback: new_open.negotiated_fallback, - endpoint: self.endpoint.clone(), - received_handshake: new_open.handshake, - notifications_sink, + match self.protocols[protocol_index].state { + State::Closed { ref mut pending_opening } | + State::OpenDesiredByRemote { ref mut pending_opening, .. } => { + debug_assert!(*pending_opening); + *pending_opening = false; }, - )); + State::Open { .. } => { + error!(target: "sub-libp2p", "☎️ State mismatch in notifications handler"); + debug_assert!(false); + }, + State::Opening { ref mut in_substream } => { + let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: self.peer_id, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + + self.protocols[protocol_index].state = State::Open { + notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()) + .peekable(), + out_substream: Some(new_open.substream), + in_substream: in_substream.take(), + }; + + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenResultOk { + protocol_index, + negotiated_fallback: new_open.negotiated_fallback, + endpoint: self.endpoint.clone(), + received_handshake: new_open.handshake, + notifications_sink, + }, + )); + }, + } }, + ConnectionEvent::AddressChange(_address_change) => {}, + ConnectionEvent::DialUpgradeError(dial_upgrade_error) => match self.protocols + [dial_upgrade_error.info] + .state + { + State::Closed { ref mut pending_opening } | + State::OpenDesiredByRemote { ref mut pending_opening, .. } => { + debug_assert!(*pending_opening); + *pending_opening = false; + }, + + State::Opening { .. } => { + self.protocols[dial_upgrade_error.info].state = + State::Closed { pending_opening: false }; + + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenResultErr { protocol_index: dial_upgrade_error.info }, + )); + }, + + // No substream is being open when already `Open`. + State::Open { .. } => debug_assert!(false), + }, + ConnectionEvent::ListenUpgradeError(_listen_upgrade_error) => {}, } } - fn inject_event(&mut self, message: NotifsHandlerIn) { + fn on_behaviour_event(&mut self, message: NotifsHandlerIn) { match message { NotifsHandlerIn::Open { protocol_index } => { let protocol_info = &mut self.protocols[protocol_index]; @@ -676,31 +703,6 @@ impl ConnectionHandler for NotifsHandler { } } - fn inject_dial_upgrade_error( - &mut self, - num: usize, - _: ConnectionHandlerUpgrErr, - ) { - match self.protocols[num].state { - State::Closed { ref mut pending_opening } | - State::OpenDesiredByRemote { ref mut pending_opening, .. } => { - debug_assert!(*pending_opening); - *pending_opening = false; - }, - - State::Opening { .. } => { - self.protocols[num].state = State::Closed { pending_opening: false }; - - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenResultErr { protocol_index: num }, - )); - }, - - // No substream is being open when already `Open`. - State::Open { .. } => debug_assert!(false), - } - } - fn connection_keep_alive(&self) -> KeepAlive { // `Yes` if any protocol has some activity. if self.protocols.iter().any(|p| !matches!(p.state, State::Closed { .. })) { @@ -850,3 +852,792 @@ impl ConnectionHandler for NotifsHandler { Poll::Pending } } + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::protocol::notifications::upgrade::{ + NotificationsInOpen, NotificationsInSubstreamHandshake, NotificationsOutOpen, + }; + use asynchronous_codec::Framed; + use libp2p::{ + core::muxing::SubstreamBox, + swarm::{handler, ConnectionHandlerUpgrErr}, + Multiaddr, + }; + use multistream_select::{dialer_select_proto, listener_select_proto, Negotiated, Version}; + use std::{ + collections::HashMap, + io::{Error, IoSlice, IoSliceMut}, + }; + use tokio::sync::mpsc; + use unsigned_varint::codec::UviBytes; + + struct OpenSubstream { + notifications: stream::Peekable< + stream::Select< + stream::Fuse>, + stream::Fuse>, + >, + >, + _in_substream: MockSubstream, + _out_substream: MockSubstream, + } + + pub struct ConnectionYielder { + connections: HashMap<(PeerId, usize), OpenSubstream>, + } + + impl ConnectionYielder { + /// Create new [`ConnectionYielder`]. + pub fn new() -> Self { + Self { connections: HashMap::new() } + } + + /// Open a new substream for peer. + pub fn open_substream( + &mut self, + peer: PeerId, + protocol_index: usize, + endpoint: ConnectedPoint, + received_handshake: Vec, + ) -> NotifsHandlerOut { + let (async_tx, async_rx) = + futures::channel::mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = + futures::channel::mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: peer, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + let (in_substream, out_substream) = MockSubstream::new(); + + self.connections.insert( + (peer, protocol_index), + OpenSubstream { + notifications: stream::select(async_rx.fuse(), sync_rx.fuse()).peekable(), + _in_substream: in_substream, + _out_substream: out_substream, + }, + ); + + NotifsHandlerOut::OpenResultOk { + protocol_index, + negotiated_fallback: None, + endpoint, + received_handshake, + notifications_sink, + } + } + + /// Attempt to get next pending event from one of the notification sinks. + pub async fn get_next_event(&mut self, peer: PeerId, set: usize) -> Option> { + let substream = if let Some(info) = self.connections.get_mut(&(peer, set)) { + info + } else { + return None + }; + + futures::future::poll_fn(|cx| match substream.notifications.poll_next_unpin(cx) { + Poll::Ready(Some(NotificationsSinkMessage::Notification { message })) => + Poll::Ready(Some(message)), + Poll::Pending => Poll::Ready(None), + Poll::Ready(Some(NotificationsSinkMessage::ForceClose)) | Poll::Ready(None) => + panic!("sink closed"), + }) + .await + } + } + + struct MockSubstream { + pub rx: mpsc::Receiver>, + pub tx: mpsc::Sender>, + rx_buffer: BytesMut, + } + + impl MockSubstream { + /// Create new substream pair. + pub fn new() -> (Self, Self) { + let (tx1, rx1) = mpsc::channel(32); + let (tx2, rx2) = mpsc::channel(32); + + ( + Self { rx: rx1, tx: tx2, rx_buffer: BytesMut::with_capacity(512) }, + Self { rx: rx2, tx: tx1, rx_buffer: BytesMut::with_capacity(512) }, + ) + } + + /// Create new negotiated substream pair. + pub async fn negotiated() -> (Negotiated, Negotiated) { + let (socket1, socket2) = Self::new(); + let socket1 = SubstreamBox::new(socket1); + let socket2 = SubstreamBox::new(socket2); + + let protos = vec![b"/echo/1.0.0", b"/echo/2.5.0"]; + let (res1, res2) = tokio::join!( + dialer_select_proto(socket1, protos.clone(), Version::V1), + listener_select_proto(socket2, protos), + ); + + (res1.unwrap().1, res2.unwrap().1) + } + } + + impl AsyncWrite for MockSubstream { + fn poll_write<'a>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + buf: &[u8], + ) -> Poll> { + match self.tx.try_send(buf.to_vec()) { + Ok(_) => Poll::Ready(Ok(buf.len())), + Err(_) => Poll::Ready(Err(std::io::ErrorKind::UnexpectedEof.into())), + } + } + + fn poll_flush<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_write_vectored<'a, 'b>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + _bufs: &[IoSlice<'b>], + ) -> Poll> { + unimplemented!(); + } + } + + impl AsyncRead for MockSubstream { + fn poll_read<'a>( + mut self: Pin<&mut Self>, + cx: &mut Context<'a>, + buf: &mut [u8], + ) -> Poll> { + match self.rx.poll_recv(cx) { + Poll::Ready(Some(data)) => self.rx_buffer.extend_from_slice(&data), + Poll::Ready(None) => + return Poll::Ready(Err(std::io::ErrorKind::UnexpectedEof.into())), + _ => {}, + } + + let nsize = std::cmp::min(self.rx_buffer.len(), buf.len()); + let data = self.rx_buffer.split_to(nsize); + buf[..nsize].copy_from_slice(&data[..]); + + if nsize > 0 { + return Poll::Ready(Ok(nsize)) + } + + Poll::Pending + } + + fn poll_read_vectored<'a, 'b>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + _bufs: &mut [IoSliceMut<'b>], + ) -> Poll> { + unimplemented!(); + } + } + + /// Create new [`NotifsHandler`]. + fn notifs_handler() -> NotifsHandler { + let proto = Protocol { + config: ProtocolConfig { + name: "/foo".into(), + fallback_names: vec![], + handshake: Arc::new(RwLock::new(b"hello, world".to_vec())), + max_notification_size: u64::MAX, + }, + in_upgrade: NotificationsIn::new("/foo", Vec::new(), u64::MAX), + state: State::Closed { pending_opening: false }, + }; + + NotifsHandler { + protocols: vec![proto], + when_connection_open: Instant::now(), + endpoint: ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + peer_id: PeerId::random(), + events_queue: VecDeque::new(), + } + } + + // verify that if another substream is attempted to be opened by remote while an inbound + // substream already exists, the new inbound stream is rejected and closed by the local node. + #[tokio::test] + async fn second_open_desired_by_remote_rejected() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // attempt to open another inbound substream and verify that it is rejected + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof,); + } + + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn open_rejected_if_substream_is_opening() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // move the handler state to 'Opening' + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + // remote now tries to open another substream, verify that it is rejected and closed + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed but that the first substream is + // still in correct state + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof,); + } else { + panic!("unexpected result"); + } + + Poll::Ready(()) + }) + .await; + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + } + + #[tokio::test] + async fn open_rejected_if_substream_already_open() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // move the handler state to 'Opening' + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + // accept the substream and move its state to `Open` + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::Open { in_substream: Some(_), .. } + )); + + // remote now tries to open another substream, verify that it is rejected and closed + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed but that the first substream is + // still in correct state + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof); + } else { + panic!("unexpected result"); + } + + Poll::Ready(()) + }) + .await; + assert!(std::matches!( + handler.protocols[0].state, + State::Open { in_substream: Some(_), .. } + )); + } + + #[tokio::test] + async fn fully_negotiated_resets_state_for_closed_substream() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // verify that if the the outbound substream is successfully negotiated, the state is not + // changed as the substream was commanded to be closed by the handler. + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::Closed { pending_opening: false } + )); + } + + #[tokio::test] + async fn fully_negotiated_resets_state_for_open_desired_substream() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // attempt to open another inbound substream and verify that it is rejected + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: true, .. } + )); + + // verify that if the the outbound substream is successfully negotiated, the state is not + // changed as the substream was commanded to be closed by the handler. + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: false, .. } + )); + } + + #[tokio::test] + async fn dial_upgrade_error_resets_closed_outbound_state() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // inject dial failure to an already closed substream and verify outbound state is reset + handler.on_connection_event(handler::ConnectionEvent::DialUpgradeError( + handler::DialUpgradeError { info: 0, error: ConnectionHandlerUpgrErr::Timeout }, + )); + assert!(std::matches!( + handler.protocols[0].state, + State::Closed { pending_opening: false } + )); + } + + #[tokio::test] + async fn dial_upgrade_error_resets_open_desired_state() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: true, .. } + )); + + // inject dial failure to an already closed substream and verify outbound state is reset + handler.on_connection_event(handler::ConnectionEvent::DialUpgradeError( + handler::DialUpgradeError { info: 0, error: ConnectionHandlerUpgrErr::Timeout }, + )); + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: false, .. } + )); + } + + #[tokio::test] + async fn sync_notifications_clogged() { + let mut handler = notifs_handler(); + let (io, _) = MockSubstream::negotiated().await; + let codec = UviBytes::default(); + + let (async_tx, async_rx) = futures::channel::mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = futures::channel::mpsc::channel(1); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: PeerId::random(), + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + + handler.protocols[0].state = State::Open { + notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()).peekable(), + out_substream: Some(NotificationsOutSubstream::new(Framed::new(io, codec))), + in_substream: None, + }; + + notifications_sink.send_sync_notification(vec![1, 3, 3, 7]); + notifications_sink.send_sync_notification(vec![1, 3, 3, 8]); + notifications_sink.send_sync_notification(vec![1, 3, 3, 9]); + notifications_sink.send_sync_notification(vec![1, 3, 4, 0]); + + futures::future::poll_fn(|cx| { + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Close( + NotifsHandlerError::SyncNotificationsClogged, + )) + )); + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn close_desired_by_remote() { + let mut handler = notifs_handler(); + let (io, io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::PendingSend(vec![1, 2, 3, 4]), + ), + }; + + // add new inbound substream but close it immediately and verify that correct events are + // emitted + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + drop(io2); + + futures::future::poll_fn(|cx| { + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + )) + )); + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Custom(NotifsHandlerOut::CloseDesired { + protocol_index: 0 + },)) + )); + Poll::Ready(()) + }) + .await; + } +} diff --git a/client/network/src/protocol/notifications/upgrade.rs b/client/network/src/protocol/notifications/upgrade.rs index c273361acabdd..89fede25f6ae7 100644 --- a/client/network/src/protocol/notifications/upgrade.rs +++ b/client/network/src/protocol/notifications/upgrade.rs @@ -20,8 +20,8 @@ pub use self::{ collec::UpgradeCollec, notifications::{ NotificationsHandshakeError, NotificationsIn, NotificationsInOpen, - NotificationsInSubstream, NotificationsOut, NotificationsOutError, NotificationsOutOpen, - NotificationsOutSubstream, + NotificationsInSubstream, NotificationsInSubstreamHandshake, NotificationsOut, + NotificationsOutError, NotificationsOutOpen, NotificationsOutSubstream, }, }; diff --git a/client/network/src/protocol/notifications/upgrade/collec.rs b/client/network/src/protocol/notifications/upgrade/collec.rs index db9850c8da74b..288b8bfd4849c 100644 --- a/client/network/src/protocol/notifications/upgrade/collec.rs +++ b/client/network/src/protocol/notifications/upgrade/collec.rs @@ -73,7 +73,7 @@ where } /// Groups a `ProtocolName` with a `usize`. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ProtoNameWithUsize(T, usize); impl ProtocolName for ProtoNameWithUsize { @@ -99,3 +99,81 @@ impl>, O, E> Future for FutWithUsize { } } } + +#[cfg(test)] +mod tests { + use super::*; + use libp2p::core::upgrade::{ProtocolName, UpgradeInfo}; + use sc_network_common::protocol::ProtocolName as ProtoName; + + // TODO: move to mocks + mockall::mock! { + pub ProtocolUpgrade {} + + impl UpgradeInfo for ProtocolUpgrade { + type Info = T; + type InfoIter = vec::IntoIter; + fn protocol_info(&self) -> vec::IntoIter; + } + } + + #[test] + fn protocol_info() { + let upgrades = (1..=3) + .map(|i| { + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ProtoNameWithUsize(ProtoName::from(format!("protocol{i}")), i)].into_iter() + }); + upgrade + }) + .collect::>(); + + let upgrade: UpgradeCollec<_> = upgrades.into_iter().collect::>(); + let protos = vec![ + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol1".to_string()), 1), 0), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol2".to_string()), 2), 1), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol3".to_string()), 3), 2), + ]; + let upgrades = upgrade.protocol_info().collect::>(); + + assert_eq!(upgrades, protos,); + } + + #[test] + fn nested_protocol_info() { + let mut upgrades = (1..=2) + .map(|i| { + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ProtoNameWithUsize(ProtoName::from(format!("protocol{i}")), i)].into_iter() + }); + upgrade + }) + .collect::>(); + + upgrades.push({ + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ + ProtoNameWithUsize(ProtoName::from("protocol22".to_string()), 1), + ProtoNameWithUsize(ProtoName::from("protocol33".to_string()), 2), + ProtoNameWithUsize(ProtoName::from("protocol44".to_string()), 3), + ] + .into_iter() + }); + upgrade + }); + + let upgrade: UpgradeCollec<_> = upgrades.into_iter().collect::>(); + let protos = vec![ + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol1".to_string()), 1), 0), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol2".to_string()), 2), 1), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol22".to_string()), 1), 2), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol33".to_string()), 2), 2), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol44".to_string()), 3), 2), + ]; + let upgrades = upgrade.protocol_info().collect::>(); + assert_eq!(upgrades, protos,); + } +} diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 5a4ec832dbea1..71afc3c90e37f 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -88,7 +88,8 @@ pub struct NotificationsInSubstream { } /// State of the handshake sending back process. -enum NotificationsInSubstreamHandshake { +#[derive(Debug)] +pub enum NotificationsInSubstreamHandshake { /// Waiting for the user to give us the handshake message. NotSent, /// User gave us the handshake message. Trying to push it in the socket. @@ -111,6 +112,13 @@ pub struct NotificationsOutSubstream { socket: Framed>>>, } +#[cfg(test)] +impl NotificationsOutSubstream { + pub fn new(socket: Framed>>>) -> Self { + Self { socket } + } +} + impl NotificationsIn { /// Builds a new potential upgrade. pub fn new( @@ -193,6 +201,14 @@ impl NotificationsInSubstream where TSubstream: AsyncRead + AsyncWrite + Unpin, { + #[cfg(test)] + pub fn new( + socket: Framed>>>, + handshake: NotificationsInSubstreamHandshake, + ) -> Self { + Self { socket, handshake } + } + /// Sends the handshake in order to inform the remote that we accept the substream. pub fn send_handshake(&mut self, message: impl Into>) { if !matches!(self.handshake, NotificationsInSubstreamHandshake::NotSent) { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index ff72b4e993026..532e873836204 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -23,7 +23,7 @@ futures = "0.3.21" libp2p = "0.50.0" log = "0.4.17" lru = "0.8.1" -mockall = "0.11.2" +mockall = "0.11.3" prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" From b7d764c25af094a19069715e88a24ab118cf323d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 14 Feb 2023 22:45:49 +0100 Subject: [PATCH 17/24] refactors runtime API logic to own pallet impl block --- frame/nomination-pools/src/lib.rs | 86 ++++++++++++++++--------------- frame/staking/src/pallet/impls.rs | 24 +++++---- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index bb7061a1406ff..9c52cf71c6b30 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2142,48 +2142,6 @@ pub mod pallet { } impl Pallet { - /// Returns the pending rewards for the specified `who` account. - /// - /// In the case of error, `None` is returned. Used by runtime API. - pub fn api_pending_rewards(who: T::AccountId) -> Option> { - if let Some(pool_member) = PoolMembers::::get(who) { - if let Some((reward_pool, bonded_pool)) = RewardPools::::get(pool_member.pool_id) - .zip(BondedPools::::get(pool_member.pool_id)) - { - let current_reward_counter = reward_pool - .current_reward_counter(pool_member.pool_id, bonded_pool.points) - .ok()?; - return pool_member.pending_rewards(current_reward_counter).ok() - } - } - - None - } - - /// Returns the points to balance conversion for a specified pool. - /// - /// If the pool ID does not exist, it returns 0 ratio points to balance. Used by runtime API. - pub fn api_points_to_balance(pool_id: PoolId, points: BalanceOf) -> BalanceOf { - if let Some(pool) = BondedPool::::get(pool_id) { - pool.points_to_balance(points) - } else { - Zero::zero() - } - } - - /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. - /// - /// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API. - pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { - if let Some(pool) = BondedPool::::get(pool_id) { - let bonded_balance = - T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); - Pallet::::balance_to_point(bonded_balance, pool.points, new_funds) - } else { - Zero::zero() - } - } - /// The amount of bond that MUST REMAIN IN BONDED in ALL POOLS. /// /// It is the responsibility of the depositor to put these funds into the pool initially. Upon @@ -2603,6 +2561,50 @@ impl Pallet { } } +impl Pallet { + /// Returns the pending rewards for the specified `who` account. + /// + /// In the case of error, `None` is returned. Used by runtime API. + pub fn api_pending_rewards(who: T::AccountId) -> Option> { + if let Some(pool_member) = PoolMembers::::get(who) { + if let Some((reward_pool, bonded_pool)) = RewardPools::::get(pool_member.pool_id) + .zip(BondedPools::::get(pool_member.pool_id)) + { + let current_reward_counter = reward_pool + .current_reward_counter(pool_member.pool_id, bonded_pool.points) + .ok()?; + return pool_member.pending_rewards(current_reward_counter).ok() + } + } + + None + } + + /// Returns the points to balance conversion for a specified pool. + /// + /// If the pool ID does not exist, it returns 0 ratio points to balance. Used by runtime API. + pub fn api_points_to_balance(pool_id: PoolId, points: BalanceOf) -> BalanceOf { + if let Some(pool) = BondedPool::::get(pool_id) { + pool.points_to_balance(points) + } else { + Zero::zero() + } + } + + /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. + /// + /// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API. + pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { + if let Some(pool) = BondedPool::::get(pool_id) { + let bonded_balance = + T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); + Pallet::::balance_to_point(bonded_balance, pool.points, new_funds) + } else { + Zero::zero() + } + } +} + impl OnStakerSlash> for Pallet { fn on_slash( pool_account: &T::AccountId, diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 4219c9d9f6130..c190407b7927e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -59,17 +59,6 @@ use super::{pallet::*, STAKING_ID}; const NPOS_MAX_ITERATIONS_COEFFICIENT: u32 = 2; impl Pallet { - /// Returns the current nominations quota for nominators. - /// - /// Used by runtime API. - /// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it - /// is redundant. However, with the upcoming changes in https://github.com/paritytech/substrate/pull/12970 - /// the nominations quota will change depending on the nominators balance. We're introducing - /// this runtime API now to prepare the community to use it before rolling out PR#12970. - pub fn api_nominations_quota(_balance: BalanceOf) -> u32 { - T::MaxNominations::get() - } - /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. @@ -983,6 +972,19 @@ impl Pallet { } } +impl Pallet { + /// Returns the current nominations quota for nominators. + /// + /// Used by runtime API. + /// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it + /// is redundant. However, with the upcoming changes in https://github.com/paritytech/substrate/pull/12970 + /// the nominations quota will change depending on the nominators balance. We're introducing + /// this runtime API now to prepare the community to use it before rolling out PR#12970. + pub fn api_nominations_quota(_balance: BalanceOf) -> u32 { + T::MaxNominations::get() + } +} + impl ElectionDataProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; From 6a54821eae234abbec21203d015c729d440e1d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 15 Feb 2023 00:21:08 +0100 Subject: [PATCH 18/24] removes unrelated changes --- client/db/src/lib.rs | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 935b70e79670d..03de383f2c7f4 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -3559,50 +3559,6 @@ pub(crate) mod tests { assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); } - #[test] - fn prune_blocks_on_finalize_and_reorg() { - // 0 - 1b - // \ - 1a - 2a - 3a - // \ - 2b - - let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); - - let make_block = |index, parent, val: u64| { - insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) - .unwrap() - }; - - let block_0 = make_block(0, Default::default(), 0x00); - let block_1a = make_block(1, block_0, 0x1a); - let block_1b = make_block(1, block_0, 0x1b); - let block_2a = make_block(2, block_1a, 0x2a); - let block_2b = make_block(2, block_1a, 0x2b); - let block_3a = make_block(3, block_2a, 0x3a); - - // Make sure 1b is head - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block_0).unwrap(); - op.mark_head(block_1b).unwrap(); - backend.commit_operation(op).unwrap(); - - // Finalize 3a - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block_0).unwrap(); - op.mark_head(block_3a).unwrap(); - op.mark_finalized(block_1a, None).unwrap(); - op.mark_finalized(block_2a, None).unwrap(); - op.mark_finalized(block_3a, None).unwrap(); - backend.commit_operation(op).unwrap(); - - let bc = backend.blockchain(); - assert_eq!(None, bc.body(block_1b).unwrap()); - assert_eq!(None, bc.body(block_2b).unwrap()); - assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); - assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); - assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); - assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); - } - #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); From 3f1677771a8b117751cd82c14ff07e538fa06056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 16 Feb 2023 12:09:27 +0100 Subject: [PATCH 19/24] Fixes cargo doc comments lint --- frame/staking/src/pallet/impls.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 250e9bf061a46..63384e4b836de 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -977,9 +977,10 @@ impl Pallet { /// /// Used by runtime API. /// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it - /// is redundant. However, with the upcoming changes in https://github.com/paritytech/substrate/pull/12970 - /// the nominations quota will change depending on the nominators balance. We're introducing - /// this runtime API now to prepare the community to use it before rolling out PR#12970. + /// is redundant. However, with the upcoming changes in + /// , the nominations quota will change + /// depending on the nominators balance. We're introducing this runtime API now to prepare the + /// community to use it before rolling out PR#12970. pub fn api_nominations_quota(_balance: BalanceOf) -> u32 { T::MaxNominations::get() } From 842286467375799ee8b6c59765a95b0b447af52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 16 Feb 2023 12:32:04 +0100 Subject: [PATCH 20/24] fixes node cargo --- bin/node/runtime/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index b48e3239b8a07..e27e4f7f8a545 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -176,6 +176,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-staking/std", + "pallet-staking-runtime-api/std", "pallet-state-trie-migration/std", "sp-session/std", "pallet-sudo/std", From eb282184fdfa86999e3df6be3497d5dfe585d811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 20 Feb 2023 07:34:53 +0100 Subject: [PATCH 21/24] fixes comment --- frame/staking/src/pallet/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 63384e4b836de..fc0bf082c7caf 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -975,7 +975,7 @@ impl Pallet { impl Pallet { /// Returns the current nominations quota for nominators. /// - /// Used by runtime API. + /// Used by the runtime API. /// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it /// is redundant. However, with the upcoming changes in /// , the nominations quota will change From a1a5c3c94de8fecc074e70d6e348d4e7ef61766d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Feb 2023 00:19:04 +0100 Subject: [PATCH 22/24] restart ci From 7c23d17812db2433f1105c9c9676caee4ef35cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Feb 2023 01:02:36 +0100 Subject: [PATCH 23/24] restart ci From 4492a2dc3a80317e8f187833cc81926766bb9d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Feb 2023 09:05:06 +0100 Subject: [PATCH 24/24] restart ci