diff --git a/Cargo.lock b/Cargo.lock index 37b48073b78f..3ae6c40a9c22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13369,6 +13369,7 @@ dependencies = [ "log", "pallet-bags-list 27.0.0", "pallet-balances 28.0.0", + "pallet-delegated-staking 1.0.0", "pallet-election-provider-multi-phase 27.0.0", "pallet-nomination-pools 25.0.0", "pallet-session 28.0.0", @@ -14459,29 +14460,6 @@ dependencies = [ "sp-tracing 16.0.0", ] -[[package]] -name = "pallet-nomination-pools-test-transfer-stake" -version = "1.0.0" -dependencies = [ - "frame-election-provider-support 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-bags-list 27.0.0", - "pallet-balances 28.0.0", - "pallet-nomination-pools 25.0.0", - "pallet-staking 28.0.0", - "pallet-staking-reward-curve", - "pallet-timestamp 27.0.0", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-tracing 16.0.0", -] - [[package]] name = "pallet-offences" version = "27.0.0" diff --git a/Cargo.toml b/Cargo.toml index 509775fe99e4..e17f08148b16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -389,7 +389,6 @@ members = [ "substrate/frame/nomination-pools/fuzzer", "substrate/frame/nomination-pools/runtime-api", "substrate/frame/nomination-pools/test-delegate-stake", - "substrate/frame/nomination-pools/test-transfer-stake", "substrate/frame/offences", "substrate/frame/offences/benchmarking", "substrate/frame/paged-list", diff --git a/bridges/relays/lib-substrate-relay/src/error.rs b/bridges/relays/lib-substrate-relay/src/error.rs index 2ebd9130f391..3a62f30838c7 100644 --- a/bridges/relays/lib-substrate-relay/src/error.rs +++ b/bridges/relays/lib-substrate-relay/src/error.rs @@ -47,7 +47,7 @@ pub enum Error { #[error("Failed to guess initial {0} GRANDPA authorities set id: checked all possible ids in range [0; {1}]")] GuessInitialAuthorities(&'static str, HeaderNumber), /// Failed to retrieve GRANDPA authorities at the given header from the source chain. - #[error("Failed to retrive {0} GRANDPA authorities set at header {1}: {2:?}")] + #[error("Failed to retrieve {0} GRANDPA authorities set at header {1}: {2:?}")] RetrieveAuthorities(&'static str, Hash, client::Error), /// Failed to decode GRANDPA authorities at the given header of the source chain. #[error("Failed to decode {0} GRANDPA authorities set at header {1}: {2:?}")] diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index 36de637f04c4..cdc94b9fae49 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -1041,7 +1041,7 @@ pub(crate) mod tests { #[test] fn message_lane_loop_is_able_to_recover_from_unsuccessful_transaction() { // with this configuration, both source and target clients will mine their transactions, but - // their corresponding nonce won't be udpated => reconnect will happen + // their corresponding nonce won't be updated => reconnect will happen let (exit_sender, exit_receiver) = unbounded(); let result = run_loop_test( Arc::new(Mutex::new(TestClientData { diff --git a/bridges/snowbridge/primitives/core/src/location.rs b/bridges/snowbridge/primitives/core/src/location.rs index f49a245c4126..eb5ac66d46db 100644 --- a/bridges/snowbridge/primitives/core/src/location.rs +++ b/bridges/snowbridge/primitives/core/src/location.rs @@ -206,7 +206,7 @@ mod tests { for token in token_locations { assert!( TokenIdOf::convert_location(&token).is_some(), - "Valid token = {token:?} yeilds no TokenId." + "Valid token = {token:?} yields no TokenId." ); } @@ -220,7 +220,7 @@ mod tests { for token in non_token_locations { assert!( TokenIdOf::convert_location(&token).is_none(), - "Invalid token = {token:?} yeilds a TokenId." + "Invalid token = {token:?} yields a TokenId." ); } } diff --git a/docs/sdk/packages/guides/first-pallet/Cargo.toml b/docs/sdk/packages/guides/first-pallet/Cargo.toml index a1411580119d..e6325c31781a 100644 --- a/docs/sdk/packages/guides/first-pallet/Cargo.toml +++ b/docs/sdk/packages/guides/first-pallet/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } docify = { workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } scale-info = { workspace = true } [features] diff --git a/docs/sdk/packages/guides/first-runtime/Cargo.toml b/docs/sdk/packages/guides/first-runtime/Cargo.toml index 303d5c5e7f5f..8ed17dea1b71 100644 --- a/docs/sdk/packages/guides/first-runtime/Cargo.toml +++ b/docs/sdk/packages/guides/first-runtime/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { workspace = true } serde_json = { workspace = true } # this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } # pallets that we want to use pallet-balances = { workspace = true } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 4f9ba8d8508c..cdf6fa92da2f 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -366,11 +366,13 @@ impl onchain::Config for OnChainSeqPhragmen { const MAX_QUOTA_NOMINATIONS: u32 = 16; impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; type CurrencyToVote = polkadot_runtime_common::CurrencyToVote; type RewardRemainder = (); + type RuntimeHoldReason = RuntimeHoldReason; type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 58d2bdcb7c7d..8a5771fe7cc0 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -728,8 +728,10 @@ parameter_types! { } impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; + type RuntimeHoldReason = RuntimeHoldReason; type UnixTime = Timestamp; type CurrencyToVote = CurrencyToVote; type RewardRemainder = (); diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index fcdaf7ff2de6..65b81cc00f06 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -155,25 +155,27 @@ mod remote_tests { let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into(); let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); + let online_config = OnlineConfig { + transport, + state_snapshot: maybe_state_snapshot.clone(), + child_trie: false, + pallets: vec![ + "Staking".into(), + "System".into(), + "Balances".into(), + "NominationPools".into(), + "DelegatedStaking".into(), + ], + ..Default::default() + }; let mut ext = Builder::::default() .mode(if let Some(state_snapshot) = maybe_state_snapshot { Mode::OfflineOrElseOnline( OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - pallets: vec![ - "staking".into(), - "system".into(), - "balances".into(), - "nomination-pools".into(), - "delegated-staking".into(), - ], - ..Default::default() - }, + online_config, ) } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) + Mode::Online(online_config) }) .build() .await @@ -241,6 +243,77 @@ mod remote_tests { ); }); } + + #[tokio::test] + async fn staking_curr_fun_migrate() { + // Intended to be run only manually. + if var("RUN_MIGRATION_TESTS").is_err() { + return; + } + sp_tracing::try_init_simple(); + + let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9944".to_string()).into(); + let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); + let online_config = OnlineConfig { + transport, + state_snapshot: maybe_state_snapshot.clone(), + child_trie: false, + pallets: vec!["Staking".into(), "System".into(), "Balances".into()], + ..Default::default() + }; + let mut ext = Builder::::default() + .mode(if let Some(state_snapshot) = maybe_state_snapshot { + Mode::OfflineOrElseOnline( + OfflineConfig { state_snapshot: state_snapshot.clone() }, + online_config, + ) + } else { + Mode::Online(online_config) + }) + .build() + .await + .unwrap(); + ext.execute_with(|| { + // create an account with some balance + let alice = AccountId::from([1u8; 32]); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&alice, 100_000 * UNITS); + + let mut success = 0; + let mut err = 0; + let mut force_withdraw_acc = 0; + // iterate over all pools + pallet_staking::Ledger::::iter().for_each(|(ctrl, ledger)| { + match pallet_staking::Pallet::::migrate_currency( + RuntimeOrigin::signed(alice.clone()).into(), + ledger.stash.clone(), + ) { + Ok(_) => { + let updated_ledger = + pallet_staking::Ledger::::get(&ctrl).expect("ledger exists"); + let force_withdraw = ledger.total - updated_ledger.total; + if force_withdraw > 0 { + force_withdraw_acc += force_withdraw; + log::info!(target: "remote_test", "Force withdraw from stash {:?}: value {:?}", ledger.stash, force_withdraw); + } + success += 1; + }, + Err(e) => { + log::error!(target: "remote_test", "Error migrating {:?}: {:?}", ledger.stash, e); + err += 1; + }, + } + }); + + log::info!( + target: "remote_test", + "Migration stats: success: {}, err: {}, total force withdrawn stake: {}", + success, + err, + force_withdraw_acc + ); + }); + } } #[test] diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 393fa0b37176..f1e7f5ba1576 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-09-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-obbyq9g6-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,19 +52,19 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1009` - // Estimated: `4764` - // Minimum execution time: 40_585_000 picoseconds. - Weight::from_parts(41_800_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) + // Measured: `1035` + // Estimated: `4556` + // Minimum execution time: 70_147_000 picoseconds. + Weight::from_parts(71_795_000, 0) + .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -72,20 +72,20 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1921` + // Measured: `1947` // Estimated: `8877` - // Minimum execution time: 81_809_000 picoseconds. - Weight::from_parts(84_387_000, 0) + // Minimum execution time: 125_203_000 picoseconds. + Weight::from_parts(128_088_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) @@ -100,23 +100,23 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2128` + // Measured: `2051` // Estimated: `8877` - // Minimum execution time: 89_419_000 picoseconds. - Weight::from_parts(91_237_000, 0) + // Minimum execution time: 101_991_000 picoseconds. + Weight::from_parts(104_567_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -124,23 +124,25 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `DelegatedStaking::Agents` (r:1 w:0) + /// Proof: `DelegatedStaking::Agents` (`max_values`: None, `max_size`: Some(120), added: 2595, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1223` - // Estimated: `4764` - // Minimum execution time: 45_152_000 picoseconds. - Weight::from_parts(46_460_819, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 972 - .saturating_add(Weight::from_parts(55_473, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `1253` + // Estimated: `4556` + // Minimum execution time: 76_450_000 picoseconds. + Weight::from_parts(78_836_594, 0) + .saturating_add(Weight::from_parts(0, 4556)) + // Standard Error: 1_529 + .saturating_add(Weight::from_parts(66_662, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -151,10 +153,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -174,15 +176,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2153 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 82_762_000 picoseconds. - Weight::from_parts(91_035_077, 0) + // Minimum execution time: 121_962_000 picoseconds. + Weight::from_parts(131_000_151, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_771 - .saturating_add(Weight::from_parts(1_217_871, 0).saturating_mul(s.into())) + // Standard Error: 3_846 + .saturating_add(Weight::from_parts(1_277_843, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(11)) + .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -210,10 +212,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1301` + // Measured: `1334` // Estimated: `4556` - // Minimum execution time: 50_555_000 picoseconds. - Weight::from_parts(52_052_000, 0) + // Minimum execution time: 66_450_000 picoseconds. + Weight::from_parts(68_302_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) @@ -227,13 +229,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1778 + k * (572 ±0)` + // Measured: `1811 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 35_037_000 picoseconds. - Weight::from_parts(35_081_878, 0) + // Minimum execution time: 43_875_000 picoseconds. + Weight::from_parts(47_332_240, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 5_473 - .saturating_add(Weight::from_parts(6_667_924, 0).saturating_mul(k.into())) + // Standard Error: 6_530 + .saturating_add(Weight::from_parts(7_398_001, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -264,13 +266,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1797 + n * (102 ±0)` + // Measured: `1830 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 62_098_000 picoseconds. - Weight::from_parts(60_154_061, 0) + // Minimum execution time: 80_640_000 picoseconds. + Weight::from_parts(78_801_092, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 19_257 - .saturating_add(Weight::from_parts(3_839_855, 0).saturating_mul(n.into())) + // Standard Error: 22_249 + .saturating_add(Weight::from_parts(4_996_344, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -294,10 +296,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1747` + // Measured: `1780` // Estimated: `6248` - // Minimum execution time: 54_993_000 picoseconds. - Weight::from_parts(56_698_000, 0) + // Minimum execution time: 71_494_000 picoseconds. + Weight::from_parts(73_487_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(6)) @@ -310,10 +312,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `865` + // Measured: `898` // Estimated: `4556` - // Minimum execution time: 18_100_000 picoseconds. - Weight::from_parts(18_547_000, 0) + // Minimum execution time: 24_310_000 picoseconds. + Weight::from_parts(24_676_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -326,10 +328,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `932` + // Measured: `965` // Estimated: `4556` - // Minimum execution time: 23_428_000 picoseconds. - Weight::from_parts(24_080_000, 0) + // Minimum execution time: 31_348_000 picoseconds. + Weight::from_parts(32_384_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -340,10 +342,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `865` + // Measured: `898` // Estimated: `8122` - // Minimum execution time: 21_159_000 picoseconds. - Weight::from_parts(21_706_000, 0) + // Minimum execution time: 27_537_000 picoseconds. + Weight::from_parts(28_714_000, 0) .saturating_add(Weight::from_parts(0, 8122)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -354,8 +356,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_910_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 2_362_000 picoseconds. + Weight::from_parts(2_518_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -365,8 +367,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_076_000 picoseconds. - Weight::from_parts(7_349_000, 0) + // Minimum execution time: 7_752_000 picoseconds. + Weight::from_parts(8_105_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -376,8 +378,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_389_000, 0) + // Minimum execution time: 7_868_000 picoseconds. + Weight::from_parts(8_175_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -387,8 +389,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_148_000 picoseconds. - Weight::from_parts(7_446_000, 0) + // Minimum execution time: 7_945_000 picoseconds. + Weight::from_parts(8_203_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -399,11 +401,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_025_000 picoseconds. - Weight::from_parts(2_229_953, 0) + // Minimum execution time: 2_458_000 picoseconds. + Weight::from_parts(2_815_664, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 67 - .saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(12_287, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:1502 w:1502) @@ -415,13 +417,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 751]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `680 + i * (227 ±0)` + // Measured: `713 + i * (227 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 4_321_000 picoseconds. - Weight::from_parts(4_407_000, 0) + // Minimum execution time: 4_976_000 picoseconds. + Weight::from_parts(5_102_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 37_239 - .saturating_add(Weight::from_parts(21_300_598, 0).saturating_mul(i.into())) + // Standard Error: 36_458 + .saturating_add(Weight::from_parts(25_359_275, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -432,10 +434,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) @@ -457,15 +459,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2153 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 78_908_000 picoseconds. - Weight::from_parts(84_886_373, 0) + // Minimum execution time: 116_776_000 picoseconds. + Weight::from_parts(125_460_389, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_376 - .saturating_add(Weight::from_parts(1_217_850, 0).saturating_mul(s.into())) + // Standard Error: 3_095 + .saturating_add(Weight::from_parts(1_300_502, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().writes(13)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -474,13 +476,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66639` - // Estimated: `70104` - // Minimum execution time: 136_389_000 picoseconds. - Weight::from_parts(1_207_241_524, 0) - .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 77_138 - .saturating_add(Weight::from_parts(6_443_948, 0).saturating_mul(s.into())) + // Measured: `66672` + // Estimated: `70137` + // Minimum execution time: 135_135_000 picoseconds. + Weight::from_parts(937_565_332, 0) + .saturating_add(Weight::from_parts(0, 70137)) + // Standard Error: 57_675 + .saturating_add(Weight::from_parts(4_828_080, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -498,12 +500,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:65 w:65) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:65 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:65 w:65) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:65 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:65 w:65) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) @@ -512,30 +512,32 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:65 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:65 w:65) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 64]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8249 + n * (396 ±0)` - // Estimated: `10779 + n * (3774 ±0)` - // Minimum execution time: 130_222_000 picoseconds. - Weight::from_parts(167_236_150, 0) - .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 34_051 - .saturating_add(Weight::from_parts(39_899_917, 0).saturating_mul(n.into())) + // Measured: `8275 + n * (389 ±0)` + // Estimated: `10805 + n * (3566 ±0)` + // Minimum execution time: 180_144_000 picoseconds. + Weight::from_parts(237_134_733, 0) + .saturating_add(Weight::from_parts(0, 10805)) + // Standard Error: 52_498 + .saturating_add(Weight::from_parts(73_633_326, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) @@ -543,26 +545,26 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1922 + l * (5 ±0)` + // Measured: `1845 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 79_136_000 picoseconds. - Weight::from_parts(82_129_497, 0) + // Minimum execution time: 89_307_000 picoseconds. + Weight::from_parts(92_902_634, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 3_867 - .saturating_add(Weight::from_parts(75_156, 0).saturating_mul(l.into())) + // Standard Error: 4_446 + .saturating_add(Weight::from_parts(73_546, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -582,15 +584,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2153 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_375_000 picoseconds. - Weight::from_parts(91_224_907, 0) + // Minimum execution time: 130_544_000 picoseconds. + Weight::from_parts(133_260_598, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_424 - .saturating_add(Weight::from_parts(1_219_542, 0).saturating_mul(s.into())) + // Standard Error: 3_545 + .saturating_add(Weight::from_parts(1_313_348, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(11)) + .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -633,14 +635,14 @@ impl pallet_staking::WeightInfo for WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±0)` - // Minimum execution time: 520_905_000 picoseconds. - Weight::from_parts(523_771_000, 0) + // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±40)` + // Minimum execution time: 654_756_000 picoseconds. + Weight::from_parts(658_861_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_142_714 - .saturating_add(Weight::from_parts(68_631_588, 0).saturating_mul(v.into())) - // Standard Error: 213_509 - .saturating_add(Weight::from_parts(19_343_025, 0).saturating_mul(n.into())) + // Standard Error: 2_078_102 + .saturating_add(Weight::from_parts(67_775_668, 0).saturating_mul(v.into())) + // Standard Error: 207_071 + .saturating_add(Weight::from_parts(22_624_711, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -669,15 +671,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` + // Measured: `3141 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 36_848_619_000 picoseconds. - Weight::from_parts(37_362_442_000, 0) + // Minimum execution time: 42_790_195_000 picoseconds. + Weight::from_parts(42_954_437_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 415_031 - .saturating_add(Weight::from_parts(5_204_987, 0).saturating_mul(v.into())) - // Standard Error: 415_031 - .saturating_add(Weight::from_parts(4_132_636, 0).saturating_mul(n.into())) + // Standard Error: 478_107 + .saturating_add(Weight::from_parts(6_744_044, 0).saturating_mul(v.into())) + // Standard Error: 478_107 + .saturating_add(Weight::from_parts(4_837_739, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -692,13 +694,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `946 + v * (50 ±0)` + // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_512_817_000 picoseconds. - Weight::from_parts(119_401_374, 0) + // Minimum execution time: 2_851_801_000 picoseconds. + Weight::from_parts(4_477_533, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 8_463 - .saturating_add(Weight::from_parts(4_860_364, 0).saturating_mul(v.into())) + // Standard Error: 8_644 + .saturating_add(Weight::from_parts(5_811_682, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -721,8 +723,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_686_000 picoseconds. - Weight::from_parts(3_881_000, 0) + // Minimum execution time: 4_250_000 picoseconds. + Weight::from_parts(4_472_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -744,8 +746,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_143_000 picoseconds. - Weight::from_parts(3_424_000, 0) + // Minimum execution time: 3_986_000 picoseconds. + Weight::from_parts(4_144_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -773,10 +775,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1870` + // Measured: `1903` // Estimated: `6248` - // Minimum execution time: 66_946_000 picoseconds. - Weight::from_parts(69_382_000, 0) + // Minimum execution time: 87_291_000 picoseconds. + Weight::from_parts(89_344_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(6)) @@ -787,10 +789,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `658` + // Measured: `691` // Estimated: `3510` - // Minimum execution time: 11_278_000 picoseconds. - Weight::from_parts(11_603_000, 0) + // Minimum execution time: 16_113_000 picoseconds. + Weight::from_parts(16_593_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -801,29 +803,53 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_963_000 picoseconds. - Weight::from_parts(2_077_000, 0) + // Minimum execution time: 2_433_000 picoseconds. + Weight::from_parts(2_561_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + fn restore_ledger() -> Weight { + // Proof Size summary in bytes: + // Measured: `1040` + // Estimated: `4764` + // Minimum execution time: 50_167_000 picoseconds. + Weight::from_parts(51_108_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - fn restore_ledger() -> Weight { + fn migrate_currency() -> Weight { // Proof Size summary in bytes: - // Measured: `1014` + // Measured: `1209` // Estimated: `4764` - // Minimum execution time: 40_258_000 picoseconds. - Weight::from_parts(41_210_000, 0) + // Minimum execution time: 91_790_000 picoseconds. + Weight::from_parts(92_991_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } } diff --git a/polkadot/xcm/docs/Cargo.toml b/polkadot/xcm/docs/Cargo.toml index 6fa7ea9a23a9..c3bda50619c1 100644 --- a/polkadot/xcm/docs/Cargo.toml +++ b/polkadot/xcm/docs/Cargo.toml @@ -18,7 +18,7 @@ xcm-simulator = { workspace = true, default-features = true } # For building FRAME runtimes codec = { workspace = true, default-features = true } -frame = { features = ["experimental", "runtime"], workspace = true, default-features = true } +frame = { features = ["runtime"], workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc new file mode 100644 index 000000000000..f2a5aa9a4667 --- /dev/null +++ b/prdoc/pr_5501.prdoc @@ -0,0 +1,47 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Currency to Fungible migration for pallet-staking + +doc: + - audience: Runtime User + description: | + Lazy migration of staking balance from `Currency::locks` to `Fungible::holds`. New extrinsic + `staking::migrate_currency` removes the old lock along with other housekeeping. Additionally, any ledger mutation + creates hold if it does not exist. + + The pallet-staking configuration item `Currency` is updated to use `fungible::hold::Mutate` type while still + requiring `LockableCurrency` type to be passed as `OldCurrency` for migration purposes. + + +crates: + - name: westend-runtime + bump: major + - name: kitchensink-runtime + bump: minor + - name: pallet-delegated-staking + bump: patch + - name: pallet-nomination-pools + bump: minor + - name: pallet-nomination-pools-runtime-api + bump: patch + - name: sp-staking + bump: patch + - name: pallet-beefy + bump: patch + - name: pallet-fast-unstake + bump: patch + - name: pallet-staking + bump: major + - name: pallet-grandpa + bump: patch + - name: pallet-babe + bump: patch + - name: pallet-nomination-pools-benchmarking + bump: patch + - name: pallet-session-benchmarking + bump: patch + - name: pallet-root-offences + bump: patch + - name: pallet-offences-benchmarking + bump: patch diff --git a/prdoc/pr_7177.prdoc b/prdoc/pr_7177.prdoc new file mode 100644 index 000000000000..9ab0be1f20a9 --- /dev/null +++ b/prdoc/pr_7177.prdoc @@ -0,0 +1,20 @@ +title: Make frame crate not experimental +doc: +- audience: Runtime Dev + description: |- + Frame crate may still be unstable, but it is no longer feature gated by the feature `experimental`. +crates: +- name: polkadot-sdk-frame + bump: minor +- name: pallet-salary + bump: patch +- name: pallet-multisig + bump: patch +- name: pallet-proxy + bump: patch +- name: pallet-atomic-swap + bump: patch +- name: pallet-mixnet + bump: patch +- name: pallet-node-authorization + bump: patch diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index de377a55bc88..117d306e3060 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -53,7 +53,9 @@ use frame_support::{ Balanced, Credit, HoldConsideration, ItemOf, NativeFromLeft, NativeOrWithId, UnionOf, }, tokens::{ - imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, + imbalance::{ResolveAssetTo, ResolveTo}, + nonfungibles_v2::Inspect, + pay::PayAssetFromAccount, GetSalary, PayFromAccount, }, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, @@ -719,13 +721,15 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { } impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; type CurrencyToVote = sp_staking::currency_to_vote::U128CurrencyToVote; - type RewardRemainder = Treasury; + type RewardRemainder = ResolveTo; type RuntimeEvent = RuntimeEvent; - type Slash = Treasury; // send the slashed funds to the treasury. + type RuntimeHoldReason = RuntimeHoldReason; + type Slash = ResolveTo; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; @@ -748,7 +752,7 @@ impl pallet_staking::Config for Runtime { type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type HistoryDepth = HistoryDepth; - type EventListeners = NominationPools; + type EventListeners = (NominationPools, DelegatedStaking); type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; @@ -932,6 +936,21 @@ impl pallet_bags_list::Config for Runtime { type WeightInfo = pallet_bags_list::weights::SubstrateWeight; } +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); + pub const SlashRewardFraction: Perbill = Perbill::from_percent(1); +} + +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type SlashRewardFraction = SlashRewardFraction; + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + parameter_types! { pub const PostUnbondPoolsWindow: u32 = 4; pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls"); @@ -960,7 +979,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; @@ -2691,6 +2711,9 @@ mod runtime { #[runtime::pallet_index(81)] pub type VerifySignature = pallet_verify_signature::Pallet; + #[runtime::pallet_index(82)] + pub type DelegatedStaking = pallet_delegated_staking::Pallet; + #[runtime::pallet_index(83)] pub type AssetRewards = pallet_asset_rewards::Pallet; diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 7f5364744c66..0394f6cd7394 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -38,9 +38,9 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { (alice(), 111 * DOLLARS), (bob(), 100 * DOLLARS), (charlie(), 100_000_000 * DOLLARS), - (dave(), 111 * DOLLARS), + (dave(), 112 * DOLLARS), (eve(), 101 * DOLLARS), - (ferdie(), 100 * DOLLARS), + (ferdie(), 101 * DOLLARS), ]; endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS))); diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index 785bfee71b68..05a38ded91c5 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } scale-info = { features = ["derive"], workspace = true } [dev-dependencies] diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 23857470adc4..8d00509e800b 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -157,6 +157,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 7ae41c609180..38e0cc4cfc26 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -235,6 +235,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { type RuntimeEvent = RuntimeEvent; + type OldCurrency = Balances; type Currency = Balances; type AdminOrigin = frame_system::EnsureRoot; type SessionInterface = Self; diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 1d181eb29cab..0dacfe9c5579 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -520,7 +520,7 @@ impl Pallet { let stake = T::CoreStaking::stake(who)?; // release funds from core staking. - T::CoreStaking::migrate_to_virtual_staker(who); + T::CoreStaking::migrate_to_virtual_staker(who)?; // transfer just released staked amount plus any free amount. let amount_to_transfer = diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 811d5739f4e9..875279864f7a 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -102,6 +102,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index b7b82a43771e..c764e2741a2a 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -671,12 +671,14 @@ mod staking_integration { )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(agent), vec![GENESIS_VALIDATOR],)); let init_stake = Staking::stake(&agent).unwrap(); + // no extra provider added. + assert_eq!(System::providers(&agent), 1); // scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304) // in equal parts. lets try to migrate this nominator into delegate based stake. // all balance currently is in 200 - assert_eq!(pallet_staking::asset::stakeable_balance::(&agent), agent_amount); + assert_eq!(pallet_staking::asset::total_balance::(&agent), agent_amount); // to migrate, nominator needs to set an account as a proxy delegator where staked funds // will be moved and delegated back to this old nominator account. This should be funded @@ -685,8 +687,9 @@ mod staking_integration { DelegatedStaking::generate_proxy_delegator(Agent::from(agent)).get(); assert_ok!(DelegatedStaking::migrate_to_agent(RawOrigin::Signed(agent).into(), 201)); - // after migration, funds are moved to proxy delegator, still a provider exists. - assert_eq!(System::providers(&agent), 1); + // after migration, no provider left since free balance is 0 and staking pallet released + // all funds. + assert_eq!(System::providers(&agent), 0); assert_eq!(Balances::free_balance(agent), 0); // proxy delegator has one provider as well with no free balance. assert_eq!(System::providers(&proxy_delegator), 1); @@ -798,8 +801,6 @@ mod staking_integration { RawOrigin::Signed(agent).into(), reward_acc )); - // becoming an agent adds another provider. - assert_eq!(System::providers(&agent), 2); // delegate to this account fund(&delegator, 1000); diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index a78aa3f55906..14f49466f0e2 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -131,10 +131,6 @@ impl AgentLedger { /// /// Increments provider count if this is a new agent. pub(crate) fn update(self, key: &T::AccountId) { - if !>::contains_key(key) { - // This is a new agent. Provide for this account. - frame_system::Pallet::::inc_providers(key); - } >::insert(key, self) } @@ -142,8 +138,6 @@ impl AgentLedger { pub(crate) fn remove(key: &T::AccountId) { debug_assert!(>::contains_key(key), "Agent should exist in storage"); >::remove(key); - // Remove provider reference. - let _ = frame_system::Pallet::::dec_providers(key).defensive(); } /// Effective total balance of the `Agent`. diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 7a48ae868a5a..f11f9c04dbf4 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -34,6 +34,7 @@ frame-system = { workspace = true, default-features = true } pallet-bags-list = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +pallet-delegated-staking = { workspace = true, default-features = true } pallet-election-provider-multi-phase = { workspace = true, default-features = true } pallet-nomination-pools = { workspace = true, default-features = true } pallet-session = { workspace = true, default-features = true } @@ -47,6 +48,7 @@ try-runtime = [ "frame-system/try-runtime", "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", + "pallet-delegated-staking/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-session/try-runtime", diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 26a6345e145f..b1029e89fe85 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -327,8 +327,8 @@ fn automatic_unbonding_pools() { assert_eq!(::MaxUnbonding::get(), 1); // init state of pool members. - let init_stakeable_balance_2 = pallet_staking::asset::stakeable_balance::(&2); - let init_stakeable_balance_3 = pallet_staking::asset::stakeable_balance::(&3); + let init_free_balance_2 = Balances::free_balance(2); + let init_free_balance_3 = Balances::free_balance(3); let pool_bonded_account = Pools::generate_bonded_account(1); @@ -378,7 +378,7 @@ fn automatic_unbonding_pools() { System::reset_events(); let staked_before_withdraw_pool = staked_amount_for(pool_bonded_account); - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(delegated_balance_for(pool_bonded_account), 5 + 10 + 10); // now unbonding 3 will work, although the pool's ledger still has the unlocking chunks // filled up. @@ -390,13 +390,13 @@ fn automatic_unbonding_pools() { [ // auto-withdraw happened as expected to release 2's unbonding funds, but the funds // were not transferred to 2 and stay in the pool's transferrable balance instead. - pallet_staking::Event::Withdrawn { stash: 7939698191839293293, amount: 10 }, - pallet_staking::Event::Unbonded { stash: 7939698191839293293, amount: 10 } + pallet_staking::Event::Withdrawn { stash: pool_bonded_account, amount: 10 }, + pallet_staking::Event::Unbonded { stash: pool_bonded_account, amount: 10 } ] ); // balance of the pool remains the same, it hasn't withdraw explicitly from the pool yet. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(delegated_balance_for(pool_bonded_account), 25); // but the locked amount in the pool's account decreases due to the auto-withdraw: assert_eq!(staked_before_withdraw_pool - 10, staked_amount_for(pool_bonded_account)); @@ -405,12 +405,12 @@ fn automatic_unbonding_pools() { // however, note that the withdrawing from the pool still works for 2, the funds are taken // from the pool's non staked balance. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); - assert_eq!(pallet_staking::asset::staked::(&pool_bonded_account), 15); + assert_eq!(delegated_balance_for(pool_bonded_account), 25); + assert_eq!(staked_amount_for(pool_bonded_account), 15); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 16); + assert_eq!(delegated_balance_for(pool_bonded_account), 15); - assert_eq!(pallet_staking::asset::stakeable_balance::(&2), 20); + assert_eq!(Balances::free_balance(2), 20); assert_eq!(TotalValueLocked::::get(), 15); // 3 cannot withdraw yet. @@ -429,15 +429,9 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10)); // final conditions are the expected. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED - assert_eq!( - pallet_staking::asset::stakeable_balance::(&2), - init_stakeable_balance_2 - ); - assert_eq!( - pallet_staking::asset::stakeable_balance::(&3), - init_stakeable_balance_3 - ); + assert_eq!(delegated_balance_for(pool_bonded_account), 5); // 5 init bonded + assert_eq!(Balances::free_balance(2), init_free_balance_2); + assert_eq!(Balances::free_balance(3), init_free_balance_3); assert_eq!(TotalValueLocked::::get(), init_tvl); }); diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index eaab848c1694..bcb25f8287b3 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -21,6 +21,7 @@ use frame_support::{ assert_ok, parameter_types, traits, traits::{Hooks, UnfilteredDispatchable, VariantCountOf}, weights::constants, + PalletId, }; use frame_system::EnsureRoot; use sp_core::{ConstU32, Get}; @@ -36,7 +37,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, + Agent, DelegationInterface, EraIndex, SessionIndex, StakingInterface, }; use std::collections::BTreeMap; @@ -68,6 +69,7 @@ frame_support::construct_runtime!( System: frame_system, ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, + DelegatedStaking: pallet_delegated_staking, Pools: pallet_nomination_pools, Balances: pallet_balances, BagsList: pallet_bags_list, @@ -77,7 +79,7 @@ frame_support::construct_runtime!( } ); -pub(crate) type AccountId = u64; +pub(crate) type AccountId = u128; pub(crate) type AccountIndex = u32; pub(crate) type BlockNumber = u32; pub(crate) type Balance = u64; @@ -87,8 +89,10 @@ pub(crate) type Moment = u32; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { + type AccountId = AccountId; type Block = Block; type AccountData = pallet_balances::AccountData; + type Lookup = sp_runtime::traits::IdentityLookup; } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); @@ -265,7 +269,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = sp_runtime::FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = ConstU32<2>; type PalletId = PoolsPalletId; type MaxMetadataLen = ConstU32<256>; @@ -274,6 +279,21 @@ impl pallet_nomination_pools::Config for Runtime { type AdminOrigin = frame_system::EnsureRoot; } +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); + pub const SlashRewardFraction: Perbill = Perbill::from_percent(1); +} + +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type SlashRewardFraction = SlashRewardFraction; + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + parameter_types! { pub static MaxUnlockingChunks: u32 = 32; } @@ -285,6 +305,7 @@ pub(crate) const SLASHING_DISABLING_FACTOR: usize = 3; #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; @@ -302,7 +323,7 @@ impl pallet_staking::Config for Runtime { type NominationsQuota = pallet_staking::FixedNominationsQuota; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = MaxUnlockingChunks; - type EventListeners = Pools; + type EventListeners = (Pools, DelegatedStaking); type WeightInfo = pallet_staking::weights::SubstrateWeight; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; @@ -502,7 +523,7 @@ impl Default for BalancesExtBuilder { (100, 100), (200, 100), // stashes - (11, 1000), + (11, 1100), (21, 2000), (31, 3000), (41, 4000), @@ -581,7 +602,7 @@ impl ExtBuilder { // set the keys for the first session. keys: stakers .into_iter() - .map(|(id, ..)| (id, id, SessionKeys { other: (id as u64).into() })) + .map(|(id, ..)| (id, id, SessionKeys { other: (id as AccountId as u64).into() })) .collect(), ..Default::default() } @@ -926,7 +947,11 @@ pub(crate) fn set_minimum_election_score( } pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance { - pallet_staking::asset::staked::(&account_id) + Staking::total_stake(&account_id).expect("account must be staker") +} + +pub(crate) fn delegated_balance_for(account_id: AccountId) -> Balance { + DelegatedStaking::agent_balance(Agent::from(account_id)).unwrap_or_default() } pub(crate) fn staking_events() -> Vec> { diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index f174c6b9054b..46db1afc3464 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { workspace = true } scale-info = { features = ["derive"], workspace = true } -frame = { features = ["experimental", "runtime"], workspace = true } +frame = { features = ["runtime"], workspace = true } [features] diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index f044fc610187..cf4f5f49240e 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -105,6 +105,7 @@ impl frame_election_provider_support::ElectionProvider for MockElection { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; @@ -223,8 +224,9 @@ impl ExtBuilder { .clone() .into_iter() .map(|(stash, _, balance)| (stash, balance * 2)) - .chain(validators_range.clone().map(|x| (x, 7 + 100))) - .chain(nominators_range.clone().map(|x| (x, 7 + 100))) + // give stakers enough balance for stake, ed and fast unstake deposit. + .chain(validators_range.clone().map(|x| (x, 7 + 1 + 100))) + .chain(nominators_range.clone().map(|x| (x, 7 + 1 + 100))) .collect::>(), } .assimilate_storage(&mut storage); diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 7c11f381ca10..0fddb88e02b7 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -19,7 +19,15 @@ use super::*; use crate::{mock::*, types::*, Event}; -use frame_support::{pallet_prelude::*, testing_prelude::*, traits::Currency}; +use frame_support::{ + pallet_prelude::*, + testing_prelude::*, + traits::{ + fungible::Inspect, + tokens::{Fortitude::Polite, Preservation::Expendable}, + Currency, + }, +}; use pallet_staking::{CurrentEra, RewardDestination}; use sp_runtime::traits::BadOrigin; @@ -146,7 +154,7 @@ fn deregister_works() { // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); + assert_eq!(::Currency::reserved_balance(&1), pre_reserved); // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); @@ -297,7 +305,7 @@ mod on_idle { ); assert_eq!(Queue::::count(), 3); - assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); + assert_eq!(::Currency::reserved_balance(&1), pre_reserved); assert_eq!( fast_unstake_events_since_last_call(), @@ -793,6 +801,8 @@ mod on_idle { RuntimeOrigin::signed(VALIDATOR_PREFIX), vec![VALIDATOR_PREFIX] )); + + assert_eq!(Balances::reducible_balance(&VALIDATOR_PREFIX, Expendable, Polite), 7); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(VALIDATOR_PREFIX))); // but they indeed are exposed! diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 87369c23948c..0a85d9ffd2b0 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -161,6 +161,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type SessionsPerEra = SessionsPerEra; diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index 0ae3b3938c60..33bf7146980d 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive", "max-encoded-len"], workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { features = ["derive"], workspace = true } diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index 0d175617c9c2..e18e14f2626b 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } scale-info = { features = ["derive"], workspace = true } # third party diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index 7e55ad178091..86a78e6e3615 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index 7ddb78cca3f9..20c5eafbcfc5 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -132,6 +132,10 @@ fn migrate_to_transfer_stake(pool_id: PoolId) { .expect("member should have enough balance to transfer"); }); + // Pool needs to have ED balance free to stake so give it some. + // Note: we didn't require ED until pallet-staking migrated from locks to holds. + let _ = CurrencyOf::::mint_into(&pool_acc, CurrencyOf::::minimum_balance()); + pallet_staking::Pallet::::migrate_to_direct_staker(&pool_acc); } @@ -141,14 +145,6 @@ fn vote_to_balance( vote.try_into().map_err(|_| "could not convert u64 to Balance") } -/// `assertion` should strictly be true if the adapter is using `Delegate` strategy and strictly -/// false if the adapter is not using `Delegate` strategy. -fn assert_if_delegate(assertion: bool) { - let legacy_adapter_used = T::StakeAdapter::strategy_type() != StakeStrategyType::Delegate; - // one and only one of the two should be true. - assert!(assertion ^ legacy_adapter_used); -} - #[allow(unused)] struct ListScenario { /// Stash/Controller that is expected to be moved. @@ -981,9 +977,6 @@ mod benchmarks { #[benchmark] fn apply_slash() { - // Note: With older `TransferStake` strategy, slashing is greedy and apply_slash should - // always fail. - // We want to fill member's unbonding pools. So let's bond with big enough amount. let deposit_amount = Pools::::depositor_min_bond() * T::MaxUnbonding::get().into() * 4u32.into(); @@ -993,7 +986,7 @@ mod benchmarks { // verify user balance in the pool. assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount); // verify delegated balance. - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount), ); @@ -1017,7 +1010,7 @@ mod benchmarks { deposit_amount / 2u32.into() ); // verify delegated balance are not yet slashed. - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount), ); @@ -1041,13 +1034,11 @@ mod benchmarks { #[block] { - assert_if_delegate::( - Pools::::apply_slash( - RuntimeOrigin::Signed(slash_reporter.clone()).into(), - depositor_lookup.clone(), - ) - .is_ok(), - ); + assert!(Pools::::apply_slash( + RuntimeOrigin::Signed(slash_reporter.clone()).into(), + depositor_lookup.clone(), + ) + .is_ok(),); } // verify balances are correct and slash applied. @@ -1055,7 +1046,7 @@ mod benchmarks { PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount / 2u32.into() ); - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount / 2u32.into()), ); @@ -1126,18 +1117,16 @@ mod benchmarks { let _ = migrate_to_transfer_stake::(1); #[block] { - assert_if_delegate::( - Pools::::migrate_pool_to_delegate_stake( - RuntimeOrigin::Signed(depositor.clone()).into(), - 1u32.into(), - ) - .is_ok(), - ); + assert!(Pools::::migrate_pool_to_delegate_stake( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + ) + .is_ok(),); } - // this queries agent balance if `DelegateStake` strategy. + // this queries agent balance. assert_eq!( T::StakeAdapter::total_balance(Pool::from(pool_account.clone())), - Some(deposit_amount) + Some(deposit_amount + CurrencyOf::::minimum_balance()) ); } @@ -1152,13 +1141,11 @@ mod benchmarks { let _ = migrate_to_transfer_stake::(1); // Now migrate pool to delegate stake keeping delegators unmigrated. - assert_if_delegate::( - Pools::::migrate_pool_to_delegate_stake( - RuntimeOrigin::Signed(depositor.clone()).into(), - 1u32.into(), - ) - .is_ok(), - ); + assert!(Pools::::migrate_pool_to_delegate_stake( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + ) + .is_ok(),); // delegation does not exist. assert!( @@ -1171,16 +1158,14 @@ mod benchmarks { #[block] { - assert_if_delegate::( - Pools::::migrate_delegation( - RuntimeOrigin::Signed(depositor.clone()).into(), - depositor_lookup.clone(), - ) - .is_ok(), - ); + assert!(Pools::::migrate_delegation( + RuntimeOrigin::Signed(depositor.clone()).into(), + depositor_lookup.clone(), + ) + .is_ok(),); } // verify balances once more. - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount), ); diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 15d9e2c56031..7c09cf22ad51 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -78,6 +78,7 @@ parameter_types! { } #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index f125919dabfa..f1c68af4ea6a 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::*; +use frame_support::traits::tokens::{Fortitude::Polite, Preservation::Expendable}; use sp_staking::{Agent, DelegationInterface, DelegationMigrator, Delegator}; /// Types of stake strategies. @@ -245,8 +246,10 @@ pub trait StakeStrategy { /// strategy in an existing runtime, storage migration is required. See /// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended /// to use the [`DelegateStake`] strategy. +#[deprecated = "consider migrating to DelegateStake"] pub struct TransferStake(PhantomData<(T, Staking)>); +#[allow(deprecated)] impl, AccountId = T::AccountId>> StakeStrategy for TransferStake { @@ -262,7 +265,8 @@ impl, AccountId = T: pool_account: Pool, _: Member, ) -> BalanceOf { - T::Currency::balance(&pool_account.0).saturating_sub(Self::active_stake(pool_account)) + // free/liquid balance of the pool account. + T::Currency::reducible_balance(&pool_account.get(), Expendable, Polite) } fn total_balance(pool_account: Pool) -> Option> { diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index f544e79ec481..f4552389a267 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -23,8 +23,10 @@ use frame_support::{ PalletId, }; use frame_system::{EnsureSignedBy, RawOrigin}; -use sp_runtime::{BuildStorage, FixedU128}; -use sp_staking::{OnStakingUpdate, Stake}; +use sp_runtime::{BuildStorage, DispatchResult, FixedU128}; +use sp_staking::{ + Agent, DelegationInterface, DelegationMigrator, Delegator, OnStakingUpdate, Stake, +}; pub type BlockNumber = u64; pub type AccountId = u128; @@ -76,6 +78,7 @@ impl StakingMock { let bonded = BondedBalanceMap::get(); let pre_total = bonded.get(&acc).unwrap(); Self::set_bonded_balance(acc, pre_total - amount); + DelegateMock::on_slash(acc, amount); Pools::on_slash(&acc, pre_total - amount, &Default::default(), amount); } } @@ -112,8 +115,8 @@ impl sp_staking::StakingInterface for StakingMock { .ok_or(DispatchError::Other("NotStash")) } - fn is_virtual_staker(_who: &Self::AccountId) -> bool { - false + fn is_virtual_staker(who: &Self::AccountId) -> bool { + AgentBalanceMap::get().contains_key(who) } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { @@ -162,7 +165,9 @@ impl sp_staking::StakingInterface for StakingMock { staker_map.retain(|(unlocking_at, _amount)| *unlocking_at > current_era); // if there was a withdrawal, notify the pallet. - Pools::on_withdraw(&who, unlocking_before.saturating_sub(unlocking(&staker_map))); + let withdraw_amount = unlocking_before.saturating_sub(unlocking(&staker_map)); + Pools::on_withdraw(&who, withdraw_amount); + DelegateMock::on_withdraw(who, withdraw_amount); UnbondingBalanceMap::set(&unbonding_map); Ok(UnbondingBalanceMap::get().get(&who).unwrap().is_empty() && @@ -239,6 +244,176 @@ impl sp_staking::StakingInterface for StakingMock { } } +parameter_types! { + // Map of agent to their (delegated balance, unclaimed withdrawal, pending slash). + pub storage AgentBalanceMap: BTreeMap = Default::default(); + pub storage DelegatorBalanceMap: BTreeMap = Default::default(); +} +pub struct DelegateMock; +impl DelegationInterface for DelegateMock { + type Balance = Balance; + type AccountId = AccountId; + fn agent_balance(agent: Agent) -> Option { + AgentBalanceMap::get() + .get(&agent.get()) + .copied() + .map(|(delegated, _, pending)| delegated - pending) + } + + fn agent_transferable_balance(agent: Agent) -> Option { + AgentBalanceMap::get() + .get(&agent.get()) + .copied() + .map(|(_, unclaimed_withdrawals, _)| unclaimed_withdrawals) + } + + fn delegator_balance(delegator: Delegator) -> Option { + DelegatorBalanceMap::get().get(&delegator.get()).copied() + } + + fn register_agent( + agent: Agent, + _reward_account: &Self::AccountId, + ) -> DispatchResult { + let mut agents = AgentBalanceMap::get(); + agents.insert(agent.get(), (0, 0, 0)); + AgentBalanceMap::set(&agents); + Ok(()) + } + + fn remove_agent(agent: Agent) -> DispatchResult { + let mut agents = AgentBalanceMap::get(); + let agent = agent.get(); + assert!(agents.contains_key(&agent)); + agents.remove(&agent); + AgentBalanceMap::set(&agents); + Ok(()) + } + + fn delegate( + delegator: Delegator, + agent: Agent, + amount: Self::Balance, + ) -> DispatchResult { + let delegator = delegator.get(); + let mut delegators = DelegatorBalanceMap::get(); + delegators.entry(delegator).and_modify(|b| *b += amount).or_insert(amount); + DelegatorBalanceMap::set(&delegators); + + let agent = agent.get(); + let mut agents = AgentBalanceMap::get(); + agents + .get_mut(&agent) + .map(|(d, _, _)| *d += amount) + .ok_or(DispatchError::Other("agent not registered"))?; + AgentBalanceMap::set(&agents); + + if BondedBalanceMap::get().contains_key(&agent) { + StakingMock::bond_extra(&agent, amount) + } else { + // reward account does not matter in this context. + StakingMock::bond(&agent, amount, &999) + } + } + + fn withdraw_delegation( + delegator: Delegator, + agent: Agent, + amount: Self::Balance, + _num_slashing_spans: u32, + ) -> DispatchResult { + let mut delegators = DelegatorBalanceMap::get(); + delegators.get_mut(&delegator.get()).map(|b| *b -= amount); + DelegatorBalanceMap::set(&delegators); + + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent.get()).map(|(d, u, _)| { + *d -= amount; + *u -= amount; + }); + AgentBalanceMap::set(&agents); + + Ok(()) + } + + fn pending_slash(agent: Agent) -> Option { + AgentBalanceMap::get() + .get(&agent.get()) + .copied() + .map(|(_, _, pending_slash)| pending_slash) + } + + fn delegator_slash( + agent: Agent, + delegator: Delegator, + value: Self::Balance, + _maybe_reporter: Option, + ) -> DispatchResult { + let mut delegators = DelegatorBalanceMap::get(); + delegators.get_mut(&delegator.get()).map(|b| *b -= value); + DelegatorBalanceMap::set(&delegators); + + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent.get()).map(|(_, _, p)| { + p.saturating_reduce(value); + }); + AgentBalanceMap::set(&agents); + + Ok(()) + } +} + +impl DelegateMock { + pub fn set_agent_balance(who: AccountId, delegated: Balance) { + let mut agents = AgentBalanceMap::get(); + agents.insert(who, (delegated, 0, 0)); + AgentBalanceMap::set(&agents); + } + + pub fn set_delegator_balance(who: AccountId, amount: Balance) { + let mut delegators = DelegatorBalanceMap::get(); + delegators.insert(who, amount); + DelegatorBalanceMap::set(&delegators); + } + + pub fn on_slash(agent: AccountId, amount: Balance) { + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent).map(|(_, _, p)| *p += amount); + AgentBalanceMap::set(&agents); + } + + fn on_withdraw(agent: AccountId, amount: Balance) { + let mut agents = AgentBalanceMap::get(); + // if agent exists, add the amount to unclaimed withdrawals. + agents.get_mut(&agent).map(|(_, u, _)| *u += amount); + AgentBalanceMap::set(&agents); + } +} + +impl DelegationMigrator for DelegateMock { + type Balance = Balance; + type AccountId = AccountId; + fn migrate_nominator_to_agent( + _agent: Agent, + _reward_account: &Self::AccountId, + ) -> DispatchResult { + unimplemented!("not used in current unit tests") + } + + fn migrate_delegation( + _agent: Agent, + _delegator: Delegator, + _value: Self::Balance, + ) -> DispatchResult { + unimplemented!("not used in current unit tests") + } + + #[cfg(feature = "runtime-benchmarks")] + fn force_kill_agent(_agent: Agent) { + unimplemented!("not used in current unit tests") + } +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Nonce = u64; @@ -295,7 +470,7 @@ impl pools::Config for Runtime { type RewardCounter = RewardCounter; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = adapter::TransferStake; + type StakeAdapter = adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; @@ -522,6 +697,21 @@ pub fn reward_imbalance(pool: PoolId) -> RewardImbalance { } } +pub fn set_pool_balance(who: AccountId, amount: Balance) { + StakingMock::set_bonded_balance(who, amount); + DelegateMock::set_agent_balance(who, amount); +} + +pub fn member_delegation(who: AccountId) -> Balance { + ::StakeAdapter::member_delegation_balance(Member::from(who)) + .expect("who must be a pool member") +} + +pub fn pool_balance(id: PoolId) -> Balance { + ::StakeAdapter::total_balance(Pool::from(Pools::generate_bonded_account(id))) + .expect("who must be a bonded pool account") +} + #[cfg(test)] mod test { use super::*; diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 06261699a5b2..c46638d2f8f7 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -24,6 +24,7 @@ use sp_runtime::{ traits::{BadOrigin, Dispatchable}, FixedU128, }; +use sp_staking::{Agent, DelegationInterface}; macro_rules! unbonding_pools_with_era { ($($k:expr => $v:expr),* $(,)?) => {{ @@ -127,41 +128,41 @@ mod bonded_pool { }; // 1 points : 1 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); assert_eq!(bonded_pool.balance_to_point(10), 10); assert_eq!(bonded_pool.balance_to_point(0), 0); // 2 points : 1 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 50); + set_pool_balance(bonded_pool.bonded_account(), 50); assert_eq!(bonded_pool.balance_to_point(10), 20); // 1 points : 2 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 50; assert_eq!(bonded_pool.balance_to_point(10), 5); // 100 points : 0 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + set_pool_balance(bonded_pool.bonded_account(), 0); bonded_pool.points = 100; assert_eq!(bonded_pool.balance_to_point(10), 100 * 10); // 0 points : 100 balance - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 0; assert_eq!(bonded_pool.balance_to_point(10), 10); // 10 points : 3 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 30); + set_pool_balance(bonded_pool.bonded_account(), 30); bonded_pool.points = 100; assert_eq!(bonded_pool.balance_to_point(10), 33); // 2 points : 3 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 300); + set_pool_balance(bonded_pool.bonded_account(), 300); bonded_pool.points = 200; assert_eq!(bonded_pool.balance_to_point(10), 6); // 4 points : 9 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 900); + set_pool_balance(bonded_pool.bonded_account(), 900); bonded_pool.points = 400; assert_eq!(bonded_pool.balance_to_point(90), 40); }) @@ -182,7 +183,7 @@ mod bonded_pool { }, }; - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); assert_eq!(bonded_pool.points_to_balance(10), 10); assert_eq!(bonded_pool.points_to_balance(0), 0); @@ -191,27 +192,27 @@ mod bonded_pool { assert_eq!(bonded_pool.points_to_balance(10), 20); // 100 balance : 0 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 0; assert_eq!(bonded_pool.points_to_balance(10), 0); // 0 balance : 100 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + set_pool_balance(bonded_pool.bonded_account(), 0); bonded_pool.points = 100; assert_eq!(bonded_pool.points_to_balance(10), 0); // 10 balance : 3 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 30; assert_eq!(bonded_pool.points_to_balance(10), 33); // 2 balance : 3 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 200); + set_pool_balance(bonded_pool.bonded_account(), 200); bonded_pool.points = 300; assert_eq!(bonded_pool.points_to_balance(10), 6); // 4 balance : 9 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 400); + set_pool_balance(bonded_pool.bonded_account(), 400); bonded_pool.points = 900; assert_eq!(bonded_pool.points_to_balance(90), 40); }) @@ -269,30 +270,21 @@ mod bonded_pool { <::MaxPointsToBalance as Get>::get().into(); // Simulate a 100% slashed pool - StakingMock::set_bonded_balance(pool.bonded_account(), 0); + set_pool_balance(pool.bonded_account(), 0); assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); // Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool - StakingMock::set_bonded_balance( - pool.bonded_account(), - max_points_to_balance.saturating_add(1), - ); + set_pool_balance(pool.bonded_account(), max_points_to_balance.saturating_add(1)); assert_ok!(pool.ok_to_join()); // Simulate a slashed pool at `MaxPointsToBalance` - StakingMock::set_bonded_balance(pool.bonded_account(), max_points_to_balance); + set_pool_balance(pool.bonded_account(), max_points_to_balance); assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); - StakingMock::set_bonded_balance( - pool.bonded_account(), - Balance::MAX / max_points_to_balance, - ); + set_pool_balance(pool.bonded_account(), Balance::MAX / max_points_to_balance); // and a sanity check - StakingMock::set_bonded_balance( - pool.bonded_account(), - Balance::MAX / max_points_to_balance - 1, - ); + set_pool_balance(pool.bonded_account(), Balance::MAX / max_points_to_balance - 1); assert_ok!(pool.ok_to_join()); }); } @@ -310,7 +302,7 @@ mod bonded_pool { state: PoolState::Open, }, }; - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), u128::MAX); + set_pool_balance(bonded_pool.bonded_account(), u128::MAX); // Max out the points and balance of the pool and make sure the conversion works as // expected and does not overflow. @@ -640,8 +632,6 @@ mod sub_pools { } mod join { - use sp_runtime::TokenError; - use super::*; #[test] @@ -728,7 +718,7 @@ mod join { ); // Force the pools bonded balance to 0, simulating a 100% slash - StakingMock::set_bonded_balance(Pools::generate_bonded_account(1), 0); + set_pool_balance(Pools::generate_bonded_account(1), 0); assert_noop!( Pools::join(RuntimeOrigin::signed(11), 420, 1), Error::::OverflowRisk @@ -754,29 +744,13 @@ mod join { let max_points_to_balance: u128 = <::MaxPointsToBalance as Get>::get().into(); - StakingMock::set_bonded_balance( - Pools::generate_bonded_account(123), - max_points_to_balance, - ); + set_pool_balance(Pools::generate_bonded_account(123), max_points_to_balance); assert_noop!( Pools::join(RuntimeOrigin::signed(11), 420, 123), Error::::OverflowRisk ); - StakingMock::set_bonded_balance( - Pools::generate_bonded_account(123), - Balance::MAX / max_points_to_balance, - ); - // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` - assert_noop!( - Pools::join(RuntimeOrigin::signed(11), 5, 123), - TokenError::FundsUnavailable, - ); - - StakingMock::set_bonded_balance( - Pools::generate_bonded_account(1), - max_points_to_balance, - ); + set_pool_balance(Pools::generate_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open unsafe_set_state(123, PoolState::Blocked); @@ -807,7 +781,7 @@ mod join { #[cfg_attr(not(debug_assertions), should_panic)] fn join_panics_when_reward_pool_not_found() { ExtBuilder::default().build_and_execute(|| { - StakingMock::set_bonded_balance(Pools::generate_bonded_account(123), 100); + set_pool_balance(Pools::generate_bonded_account(123), 100); BondedPool:: { id: 123, inner: BondedPoolInner { @@ -2321,8 +2295,8 @@ mod claim_payout { fn rewards_are_rounded_down_depositor_collects_them() { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { // initial balance of 10. - - assert_eq!(Currency::free_balance(&10), 35); + let init_balance_10 = Currency::free_balance(&10); + assert_eq!(member_delegation(10), 10); assert_eq!( Currency::free_balance(&default_reward_account()), Currency::minimum_balance() @@ -2373,8 +2347,10 @@ mod claim_payout { ); assert!(!Metadata::::contains_key(1)); - // original ed + ed put into reward account + reward + bond + dust. - assert_eq!(Currency::free_balance(&10), 35 + 5 + 13 + 10 + 1); + // original ed + ed put into reward account + reward + dust. + assert_eq!(Currency::free_balance(&10), init_balance_10 + 5 + 13 + 1); + // delegation reduced from 10 to 0. + assert_eq!(member_delegation(10), 0); }) } @@ -2444,9 +2420,10 @@ mod claim_payout { let claimable_reward = 8 - ExistentialDeposit::get(); // NOTE: easier to read if we use 3, so let's use the number instead of variable. assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3"); + let init_balance = Currency::free_balance(&10); // given - assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(member_delegation(10), 10); // when @@ -2455,7 +2432,10 @@ mod claim_payout { assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10)); // then - assert_eq!(Currency::free_balance(&10), 36); + // delegated balance does not change. + assert_eq!(member_delegation(10), 10); + // reward of 1 is paid out to 10. + assert_eq!(Currency::free_balance(&10), init_balance + 1); assert_eq!(Currency::free_balance(&default_reward_account()), 7); }) } @@ -2818,6 +2798,8 @@ mod unbond { ExtBuilder::default() .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { + let init_balance_40 = Currency::free_balance(&40); + let init_balance_550 = Currency::free_balance(&550); let ed = Currency::minimum_balance(); // Given a slash from 600 -> 500 StakingMock::slash_by(1, 500); @@ -2864,7 +2846,9 @@ mod unbond { PoolMembers::::get(40).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6) ); - assert_eq!(Currency::free_balance(&40), 40 + 40); // We claim rewards when unbonding + assert_eq!(member_delegation(40), 40); + // We claim rewards when unbonding + assert_eq!(Currency::free_balance(&40), init_balance_40 + 40); // When unsafe_set_state(1, PoolState::Destroying); @@ -2893,7 +2877,8 @@ mod unbond { PoolMembers::::get(550).unwrap().unbonding_eras, member_unbonding_eras!(3 => 92) ); - assert_eq!(Currency::free_balance(&550), 550 + 550); + assert_eq!(member_delegation(550), 550); + assert_eq!(Currency::free_balance(&550), init_balance_550 + 550); assert_eq!( pool_events_since_last_call(), vec![ @@ -2934,7 +2919,8 @@ mod unbond { ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); - assert_eq!(Currency::free_balance(&550), 550 + 550 + 92); + // 550 is removed from pool. + assert_eq!(member_delegation(550), 0); assert_eq!( pool_events_since_last_call(), vec![ @@ -3532,7 +3518,7 @@ mod pool_withdraw_unbonded { assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); // When CurrentEra::set(StakingMock::current_era() + StakingMock::bonding_duration() + 1); @@ -3541,7 +3527,7 @@ mod pool_withdraw_unbonded { // Then their unbonding balance is no longer locked assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); }); } #[test] @@ -3552,7 +3538,7 @@ mod pool_withdraw_unbonded { assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); assert_eq!(TotalValueLocked::::get(), 20); // When @@ -3568,14 +3554,14 @@ mod pool_withdraw_unbonded { // Then their unbonding balance is no longer locked assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15)); - assert_eq!(Currency::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); // The difference between TVL and member_balance is exactly the difference between - // `total_stake` and the `free_balance`. - // This relation is not guaranteed in the wild as arbitrary transfers towards - // `free_balance` can be made to the pool that are not accounted for. - let non_locked_balance = Balances::free_balance(&default_bonded_account()) - - StakingMock::total_stake(&default_bonded_account()).unwrap(); + // `pool balance` (sum of all balance delegated to pool) and the `staked balance`. + // This is the withdrawn funds from the pool stake that has not yet been claimed by the + // respective members. + let non_locked_balance = + pool_balance(1) - StakingMock::total_stake(&default_bonded_account()).unwrap(); assert_eq!(member_balance, TotalValueLocked::::get() + non_locked_balance); }); } @@ -3597,7 +3583,7 @@ mod withdraw_unbonded { assert_eq!(StakingMock::bonding_duration(), 3); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(550), 550)); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(40), 40)); - assert_eq!(Currency::free_balance(&default_bonded_account()), 600); + assert_eq!(pool_balance(1), 600); let mut current_era = 1; CurrentEra::set(current_era); @@ -3626,10 +3612,7 @@ mod withdraw_unbonded { .1 /= 2; UnbondingBalanceMap::set(&x); - Currency::set_balance( - &default_bonded_account(), - Currency::free_balance(&default_bonded_account()) / 2, // 300 - ); + set_pool_balance(1, pool_balance(1) / 2); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 10); StakingMock::slash_by(1, 5); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 5); @@ -3671,11 +3654,6 @@ mod withdraw_unbonded { Event::PoolSlashed { pool_id: 1, balance: 5 } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Burned { who: default_bonded_account(), amount: 300 }] - ); - // When assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); @@ -3691,10 +3669,9 @@ mod withdraw_unbonded { Event::MemberRemoved { pool_id: 1, member: 550, released_balance: 0 } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 }] - ); + + // member has 40 tokens in delegation, but only 20 can be withdrawan. + assert_eq!(member_delegation(40), 40); // When assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); @@ -3708,18 +3685,18 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ + // out of 40, 20 is withdrawn. Event::Withdrawn { member: 40, pool_id: 1, balance: 20, points: 40 }, - Event::MemberRemoved { pool_id: 1, member: 40, released_balance: 0 } + // member is removed and the dangling delegation of 20 tokens left in their + // account is released. + Event::MemberRemoved { pool_id: 1, member: 40, released_balance: 20 } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 }] - ); // now, finally, the depositor can take out its share. unsafe_set_state(1, PoolState::Destroying); assert_ok!(fully_unbond_permissioned(10)); + assert_eq!(member_delegation(10), 10); current_era += 3; CurrentEra::set(current_era); @@ -3731,7 +3708,9 @@ mod withdraw_unbonded { vec![ Event::Unbonded { member: 10, pool_id: 1, balance: 5, points: 5, era: 9 }, Event::Withdrawn { member: 10, pool_id: 1, balance: 5, points: 5 }, - Event::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, + // when member is removed, any leftover delegation is released. + Event::MemberRemoved { pool_id: 1, member: 10, released_balance: 5 }, + // when the last member leaves, the pool is destroyed. Event::Destroyed { pool_id: 1 } ] ); @@ -3739,7 +3718,6 @@ mod withdraw_unbonded { assert_eq!( balances_events_since_last_call(), vec![ - BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, BEvent::Thawed { who: default_reward_account(), amount: 5 }, BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } ] @@ -3753,11 +3731,9 @@ mod withdraw_unbonded { .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { let _ = balances_events_since_last_call(); - // Given // current bond is 600, we slash it all to 300. StakingMock::slash_by(1, 300); - Currency::set_balance(&default_bonded_account(), 300); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(300)); assert_ok!(fully_unbond_permissioned(40)); @@ -3787,10 +3763,6 @@ mod withdraw_unbonded { } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Burned { who: default_bonded_account(), amount: 300 },] - ); CurrentEra::set(StakingMock::bonding_duration()); @@ -3798,10 +3770,6 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); // Then - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 },] - ); assert_eq!( pool_events_since_last_call(), vec![ @@ -3819,10 +3787,6 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); // Then - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 },] - ); assert_eq!( pool_events_since_last_call(), vec![ @@ -3852,9 +3816,11 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then - assert_eq!(Currency::free_balance(&10), 10 + 35); - assert_eq!(Currency::free_balance(&default_bonded_account()), 0); - + assert_eq!( + DelegateMock::agent_balance(Agent::from(default_bonded_account())), + None + ); + assert_eq!(StakingMock::stake(&default_bonded_account()).unwrap().total, 0); // in this test 10 also gets a fair share of the slash, because the slash was // applied to the bonded account. assert_eq!( @@ -3870,7 +3836,6 @@ mod withdraw_unbonded { assert_eq!( balances_events_since_last_call(), vec![ - BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, BEvent::Thawed { who: default_reward_account(), amount: 5 }, BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } ] @@ -3878,35 +3843,6 @@ mod withdraw_unbonded { }); } - #[test] - fn withdraw_unbonded_handles_faulty_sub_pool_accounting() { - ExtBuilder::default().build_and_execute(|| { - // Given - assert_eq!(Currency::minimum_balance(), 5); - assert_eq!(Currency::free_balance(&10), 35); - assert_eq!(Currency::free_balance(&default_bonded_account()), 10); - unsafe_set_state(1, PoolState::Destroying); - assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); - - // Simulate a slash that is not accounted for in the sub pools. - Currency::set_balance(&default_bonded_account(), 5); - assert_eq!( - SubPoolsStorage::::get(1).unwrap().with_era, - //------------------------------balance decrease is not account for - unbonding_pools_with_era! { 3 => UnbondPool { points: 10, balance: 10 } } - ); - - CurrentEra::set(3); - - // When - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); - - // Then - assert_eq!(Currency::free_balance(&10), 10 + 35); - assert_eq!(Currency::free_balance(&default_bonded_account()), 0); - }); - } - #[test] fn withdraw_unbonded_errors_correctly() { ExtBuilder::default().with_check(0).build_and_execute(|| { @@ -3925,6 +3861,10 @@ mod withdraw_unbonded { let mut member = PoolMember { pool_id: 1, points: 10, ..Default::default() }; PoolMembers::::insert(11, member.clone()); + // set agent and delegator balance + DelegateMock::set_agent_balance(Pools::generate_bonded_account(1), 10); + DelegateMock::set_delegator_balance(11, 10); + // Simulate calling `unbond` member.unbonding_eras = member_unbonding_eras!(3 => 10); PoolMembers::::insert(11, member.clone()); @@ -4045,7 +3985,7 @@ mod withdraw_unbonded { } ); CurrentEra::set(StakingMock::bonding_duration()); - assert_eq!(Currency::free_balance(&100), 100); + assert_eq!(member_delegation(100), 100); // Cannot permissionlessly withdraw assert_noop!( @@ -4061,6 +4001,7 @@ mod withdraw_unbonded { assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); assert_eq!(Currency::free_balance(&100), 100 + 100); + assert_eq!(member_delegation(100), 0); assert!(!PoolMembers::::contains_key(100)); assert_eq!( pool_events_since_last_call(), @@ -4662,10 +4603,6 @@ mod withdraw_unbonded { // move to era when unbonded funds can be withdrawn. CurrentEra::set(4); - - // increment consumer by 1 reproducing the erroneous consumer bug. - // refer https://github.com/paritytech/polkadot-sdk/issues/4440. - assert_ok!(frame_system::Pallet::::inc_consumers(&pool_one)); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( @@ -4712,7 +4649,7 @@ mod create { )); assert_eq!(TotalValueLocked::::get(), 10 + StakingMock::minimum_nominator_bond()); - assert_eq!(Currency::free_balance(&11), 0); + assert_eq!(member_delegation(11), StakingMock::minimum_nominator_bond()); assert_eq!( PoolMembers::::get(11).unwrap(), PoolMember { @@ -4851,7 +4788,7 @@ mod create { 789 )); - assert_eq!(Currency::free_balance(&11), 0); + assert_eq!(member_delegation(11), StakingMock::minimum_nominator_bond()); // delete the initial pool created, then pool_Id `1` will be free assert_noop!( @@ -5014,16 +4951,9 @@ mod set_state { // surpassed. Making this pool destroyable by anyone. StakingMock::slash_by(1, 10); - // in mock we are using transfer stake which implies slash is greedy. Extrinsic to - // apply pending slash should fail. - assert_noop!( - Pools::apply_slash(RuntimeOrigin::signed(11), 10), - Error::::NotSupported - ); - - // pending slash api should return zero as well. - assert_eq!(Pools::api_pool_pending_slash(1), 0); - assert_eq!(Pools::api_member_pending_slash(10), 0); + // pending slash is correct. + assert_eq!(Pools::api_pool_pending_slash(1), 10); + assert_eq!(Pools::api_member_pending_slash(10), 10); // When assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); @@ -5175,13 +5105,13 @@ mod bond_extra { // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Currency::free_balance(&10), 100); + assert_eq!(member_delegation(10), 10); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // then - assert_eq!(Currency::free_balance(&10), 90); + assert_eq!(member_delegation(10), 10 + 10); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 20); @@ -5198,7 +5128,7 @@ mod bond_extra { assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(20))); // then - assert_eq!(Currency::free_balance(&10), 70); + assert_eq!(member_delegation(10), 20 + 20); assert_eq!(PoolMembers::::get(10).unwrap().points, 40); assert_eq!(BondedPools::::get(1).unwrap().points, 40); @@ -5221,13 +5151,15 @@ mod bond_extra { // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Currency::free_balance(&10), 35); + // 10 has delegated 10 tokens to the pool. + assert_eq!(member_delegation(10), 10); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then - assert_eq!(Currency::free_balance(&10), 35); + // delegator balance is increased by the claimable reward. + assert_eq!(member_delegation(10), 10 + claimable_reward); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + claimable_reward); assert_eq!(BondedPools::::get(1).unwrap().points, 10 + claimable_reward); @@ -5264,8 +5196,8 @@ mod bond_extra { assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Currency::free_balance(&10), 35); - assert_eq!(Currency::free_balance(&20), 20); + assert_eq!(member_delegation(10), 10); + assert_eq!(member_delegation(20), 20); assert_eq!(TotalValueLocked::::get(), 30); // when @@ -5273,7 +5205,7 @@ mod bond_extra { assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(member_delegation(10), 10 + 1); assert_eq!(TotalValueLocked::::get(), 31); // 10's share of the reward is 1/3, since they gave 10/30 of the total shares. @@ -5284,11 +5216,11 @@ mod bond_extra { assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); // then - assert_eq!(Currency::free_balance(&20), 20); assert_eq!(TotalValueLocked::::get(), 33); // 20's share of the rewards is the other 2/3 of the rewards, since they have 20/30 of // the shares + assert_eq!(member_delegation(20), 20 + 2); assert_eq!(PoolMembers::::get(20).unwrap().points, 20 + 2); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 3); @@ -5320,8 +5252,8 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Currency::free_balance(&10), 35); - assert_eq!(Currency::free_balance(&20), 20); + assert_eq!(member_delegation(10), 10); + assert_eq!(member_delegation(20), 20); // Permissioned by default assert_noop!( @@ -5337,7 +5269,7 @@ mod bond_extra { assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(member_delegation(10), 10 + 1); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); @@ -5355,7 +5287,7 @@ mod bond_extra { )); // then - assert_eq!(Currency::free_balance(&20), 12); + assert_eq!(member_delegation(20), 20 + 10); assert_eq!(Currency::free_balance(&default_reward_account()), 5); assert_eq!(PoolMembers::::get(20).unwrap().points, 30); assert_eq!(BondedPools::::get(1).unwrap().points, 41); @@ -7487,63 +7419,3 @@ mod chill { }) } } - -// the test mock is using `TransferStake` and so `DelegateStake` is not tested here. Extrinsics -// meant for `DelegateStake` should be gated. -// -// `DelegateStake` tests are in `pallet-nomination-pools-test-delegate-stake`. Since we support both -// strategies currently, we keep these tests as it is but in future we may remove `TransferStake` -// completely. -mod delegate_stake { - use super::*; - #[test] - fn delegation_specific_calls_are_gated() { - ExtBuilder::default().with_check(0).build_and_execute(|| { - // Given - Currency::set_balance(&11, ExistentialDeposit::get() + 2); - assert!(!PoolMembers::::contains_key(11)); - - // When - assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); - - // Then - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true }, - ] - ); - - assert_eq!( - PoolMembers::::get(11).unwrap(), - PoolMember:: { pool_id: 1, points: 2, ..Default::default() } - ); - - // ensure pool 1 cannot be migrated. - assert!(!Pools::api_pool_needs_delegate_migration(1)); - assert_noop!( - Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1), - Error::::NotSupported - ); - - // members cannot be migrated either. - assert!(!Pools::api_member_needs_delegate_migration(10)); - assert_noop!( - Pools::migrate_delegation(RuntimeOrigin::signed(10), 11), - Error::::NotSupported - ); - - // Given - // The bonded balance is slashed in half - StakingMock::slash_by(1, 6); - - // since slash is greedy with `TransferStake`, `apply_slash` should not work either. - assert_noop!( - Pools::apply_slash(RuntimeOrigin::signed(10), 11), - Error::::NotSupported - ); - }); - } -} diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index cc6335959ab7..54783332aa3e 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -21,7 +21,10 @@ mod mock; use frame_support::{ assert_noop, assert_ok, hypothetically, - traits::{fungible::InspectHold, Currency}, + traits::{ + fungible::{InspectHold, Mutate}, + Currency, + }, }; use mock::*; use pallet_nomination_pools::{ @@ -942,9 +945,13 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { fn pool_migration_e2e() { new_test_ext().execute_with(|| { LegacyAdapter::set(true); - assert_eq!(Balances::minimum_balance(), 5); assert_eq!(CurrentEra::::get(), None); + // hack: mint ED to pool so that the deprecated `TransferStake` works correctly with + // staking. + assert_eq!(Balances::minimum_balance(), 5); + assert_ok!(Balances::mint_into(&POOL1_BONDED, 5)); + // create the pool with TransferStake strategy. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); @@ -1050,10 +1057,11 @@ fn pool_migration_e2e() { assert_eq!( delegated_staking_events_since_last_call(), + // delegated also contains the extra ED that we minted when pool was `TransferStake` . vec![DelegatedStakingEvent::Delegated { agent: POOL1_BONDED, delegator: proxy_delegator_1, - amount: 50 + 10 * 3 + amount: 50 + 10 * 3 + 5 }] ); @@ -1223,6 +1231,11 @@ fn disable_pool_operations_on_non_migrated() { assert_eq!(Balances::minimum_balance(), 5); assert_eq!(CurrentEra::::get(), None); + // hack: mint ED to pool so that the deprecated `TransferStake` works correctly with + // staking. + assert_eq!(Balances::minimum_balance(), 5); + assert_ok!(Balances::mint_into(&POOL1_BONDED, 5)); + // create the pool with TransferStake strategy. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); @@ -1331,11 +1344,12 @@ fn disable_pool_operations_on_non_migrated() { assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1)); assert_eq!( delegated_staking_events_since_last_call(), + // delegated also contains the extra ED that we minted when pool was `TransferStake` . vec![DelegatedStakingEvent::Delegated { agent: POOL1_BONDED, delegator: DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED)) .get(), - amount: 50 + 10 + amount: 50 + 10 + 5 },] ); diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index d1bc4ef8ff28..d943ba6f5333 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -15,6 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Disable warnings for `TransferStake` being deprecated. +#![allow(deprecated)] + use frame_election_provider_support::VoteWeight; use frame_support::{ assert_ok, derive_impl, @@ -92,6 +95,7 @@ parameter_types! { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml deleted file mode 100644 index 0b21d5f4e8cf..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "pallet-nomination-pools-test-transfer-stake" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage.workspace = true -repository.workspace = true -description = "FRAME nomination pools pallet tests with the staking pallet" -publish = false - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dev-dependencies] -codec = { features = ["derive"], workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } - -sp-core = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-staking = { workspace = true, default-features = true } - -frame-election-provider-support = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } - -pallet-bags-list = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } - -log = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs deleted file mode 100644 index cc39cfee91c8..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs +++ /dev/null @@ -1,912 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -#![cfg(test)] - -mod mock; - -use frame_support::{assert_noop, assert_ok, traits::Currency}; -use mock::*; -use pallet_nomination_pools::{ - BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, - PoolMembers, PoolState, -}; -use pallet_staking::{ - CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, -}; -use sp_runtime::{bounded_btree_map, traits::Zero}; - -#[test] -fn pool_lifecycle_e2e() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - // pool goes into destroying - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - - // depositor cannot unbond yet. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - // now the members want to unbond. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(20).unwrap().points, 0); - assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(21).unwrap().points, 0); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 }, - ] - ); - - // depositor cannot still unbond - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - for e in 1..BondingDuration::get() { - CurrentEra::::set(Some(e)); - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), - PoolsError::::CannotWithdrawAny - ); - } - - // members are now unlocked. - CurrentEra::::set(Some(BondingDuration::get())); - - // depositor cannot still unbond - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - // but members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - assert!(PoolMembers::::get(20).is_none()); - assert!(PoolMembers::::get(21).is_none()); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, - PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 }, - ] - ); - - // as soon as all members have left, the depositor can try to unbond, but since the - // min-nominator intention is set, they must chill first. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - pallet_staking::Error::::InsufficientBond - ); - - assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }] - ); - - // waiting another bonding duration: - CurrentEra::::set(Some(BondingDuration::get() * 2)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); - - // pools is fully destroyed now. - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }) -} - -#[test] -fn destroy_pool_with_erroneous_consumer() { - new_test_ext().execute_with(|| { - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // expect consumers on pool account to be 2 (staking lock and an explicit inc by staking). - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 2); - - // increment consumer by 1 reproducing the erroneous consumer bug. - // refer https://github.com/paritytech/polkadot-sdk/issues/4440. - assert_ok!(frame_system::Pallet::::inc_consumers(&POOL1_BONDED)); - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 3); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // pool goes into destroying - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },] - ); - - // move to era 1 - CurrentEra::::set(Some(1)); - - // depositor need to chill before unbonding - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - pallet_staking::Error::::InsufficientBond - ); - - assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 10, - pool_id: 1, - points: 50, - balance: 50, - era: 1 + 3 - }] - ); - - // waiting bonding duration: - CurrentEra::::set(Some(1 + 3)); - // this should work even with an extra consumer count on pool account. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); - - // pools is fully destroyed now. - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }) -} - -#[test] -fn pool_chill_e2e() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - // in case depositor does not have more than `MinNominatorBond` staked, we can end up in - // situation where a member unbonding would cause pool balance to drop below - // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is - // increased after the pool is created. - assert_ok!(Staking::set_staking_configs( - RuntimeOrigin::root(), - pallet_staking::ConfigOp::Set(55), // minimum nominator bond - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - )); - - // members can unbond as long as total stake of the pool is above min nominator bond - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); - assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(20).unwrap().points, 0); - - // this member cannot unbond since it will cause `pool stake < MinNominatorBond` - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(21), 21, 10), - StakingError::::InsufficientBond, - ); - - // members can call `chill` permissionlessly now - assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); - - // now another member can unbond. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(21).unwrap().points, 0); - - // nominator can not resume nomination until depositor have enough stake - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::MinimumBondNotMet, - ); - - // other members joining pool does not affect the depositor's ability to resume nomination - assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); - - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::MinimumBondNotMet, - ); - - // depositor can bond extra stake - assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); - - // `chill` can not be called permissionlessly anymore - assert_noop!( - Pools::chill(RuntimeOrigin::signed(20), 1), - PoolsError::::NotNominator, - ); - - // now nominator can resume nomination - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - // skip to make the unbonding period end. - CurrentEra::::set(Some(BondingDuration::get())); - - // members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra - StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, - ] - ); - }) -} - -#[test] -fn pool_slash_e2e() { - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - assert_eq!( - Payee::::get(POOL1_BONDED), - Some(RewardDestination::Account(POOL1_REWARD)) - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true }, - ] - ); - - // now let's progress a bit. - CurrentEra::::set(Some(1)); - - // 20 / 80 of the total funds are unlocked, and safe from any further slash. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 } - ] - ); - - CurrentEra::::set(Some(2)); - - // note: depositor cannot fully unbond at this point. - // these funds will still get slashed. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 }, - ] - ); - - // At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and - // another 30 are active and vulnerable to slash. Let's slash half of them. - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 30, - &mut Default::default(), - &mut Default::default(), - 2, // slash era 2, affects chunks at era 5 onwards. - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // 30 has been slashed to 15 (15 slash) - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 }, - // 30 has been slashed to 15 (15 slash) - PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } - ] - ); - - CurrentEra::::set(Some(3)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - PoolMembers::::get(21).unwrap(), - PoolMember { - pool_id: 1, - points: 0, - last_recorded_reward_counter: Zero::zero(), - // the 10 points unlocked just now correspond to 5 points in the unbond pool. - unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) - } - ); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] - ); - - // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. - CurrentEra::::set(Some(6)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - // 20 had unbonded 10 safely, and 10 got slashed by half. - PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, - // 21 unbonded all of it after the slash - PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 } - ] - ); - assert_eq!( - staking_events_since_last_call(), - // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] - ); - - // now, finally, we can unbond the depositor further than their current limit. - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } - ] - ); - - CurrentEra::::set(Some(9)); - assert_eq!( - PoolMembers::::get(10).unwrap(), - PoolMember { - pool_id: 1, - points: 0, - last_recorded_reward_counter: Zero::zero(), - unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) - } - ); - // withdraw the depositor, they should lose 12 balance in total due to slash. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }); -} - -#[test] -fn pool_slash_proportional() { - // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that - // happened in era 100 should only affect the latter two. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true }, - PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true }, - ] - ); - - // now let's progress a lot. - CurrentEra::::set(Some(99)); - - // and unbond - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - CurrentEra::::set(Some(100)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 21, - pool_id: 1, - balance: bond, - points: bond, - era: 128 - }] - ); - - CurrentEra::::set(Some(101)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 22, - pool_id: 1, - balance: bond, - points: bond, - era: 129 - }] - ); - - // Apply a slash that happened in era 100. This is typically applied with a delay. - // Of the total 100, 50 is slashed. - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 50, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // This era got slashed 12.5, which rounded up to 13. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 }, - // This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more - // slashed, and 12 is all the remaining slash - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, - // Bonded pool got slashed for 25, remaining 15 in it. - PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } - ] - ); - }); -} - -#[test] -fn pool_slash_non_proportional_only_bonded_pool() { - // A typical example where a pool member unbonds in era 99, and they can get away with a slash - // that happened in era 100, as long as the pool has enough active bond to cover the slash. If - // everything else in the slashing/staking system works, this should always be the case. - // Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk - // if it runs out of chunks that it thinks should be affected by the slash. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] - ); - - // progress and unbond. - CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - // slash for 30. This will be deducted only from the bonded pool. - CurrentEra::::set(Some(100)); - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 30, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] - ); - }); -} - -#[test] -fn pool_slash_non_proportional_bonded_pool_and_chunks() { - // An uncommon example where even though some funds are unlocked such that they should not be - // affected by a slash, we still slash out of them. This should not happen at all. If a - // nomination has unbonded, from the next era onwards, their exposure will drop, so if an era - // happens in that era, then their share of that slash should naturally be less, such that only - // their active ledger stake is enough to compensate it. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] - ); - - // progress and unbond. - CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. - CurrentEra::::set(Some(100)); - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 50, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // out of 20, 10 was taken. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 }, - // out of 40, all was taken. - PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 } - ] - ); - }); -} diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs deleted file mode 100644 index d913c5fe6948..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ /dev/null @@ -1,231 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -use frame_election_provider_support::VoteWeight; -use frame_support::{ - assert_ok, derive_impl, - pallet_prelude::*, - parameter_types, - traits::{ConstU64, ConstU8, VariantCountOf}, - PalletId, -}; -use sp_runtime::{ - traits::{Convert, IdentityLookup}, - BuildStorage, FixedU128, Perbill, -}; - -type AccountId = u128; -type BlockNumber = u64; -type Balance = u128; - -pub(crate) type T = Runtime; - -pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; -pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Runtime { - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<5>; - type WeightInfo = (); -} - -parameter_types! { - pub static ExistentialDeposit: Balance = 5; -} - -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type FreezeIdentifier = RuntimeFreezeReason; - type MaxFreezes = VariantCountOf; - type RuntimeFreezeReason = RuntimeFreezeReason; -} - -pallet_staking_reward_curve::build! { - const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} - -parameter_types! { - pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub static BondingDuration: u32 = 3; -} - -#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] -impl pallet_staking::Config for Runtime { - type Currency = Balances; - type UnixTime = pallet_timestamp::Pallet; - type AdminOrigin = frame_system::EnsureRoot; - type BondingDuration = BondingDuration; - type EraPayout = pallet_staking::ConvertCurve; - type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; - type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = VoterList; - type TargetList = pallet_staking::UseValidatorsMap; - type EventListeners = Pools; - type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; -} - -parameter_types! { - pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; -} - -type VoterBagsListInstance = pallet_bags_list::Instance1; -impl pallet_bags_list::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type BagThresholds = BagThresholds; - type ScoreProvider = Staking; - type Score = VoteWeight; -} - -pub struct BalanceToU256; -impl Convert for BalanceToU256 { - fn convert(n: Balance) -> sp_core::U256 { - n.into() - } -} - -pub struct U256ToBalance; -impl Convert for U256ToBalance { - fn convert(n: sp_core::U256) -> Balance { - n.try_into().unwrap() - } -} - -parameter_types! { - pub const PostUnbondingPoolsWindow: u32 = 10; - pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = Balances; - type RuntimeFreezeReason = RuntimeFreezeReason; - type RewardCounter = FixedU128; - type BalanceToU256 = BalanceToU256; - type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; - type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; - type MaxMetadataLen = ConstU32<256>; - type MaxUnbonding = ConstU32<8>; - type MaxPointsToBalance = ConstU8<10>; - type PalletId = PoolsPalletId; - type AdminOrigin = frame_system::EnsureRoot; -} - -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - Staking: pallet_staking, - VoterList: pallet_bags_list::, - Pools: pallet_nomination_pools, - } -); - -pub fn new_test_ext() -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let _ = pallet_nomination_pools::GenesisConfig:: { - min_join_bond: 2, - min_create_bond: 2, - max_pools: Some(3), - max_members_per_pool: Some(5), - max_members: Some(3 * 5), - global_max_commission: Some(Perbill::from_percent(90)), - } - .assimilate_storage(&mut storage) - .unwrap(); - - let _ = pallet_balances::GenesisConfig:: { - balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], - } - .assimilate_storage(&mut storage) - .unwrap(); - - let mut ext = sp_io::TestExternalities::from(storage); - - ext.execute_with(|| { - // for events to be deposited. - frame_system::Pallet::::set_block_number(1); - - // set some limit for nominations. - assert_ok!(Staking::set_staking_configs( - RuntimeOrigin::root(), - pallet_staking::ConfigOp::Set(10), // minimum nominator bond - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - )); - }); - - ext -} - -parameter_types! { - static ObservedEventsPools: usize = 0; - static ObservedEventsStaking: usize = 0; - static ObservedEventsBalances: usize = 0; -} - -pub(crate) fn pool_events_since_last_call() -> Vec> { - let events = System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) - .collect::>(); - let already_seen = ObservedEventsPools::get(); - ObservedEventsPools::set(events.len()); - events.into_iter().skip(already_seen).collect() -} - -pub(crate) fn staking_events_since_last_call() -> Vec> { - let events = System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) - .collect::>(); - let already_seen = ObservedEventsStaking::get(); - ObservedEventsStaking::set(events.len()); - events.into_iter().skip(already_seen).collect() -} diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 75f3e9931e34..3d3cd470bc24 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -180,16 +180,12 @@ where ::RuntimeEvent: TryInto>, { // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + - // reporter account endowed + some funds rescinded from issuance. - assert_eq!( - System::::read_events_for_pallet::>().len(), - 2 * (offender_count + 1) + 3 - ); + // deposit to reporter + reporter account endowed. + assert_eq!(System::::read_events_for_pallet::>().len(), 2); // (n nominators + one validator) * slashed + Slash Reported assert_eq!( System::::read_events_for_pallet::>().len(), - 1 * (offender_count + 1) + 1 + 1 * (offender_count + 1) as usize + 1 ); // offence assert_eq!(System::::read_events_for_pallet::().len(), 1); diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index c5c178aa4443..3c81f2a664e3 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -125,6 +125,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index a36b2c1cb9c3..3f2565abac88 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["max-encoded-len"], workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } scale-info = { features = ["derive"], workspace = true } [dev-dependencies] diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 7a96b8eade4e..3f14dc00b560 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -126,6 +126,7 @@ parameter_types! { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type UnixTime = Timestamp; @@ -206,10 +207,10 @@ impl ExtBuilder { (30, self.balance_factor * 50), (40, self.balance_factor * 50), // stashes - (11, self.balance_factor * 1000), - (21, self.balance_factor * 1000), - (31, self.balance_factor * 500), - (41, self.balance_factor * 1000), + (11, self.balance_factor * 1500), + (21, self.balance_factor * 1500), + (31, self.balance_factor * 1000), + (41, self.balance_factor * 2000), ], } .assimilate_storage(&mut storage) diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 626993a0547b..84c55b110c8c 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } +frame = { workspace = true, features = ["runtime"] } log = { workspace = true } pallet-ranked-collective = { optional = true, workspace = true } scale-info = { features = ["derive"], workspace = true } diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 346cd04c0fa9..74201da3d2f3 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -133,6 +133,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index e3e58fc01b5f..18c7bd123944 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -106,7 +106,7 @@ //! [dependencies] //! codec = { features = ["max-encoded-len"], workspace = true } //! scale-info = { features = ["derive"], workspace = true } -//! frame = { workspace = true, features = ["experimental", "runtime"] } +//! frame = { workspace = true, features = ["runtime"] } //! //! [features] //! default = ["std"] @@ -150,7 +150,6 @@ //! * `runtime::apis` should expose all common runtime APIs that all FRAME-based runtimes need. #![cfg_attr(not(feature = "std"), no_std)] -#![cfg(feature = "experimental")] #[doc(no_inline)] pub use frame_support::pallet; diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 22176b6d720b..74b1c78e9cbe 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -41,6 +41,7 @@ rand_chacha = { optional = true, workspace = true } [dev-dependencies] frame-benchmarking = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +frame-support = { features = ["experimental"], workspace = true, default-features = true } pallet-bags-list = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-staking-reward-curve = { workspace = true, default-features = true } diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 23368b1f8fca..a1140d317c20 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -18,9 +18,15 @@ //! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking //! asset. -use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency}; - -use crate::{BalanceOf, Config, NegativeImbalanceOf, PositiveImbalanceOf}; +use crate::{BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf}; +use frame_support::traits::{ + fungible::{ + hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, + Balanced, Inspect as FunInspect, + }, + tokens::{Fortitude, Precision, Preservation}, +}; +use sp_runtime::{DispatchResult, Saturating}; /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { @@ -32,7 +38,7 @@ pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } -/// Total balance of `who`. Includes both, free and reserved. +/// Total balance of `who`. Includes both free and staked. pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } @@ -41,42 +47,65 @@ pub fn total_balance(who: &T::AccountId) -> BalanceOf { /// /// This includes balance free to stake along with any balance that is already staked. pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { - T::Currency::free_balance(who) + free_to_stake::(who).saturating_add(staked::(who)) } /// Balance of `who` that is currently at stake. /// -/// The staked amount is locked and cannot be transferred out of `who`s account. +/// The staked amount is on hold and cannot be transferred out of `who`s account. pub fn staked(who: &T::AccountId) -> BalanceOf { - T::Currency::balance_locked(crate::STAKING_ID, who) + T::Currency::balance_on_hold(&HoldReason::Staking.into(), who) +} + +/// Balance of who that can be staked additionally. +/// +/// Does not include the current stake. +pub fn free_to_stake(who: &T::AccountId) -> BalanceOf { + // since we want to be able to use frozen funds for staking, we force the reduction. + T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Force) } /// Set balance that can be staked for `who`. /// -/// This includes any balance that is already staked. +/// If `Value` is lower than the current staked balance, the difference is unlocked. +/// +/// Should only be used with test. #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { - T::Currency::make_free_balance_be(who, value); + use frame_support::traits::fungible::Mutate; + + // minimum free balance (non-staked) required to keep the account alive. + let ed = existential_deposit::(); + // currently on stake + let staked_balance = staked::(who); + + // if new value is greater than staked balance, mint some free balance. + if value > staked_balance { + let _ = T::Currency::set_balance(who, value - staked_balance + ed); + } else { + // else reduce the staked balance. + update_stake::(who, value).expect("can remove from what is staked"); + // burn all free, only leaving ED. + let _ = T::Currency::set_balance(who, ed); + } + + // ensure new stakeable balance same as desired `value`. + assert_eq!(stakeable_balance::(who), value); } /// Update `amount` at stake for `who`. /// /// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the /// difference is unlocked. -pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { - T::Currency::set_lock( - crate::STAKING_ID, - who, - amount, - frame_support::traits::WithdrawReasons::all(), - ); +pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> DispatchResult { + T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount) } -/// Kill the stake of `who`. +/// Release all staked amount to `who`. /// -/// All locked amount is unlocked. -pub fn kill_stake(who: &T::AccountId) { - T::Currency::remove_lock(crate::STAKING_ID, who); +/// Fails if there are consumers left on `who` that restricts it from being reaped. +pub fn kill_stake(who: &T::AccountId) -> DispatchResult { + T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ()) } /// Slash the value from `who`. @@ -86,29 +115,32 @@ pub fn slash( who: &T::AccountId, value: BalanceOf, ) -> (NegativeImbalanceOf, BalanceOf) { - T::Currency::slash(who, value) + T::Currency::slash(&HoldReason::Staking.into(), who, value) } /// Mint `value` into an existing account `who`. /// /// This does not increase the total issuance. -pub fn mint_existing( +pub fn mint_into_existing( who: &T::AccountId, value: BalanceOf, ) -> Option> { - T::Currency::deposit_into_existing(who, value).ok() + // since the account already exists, we mint exact value even if value is below ED. + T::Currency::deposit(who, value, Precision::Exact).ok() } -/// Mint reward and create account for `who` if it does not exist. +/// Mint `value` and create account for `who` if it does not exist. /// -/// This does not increase the total issuance. +/// If value is below existential deposit, the account is not created. +/// +/// Note: This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { - T::Currency::deposit_creating(who, value) + T::Currency::deposit(who, value, Precision::BestEffort).unwrap_or_default() } /// Deposit newly issued or slashed `value` into `who`. pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf) { - T::Currency::resolve_creating(who, value) + let _ = T::Currency::resolve(who, value); } /// Issue `value` increasing total issuance. @@ -121,5 +153,5 @@ pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { /// Burn the amount from the total issuance. #[cfg(feature = "runtime-benchmarks")] pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { - T::Currency::burn(amount) + T::Currency::rescind(amount) } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 79d8dd3fbc30..59d272168d68 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -257,7 +257,11 @@ mod benchmarks { .map(|l| l.active) .ok_or("ledger not created after")?; - let _ = asset::mint_existing::(&stash, max_additional).unwrap(); + let _ = asset::mint_into_existing::( + &stash, + max_additional + asset::existential_deposit::(), + ) + .unwrap(); whitelist_account!(stash); @@ -1133,6 +1137,23 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn migrate_currency() -> Result<(), BenchmarkError> { + let (stash, _ctrl) = + create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + let stake = asset::staked::(&stash); + migrate_to_old_currency::(stash.clone()); + // no holds + assert!(asset::staked::(&stash).is_zero()); + whitelist_account!(stash); + + #[extrinsic_call] + _(RawOrigin::Signed(stash.clone()), stash.clone()); + + assert_eq!(asset::staked::(&stash), stake); + Ok(()) + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index ac3be04cf607..1d66ebd27e9f 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -32,6 +32,7 @@ //! state consistency. use frame_support::{defensive, ensure, traits::Defensive}; +use sp_runtime::DispatchResult; use sp_staking::{StakingAccount, StakingInterface}; use crate::{ @@ -187,7 +188,8 @@ impl StakingLedger { // We skip locking virtual stakers. if !Pallet::::is_virtual_staker(&self.stash) { // for direct stakers, update lock on stash based on ledger. - asset::update_stake::(&self.stash, self.total); + asset::update_stake::(&self.stash, self.total) + .map_err(|_| Error::::NotEnoughFunds)?; } Ledger::::insert( @@ -250,7 +252,7 @@ impl StakingLedger { /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. - pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { + pub(crate) fn kill(stash: &T::AccountId) -> DispatchResult { let controller = >::get(stash).ok_or(Error::::NotStash)?; >::get(&controller).ok_or(Error::::NotController).map(|ledger| { @@ -259,9 +261,9 @@ impl StakingLedger { >::remove(&stash); // kill virtual staker if it exists. - if >::take(&stash).is_none() { + if >::take(&ledger.stash).is_none() { // if not virtual staker, clear locks. - asset::kill_stake::(&ledger.stash); + asset::kill_stake::(&ledger.stash)?; } Ok(()) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 6361663b2b1c..42230cb27b75 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -312,7 +312,8 @@ use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ defensive, defensive_assert, traits::{ - ConstU32, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, + tokens::fungible::{Credit, Debt}, + ConstU32, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, }, weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -361,12 +362,9 @@ pub type RewardPoint = u32; /// The balance type of this pallet. pub type BalanceOf = ::CurrencyBalance; -type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::PositiveImbalance; -pub type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; +type PositiveImbalanceOf = Debt<::AccountId, ::Currency>; +pub type NegativeImbalanceOf = + Credit<::AccountId, ::Currency>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 769b84826b41..6346949576fa 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,8 +25,7 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ - ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Imbalance, LockableCurrency, - OnUnbalanced, OneSessionHandler, WithdrawReasons, + ConstU64, EitherOfDiverse, FindAuthor, Get, Imbalance, OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, }; @@ -264,6 +263,7 @@ pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3; #[derive_impl(crate::config_preludes::TestDefaultConfig)] impl crate::pallet::pallet::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = Timestamp; type RewardRemainder = RewardRemainderMock; @@ -432,6 +432,7 @@ impl ExtBuilder { fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let ed = ExistentialDeposit::get(); let _ = pallet_balances::GenesisConfig:: { balances: vec![ @@ -446,19 +447,23 @@ impl ExtBuilder { (40, self.balance_factor), (50, self.balance_factor), // stashes - (11, self.balance_factor * 1000), - (21, self.balance_factor * 2000), - (31, self.balance_factor * 2000), - (41, self.balance_factor * 2000), - (51, self.balance_factor * 2000), - (201, self.balance_factor * 2000), - (202, self.balance_factor * 2000), + // Note: Previously this pallet used locks and stakers could stake all their + // balance including ED. Now with holds, stakers are required to maintain + // (non-staked) ED in their accounts. Therefore, we drop an additional existential + // deposit to genesis stakers. + (11, self.balance_factor * 1000 + ed), + (21, self.balance_factor * 2000 + ed), + (31, self.balance_factor * 2000 + ed), + (41, self.balance_factor * 2000 + ed), + (51, self.balance_factor * 2000 + ed), + (201, self.balance_factor * 2000 + ed), + (202, self.balance_factor * 2000 + ed), // optional nominator - (100, self.balance_factor * 2000), - (101, self.balance_factor * 2000), + (100, self.balance_factor * 2000 + ed), + (101, self.balance_factor * 2000 + ed), // aux accounts (60, self.balance_factor), - (61, self.balance_factor * 2000), + (61, self.balance_factor * 2000 + ed), (70, self.balance_factor), (71, self.balance_factor * 2000), (80, self.balance_factor), @@ -575,7 +580,7 @@ pub(crate) fn current_era() -> EraIndex { } pub(crate) fn bond(who: AccountId, val: Balance) { - let _ = Balances::make_free_balance_be(&who, val); + let _ = asset::set_stakeable_balance::(&who, val); assert_ok!(Staking::bond(RuntimeOrigin::signed(who), val, RewardDestination::Stash)); } @@ -600,10 +605,6 @@ pub(crate) fn bond_virtual_nominator( val: Balance, target: Vec, ) { - // In a real scenario, `who` is a keyless account managed by another pallet which provides for - // it. - System::inc_providers(&who); - // Bond who virtually. assert_ok!(::virtual_bond(&who, val, &payee)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(who), target)); @@ -809,7 +810,7 @@ pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) { let mut ledger = Ledger::::get(&controller).expect("ledger must exist to bond_extra"); let new_total = ledger.total + amount; - Balances::set_lock(crate::STAKING_ID, stash, new_total, WithdrawReasons::all()); + let _ = asset::update_stake::(stash, new_total); ledger.total = new_total; ledger.active = new_total; Ledger::::insert(controller, ledger); @@ -818,10 +819,10 @@ pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) { pub(crate) fn setup_double_bonded_ledgers() { let init_ledgers = Ledger::::iter().count(); - let _ = Balances::make_free_balance_be(&333, 2000); - let _ = Balances::make_free_balance_be(&444, 2000); - let _ = Balances::make_free_balance_be(&555, 2000); - let _ = Balances::make_free_balance_be(&777, 2000); + let _ = asset::set_stakeable_balance::(&333, 2000); + let _ = asset::set_stakeable_balance::(&444, 2000); + let _ = asset::set_stakeable_balance::(&555, 2000); + let _ = asset::set_stakeable_balance::(&777, 2000); assert_ok!(Staking::bond(RuntimeOrigin::signed(333), 10, RewardDestination::Staked)); assert_ok!(Staking::bond(RuntimeOrigin::signed(444), 20, RewardDestination::Staked)); @@ -923,5 +924,5 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { } pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { - (Balances::free_balance(who), Balances::reserved_balance(who)) + (asset::stakeable_balance::(who), Balances::reserved_balance(who)) } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 2ae925d03643..8c3ff23315a4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -27,8 +27,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced, - TryCollect, UnixTime, + Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, + InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; @@ -36,10 +36,9 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ traits::{ - Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, - StaticLookup, Zero, + Bounded, CheckedAdd, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero, }, - ArithmeticError, Perbill, Percent, + ArithmeticError, DispatchResult, Perbill, Percent, }; use sp_staking::{ currency_to_vote::CurrencyToVote, @@ -54,6 +53,7 @@ use crate::{ BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, + STAKING_ID, }; use alloc::{boxed::Box, vec, vec::Vec}; @@ -96,10 +96,12 @@ impl Pallet { pub(crate) fn inspect_bond_state( stash: &T::AccountId, ) -> Result> { - let lock = asset::staked::(&stash); + // look at any old unmigrated lock as well. + let hold_or_lock = asset::staked::(&stash) + .max(T::OldCurrency::balance_locked(STAKING_ID, &stash).into()); let controller = >::get(stash).ok_or_else(|| { - if lock == Zero::zero() { + if hold_or_lock == Zero::zero() { Error::::NotStash } else { Error::::BadState @@ -111,7 +113,7 @@ impl Pallet { if ledger.stash != *stash { Ok(LedgerIntegrityState::Corrupted) } else { - if lock != ledger.total { + if hold_or_lock != ledger.total { Ok(LedgerIntegrityState::LockCorrupted) } else { Ok(LedgerIntegrityState::Ok) @@ -163,11 +165,7 @@ impl Pallet { additional } else { // additional amount or actual balance of stash whichever is lower. - additional.min( - asset::stakeable_balance::(stash) - .checked_sub(&ledger.total) - .ok_or(ArithmeticError::Overflow)?, - ) + additional.min(asset::free_to_stake::(stash)) }; ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; @@ -416,12 +414,12 @@ impl Pallet { let dest = Self::payee(StakingAccount::Stash(stash.clone()))?; let maybe_imbalance = match dest { - RewardDestination::Stash => asset::mint_existing::(stash, amount), + RewardDestination::Stash => asset::mint_into_existing::(stash, amount), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { ledger.active += amount; ledger.total += amount; - let r = asset::mint_existing::(stash, amount); + let r = asset::mint_into_existing::(stash, amount); let _ = ledger .update() @@ -799,8 +797,6 @@ impl Pallet { Self::do_remove_validator(&stash); Self::do_remove_nominator(&stash); - frame_system::Pallet::::dec_consumers(&stash); - Ok(()) } @@ -1163,6 +1159,81 @@ impl Pallet { ) -> Exposure> { EraInfo::::get_full_exposure(era, account) } + + pub(super) fn do_migrate_currency(stash: &T::AccountId) -> DispatchResult { + if Self::is_virtual_staker(stash) { + return Self::do_migrate_virtual_staker(stash); + } + + let ledger = Self::ledger(Stash(stash.clone()))?; + let staked: BalanceOf = T::OldCurrency::balance_locked(STAKING_ID, stash).into(); + ensure!(!staked.is_zero(), Error::::AlreadyMigrated); + ensure!(ledger.total == staked, Error::::BadState); + + // remove old staking lock + T::OldCurrency::remove_lock(STAKING_ID, &stash); + + // check if we can hold all stake. + let max_hold = asset::free_to_stake::(&stash); + let force_withdraw = if max_hold >= staked { + // this means we can hold all stake. yay! + asset::update_stake::(&stash, staked)?; + Zero::zero() + } else { + // if we are here, it means we cannot hold all user stake. We will do a force withdraw + // from ledger, but that's okay since anyways user do not have funds for it. + let force_withdraw = staked.saturating_sub(max_hold); + + // we ignore if active is 0. It implies the locked amount is not actively staked. The + // account can still get away from potential slash but we can't do much better here. + StakingLedger { + total: max_hold, + active: ledger.active.saturating_sub(force_withdraw), + // we are not changing the stash, so we can keep the stash. + ..ledger + } + .update()?; + force_withdraw + }; + + // Get rid of the extra consumer we used to have with OldCurrency. + frame_system::Pallet::::dec_consumers(&stash); + + Self::deposit_event(Event::::CurrencyMigrated { stash: stash.clone(), force_withdraw }); + Ok(()) + } + + fn do_migrate_virtual_staker(stash: &T::AccountId) -> DispatchResult { + // Funds for virtual stakers not managed/held by this pallet. We only need to clear + // the extra consumer we used to have with OldCurrency. + frame_system::Pallet::::dec_consumers(&stash); + + // The delegation system that manages the virtual staker needed to increment provider + // previously because of the consumer needed by this pallet. In reality, this stash + // is just a key for managing the ledger and the account does not need to hold any + // balance or exist. We decrement this provider. + let actual_providers = frame_system::Pallet::::providers(stash); + + let expected_providers = + // provider is expected to be 1 but someone can always transfer some free funds to + // these accounts, increasing the provider. + if asset::free_to_stake::(&stash) >= asset::existential_deposit::() { + 2 + } else { + 1 + }; + + // We should never have more than expected providers. + ensure!(actual_providers <= expected_providers, Error::::BadState); + + // if actual provider is less than expected, it is already migrated. + ensure!(actual_providers == expected_providers, Error::::AlreadyMigrated); + + // dec provider + let _ = frame_system::Pallet::::dec_providers(&stash)?; + + return Ok(()) + } } impl Pallet { @@ -1925,9 +1996,10 @@ impl StakingInterface for Pallet { } impl sp_staking::StakingUnchecked for Pallet { - fn migrate_to_virtual_staker(who: &Self::AccountId) { - asset::kill_stake::(who); + fn migrate_to_virtual_staker(who: &Self::AccountId) -> DispatchResult { + asset::kill_stake::(who)?; VirtualStakers::::insert(who, ()); + Ok(()) } /// Virtually bonds `keyless_who` to `payee` with `value`. @@ -1945,9 +2017,6 @@ impl sp_staking::StakingUnchecked for Pallet { // check if payee not same as who. ensure!(keyless_who != payee, Error::::RewardDestinationRestricted); - // mark this pallet as consumer of `who`. - frame_system::Pallet::::inc_consumers(&keyless_who).map_err(|_| Error::::BadState)?; - // mark who as a virtual staker. VirtualStakers::::insert(keyless_who, ()); @@ -1959,11 +2028,13 @@ impl sp_staking::StakingUnchecked for Pallet { Ok(()) } + /// Only meant to be used in tests. #[cfg(feature = "runtime-benchmarks")] fn migrate_to_direct_staker(who: &Self::AccountId) { assert!(VirtualStakers::::contains_key(who)); let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); - asset::update_stake::(who, ledger.total); + let _ = asset::update_stake::(who, ledger.total) + .expect("funds must be transferred to stash"); VirtualStakers::::remove(who); } } @@ -2100,7 +2171,7 @@ impl Pallet { if VirtualStakers::::contains_key(stash.clone()) { ensure!( asset::staked::(&stash) == Zero::zero(), - "virtual stakers should not have any locked balance" + "virtual stakers should not have any staked balance" ); ensure!( >::get(stash.clone()).unwrap() == stash.clone(), @@ -2128,7 +2199,7 @@ impl Pallet { } else { ensure!( Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), - "bond, ledger and/or staking lock inconsistent for a bonded stash." + "bond, ledger and/or staking hold inconsistent for a bonded stash." ); } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index b3f8c18f704c..7d5da9ea0c49 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,8 +25,12 @@ use frame_election_provider_support::{ use frame_support::{ pallet_prelude::*, traits::{ + fungible::{ + hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate}, + Mutate as FunMutate, + }, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, + InspectLockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, @@ -89,13 +93,27 @@ pub mod pallet { #[pallet::config(with_default)] pub trait Config: frame_system::Config { + /// The old trait for staking balance. Deprecated and only used for migrating old ledgers. + #[pallet::no_default] + type OldCurrency: InspectLockableCurrency< + Self::AccountId, + Moment = BlockNumberFor, + Balance = Self::CurrencyBalance, + >; + /// The staking balance. #[pallet::no_default] - type Currency: LockableCurrency< + type Currency: FunHoldMutate< Self::AccountId, - Moment = BlockNumberFor, + Reason = Self::RuntimeHoldReason, Balance = Self::CurrencyBalance, - > + InspectLockableCurrency; + > + FunMutate + + FunHoldBalanced; + + /// Overarching hold reason. + #[pallet::no_default_bounds] + type RuntimeHoldReason: From; + /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned @@ -106,6 +124,8 @@ pub mod pallet { + Default + From + TypeInfo + + Send + + Sync + MaxEncodedLen; /// Time used for computing era duration. /// @@ -309,6 +329,14 @@ pub mod pallet { type WeightInfo: WeightInfo; } + /// A reason for placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Funds on stake by a nominator or a validator. + #[codec(index = 0)] + Staking, + } + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::*; @@ -327,6 +355,8 @@ pub mod pallet { impl DefaultConfig for TestDefaultConfig { #[inject_runtime_type] type RuntimeEvent = (); + #[inject_runtime_type] + type RuntimeHoldReason = (); type CurrencyBalance = u128; type CurrencyToVote = (); type NominationsQuota = crate::FixedNominationsQuota<16>; @@ -765,7 +795,7 @@ pub mod pallet { status ); assert!( - asset::stakeable_balance::(stash) >= balance, + asset::free_to_stake::(stash) >= balance, "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( @@ -858,6 +888,9 @@ pub mod pallet { ValidatorDisabled { stash: T::AccountId }, /// Validator has been re-enabled. ValidatorReenabled { stash: T::AccountId }, + /// Staking balance migrated from locks to holds, with any balance that could not be held + /// is force withdrawn. + CurrencyMigrated { stash: T::AccountId, force_withdraw: BalanceOf }, } #[pallet::error] @@ -929,6 +962,10 @@ pub mod pallet { NotEnoughFunds, /// Operation not allowed for virtual stakers. VirtualStakerNotAllowed, + /// Stash could not be reaped as other pallet might depend on it. + CannotReapStash, + /// The stake of this account is already migrated to `Fungible` holds. + AlreadyMigrated, } #[pallet::hooks] @@ -1172,10 +1209,7 @@ pub mod pallet { return Err(Error::::InsufficientBond.into()) } - // Would fail if account has no provider. - frame_system::Pallet::::inc_consumers(&stash)?; - - let stash_balance = asset::stakeable_balance::(&stash); + let stash_balance = asset::free_to_stake::(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let ledger = StakingLedger::::new(stash.clone(), value); @@ -2231,8 +2265,8 @@ pub mod pallet { let new_total = if let Some(total) = maybe_total { let new_total = total.min(stash_balance); - // enforce lock == ledger.amount. - asset::update_stake::(&stash, new_total); + // enforce hold == ledger.amount. + asset::update_stake::(&stash, new_total)?; new_total } else { current_lock @@ -2259,13 +2293,13 @@ pub mod pallet { // to enforce a new ledger.total and staking lock for this stash. let new_total = maybe_total.ok_or(Error::::CannotRestoreLedger)?.min(stash_balance); - asset::update_stake::(&stash, new_total); + asset::update_stake::(&stash, new_total)?; Ok((stash.clone(), new_total)) }, Err(Error::::BadState) => { // the stash and ledger do not exist but lock is lingering. - asset::kill_stake::(&stash); + asset::kill_stake::(&stash)?; ensure!( Self::inspect_bond_state(&stash) == Err(Error::::NotStash), Error::::BadState @@ -2291,6 +2325,26 @@ pub mod pallet { ); Ok(()) } + + /// Migrates permissionlessly a stash from locks to holds. + /// + /// This removes the old lock on the stake and creates a hold on it atomically. If all + /// stake cannot be held, the best effort is made to hold as much as possible. The remaining + /// stake is removed from the ledger. + /// + /// The fee is waived if the migration is successful. + #[pallet::call_index(30)] + #[pallet::weight(T::WeightInfo::migrate_currency())] + pub fn migrate_currency( + origin: OriginFor, + stash: T::AccountId, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + Self::do_migrate_currency(&stash)?; + + // Refund the transaction fee if successful. + Ok(Pays::No.into()) + } } } diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index 81337710aa90..dfd5422106c0 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -238,3 +238,21 @@ pub fn create_validators_with_nominators_for_era( pub fn current_era() -> EraIndex { CurrentEra::::get().unwrap_or(0) } + +pub fn migrate_to_old_currency(who: T::AccountId) { + use frame_support::traits::LockableCurrency; + let staked = asset::staked::(&who); + + // apply locks (this also adds a consumer). + T::OldCurrency::set_lock( + STAKING_ID, + &who, + staked, + frame_support::traits::WithdrawReasons::all(), + ); + // remove holds. + asset::kill_stake::(&who).expect("remove hold failed"); + + // replicate old behaviour of explicit increment of consumer. + frame_system::Pallet::::inc_consumers(&who).expect("increment consumer failed"); +} diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6c2335e1aac8..908415143994 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -26,8 +26,12 @@ use frame_election_provider_support::{ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, + hypothetically, pallet_prelude::*, - traits::{Currency, Get, ReservableCurrency}, + traits::{ + fungible::Inspect, Currency, Get, InspectLockableCurrency, LockableCurrency, + ReservableCurrency, WithdrawReasons, + }, }; use mock::*; @@ -108,7 +112,7 @@ fn force_unstake_works() { // Cant transfer assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10), - TokenError::Frozen, + TokenError::FundsUnavailable, ); // Force unstake requires root. assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); @@ -229,8 +233,7 @@ fn basic_setup_works() { assert_eq!(active_era(), 0); // Account 10 has `balance_factor` free balance - assert_eq!(asset::stakeable_balance::(&10), 1); - assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(Balances::balance(&10), 1); // New era is not being forced assert_eq!(ForceEra::::get(), Forcing::NotForcing); @@ -360,8 +363,16 @@ fn rewards_should_work() { remainder: maximum_payout - total_payout_0 } ); + + // make note of total issuance before rewards. + let total_issuance_0 = asset::total_issuance::(); + mock::make_all_reward_payment(0); + // total issuance should have increased + let total_issuance_1 = asset::total_issuance::(); + assert_eq!(total_issuance_1, total_issuance_0 + total_payout_0); + assert_eq_error_rate!( asset::total_balance::(&11), init_balance_11 + part_for_11 * total_payout_0 * 2 / 3, @@ -401,6 +412,7 @@ fn rewards_should_work() { ); mock::make_all_reward_payment(1); + assert_eq!(asset::total_issuance::(), total_issuance_1 + total_payout_1); assert_eq_error_rate!( asset::total_balance::(&11), init_balance_11 + part_for_11 * (total_payout_0 * 2 / 3 + total_payout_1), @@ -490,7 +502,7 @@ fn staking_should_work() { } ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 - assert_noop!(Balances::reserve(&3, 501), BalancesError::::LiquidityRestrictions); + assert_noop!(Balances::reserve(&3, 501), DispatchError::ConsumerRemaining); assert_ok!(Balances::reserve(&3, 409)); }); } @@ -689,7 +701,7 @@ fn nominating_and_rewards_should_work() { ); // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 - assert_eq!(asset::total_balance::(&3), initial_balance); + assert_eq!(asset::stakeable_balance::(&3), initial_balance); // 333 is the reward destination for 3. assert_eq_error_rate!( asset::total_balance::(&333), @@ -992,9 +1004,9 @@ fn cannot_transfer_staked_balance() { ExtBuilder::default().nominate(false).build_and_execute(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); - // Confirm account 11 has some free balance + // Confirm account 11 has some stakeable balance assert_eq!(asset::stakeable_balance::(&11), 1000); - // Confirm account 11 (via controller) is totally staked + // Confirm account 11 is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result assert_noop!( @@ -1021,11 +1033,12 @@ fn cannot_transfer_staked_balance_2() { assert_eq!(asset::stakeable_balance::(&21), 2000); // Confirm account 21 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); - // Confirm account 21 can transfer at most 1000 + // Confirm account 21 cannot transfer more than 1000 assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001), TokenError::Frozen, ); + // Confirm account 21 needs to leave at least ED in free balance to be able to transfer assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1000)); }); } @@ -1036,17 +1049,61 @@ fn cannot_reserve_staked_balance() { ExtBuilder::default().build_and_execute(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); - // Confirm account 11 has some free balance - assert_eq!(asset::stakeable_balance::(&11), 1000); - // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); + // Confirm account 11 is totally staked + assert_eq!(asset::staked::(&11), 1000); + // Confirm account 11 cannot reserve as a result - assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); + assert_noop!(Balances::reserve(&11, 2), BalancesError::::InsufficientBalance); + assert_noop!(Balances::reserve(&11, 1), DispatchError::ConsumerRemaining); // Give account 11 extra free balance - let _ = asset::set_stakeable_balance::(&11, 10000); + let _ = asset::set_stakeable_balance::(&11, 1000 + 1000); + assert_eq!(asset::free_to_stake::(&11), 1000); + // Confirm account 11 can now reserve balance - assert_ok!(Balances::reserve(&11, 1)); + assert_ok!(Balances::reserve(&11, 500)); + + // free to stake balance has reduced + assert_eq!(asset::free_to_stake::(&11), 500); + }); +} + +#[test] +fn locked_balance_can_be_staked() { + // Checks that a bonded account cannot reserve balance from free balance + ExtBuilder::default().build_and_execute(|| { + // Confirm account 11 is stashed + assert_eq!(Staking::bonded(&11), Some(11)); + assert_eq!(asset::staked::(&11), 1000); + assert_eq!(asset::free_to_stake::(&11), 0); + + // add some staking balance to 11 + let _ = asset::set_stakeable_balance::(&11, 1000 + 1000); + // free to stake is 1000 + assert_eq!(asset::free_to_stake::(&11), 1000); + + // lock some balance + Balances::set_lock(*b"somelock", &11, 500, WithdrawReasons::all()); + + // locked balance still available for staking + assert_eq!(asset::free_to_stake::(&11), 1000); + + // can stake free balance + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 500)); + assert_eq!(asset::staked::(&11), 1500); + + // Can stake the locked balance + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 500)); + assert_eq!(asset::staked::(&11), 2000); + // no balance left to stake + assert_eq!(asset::free_to_stake::(&11), 0); + + // this does not fail if someone tries to stake more than free balance but just stakes + // whatever is available. (not sure if that is the best way, but we keep it backward + // compatible) + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 10)); + // no extra balance staked. + assert_eq!(asset::staked::(&11), 2000); }); } @@ -1057,9 +1114,9 @@ fn reward_destination_works() { // Check that account 11 is a validator assert!(Session::validators().contains(&11)); // Check the balance of the validator account - assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(asset::total_balance::(&10), 1); // Check the balance of the stash account - assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::total_balance::(&11), 1001); // Check how much is at stake assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1294,12 +1351,12 @@ fn bond_extra_and_withdraw_unbonded_works() { // Give account 11 some large free balance greater than total let _ = asset::set_stakeable_balance::(&11, 1000000); + // ensure it has the correct balance. + assert_eq!(asset::stakeable_balance::(&11), 1000000); + // Initial config should be correct assert_eq!(active_era(), 0); - // check the balance of a validator accounts. - assert_eq!(asset::total_balance::(&11), 1000000); - // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -2077,7 +2134,7 @@ fn bond_with_no_staked_value() { ); // bonded with absolute minimum value possible. assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 5, RewardDestination::Account(1))); - assert_eq!(pallet_balances::Locks::::get(&1)[0].amount, 5); + assert_eq!(pallet_balances::Holds::::get(&1)[0].amount, 5); // unbonding even 1 will cause all to be unbonded. assert_ok!(Staking::unbond(RuntimeOrigin::signed(1), 1)); @@ -2098,14 +2155,14 @@ fn bond_with_no_staked_value() { // not yet removed. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0)); assert!(Staking::ledger(1.into()).is_ok()); - assert_eq!(pallet_balances::Locks::::get(&1)[0].amount, 5); + assert_eq!(pallet_balances::Holds::::get(&1)[0].amount, 5); mock::start_active_era(3); // poof. Account 1 is removed from the staking system. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0)); assert!(Staking::ledger(1.into()).is_err()); - assert_eq!(pallet_balances::Locks::::get(&1).len(), 0); + assert_eq!(pallet_balances::Holds::::get(&1).len(), 0); }); } @@ -2338,9 +2395,20 @@ fn reward_validator_slashing_validator_does_not_overflow() { EraInfo::::set_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); - assert_eq!(asset::total_balance::(&11), stake * 2); + assert_eq!(asset::stakeable_balance::(&11), stake * 2); - // Set staker + // ensure ledger has `stake` and no more. + Ledger::::insert( + 11, + StakingLedgerInspect { + stash: 11, + total: stake, + active: stake, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![1], + }, + ); + // Set staker (unsafe, can reduce balance below actual stake) let _ = asset::set_stakeable_balance::(&11, stake); let _ = asset::set_stakeable_balance::(&2, stake); @@ -2366,8 +2434,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { &[Perbill::from_percent(100)], ); - assert_eq!(asset::total_balance::(&11), stake - 1); - assert_eq!(asset::total_balance::(&2), 1); + assert_eq!(asset::stakeable_balance::(&11), stake - 1); + assert_eq!(asset::stakeable_balance::(&2), 1); }) } @@ -2627,8 +2695,8 @@ fn reporters_receive_their_slice() { // 50% * (10% * initial_balance / 2) let reward = (initial_balance / 20) / 2; let reward_each = reward / 2; // split into two pieces. - assert_eq!(asset::stakeable_balance::(&1), 10 + reward_each); - assert_eq!(asset::stakeable_balance::(&2), 20 + reward_each); + assert_eq!(asset::total_balance::(&1), 10 + reward_each); + assert_eq!(asset::total_balance::(&2), 20 + reward_each); }); } @@ -2653,7 +2721,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - 0) // 50% * (10% * initial_balance * 20%) let reward = (initial_balance / 5) / 20; - assert_eq!(asset::stakeable_balance::(&1), 10 + reward); + assert_eq!(asset::total_balance::(&1), 10 + reward); on_offence_now( &[OffenceDetails { @@ -2668,7 +2736,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(asset::stakeable_balance::(&1), 10 + prior_payout + reward); + assert_eq!(asset::total_balance::(&1), 10 + prior_payout + reward); }); } @@ -2812,8 +2880,9 @@ fn garbage_collection_after_slashing() { // validator and nominator slash in era are garbage-collected by era change, // so we don't test those here. - assert_eq!(asset::stakeable_balance::(&11), 2); - assert_eq!(asset::total_balance::(&11), 2); + assert_eq!(asset::stakeable_balance::(&11), 0); + // Non staked balance is not touched. + assert_eq!(asset::total_balance::(&11), ExistentialDeposit::get()); let slashing_spans = SlashingSpans::::get(&11).unwrap(); assert_eq!(slashing_spans.iter().count(), 2); @@ -6092,7 +6161,7 @@ fn nomination_quota_max_changes_decoding() { .add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3])) .add_staker(30, 330, 10, StakerStatus::Nominator(vec![1, 2, 3, 4])) .add_staker(50, 550, 10, StakerStatus::Nominator(vec![1, 2, 3, 4])) - .balance_factor(10) + .balance_factor(11) .build_and_execute(|| { // pre-condition. assert_eq!(MaxNominationsOf::::get(), 16); @@ -6208,240 +6277,248 @@ fn force_apply_min_commission_works() { #[test] fn proportional_slash_stop_slashing_if_remaining_zero() { - let c = |era, value| UnlockChunk:: { era, value }; + ExtBuilder::default().nominate(true).build_and_execute(|| { + let c = |era, value| UnlockChunk:: { era, value }; - // we have some chunks, but they are not affected. - let unlocking = bounded_vec![c(1, 10), c(2, 10)]; + // we have some chunks, but they are not affected. + let unlocking = bounded_vec![c(1, 10), c(2, 10)]; - // Given - let mut ledger = StakingLedger::::new(123, 20); - ledger.total = 40; - ledger.unlocking = unlocking; + // Given + let mut ledger = StakingLedger::::new(123, 20); + ledger.total = 40; + ledger.unlocking = unlocking; - assert_eq!(BondingDuration::get(), 3); + assert_eq!(BondingDuration::get(), 3); - // should not slash more than the amount requested, by accidentally slashing the first chunk. - assert_eq!(ledger.slash(18, 1, 0), 18); + // should not slash more than the amount requested, by accidentally slashing the first + // chunk. + assert_eq!(ledger.slash(18, 1, 0), 18); + }); } #[test] fn proportional_ledger_slash_works() { - let c = |era, value| UnlockChunk:: { era, value }; - // Given - let mut ledger = StakingLedger::::new(123, 10); - assert_eq!(BondingDuration::get(), 3); - - // When we slash a ledger with no unlocking chunks - assert_eq!(ledger.slash(5, 1, 0), 5); - // Then - assert_eq!(ledger.total, 5); - assert_eq!(ledger.active, 5); - assert_eq!(LedgerSlashPerEra::get().0, 5); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // When we slash a ledger with no unlocking chunks and the slash amount is greater then the - // total - assert_eq!(ledger.slash(11, 1, 0), 5); - // Then - assert_eq!(ledger.total, 0); - assert_eq!(ledger.active, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // Given - ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; - ledger.total = 2 * 10; - ledger.active = 0; - // When all the chunks overlap with the slash eras - assert_eq!(ledger.slash(20, 0, 0), 20); - // Then - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.total = 4 * 100; - ledger.active = 0; - // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(140, 0, 3), 140); - // Then - assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); - assert_eq!(ledger.total, 4 * 100 - 140); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.total = 4 * 100; - ledger.active = 0; - // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(15, 0, 3), 15); - // Then - assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); - assert_eq!(ledger.total, 4 * 100 - 15); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - // 900 - ledger.total = 40 + 10 + 100 + 250 + 500; - // When we have a partial slash that touches all chunks - assert_eq!(ledger.slash(900 / 2, 0, 0), 450); - // Then - assert_eq!(ledger.active, 500 / 2); - assert_eq!(ledger.unlocking, vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]); - assert_eq!(ledger.total, 900 / 2); - assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) - ); + ExtBuilder::default().nominate(true).build_and_execute(|| { + let c = |era, value| UnlockChunk:: { era, value }; + // Given + let mut ledger = StakingLedger::::new(123, 10); + assert_eq!(BondingDuration::get(), 3); - // slash 1/4th with not chunk. - ledger.unlocking = bounded_vec![]; - ledger.active = 500; - ledger.total = 500; - // When we have a partial slash that touches all chunks - assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); - // Then - assert_eq!(ledger.active, 3 * 500 / 4); - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, ledger.active); - assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // Given we have the same as above, - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - ledger.total = 40 + 10 + 100 + 250 + 500; // 900 - assert_eq!(ledger.total, 900); - // When we have a higher min balance - assert_eq!( - ledger.slash( - 900 / 2, - 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it to - * get swept */ - 0 - ), - 450 - ); - assert_eq!(ledger.active, 500 / 2); - // the last chunk was not slashed 50% like all the rest, because some other earlier chunks got - // dusted. - assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); - assert_eq!(ledger.total, 900 / 2); - assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) - ); + // When we slash a ledger with no unlocking chunks + assert_eq!(ledger.slash(5, 1, 0), 5); + // Then + assert_eq!(ledger.total, 5); + assert_eq!(ledger.active, 5); + assert_eq!(LedgerSlashPerEra::get().0, 5); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // When we slash a ledger with no unlocking chunks and the slash amount is greater then the + // total + assert_eq!(ledger.slash(11, 1, 0), 5); + // Then + assert_eq!(ledger.total, 0); + assert_eq!(ledger.active, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - // Given - // slash order --------------------NA--------2----------0----------1---- - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - ledger.total = 40 + 10 + 100 + 250 + 500; // 900 - assert_eq!( - ledger.slash( - 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 - 0, - 3 /* slash era 6 first, so the affected parts are era 6, era 7 and - * ledge.active. This will cause the affected to go to zero, and then we will - * start slashing older chunks */ - ), - 500 + 250 + 10 + 100 / 2 - ); - // Then - assert_eq!(ledger.active, 0); - assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); - assert_eq!(ledger.total, 90); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); - - // Given - // iteration order------------------NA---------2----------0----------1---- - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.active = 100; - ledger.total = 5 * 100; - // When - assert_eq!( - ledger.slash( - 351, // active + era 6 + era 7 + era 5 / 2 + 1 - 50, // min balance - everything slashed below 50 will get dusted - 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and - * ledge.active. This will cause the affected to go to zero, and then we will - * start slashing older chunks */ - ), - 400 - ); - // Then - assert_eq!(ledger.active, 0); - assert_eq!(ledger.unlocking, vec![c(4, 100)]); - assert_eq!(ledger.total, 100); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); - - // Tests for saturating arithmetic - - // Given - let slash = u64::MAX as Balance * 2; - // The value of the other parts of ledger that will get slashed - let value = slash - (10 * 4); - - ledger.active = 10; - ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; - ledger.total = value + 40; - // When - let slash_amount = ledger.slash(slash, 0, 0); - assert_eq_error_rate!(slash_amount, slash, 5); - // Then - assert_eq!(ledger.active, 0); // slash of 9 - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); - - // Given - use sp_runtime::PerThing as _; - let slash = u64::MAX as Balance * 2; - let value = u64::MAX as Balance * 2; - let unit = 100; - // slash * value that will saturate - assert!(slash.checked_mul(value).is_none()); - // but slash * unit won't. - assert!(slash.checked_mul(unit).is_some()); - ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; - //--------------------------------------note value^^^ - ledger.active = unit; - ledger.total = unit * 4 + value; - // When - assert_eq!(ledger.slash(slash, 0, 0), slash); - // Then - // The amount slashed out of `unit` - let affected_balance = value + unit * 4; - let ratio = - Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up).unwrap(); - // `unit` after the slash is applied - let unit_slashed = { - let unit_slash = ratio.mul_ceil(unit); - unit - unit_slash - }; - let value_slashed = { - let value_slash = ratio.mul_ceil(value); - value - value_slash - }; - assert_eq!(ledger.active, unit_slashed); - assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); - assert_eq!(ledger.total, value_slashed + 32); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) - ); + // Given + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; + ledger.total = 2 * 10; + ledger.active = 0; + // When all the chunks overlap with the slash eras + assert_eq!(ledger.slash(20, 0, 0), 20); + // Then + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(140, 0, 3), 140); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); + assert_eq!(ledger.total, 4 * 100 - 140); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(15, 0, 3), 15); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); + assert_eq!(ledger.total, 4 * 100 - 15); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + // 900 + ledger.total = 40 + 10 + 100 + 250 + 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(900 / 2, 0, 0), 450); + // Then + assert_eq!(ledger.active, 500 / 2); + assert_eq!( + ledger.unlocking, + vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)] + ); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) + ); + + // slash 1/4th with not chunk. + ledger.unlocking = bounded_vec![]; + ledger.active = 500; + ledger.total = 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); + // Then + assert_eq!(ledger.active, 3 * 500 / 4); + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, ledger.active); + assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // Given we have the same as above, + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!(ledger.total, 900); + // When we have a higher min balance + assert_eq!( + ledger.slash( + 900 / 2, + 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it + * to get swept */ + 0 + ), + 450 + ); + assert_eq!(ledger.active, 500 / 2); + // the last chunk was not slashed 50% like all the rest, because some other earlier chunks + // got dusted. + assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) + ); + + // Given + // slash order --------------------NA--------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!( + ledger.slash( + 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 + 0, + 3 /* slash era 6 first, so the affected parts are era 6, era 7 and + * ledge.active. This will cause the affected to go to zero, and then we will + * start slashing older chunks */ + ), + 500 + 250 + 10 + 100 / 2 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); + assert_eq!(ledger.total, 90); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); + + // Given + // iteration order------------------NA---------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.active = 100; + ledger.total = 5 * 100; + // When + assert_eq!( + ledger.slash( + 351, // active + era 6 + era 7 + era 5 / 2 + 1 + 50, // min balance - everything slashed below 50 will get dusted + 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and + * ledge.active. This will cause the affected to go to zero, and then we + * will start slashing older chunks */ + ), + 400 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 100)]); + assert_eq!(ledger.total, 100); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); + + // Tests for saturating arithmetic + + // Given + let slash = u64::MAX as Balance * 2; + // The value of the other parts of ledger that will get slashed + let value = slash - (10 * 4); + + ledger.active = 10; + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; + ledger.total = value + 40; + // When + let slash_amount = ledger.slash(slash, 0, 0); + assert_eq_error_rate!(slash_amount, slash, 5); + // Then + assert_eq!(ledger.active, 0); // slash of 9 + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); + + // Given + use sp_runtime::PerThing as _; + let slash = u64::MAX as Balance * 2; + let value = u64::MAX as Balance * 2; + let unit = 100; + // slash * value that will saturate + assert!(slash.checked_mul(value).is_none()); + // but slash * unit won't. + assert!(slash.checked_mul(unit).is_some()); + ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; + //--------------------------------------note value^^^ + ledger.active = unit; + ledger.total = unit * 4 + value; + // When + assert_eq!(ledger.slash(slash, 0, 0), slash); + // Then + // The amount slashed out of `unit` + let affected_balance = value + unit * 4; + let ratio = Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up) + .unwrap(); + // `unit` after the slash is applied + let unit_slashed = { + let unit_slash = ratio.mul_ceil(unit); + unit - unit_slash + }; + let value_slashed = { + let value_slash = ratio.mul_ceil(value); + value - value_slash + }; + assert_eq!(ledger.active, unit_slashed); + assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); + assert_eq!(ledger.total, value_slashed + 32); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) + ); + }); } #[test] @@ -7126,7 +7203,7 @@ mod staking_unchecked { fn virtual_bond_does_not_lock() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(asset::total_balance::(&10), 1); // 10 can bond more than its balance amount since we do not require lock for virtual // bonding. assert_ok!(::virtual_bond(&10, 100, &15)); @@ -7265,7 +7342,7 @@ mod staking_unchecked { assert_eq!(asset::staked::(&200), 1000); // migrate them to virtual staker - ::migrate_to_virtual_staker(&200); + assert_ok!(::migrate_to_virtual_staker(&200)); // payee needs to be updated to a non-stash account. assert_ok!(::set_payee(&200, &201)); @@ -7292,7 +7369,7 @@ mod staking_unchecked { // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); // make 101 a virtual nominator - ::migrate_to_virtual_staker(&101); + assert_ok!(::migrate_to_virtual_staker(&101)); // set payee different to self. assert_ok!(::set_payee(&101, &102)); @@ -7367,7 +7444,7 @@ mod staking_unchecked { // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); // make 101 a virtual nominator - ::migrate_to_virtual_staker(&101); + assert_ok!(::migrate_to_virtual_staker(&101)); // set payee different to self. assert_ok!(::set_payee(&101, &102)); @@ -7423,7 +7500,7 @@ mod staking_unchecked { // 333 is corrupted assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); // migrate to virtual staker. - ::migrate_to_virtual_staker(&333); + assert_ok!(::migrate_to_virtual_staker(&333)); // recover the ledger won't work for virtual staker assert_noop!( @@ -8034,8 +8111,7 @@ mod ledger_recovery { // side effects on 333 - ledger, bonded, payee, lock should be intact. assert_eq!(asset::staked::(&333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK - assert!(Payee::::get(&333).is_some()); // OK - + assert!(Payee::::get(&333).is_some()); // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK @@ -9081,3 +9157,249 @@ mod getters { }); } } + +mod hold_migration { + use super::*; + use sp_staking::{Stake, StakingInterface}; + + #[test] + fn ledger_update_creates_hold() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // GIVEN alice who is a nominator with old currency + let alice = 300; + bond_nominator(alice, 1000, vec![11]); + assert_eq!(asset::staked::(&alice), 1000); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + // migrate alice currency to legacy locks + testing_utils::migrate_to_old_currency::(alice); + // no more holds + assert_eq!(asset::staked::(&alice), 0); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 1000 }) + ); + + // any ledger mutation should create a hold + hypothetically!({ + // give some extra balance to alice. + let _ = asset::mint_into_existing::(&alice, 100); + + // WHEN new fund is bonded to ledger. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(alice), 100)); + + // THEN new hold is created + assert_eq!(asset::staked::(&alice), 1000 + 100); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1100, active: 1100 }) + ); + + // old locked balance is untouched + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + }); + + hypothetically!({ + // WHEN new fund is unbonded from ledger. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); + + // THEN hold is updated. + assert_eq!(asset::staked::(&alice), 1000); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 900 }) + ); + + // old locked balance is untouched + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + }); + + // WHEN alice currency is migrated. + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); + + // THEN hold is updated. + assert_eq!(asset::staked::(&alice), 1000); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 1000 }) + ); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), alice), + Error::::AlreadyMigrated + ); + + // locked balance is removed + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + }); + } + + #[test] + fn migrate_removes_old_lock() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // GIVEN alice who is a nominator with old currency + let alice = 300; + bond_nominator(alice, 1000, vec![11]); + testing_utils::migrate_to_old_currency::(alice); + assert_eq!(asset::staked::(&alice), 0); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + let pre_migrate_consumer = System::consumers(&alice); + System::reset_events(); + + // WHEN alice currency is migrated. + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); + + // THEN + // the extra consumer from old code is removed. + assert_eq!(System::consumers(&alice), pre_migrate_consumer - 1); + // ensure no lock + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + // ensure stake and hold are same. + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 1000 }) + ); + assert_eq!(asset::staked::(&alice), 1000); + // ensure events are emitted. + assert_eq!( + staking_events_since_last_call(), + vec![Event::CurrencyMigrated { stash: alice, force_withdraw: 0 }] + ); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), alice), + Error::::AlreadyMigrated + ); + }); + } + #[test] + fn cannot_hold_all_stake() { + // When there is not enough funds to hold all stake, part of the stake if force withdrawn. + // At end of the migration, the stake and hold should be same. + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // GIVEN alice who is a nominator with old currency. + let alice = 300; + let stake = 1000; + bond_nominator(alice, stake, vec![11]); + testing_utils::migrate_to_old_currency::(alice); + assert_eq!(asset::staked::(&alice), 0); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), stake); + // ledger has 1000 staked. + assert_eq!( + ::stake(&alice), + Ok(Stake { total: stake, active: stake }) + ); + + // Get rid of the extra ED to emulate all their balance including ED is staked. + assert_ok!(Balances::transfer_allow_death( + RuntimeOrigin::signed(alice), + 10, + ExistentialDeposit::get() + )); + + let expected_force_withdraw = ExistentialDeposit::get(); + + // ledger mutation would fail in this case before migration because of failing hold. + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(alice), 100), + Error::::NotEnoughFunds + ); + + // clear events + System::reset_events(); + + // WHEN alice currency is migrated. + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); + + // THEN + let expected_hold = stake - expected_force_withdraw; + // ensure no lock + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + // ensure stake and hold are same. + assert_eq!( + ::stake(&alice), + Ok(Stake { total: expected_hold, active: expected_hold }) + ); + assert_eq!(asset::staked::(&alice), expected_hold); + // ensure events are emitted. + assert_eq!( + staking_events_since_last_call(), + vec![Event::CurrencyMigrated { + stash: alice, + force_withdraw: expected_force_withdraw + }] + ); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), alice), + Error::::AlreadyMigrated + ); + + // unbond works after migration. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); + }); + } + + #[test] + fn virtual_staker_consumer_provider_dec() { + // Ensure virtual stakers consumer and provider count is decremented. + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // 200 virtual bonds + bond_virtual_nominator(200, 201, 500, vec![11, 21]); + + // previously the virtual nominator had a provider inc by the delegation system as + // well as a consumer by this pallet. + System::inc_providers(&200); + System::inc_consumers(&200).expect("has provider, can consume"); + + hypothetically!({ + // migrate 200 + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200)); + + // ensure account does not exist in system anymore. + assert_eq!(System::consumers(&200), 0); + assert_eq!(System::providers(&200), 0); + assert!(!System::account_exists(&200)); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), 200), + Error::::AlreadyMigrated + ); + }); + + hypothetically!({ + // 200 has an erroneously extra provider + System::inc_providers(&200); + + // causes migration to fail. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), 200), + Error::::BadState + ); + }); + + // 200 is funded for more than ED by a random account. + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(999), 200, 10)); + + // it has an extra provider now. + assert_eq!(System::providers(&200), 2); + + // migrate 200 + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200)); + + // 1 provider is left, consumers is 0. + assert_eq!(System::providers(&200), 1); + assert_eq!(System::consumers(&200), 0); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), 200), + Error::::AlreadyMigrated + ); + }); + } +} diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 56f561679cfc..02ccdacb01c4 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-09-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-obbyq9g6-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/staking/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_staking +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/staking/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -83,6 +81,7 @@ pub trait WeightInfo { fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; fn restore_ledger() -> Weight; + fn migrate_currency() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -92,18 +91,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1042` - // Estimated: `4764` - // Minimum execution time: 46_504_000 picoseconds. - Weight::from_parts(48_459_000, 4764) + // Measured: `1068` + // Estimated: `4556` + // Minimum execution time: 71_854_000 picoseconds. + Weight::from_parts(73_408_000, 4556) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -111,20 +110,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1990` + // Measured: `2049` // Estimated: `8877` - // Minimum execution time: 90_475_000 picoseconds. - Weight::from_parts(93_619_000, 8877) + // Minimum execution time: 127_442_000 picoseconds. + Weight::from_parts(130_845_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -138,22 +137,22 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2195` + // Measured: `2151` // Estimated: `8877` - // Minimum execution time: 99_335_000 picoseconds. - Weight::from_parts(101_440_000, 8877) + // Minimum execution time: 105_259_000 picoseconds. + Weight::from_parts(107_112_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -161,21 +160,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1297` - // Estimated: `4764` - // Minimum execution time: 50_067_000 picoseconds. - Weight::from_parts(52_396_327, 4764) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into())) + // Measured: `1393` + // Estimated: `4556` + // Minimum execution time: 77_158_000 picoseconds. + Weight::from_parts(79_140_122, 4556) + // Standard Error: 1_688 + .saturating_add(Weight::from_parts(62_663, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -187,10 +186,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -210,14 +209,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_931_000 picoseconds. - Weight::from_parts(101_398_156, 6248) - // Standard Error: 4_180 - .saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into())) + // Minimum execution time: 125_396_000 picoseconds. + Weight::from_parts(134_915_543, 6248) + // Standard Error: 3_660 + .saturating_add(Weight::from_parts(1_324_736, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -245,10 +244,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1372` + // Measured: `1438` // Estimated: `4556` - // Minimum execution time: 56_291_000 picoseconds. - Weight::from_parts(58_372_000, 4556) + // Minimum execution time: 68_826_000 picoseconds. + Weight::from_parts(71_261_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -261,12 +260,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1815 + k * (572 ±0)` + // Measured: `1848 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 36_218_000 picoseconds. - Weight::from_parts(38_811_308, 4556) - // Standard Error: 8_352 - .saturating_add(Weight::from_parts(6_527_398, 0).saturating_mul(k.into())) + // Minimum execution time: 46_082_000 picoseconds. + Weight::from_parts(49_541_374, 4556) + // Standard Error: 7_218 + .saturating_add(Weight::from_parts(7_281_079, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -297,12 +296,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1866 + n * (102 ±0)` + // Measured: `1932 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_607_000 picoseconds. - Weight::from_parts(66_831_185, 6248) - // Standard Error: 14_014 - .saturating_add(Weight::from_parts(4_031_635, 0).saturating_mul(n.into())) + // Minimum execution time: 83_854_000 picoseconds. + Weight::from_parts(81_387_241, 6248) + // Standard Error: 16_811 + .saturating_add(Weight::from_parts(4_900_554, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -326,10 +325,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1816` + // Measured: `1882` // Estimated: `6248` - // Minimum execution time: 60_088_000 picoseconds. - Weight::from_parts(62_471_000, 6248) + // Minimum execution time: 73_939_000 picoseconds. + Weight::from_parts(75_639_000, 6248) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -341,10 +340,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_777_000 picoseconds. - Weight::from_parts(20_690_000, 4556) + // Minimum execution time: 24_592_000 picoseconds. + Weight::from_parts(25_092_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -356,10 +355,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_705_000 picoseconds. - Weight::from_parts(24_409_000, 4556) + // Minimum execution time: 29_735_000 picoseconds. + Weight::from_parts(30_546_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -369,10 +368,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_479_000 picoseconds. - Weight::from_parts(24_502_000, 8122) + // Minimum execution time: 28_728_000 picoseconds. + Weight::from_parts(29_709_000, 8122) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -382,8 +381,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_675_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 2_519_000 picoseconds. + Weight::from_parts(2_673_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -392,8 +391,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_413_000, 0) + // Minimum execution time: 8_050_000 picoseconds. + Weight::from_parts(8_268_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -402,8 +401,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_353_000, 0) + // Minimum execution time: 8_131_000 picoseconds. + Weight::from_parts(8_349_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -412,8 +411,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_071_000 picoseconds. - Weight::from_parts(7_463_000, 0) + // Minimum execution time: 8_104_000 picoseconds. + Weight::from_parts(8_317_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -423,10 +422,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(3_328_130, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into())) + // Minimum execution time: 2_669_000 picoseconds. + Weight::from_parts(3_013_436, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_704, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -438,12 +437,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1746 + i * (229 ±0)` + // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_300_000 picoseconds. - Weight::from_parts(5_437_000, 990) - // Standard Error: 66_261 - .saturating_add(Weight::from_parts(30_172_457, 0).saturating_mul(i.into())) + // Minimum execution time: 5_101_000 picoseconds. + Weight::from_parts(5_368_000, 990) + // Standard Error: 75_180 + .saturating_add(Weight::from_parts(33_781_643, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -454,10 +453,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) @@ -479,14 +478,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_677_000 picoseconds. - Weight::from_parts(96_386_462, 6248) - // Standard Error: 3_717 - .saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into())) + // Minimum execution time: 119_955_000 picoseconds. + Weight::from_parts(128_392_032, 6248) + // Standard Error: 3_773 + .saturating_add(Weight::from_parts(1_302_488, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -495,12 +494,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66672` - // Estimated: `70137` - // Minimum execution time: 105_086_000 picoseconds. - Weight::from_parts(1_167_895_222, 70137) - // Standard Error: 77_022 - .saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into())) + // Measured: `66705` + // Estimated: `70170` + // Minimum execution time: 139_290_000 picoseconds. + Weight::from_parts(959_667_494, 70170) + // Standard Error: 56_271 + .saturating_add(Weight::from_parts(4_798_293, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -518,12 +517,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:257 w:257) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:257 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:257 w:257) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:257 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:257 w:257) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) @@ -532,29 +529,31 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:257 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:257 w:257) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 154_210_000 picoseconds. - Weight::from_parts(192_836_012, 30944) - // Standard Error: 40_441 - .saturating_add(Weight::from_parts(47_646_642, 0).saturating_mul(n.into())) + // Measured: `33283 + n * (370 ±0)` + // Estimated: `30958 + n * (3566 ±0)` + // Minimum execution time: 193_068_000 picoseconds. + Weight::from_parts(252_762_568, 30958) + // Standard Error: 22_743 + .saturating_add(Weight::from_parts(81_185_306, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) @@ -562,25 +561,25 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1991 + l * (7 ±0)` + // Measured: `1947 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 88_337_000 picoseconds. - Weight::from_parts(91_391_254, 8877) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into())) + // Minimum execution time: 91_151_000 picoseconds. + Weight::from_parts(93_596_096, 8877) + // Standard Error: 5_313 + .saturating_add(Weight::from_parts(124_684, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -600,14 +599,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 98_014_000 picoseconds. - Weight::from_parts(102_537_670, 6248) - // Standard Error: 3_324 - .saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into())) + // Minimum execution time: 133_214_000 picoseconds. + Weight::from_parts(137_290_527, 6248) + // Standard Error: 4_153 + .saturating_add(Weight::from_parts(1_291_007, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -651,12 +650,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 608_575_000 picoseconds. - Weight::from_parts(613_663_000, 512390) - // Standard Error: 2_286_521 - .saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into())) - // Standard Error: 227_839 - .saturating_add(Weight::from_parts(20_314_085, 0).saturating_mul(n.into())) + // Minimum execution time: 692_301_000 picoseconds. + Weight::from_parts(708_732_000, 512390) + // Standard Error: 2_117_299 + .saturating_add(Weight::from_parts(70_087_600, 0).saturating_mul(v.into())) + // Standard Error: 210_977 + .saturating_add(Weight::from_parts(22_953_405, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -685,14 +684,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3241 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_173_756_000 picoseconds. - Weight::from_parts(37_488_937_000, 512390) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into())) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(3_108_193, 0).saturating_mul(n.into())) + // Minimum execution time: 43_708_472_000 picoseconds. + Weight::from_parts(44_048_436_000, 512390) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(6_697_278, 0).saturating_mul(v.into())) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(4_559_779, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -707,12 +706,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `979 + v * (50 ±0)` + // Measured: `1012 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_641_258_000 picoseconds. - Weight::from_parts(382_882_595, 3510) - // Standard Error: 11_991 - .saturating_add(Weight::from_parts(4_695_820, 0).saturating_mul(v.into())) + // Minimum execution time: 2_917_165_000 picoseconds. + Weight::from_parts(2_948_999_000, 3510) + // Standard Error: 33_372 + .saturating_add(Weight::from_parts(2_126_909, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -735,8 +734,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_753_000 picoseconds. - Weight::from_parts(6_529_000, 0) + // Minimum execution time: 4_748_000 picoseconds. + Weight::from_parts(5_052_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -757,8 +756,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_212_000 picoseconds. - Weight::from_parts(5_451_000, 0) + // Minimum execution time: 4_316_000 picoseconds. + Weight::from_parts(4_526_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -785,10 +784,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1939` + // Measured: `2005` // Estimated: `6248` - // Minimum execution time: 73_000_000 picoseconds. - Weight::from_parts(75_184_000, 6248) + // Minimum execution time: 87_374_000 picoseconds. + Weight::from_parts(89_848_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -798,10 +797,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `691` + // Measured: `724` // Estimated: `3510` - // Minimum execution time: 13_056_000 picoseconds. - Weight::from_parts(13_517_000, 3510) + // Minimum execution time: 15_529_000 picoseconds. + Weight::from_parts(16_094_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -811,28 +810,51 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_201_000 picoseconds. - Weight::from_parts(3_442_000, 0) + // Minimum execution time: 2_533_000 picoseconds. + Weight::from_parts(2_817_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + fn restore_ledger() -> Weight { + // Proof Size summary in bytes: + // Measured: `1110` + // Estimated: `4764` + // Minimum execution time: 50_105_000 picoseconds. + Weight::from_parts(50_966_000, 4764) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - fn restore_ledger() -> Weight { + fn migrate_currency() -> Weight { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `1246` // Estimated: `4764` - // Minimum execution time: 44_671_000 picoseconds. - Weight::from_parts(45_611_000, 4764) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 94_054_000 picoseconds. + Weight::from_parts(96_272_000, 4764) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -842,18 +864,18 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1042` - // Estimated: `4764` - // Minimum execution time: 46_504_000 picoseconds. - Weight::from_parts(48_459_000, 4764) + // Measured: `1068` + // Estimated: `4556` + // Minimum execution time: 71_854_000 picoseconds. + Weight::from_parts(73_408_000, 4556) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -861,20 +883,20 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1990` + // Measured: `2049` // Estimated: `8877` - // Minimum execution time: 90_475_000 picoseconds. - Weight::from_parts(93_619_000, 8877) + // Minimum execution time: 127_442_000 picoseconds. + Weight::from_parts(130_845_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -888,22 +910,22 @@ impl WeightInfo for () { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2195` + // Measured: `2151` // Estimated: `8877` - // Minimum execution time: 99_335_000 picoseconds. - Weight::from_parts(101_440_000, 8877) + // Minimum execution time: 105_259_000 picoseconds. + Weight::from_parts(107_112_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -911,21 +933,21 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1297` - // Estimated: `4764` - // Minimum execution time: 50_067_000 picoseconds. - Weight::from_parts(52_396_327, 4764) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into())) + // Measured: `1393` + // Estimated: `4556` + // Minimum execution time: 77_158_000 picoseconds. + Weight::from_parts(79_140_122, 4556) + // Standard Error: 1_688 + .saturating_add(Weight::from_parts(62_663, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -937,10 +959,10 @@ impl WeightInfo for () { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -960,14 +982,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_931_000 picoseconds. - Weight::from_parts(101_398_156, 6248) - // Standard Error: 4_180 - .saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into())) + // Minimum execution time: 125_396_000 picoseconds. + Weight::from_parts(134_915_543, 6248) + // Standard Error: 3_660 + .saturating_add(Weight::from_parts(1_324_736, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -995,10 +1017,10 @@ impl WeightInfo for () { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1372` + // Measured: `1438` // Estimated: `4556` - // Minimum execution time: 56_291_000 picoseconds. - Weight::from_parts(58_372_000, 4556) + // Minimum execution time: 68_826_000 picoseconds. + Weight::from_parts(71_261_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1011,12 +1033,12 @@ impl WeightInfo for () { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1815 + k * (572 ±0)` + // Measured: `1848 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 36_218_000 picoseconds. - Weight::from_parts(38_811_308, 4556) - // Standard Error: 8_352 - .saturating_add(Weight::from_parts(6_527_398, 0).saturating_mul(k.into())) + // Minimum execution time: 46_082_000 picoseconds. + Weight::from_parts(49_541_374, 4556) + // Standard Error: 7_218 + .saturating_add(Weight::from_parts(7_281_079, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -1047,12 +1069,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1866 + n * (102 ±0)` + // Measured: `1932 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_607_000 picoseconds. - Weight::from_parts(66_831_185, 6248) - // Standard Error: 14_014 - .saturating_add(Weight::from_parts(4_031_635, 0).saturating_mul(n.into())) + // Minimum execution time: 83_854_000 picoseconds. + Weight::from_parts(81_387_241, 6248) + // Standard Error: 16_811 + .saturating_add(Weight::from_parts(4_900_554, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1076,10 +1098,10 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1816` + // Measured: `1882` // Estimated: `6248` - // Minimum execution time: 60_088_000 picoseconds. - Weight::from_parts(62_471_000, 6248) + // Minimum execution time: 73_939_000 picoseconds. + Weight::from_parts(75_639_000, 6248) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1091,10 +1113,10 @@ impl WeightInfo for () { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_777_000 picoseconds. - Weight::from_parts(20_690_000, 4556) + // Minimum execution time: 24_592_000 picoseconds. + Weight::from_parts(25_092_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1106,10 +1128,10 @@ impl WeightInfo for () { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_705_000 picoseconds. - Weight::from_parts(24_409_000, 4556) + // Minimum execution time: 29_735_000 picoseconds. + Weight::from_parts(30_546_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1119,10 +1141,10 @@ impl WeightInfo for () { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_479_000 picoseconds. - Weight::from_parts(24_502_000, 8122) + // Minimum execution time: 28_728_000 picoseconds. + Weight::from_parts(29_709_000, 8122) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1132,8 +1154,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_675_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 2_519_000 picoseconds. + Weight::from_parts(2_673_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1142,8 +1164,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_413_000, 0) + // Minimum execution time: 8_050_000 picoseconds. + Weight::from_parts(8_268_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1152,8 +1174,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_353_000, 0) + // Minimum execution time: 8_131_000 picoseconds. + Weight::from_parts(8_349_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1162,8 +1184,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_071_000 picoseconds. - Weight::from_parts(7_463_000, 0) + // Minimum execution time: 8_104_000 picoseconds. + Weight::from_parts(8_317_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1173,10 +1195,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(3_328_130, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into())) + // Minimum execution time: 2_669_000 picoseconds. + Weight::from_parts(3_013_436, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_704, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -1188,12 +1210,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1746 + i * (229 ±0)` + // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_300_000 picoseconds. - Weight::from_parts(5_437_000, 990) - // Standard Error: 66_261 - .saturating_add(Weight::from_parts(30_172_457, 0).saturating_mul(i.into())) + // Minimum execution time: 5_101_000 picoseconds. + Weight::from_parts(5_368_000, 990) + // Standard Error: 75_180 + .saturating_add(Weight::from_parts(33_781_643, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -1204,10 +1226,10 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) @@ -1229,14 +1251,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_677_000 picoseconds. - Weight::from_parts(96_386_462, 6248) - // Standard Error: 3_717 - .saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into())) + // Minimum execution time: 119_955_000 picoseconds. + Weight::from_parts(128_392_032, 6248) + // Standard Error: 3_773 + .saturating_add(Weight::from_parts(1_302_488, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + .saturating_add(RocksDbWeight::get().writes(13_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1245,12 +1267,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66672` - // Estimated: `70137` - // Minimum execution time: 105_086_000 picoseconds. - Weight::from_parts(1_167_895_222, 70137) - // Standard Error: 77_022 - .saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into())) + // Measured: `66705` + // Estimated: `70170` + // Minimum execution time: 139_290_000 picoseconds. + Weight::from_parts(959_667_494, 70170) + // Standard Error: 56_271 + .saturating_add(Weight::from_parts(4_798_293, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1268,12 +1290,10 @@ impl WeightInfo for () { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:257 w:257) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:257 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:257 w:257) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:257 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:257 w:257) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) @@ -1282,29 +1302,31 @@ impl WeightInfo for () { /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:257 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:257 w:257) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 154_210_000 picoseconds. - Weight::from_parts(192_836_012, 30944) - // Standard Error: 40_441 - .saturating_add(Weight::from_parts(47_646_642, 0).saturating_mul(n.into())) + // Measured: `33283 + n * (370 ±0)` + // Estimated: `30958 + n * (3566 ±0)` + // Minimum execution time: 193_068_000 picoseconds. + Weight::from_parts(252_762_568, 30958) + // Standard Error: 22_743 + .saturating_add(Weight::from_parts(81_185_306, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) @@ -1312,25 +1334,25 @@ impl WeightInfo for () { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1991 + l * (7 ±0)` + // Measured: `1947 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 88_337_000 picoseconds. - Weight::from_parts(91_391_254, 8877) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into())) + // Minimum execution time: 91_151_000 picoseconds. + Weight::from_parts(93_596_096, 8877) + // Standard Error: 5_313 + .saturating_add(Weight::from_parts(124_684, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1350,14 +1372,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 98_014_000 picoseconds. - Weight::from_parts(102_537_670, 6248) - // Standard Error: 3_324 - .saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into())) + // Minimum execution time: 133_214_000 picoseconds. + Weight::from_parts(137_290_527, 6248) + // Standard Error: 4_153 + .saturating_add(Weight::from_parts(1_291_007, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1401,12 +1423,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 608_575_000 picoseconds. - Weight::from_parts(613_663_000, 512390) - // Standard Error: 2_286_521 - .saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into())) - // Standard Error: 227_839 - .saturating_add(Weight::from_parts(20_314_085, 0).saturating_mul(n.into())) + // Minimum execution time: 692_301_000 picoseconds. + Weight::from_parts(708_732_000, 512390) + // Standard Error: 2_117_299 + .saturating_add(Weight::from_parts(70_087_600, 0).saturating_mul(v.into())) + // Standard Error: 210_977 + .saturating_add(Weight::from_parts(22_953_405, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1435,14 +1457,14 @@ impl WeightInfo for () { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3241 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_173_756_000 picoseconds. - Weight::from_parts(37_488_937_000, 512390) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into())) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(3_108_193, 0).saturating_mul(n.into())) + // Minimum execution time: 43_708_472_000 picoseconds. + Weight::from_parts(44_048_436_000, 512390) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(6_697_278, 0).saturating_mul(v.into())) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(4_559_779, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1457,12 +1479,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `979 + v * (50 ±0)` + // Measured: `1012 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_641_258_000 picoseconds. - Weight::from_parts(382_882_595, 3510) - // Standard Error: 11_991 - .saturating_add(Weight::from_parts(4_695_820, 0).saturating_mul(v.into())) + // Minimum execution time: 2_917_165_000 picoseconds. + Weight::from_parts(2_948_999_000, 3510) + // Standard Error: 33_372 + .saturating_add(Weight::from_parts(2_126_909, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1485,8 +1507,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_753_000 picoseconds. - Weight::from_parts(6_529_000, 0) + // Minimum execution time: 4_748_000 picoseconds. + Weight::from_parts(5_052_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1507,8 +1529,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_212_000 picoseconds. - Weight::from_parts(5_451_000, 0) + // Minimum execution time: 4_316_000 picoseconds. + Weight::from_parts(4_526_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -1535,10 +1557,10 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1939` + // Measured: `2005` // Estimated: `6248` - // Minimum execution time: 73_000_000 picoseconds. - Weight::from_parts(75_184_000, 6248) + // Minimum execution time: 87_374_000 picoseconds. + Weight::from_parts(89_848_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1548,10 +1570,10 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `691` + // Measured: `724` // Estimated: `3510` - // Minimum execution time: 13_056_000 picoseconds. - Weight::from_parts(13_517_000, 3510) + // Minimum execution time: 15_529_000 picoseconds. + Weight::from_parts(16_094_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1561,27 +1583,50 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_201_000 picoseconds. - Weight::from_parts(3_442_000, 0) + // Minimum execution time: 2_533_000 picoseconds. + Weight::from_parts(2_817_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + fn restore_ledger() -> Weight { + // Proof Size summary in bytes: + // Measured: `1110` + // Estimated: `4764` + // Minimum execution time: 50_105_000 picoseconds. + Weight::from_parts(50_966_000, 4764) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - fn restore_ledger() -> Weight { + fn migrate_currency() -> Weight { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `1246` // Estimated: `4764` - // Minimum execution time: 44_671_000 picoseconds. - Weight::from_parts(45_611_000, 4764) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 94_054_000 picoseconds. + Weight::from_parts(96_272_000, 4764) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } \ No newline at end of file diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index f627d29cd563..157361dbd5d6 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -frame = { features = ["experimental", "runtime"], workspace = true } +frame = { features = ["runtime"], workspace = true } scale-info = { features = ["derive"], workspace = true } [features] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 17010a8907fc..8e23c6800a9d 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -325,7 +325,7 @@ pub trait StakingUnchecked: StakingInterface { /// Migrate an existing staker to a virtual staker. /// /// It would release all funds held by the implementation pallet. - fn migrate_to_virtual_staker(who: &Self::AccountId); + fn migrate_to_virtual_staker(who: &Self::AccountId) -> DispatchResult; /// Book-keep a new bond for `keyless_who` without applying any locks (hence virtual). ///