mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 18:51:12 +00:00
Nomination Pools (#10694)
* Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Add admin roles and make some calls permissionless * Destroy pool in withdraw unbonded * Add docs on pool admin * Fixup tests * Test unbond_other permissionless scenarios * Test withdraw unbonded permissionless * Test only can join open pools * Move unsafe set state to mock * Test: nominate_works * Add bounds: MinJoinBond, MinCreateBond, MaxPools * Test MinCreateBond, MinJoinBond, MaxPools * Add post checks to tests * Remove some TODOs * Setup weight infrastructure * Benchmark claim_payout * Benchmark create * Benchmark nominate * Benchmark join * Benchmark unbond_other * Refactor join benchmark to use scenario setup * Clean up and address warnings * Basic withdraw unbonded benchmarks * Refactor nominate benchmark * Refactor claim payout * Add feature sp-staking/runtime-benchmarks * Get node runtime to compile * Get node to run * Make claim_payout bench work with node * Make pool_withdraw_unbonded bench work with node * Make withdraw_unbonded_other work with node runtime' * Make create benchmark work with node * Make nominate benchmark work with node runtime * WiP new benchmark crate * Implement initial mock for benchmarks * Establish benchmark setup logic * Get claim payout and nominate benchmarks working * Remove pool bench utils; make struct fields pub insteaad * Get more benchmarks to work; trim interface trait * Some more top level docs * Finish tranistion benchmarks to crate * Hook up benchmark pallet to node runtime * Get benches to work with node runtime * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Benchmark withdraw_unbonded_other_kill * Delete old benchmarking files * Refunds for withdraw_unbonded * Remove some TODOs * 'Don't return an option for the current_era' * Streamline extrinsic docs * small docs tweaks * Refactor ledger::slash * Add on_slash impl for nomination pools * slash refactor wip * WIP slash working * DRY Ledger::stash * Fix slash saturation * Remove unused param from slash * Docs and warnings * Test ledger::slash * save progress * Introduce counter for delegators * Add tests for max delegator errors * Reproducible account ids * Adapt tests to new account id format * Simplify create_accounts api * Fix staking tests * Save PerBill slash impl before removing * Rever ledger slash test * Get node runtime to work * Organize sub pools by unbond era, not curren era * staking: Proportional ledger slashing * Some comment cleanup * Add more test post checks * Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Tests: account for storing unbond era * Improve docs for staking interface * Add events Created, Destroyed * withdraw_unbonded: Remove useless withdraw dust check * Test: withdraw_unbonded_other_handles_faulty_sub_pool_accounting * Add extrinsics: set_state_other, set_metadata * Test: set_state_other_works * Test: set_metadata_works * Add benchmarks for set_state_other, set_metadata * Fix benchmarks * Add weight info for new extrinsics * Some feedback * duo feedback * Incorporate some more feedback * integrate more kian feedback * integrate more kian feedback * More improvements * Add destroying_mul * Make do_reward_payout take refs * Remove some TODOs * Add test for saturating * feedback * Fix join test * use `inner` for nested types in nomination pools (#11030) * Use nested inner type for pool * make tests and benchmarks work * remove feat * all tests work now * fix node-runtime * nomination-pools: update benches for new account format (#11033) * Update benches to new account format * More sensible seeds * bring back rward account sanity check * Comment * Add extrinsic set_configs (#11038) * Better sanity checks for nomination pools (#11042) * new sanity checks, few other changes * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * nomination-pools: Fix state event regression + benches (#11045) * new sanity checks, few other changes * Fix benches, improve sanity check * Remove useless clear storage in benchmarking * Set state * Save * Doc * Update frame/nomination-pools/src/lib.rs Co-authored-by: kianenigma <kian@parity.io> * FMT * Try fill in all staking configs * Fix build * More changes to nomination pools (#11050) * new sanity checks, few other changes * some last touches as a whole * Apply suggestions from code review * Remove redundant event * Improve unbond_other error handling * Remove comment Co-authored-by: Zeke Mostov <z.mostov@gmail.com> Co-authored-by: emostov <32168567+emostov@users.noreply.github.com> * Remove sanity module and some TODOs * round of feedback and imp from kian * Add TODO for ED QoL at reward pool creation * Make sure reward pool never gets dusted * Improve error type * demonstrate per_thing usage * Update sanity check & fix create_works * Improve test ext pool creation & fix some more tests * Try revert * Revert "Try revert" This reverts commit c044c94730e1a370eecd8f5b2c4f632835913063. * Revert "Improve test ext pool creation & fix some more tests" This reverts commit 1e862a64a7423479260c6e5ad1bd4c8c95651f3a. * Revert "Update sanity check & fix create_works" This reverts commit 568a7b727687e4d585e2796afc638df97b83c632. Roll back reward account funding * Revert "Improve error type" This reverts commit 4b993ee601a037e7a44e4a49bbfd60cf45b38b78. * Revert "Make sure reward pool never gets dusted" This reverts commit e7a3eb45bdfd156d3f6d94d194e988032ebbc593. revert * Update some tests * FMT * Test that era offset works correctly * Update mocks * Remove unnescary docs * Doc updates * Update calculate_delegator_payout_works_with_a_pool_of_1 * Fix test: claim_payout_works * do_reward_payout_correctly_sets_pool_state_to_destroying * Remove test do_reward_payout_errors_correctly * Fix test: do_reward_payout_works * Fix test: create_errors_correctly * Fix test: create works * Fix test: unbond_other_of_3_works * Ensure that ED is transferred into reward pool upon creation * WIP pool lifecycle test * Fix benchmarks * Add sanity check for ED + reward pools * `bond_extra` for nomination pools (#11100) * bond_extra for nomination pools * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * add benchmarks * remove the min logic of bond_extra Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * FMT * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * make it compile end to end * Update some type viz * Update kick terminology * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/src/lib.rs * Cache bonded account when creating pool * Add bond extra weight stuff * Update frame/nomination-pools/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update docs for pool withdraw unbonded * Update docs for unbond * Improve Doc * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/nomination-pools/Cargo.toml Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Improve Docs * Some docs improvements * fmt * Remove unlock_era * Fix accidental frame-support regression * Fix issue with transactions in tests * Fix doc links * Make sure result in test is used * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix can toggle state * Account for new_funds in ok to be open * Update docs: ok_to_withdraw_unbonded_other_with * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove some staking comments * Rename SubPoolsWithEra to UnbondingPoolsWithEra * Use validators length for benchmarks * Use metadata length for benchmarks * Remove debug assert eq * docs * Fix test: withdraw_unbonded_other_errors_correctly * Fix check for having enough balance to create the pool * Bond event for pool creation * Ok to be open * FMT * Remove _other postfix * Update frame/staking/src/lib.rs * Adjust tests to account for only remove when < ED * Remove stale TODOs * Remove dupe test * Fix build * Make sure to convert to u256 so we don't saturate * Refund depositor with reward pool fee * FMT * Remove reachable defensive * Use compact encoding for relevant extrinsics * Remove unnescary make_free_be for cleaning reward account * Add not to maintainers for reward account accounting * Remove note to maintainers from public doc * Make sure all configs have currency balance * Avoid saturation in balance_to_unbond * Partial Unbonding for Nomination Pools (#11212) * first draft of partial unbonding for pools * remove option * Add some more tests and fix issues * Fix all tests * simplify some tests * Update frame/nomination-pools/src/mock.rs * remove clone * rename to delegator_unbonding_eras * Update frame/nomination-pools/src/tests.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update frame/nomination-pools/src/tests.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update frame/nomination-pools/src/tests.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * remove pub * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * undo * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * leftovers * fix invariant * Fix the depositor assumption * round of self-review * little bit more cleanup * Update frame/nomination-pools/src/mock.rs * Apply suggestions from code review * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Fix interpretation of MinCreateBond * controvesial refactor * rename * make everything build * add TODO about killing the reward account * Update frame/nomination-pools/src/lib.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update frame/nomination-pools/src/lib.rs * last self-review Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update Cargo.lock * Rename Delegator to PoolMember * fmt * Get runtime to build with runtime-benchmarks feature * Update Cargo.lock * Fix asserts to work in more scenarios * gte not gt * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/staking/src/mock.rs * Update frame/nomination-pools/src/lib.rs * Update frame/staking/src/slashing.rs * Apply suggestions from code review * fmt * Fix some tests Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Parity Bot <admin@parity.io> Co-authored-by: kianenigma <kian@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Generated
+42
@@ -5027,6 +5027,8 @@ dependencies = [
|
||||
"pallet-membership",
|
||||
"pallet-mmr",
|
||||
"pallet-multisig",
|
||||
"pallet-nomination-pools",
|
||||
"pallet-nomination-pools-benchmarking",
|
||||
"pallet-offences",
|
||||
"pallet-offences-benchmarking",
|
||||
"pallet-preimage",
|
||||
@@ -6182,6 +6184,46 @@ dependencies = [
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-nomination-pools"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"pallet-balances",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
"sp-staking",
|
||||
"sp-std",
|
||||
"sp-tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-nomination-pools-benchmarking"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-election-provider-support",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"pallet-bags-list",
|
||||
"pallet-balances",
|
||||
"pallet-nomination-pools",
|
||||
"pallet-staking",
|
||||
"pallet-staking-reward-curve",
|
||||
"pallet-timestamp",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
"sp-staking",
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-offences"
|
||||
version = "4.0.0-dev"
|
||||
|
||||
@@ -109,6 +109,8 @@ members = [
|
||||
"frame/offences",
|
||||
"frame/preimage",
|
||||
"frame/proxy",
|
||||
"frame/nomination-pools",
|
||||
"frame/nomination-pools/benchmarking",
|
||||
"frame/randomness-collective-flip",
|
||||
"frame/recovery",
|
||||
"frame/referenda",
|
||||
|
||||
@@ -363,6 +363,7 @@ pub fn testnet_genesis(
|
||||
gilt: Default::default(),
|
||||
transaction_storage: Default::default(),
|
||||
transaction_payment: Default::default(),
|
||||
nomination_pools: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ pallet-lottery = { version = "4.0.0-dev", default-features = false, path = "../.
|
||||
pallet-membership = { version = "4.0.0-dev", default-features = false, path = "../../../frame/membership" }
|
||||
pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../../../frame/merkle-mountain-range" }
|
||||
pallet-multisig = { version = "4.0.0-dev", default-features = false, path = "../../../frame/multisig" }
|
||||
pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../../../frame/nomination-pools"}
|
||||
pallet-nomination-pools-benchmarking = { version = "1.0.0", default-features = false, optional = true, path = "../../../frame/nomination-pools/benchmarking" }
|
||||
pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../../frame/offences" }
|
||||
pallet-offences-benchmarking = { version = "4.0.0-dev", path = "../../../frame/offences/benchmarking", default-features = false, optional = true }
|
||||
pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/preimage" }
|
||||
@@ -140,6 +142,7 @@ std = [
|
||||
"pallet-membership/std",
|
||||
"pallet-mmr/std",
|
||||
"pallet-multisig/std",
|
||||
"pallet-nomination-pools/std",
|
||||
"pallet-identity/std",
|
||||
"pallet-scheduler/std",
|
||||
"node-primitives/std",
|
||||
@@ -210,6 +213,7 @@ runtime-benchmarks = [
|
||||
"pallet-membership/runtime-benchmarks",
|
||||
"pallet-mmr/runtime-benchmarks",
|
||||
"pallet-multisig/runtime-benchmarks",
|
||||
"pallet-nomination-pools-benchmarking",
|
||||
"pallet-offences-benchmarking",
|
||||
"pallet-preimage/runtime-benchmarks",
|
||||
"pallet-proxy/runtime-benchmarks",
|
||||
|
||||
@@ -561,7 +561,7 @@ impl pallet_staking::Config for Runtime {
|
||||
type GenesisElectionProvider = onchain::UnboundedExecution<OnChainSeqPhragmen>;
|
||||
type VoterList = BagsList;
|
||||
type MaxUnlockingChunks = ConstU32<32>;
|
||||
type OnStakerSlash = ();
|
||||
type OnStakerSlash = NominationPools;
|
||||
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
|
||||
type BenchmarkingConfig = StakingBenchmarkingConfig;
|
||||
}
|
||||
@@ -705,6 +705,38 @@ impl pallet_bags_list::Config for Runtime {
|
||||
type Score = VoteWeight;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const PostUnbondPoolsWindow: u32 = 4;
|
||||
pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/npols");
|
||||
}
|
||||
|
||||
use sp_runtime::traits::Convert;
|
||||
pub struct BalanceToU256;
|
||||
impl Convert<Balance, sp_core::U256> for BalanceToU256 {
|
||||
fn convert(balance: Balance) -> sp_core::U256 {
|
||||
sp_core::U256::from(balance)
|
||||
}
|
||||
}
|
||||
pub struct U256ToBalance;
|
||||
impl Convert<sp_core::U256, Balance> for U256ToBalance {
|
||||
fn convert(n: sp_core::U256) -> Balance {
|
||||
n.try_into().unwrap_or(Balance::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_nomination_pools::Config for Runtime {
|
||||
type WeightInfo = ();
|
||||
type Event = Event;
|
||||
type Currency = Balances;
|
||||
type BalanceToU256 = BalanceToU256;
|
||||
type U256ToBalance = U256ToBalance;
|
||||
type StakingInterface = pallet_staking::Pallet<Self>;
|
||||
type PostUnbondingPoolsWindow = PostUnbondPoolsWindow;
|
||||
type MaxMetadataLen = ConstU32<256>;
|
||||
type MaxUnbonding = ConstU32<8>;
|
||||
type PalletId = NominationPoolsPalletId;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const VoteLockingPeriod: BlockNumber = 30 * DAYS;
|
||||
}
|
||||
@@ -1470,6 +1502,7 @@ construct_runtime!(
|
||||
Remark: pallet_remark,
|
||||
ConvictionVoting: pallet_conviction_voting,
|
||||
Whitelist: pallet_whitelist,
|
||||
NominationPools: pallet_nomination_pools,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1554,6 +1587,7 @@ mod benches {
|
||||
[pallet_membership, TechnicalMembership]
|
||||
[pallet_mmr, Mmr]
|
||||
[pallet_multisig, Multisig]
|
||||
[pallet_nomination_pools, NominationPoolsBench::<Runtime>]
|
||||
[pallet_offences, OffencesBench::<Runtime>]
|
||||
[pallet_preimage, Preimage]
|
||||
[pallet_proxy, Proxy]
|
||||
@@ -1869,6 +1903,7 @@ impl_runtime_apis! {
|
||||
use pallet_election_provider_support_benchmarking::Pallet as EPSBench;
|
||||
use frame_system_benchmarking::Pallet as SystemBench;
|
||||
use baseline::Pallet as BaselineBench;
|
||||
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
|
||||
|
||||
let mut list = Vec::<BenchmarkList>::new();
|
||||
list_benchmarks!(list, extra);
|
||||
@@ -1891,12 +1926,14 @@ impl_runtime_apis! {
|
||||
use pallet_election_provider_support_benchmarking::Pallet as EPSBench;
|
||||
use frame_system_benchmarking::Pallet as SystemBench;
|
||||
use baseline::Pallet as BaselineBench;
|
||||
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
|
||||
|
||||
impl pallet_session_benchmarking::Config for Runtime {}
|
||||
impl pallet_offences_benchmarking::Config for Runtime {}
|
||||
impl pallet_election_provider_support_benchmarking::Config for Runtime {}
|
||||
impl frame_system_benchmarking::Config for Runtime {}
|
||||
impl baseline::Config for Runtime {}
|
||||
impl pallet_nomination_pools_benchmarking::Config for Runtime {}
|
||||
|
||||
let whitelist: Vec<TrackedStorageKey> = vec![
|
||||
// Block Number
|
||||
|
||||
@@ -92,5 +92,6 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec<AccountId>) -> Gen
|
||||
gilt: Default::default(),
|
||||
transaction_storage: Default::default(),
|
||||
transaction_payment: Default::default(),
|
||||
nomination_pools: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,10 +179,10 @@ frame_benchmarking::benchmarks! {
|
||||
vec![heavier, lighter, heavier_prev, heavier_next]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
frame_benchmarking::impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::mock::ExtBuilder::default().skip_genesis_ids().build(),
|
||||
crate::mock::Runtime
|
||||
);
|
||||
impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::mock::ExtBuilder::default().skip_genesis_ids().build(),
|
||||
crate::mock::Runtime
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
[package]
|
||||
name = "pallet-nomination-pools"
|
||||
version = "1.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
description = "FRAME nomination pools pallet"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
# parity
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
|
||||
|
||||
# FRAME
|
||||
frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
|
||||
frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
|
||||
sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
|
||||
sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
|
||||
sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" }
|
||||
sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" }
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
|
||||
sp-io = { version = "6.0.0", path = "../../primitives/io" }
|
||||
sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" }
|
||||
|
||||
[features]
|
||||
runtime-benchmarks = []
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
"sp-staking/std",
|
||||
"sp-core/std",
|
||||
]
|
||||
@@ -0,0 +1,55 @@
|
||||
[package]
|
||||
name = "pallet-nomination-pools-benchmarking"
|
||||
version = "1.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
description = "FRAME nomination pools pallet benchmarking"
|
||||
readme = "README.md"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
# parity
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
|
||||
|
||||
# FRAME
|
||||
frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" }
|
||||
frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" }
|
||||
frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" }
|
||||
frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" }
|
||||
pallet-bags-list = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../bags-list" }
|
||||
pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" }
|
||||
pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../", features = ["runtime-benchmarks"] }
|
||||
|
||||
# Substrate Primitives
|
||||
sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" }
|
||||
sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" }
|
||||
sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" }
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" }
|
||||
pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" }
|
||||
pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" }
|
||||
sp-core = { version = "6.0.0", path = "../../../primitives/core" }
|
||||
sp-io = { version = "6.0.0", path = "../../../primitives/io" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"frame-benchmarking/std",
|
||||
"frame-election-provider-support/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"pallet-bags-list/std",
|
||||
"pallet-staking/std",
|
||||
"pallet-nomination-pools/std",
|
||||
"sp-runtime/std",
|
||||
"sp-staking/std",
|
||||
"sp-std/std",
|
||||
"pallet-balances/std",
|
||||
]
|
||||
@@ -0,0 +1,639 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarks for the nomination pools coupled with the staking and bags list pallets.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
use frame_benchmarking::{account, frame_support::traits::Currency, vec, whitelist_account, Vec};
|
||||
use frame_election_provider_support::SortedListProvider;
|
||||
use frame_support::{ensure, traits::Get};
|
||||
use frame_system::RawOrigin as Origin;
|
||||
use pallet_nomination_pools::{
|
||||
BalanceOf, BondExtra, BondedPoolInner, BondedPools, ConfigOp, MaxPoolMembers,
|
||||
MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools,
|
||||
PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage,
|
||||
};
|
||||
use sp_runtime::traits::{Bounded, Zero};
|
||||
use sp_staking::{EraIndex, StakingInterface};
|
||||
// `frame_benchmarking::benchmarks!` macro needs this
|
||||
use pallet_nomination_pools::Call;
|
||||
|
||||
type CurrencyOf<T> = <T as pallet_nomination_pools::Config>::Currency;
|
||||
|
||||
const USER_SEED: u32 = 0;
|
||||
const MAX_SPANS: u32 = 100;
|
||||
|
||||
pub trait Config:
|
||||
pallet_nomination_pools::Config + pallet_staking::Config + pallet_bags_list::Config
|
||||
{
|
||||
}
|
||||
|
||||
pub struct Pallet<T: Config>(Pools<T>);
|
||||
|
||||
fn create_funded_user_with_balance<T: pallet_nomination_pools::Config>(
|
||||
string: &'static str,
|
||||
n: u32,
|
||||
balance: BalanceOf<T>,
|
||||
) -> T::AccountId {
|
||||
let user = account(string, n, USER_SEED);
|
||||
T::Currency::make_free_balance_be(&user, balance);
|
||||
user
|
||||
}
|
||||
|
||||
// Create a bonded pool account, bonding `balance` and giving the account `balance * 2` free
|
||||
// balance.
|
||||
fn create_pool_account<T: pallet_nomination_pools::Config>(
|
||||
n: u32,
|
||||
balance: BalanceOf<T>,
|
||||
) -> (T::AccountId, T::AccountId) {
|
||||
let ed = CurrencyOf::<T>::minimum_balance();
|
||||
let pool_creator: T::AccountId =
|
||||
create_funded_user_with_balance::<T>("pool_creator", n, ed + balance * 2u32.into());
|
||||
|
||||
Pools::<T>::create(
|
||||
Origin::Signed(pool_creator.clone()).into(),
|
||||
balance,
|
||||
pool_creator.clone(),
|
||||
pool_creator.clone(),
|
||||
pool_creator.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let pool_account = pallet_nomination_pools::BondedPools::<T>::iter()
|
||||
.find(|(_, bonded_pool)| bonded_pool.roles.depositor == pool_creator)
|
||||
.map(|(pool_id, _)| Pools::<T>::create_bonded_account(pool_id))
|
||||
.expect("pool_creator created a pool above");
|
||||
|
||||
(pool_creator, pool_account)
|
||||
}
|
||||
|
||||
fn vote_to_balance<T: pallet_nomination_pools::Config>(
|
||||
vote: u64,
|
||||
) -> Result<BalanceOf<T>, &'static str> {
|
||||
vote.try_into().map_err(|_| "could not convert u64 to Balance")
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
struct ListScenario<T: pallet_nomination_pools::Config> {
|
||||
/// Stash/Controller that is expected to be moved.
|
||||
origin1: T::AccountId,
|
||||
creator1: T::AccountId,
|
||||
dest_weight: BalanceOf<T>,
|
||||
origin1_member: Option<T::AccountId>,
|
||||
}
|
||||
|
||||
impl<T: Config> ListScenario<T> {
|
||||
/// An expensive scenario for bags-list implementation:
|
||||
///
|
||||
/// - the node to be updated (r) is the head of a bag that has at least one other node. The bag
|
||||
/// itself will need to be read and written to update its head. The node pointed to by r.next
|
||||
/// will need to be read and written as it will need to have its prev pointer updated. Note
|
||||
/// that there are two other worst case scenarios for bag removal: 1) the node is a tail and
|
||||
/// 2) the node is a middle node with prev and next; all scenarios end up with the same number
|
||||
/// of storage reads and writes.
|
||||
///
|
||||
/// - the destination bag has at least one node, which will need its next pointer updated.
|
||||
pub(crate) fn new(
|
||||
origin_weight: BalanceOf<T>,
|
||||
is_increase: bool,
|
||||
) -> Result<Self, &'static str> {
|
||||
ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0");
|
||||
|
||||
ensure!(
|
||||
pallet_nomination_pools::MaxPools::<T>::get().unwrap_or(0) >= 3,
|
||||
"must allow at least three pools for benchmarks"
|
||||
);
|
||||
|
||||
// Burn the entire issuance.
|
||||
let i = CurrencyOf::<T>::burn(CurrencyOf::<T>::total_issuance());
|
||||
sp_std::mem::forget(i);
|
||||
|
||||
// Create accounts with the origin weight
|
||||
let (pool_creator1, pool_origin1) = create_pool_account::<T>(USER_SEED + 1, origin_weight);
|
||||
T::StakingInterface::nominate(
|
||||
pool_origin1.clone(),
|
||||
// NOTE: these don't really need to be validators.
|
||||
vec![account("random_validator", 0, USER_SEED)],
|
||||
)?;
|
||||
|
||||
let (_, pool_origin2) = create_pool_account::<T>(USER_SEED + 2, origin_weight);
|
||||
T::StakingInterface::nominate(
|
||||
pool_origin2.clone(),
|
||||
vec![account("random_validator", 0, USER_SEED)].clone(),
|
||||
)?;
|
||||
|
||||
// Find a destination weight that will trigger the worst case scenario
|
||||
let dest_weight_as_vote = <T as pallet_staking::Config>::VoterList::score_update_worst_case(
|
||||
&pool_origin1,
|
||||
is_increase,
|
||||
);
|
||||
|
||||
let dest_weight: BalanceOf<T> =
|
||||
dest_weight_as_vote.try_into().map_err(|_| "could not convert u64 to Balance")?;
|
||||
|
||||
// Create an account with the worst case destination weight
|
||||
let (_, pool_dest1) = create_pool_account::<T>(USER_SEED + 3, dest_weight);
|
||||
T::StakingInterface::nominate(
|
||||
pool_dest1.clone(),
|
||||
vec![account("random_validator", 0, USER_SEED)],
|
||||
)?;
|
||||
|
||||
let weight_of = pallet_staking::Pallet::<T>::weight_of_fn();
|
||||
assert_eq!(vote_to_balance::<T>(weight_of(&pool_origin1)).unwrap(), origin_weight);
|
||||
assert_eq!(vote_to_balance::<T>(weight_of(&pool_origin2)).unwrap(), origin_weight);
|
||||
assert_eq!(vote_to_balance::<T>(weight_of(&pool_dest1)).unwrap(), dest_weight);
|
||||
|
||||
Ok(ListScenario {
|
||||
origin1: pool_origin1,
|
||||
creator1: pool_creator1,
|
||||
dest_weight,
|
||||
origin1_member: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn add_joiner(mut self, amount: BalanceOf<T>) -> Self {
|
||||
let amount = MinJoinBond::<T>::get()
|
||||
.max(CurrencyOf::<T>::minimum_balance())
|
||||
// Max `amount` with minimum thresholds for account balance and joining a pool
|
||||
// to ensure 1) the user can be created and 2) can join the pool
|
||||
.max(amount);
|
||||
|
||||
let joiner: T::AccountId = account("joiner", USER_SEED, 0);
|
||||
self.origin1_member = Some(joiner.clone());
|
||||
CurrencyOf::<T>::make_free_balance_be(&joiner, amount * 2u32.into());
|
||||
|
||||
let original_bonded = T::StakingInterface::active_stake(&self.origin1).unwrap();
|
||||
|
||||
// Unbond `amount` from the underlying pool account so when the member joins
|
||||
// we will maintain `current_bonded`.
|
||||
T::StakingInterface::unbond(self.origin1.clone(), amount)
|
||||
.expect("the pool was created in `Self::new`.");
|
||||
|
||||
// Account pool points for the unbonded balance.
|
||||
BondedPools::<T>::mutate(&1, |maybe_pool| {
|
||||
maybe_pool.as_mut().map(|pool| pool.points -= amount)
|
||||
});
|
||||
|
||||
Pools::<T>::join(Origin::Signed(joiner.clone()).into(), amount, 1).unwrap();
|
||||
|
||||
// Sanity check that the vote weight is still the same as the original bonded
|
||||
let weight_of = pallet_staking::Pallet::<T>::weight_of_fn();
|
||||
assert_eq!(vote_to_balance::<T>(weight_of(&self.origin1)).unwrap(), original_bonded);
|
||||
|
||||
// Sanity check the member was added correctly
|
||||
let member = PoolMembers::<T>::get(&joiner).unwrap();
|
||||
assert_eq!(member.points, amount);
|
||||
assert_eq!(member.pool_id, 1);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
frame_benchmarking::benchmarks! {
|
||||
join {
|
||||
let origin_weight = pallet_nomination_pools::MinCreateBond::<T>::get()
|
||||
.max(CurrencyOf::<T>::minimum_balance())
|
||||
* 2u32.into();
|
||||
|
||||
// setup the worst case list scenario.
|
||||
let scenario = ListScenario::<T>::new(origin_weight, true)?;
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&scenario.origin1).unwrap(),
|
||||
origin_weight
|
||||
);
|
||||
|
||||
let max_additional = scenario.dest_weight.clone() - origin_weight;
|
||||
let joiner_free = CurrencyOf::<T>::minimum_balance() + max_additional;
|
||||
|
||||
let joiner: T::AccountId
|
||||
= create_funded_user_with_balance::<T>("joiner", 0, joiner_free);
|
||||
|
||||
whitelist_account!(joiner);
|
||||
}: _(Origin::Signed(joiner.clone()), max_additional, 1)
|
||||
verify {
|
||||
assert_eq!(CurrencyOf::<T>::free_balance(&joiner), joiner_free - max_additional);
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&scenario.origin1).unwrap(),
|
||||
scenario.dest_weight
|
||||
);
|
||||
}
|
||||
|
||||
bond_extra_transfer {
|
||||
let origin_weight = pallet_nomination_pools::MinCreateBond::<T>::get()
|
||||
.max(CurrencyOf::<T>::minimum_balance())
|
||||
* 2u32.into();
|
||||
let scenario = ListScenario::<T>::new(origin_weight, true)?;
|
||||
let extra = scenario.dest_weight.clone() - origin_weight;
|
||||
|
||||
// creator of the src pool will bond-extra, bumping itself to dest bag.
|
||||
|
||||
}: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra))
|
||||
verify {
|
||||
assert!(
|
||||
T::StakingInterface::active_stake(&scenario.origin1).unwrap() >=
|
||||
scenario.dest_weight
|
||||
);
|
||||
}
|
||||
|
||||
bond_extra_reward {
|
||||
let origin_weight = pallet_nomination_pools::MinCreateBond::<T>::get()
|
||||
.max(CurrencyOf::<T>::minimum_balance())
|
||||
* 2u32.into();
|
||||
let scenario = ListScenario::<T>::new(origin_weight, true)?;
|
||||
let extra = (scenario.dest_weight.clone() - origin_weight).max(CurrencyOf::<T>::minimum_balance());
|
||||
|
||||
// transfer exactly `extra` to the depositor of the src pool (1),
|
||||
let reward_account1 = Pools::<T>::create_reward_account(1);
|
||||
assert!(extra >= CurrencyOf::<T>::minimum_balance());
|
||||
CurrencyOf::<T>::deposit_creating(&reward_account1, extra);
|
||||
|
||||
}: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::Rewards)
|
||||
verify {
|
||||
assert!(
|
||||
T::StakingInterface::active_stake(&scenario.origin1).unwrap() >=
|
||||
scenario.dest_weight
|
||||
);
|
||||
}
|
||||
|
||||
claim_payout {
|
||||
let origin_weight = pallet_nomination_pools::MinCreateBond::<T>::get().max(CurrencyOf::<T>::minimum_balance()) * 2u32.into();
|
||||
let ed = CurrencyOf::<T>::minimum_balance();
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, origin_weight);
|
||||
let reward_account = Pools::<T>::create_reward_account(1);
|
||||
|
||||
// Send funds to the reward account of the pool
|
||||
CurrencyOf::<T>::make_free_balance_be(&reward_account, ed + origin_weight);
|
||||
|
||||
// Sanity check
|
||||
assert_eq!(
|
||||
CurrencyOf::<T>::free_balance(&depositor),
|
||||
origin_weight
|
||||
);
|
||||
|
||||
whitelist_account!(depositor);
|
||||
}:_(Origin::Signed(depositor.clone()))
|
||||
verify {
|
||||
assert_eq!(
|
||||
CurrencyOf::<T>::free_balance(&depositor),
|
||||
origin_weight * 2u32.into()
|
||||
);
|
||||
assert_eq!(
|
||||
CurrencyOf::<T>::free_balance(&reward_account),
|
||||
ed + Zero::zero()
|
||||
);
|
||||
}
|
||||
|
||||
unbond {
|
||||
// The weight the nominator will start at. The value used here is expected to be
|
||||
// significantly higher than the first position in a list (e.g. the first bag threshold).
|
||||
let origin_weight = BalanceOf::<T>::try_from(952_994_955_240_703u128)
|
||||
.map_err(|_| "balance expected to be a u128")
|
||||
.unwrap();
|
||||
let scenario = ListScenario::<T>::new(origin_weight, false)?;
|
||||
let amount = origin_weight - scenario.dest_weight.clone();
|
||||
|
||||
let scenario = scenario.add_joiner(amount);
|
||||
let member_id = scenario.origin1_member.unwrap().clone();
|
||||
let all_points = PoolMembers::<T>::get(&member_id).unwrap().points;
|
||||
whitelist_account!(member_id);
|
||||
}: _(Origin::Signed(member_id.clone()), member_id.clone(), all_points)
|
||||
verify {
|
||||
let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap();
|
||||
// We at least went down to the destination bag
|
||||
assert!(bonded_after <= scenario.dest_weight.clone());
|
||||
let member = PoolMembers::<T>::get(
|
||||
&member_id
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
member.unbonding_eras.keys().cloned().collect::<Vec<_>>(),
|
||||
vec![0 + T::StakingInterface::bonding_duration()]
|
||||
);
|
||||
assert_eq!(
|
||||
member.unbonding_eras.values().cloned().collect::<Vec<_>>(),
|
||||
vec![all_points]
|
||||
);
|
||||
}
|
||||
|
||||
pool_withdraw_unbonded {
|
||||
let s in 0 .. MAX_SPANS;
|
||||
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, min_create_bond);
|
||||
|
||||
// Add a new member
|
||||
let min_join_bond = MinJoinBond::<T>::get().max(CurrencyOf::<T>::minimum_balance());
|
||||
let joiner = create_funded_user_with_balance::<T>("joiner", 0, min_join_bond * 2u32.into());
|
||||
Pools::<T>::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1)
|
||||
.unwrap();
|
||||
|
||||
// Sanity check join worked
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&pool_account).unwrap(),
|
||||
min_create_bond + min_join_bond
|
||||
);
|
||||
assert_eq!(CurrencyOf::<T>::free_balance(&joiner), min_join_bond);
|
||||
|
||||
// Unbond the new member
|
||||
Pools::<T>::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap();
|
||||
|
||||
// Sanity check that unbond worked
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&pool_account).unwrap(),
|
||||
min_create_bond
|
||||
);
|
||||
assert_eq!(pallet_staking::Ledger::<T>::get(&pool_account).unwrap().unlocking.len(), 1);
|
||||
// Set the current era
|
||||
pallet_staking::CurrentEra::<T>::put(EraIndex::max_value());
|
||||
|
||||
// Add `s` count of slashing spans to storage.
|
||||
pallet_staking::benchmarking::add_slashing_spans::<T>(&pool_account, s);
|
||||
whitelist_account!(pool_account);
|
||||
}: _(Origin::Signed(pool_account.clone()), 1, s)
|
||||
verify {
|
||||
// The joiners funds didn't change
|
||||
assert_eq!(CurrencyOf::<T>::free_balance(&joiner), min_join_bond);
|
||||
// The unlocking chunk was removed
|
||||
assert_eq!(pallet_staking::Ledger::<T>::get(pool_account).unwrap().unlocking.len(), 0);
|
||||
}
|
||||
|
||||
withdraw_unbonded_update {
|
||||
let s in 0 .. MAX_SPANS;
|
||||
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, min_create_bond);
|
||||
|
||||
// Add a new member
|
||||
let min_join_bond = MinJoinBond::<T>::get().max(CurrencyOf::<T>::minimum_balance());
|
||||
let joiner = create_funded_user_with_balance::<T>("joiner", 0, min_join_bond * 2u32.into());
|
||||
Pools::<T>::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1)
|
||||
.unwrap();
|
||||
|
||||
// Sanity check join worked
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&pool_account).unwrap(),
|
||||
min_create_bond + min_join_bond
|
||||
);
|
||||
assert_eq!(CurrencyOf::<T>::free_balance(&joiner), min_join_bond);
|
||||
|
||||
// Unbond the new member
|
||||
pallet_staking::CurrentEra::<T>::put(0);
|
||||
Pools::<T>::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap();
|
||||
|
||||
// Sanity check that unbond worked
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&pool_account).unwrap(),
|
||||
min_create_bond
|
||||
);
|
||||
assert_eq!(pallet_staking::Ledger::<T>::get(&pool_account).unwrap().unlocking.len(), 1);
|
||||
|
||||
// Set the current era to ensure we can withdraw unbonded funds
|
||||
pallet_staking::CurrentEra::<T>::put(EraIndex::max_value());
|
||||
|
||||
pallet_staking::benchmarking::add_slashing_spans::<T>(&pool_account, s);
|
||||
whitelist_account!(joiner);
|
||||
}: withdraw_unbonded(Origin::Signed(joiner.clone()), joiner.clone(), s)
|
||||
verify {
|
||||
assert_eq!(
|
||||
CurrencyOf::<T>::free_balance(&joiner),
|
||||
min_join_bond * 2u32.into()
|
||||
);
|
||||
// The unlocking chunk was removed
|
||||
assert_eq!(pallet_staking::Ledger::<T>::get(&pool_account).unwrap().unlocking.len(), 0);
|
||||
}
|
||||
|
||||
withdraw_unbonded_kill {
|
||||
let s in 0 .. MAX_SPANS;
|
||||
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, min_create_bond);
|
||||
|
||||
// We set the pool to the destroying state so the depositor can leave
|
||||
BondedPools::<T>::try_mutate(&1, |maybe_bonded_pool| {
|
||||
maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| {
|
||||
bonded_pool.state = PoolState::Destroying;
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Unbond the creator
|
||||
pallet_staking::CurrentEra::<T>::put(0);
|
||||
// Simulate some rewards so we can check if the rewards storage is cleaned up. We check this
|
||||
// here to ensure the complete flow for destroying a pool works - the reward pool account
|
||||
// should never exist by time the depositor withdraws so we test that it gets cleaned
|
||||
// up when unbonding.
|
||||
let reward_account = Pools::<T>::create_reward_account(1);
|
||||
assert!(frame_system::Account::<T>::contains_key(&reward_account));
|
||||
Pools::<T>::fully_unbond(Origin::Signed(depositor.clone()).into(), depositor.clone()).unwrap();
|
||||
|
||||
// Sanity check that unbond worked
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&pool_account).unwrap(),
|
||||
Zero::zero()
|
||||
);
|
||||
assert_eq!(
|
||||
CurrencyOf::<T>::free_balance(&pool_account),
|
||||
min_create_bond
|
||||
);
|
||||
assert_eq!(pallet_staking::Ledger::<T>::get(&pool_account).unwrap().unlocking.len(), 1);
|
||||
|
||||
// Set the current era to ensure we can withdraw unbonded funds
|
||||
pallet_staking::CurrentEra::<T>::put(EraIndex::max_value());
|
||||
|
||||
// Some last checks that storage items we expect to get cleaned up are present
|
||||
assert!(pallet_staking::Ledger::<T>::contains_key(&pool_account));
|
||||
assert!(BondedPools::<T>::contains_key(&1));
|
||||
assert!(SubPoolsStorage::<T>::contains_key(&1));
|
||||
assert!(RewardPools::<T>::contains_key(&1));
|
||||
assert!(PoolMembers::<T>::contains_key(&depositor));
|
||||
assert!(frame_system::Account::<T>::contains_key(&reward_account));
|
||||
|
||||
whitelist_account!(depositor);
|
||||
}: withdraw_unbonded(Origin::Signed(depositor.clone()), depositor.clone(), s)
|
||||
verify {
|
||||
// Pool removal worked
|
||||
assert!(!pallet_staking::Ledger::<T>::contains_key(&pool_account));
|
||||
assert!(!BondedPools::<T>::contains_key(&1));
|
||||
assert!(!SubPoolsStorage::<T>::contains_key(&1));
|
||||
assert!(!RewardPools::<T>::contains_key(&1));
|
||||
assert!(!PoolMembers::<T>::contains_key(&depositor));
|
||||
assert!(!frame_system::Account::<T>::contains_key(&pool_account));
|
||||
assert!(!frame_system::Account::<T>::contains_key(&reward_account));
|
||||
|
||||
// Funds where transferred back correctly
|
||||
assert_eq!(
|
||||
CurrencyOf::<T>::free_balance(&depositor),
|
||||
// gets bond back + rewards collecting when unbonding
|
||||
min_create_bond * 2u32.into() + CurrencyOf::<T>::minimum_balance()
|
||||
);
|
||||
}
|
||||
|
||||
create {
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
let depositor: T::AccountId = account("depositor", USER_SEED, 0);
|
||||
|
||||
// Give the depositor some balance to bond
|
||||
CurrencyOf::<T>::make_free_balance_be(&depositor, min_create_bond * 2u32.into());
|
||||
|
||||
// Make sure no pools exist as a pre-condition for our verify checks
|
||||
assert_eq!(RewardPools::<T>::count(), 0);
|
||||
assert_eq!(BondedPools::<T>::count(), 0);
|
||||
|
||||
whitelist_account!(depositor);
|
||||
}: _(
|
||||
Origin::Signed(depositor.clone()),
|
||||
min_create_bond,
|
||||
depositor.clone(),
|
||||
depositor.clone(),
|
||||
depositor.clone()
|
||||
)
|
||||
verify {
|
||||
assert_eq!(RewardPools::<T>::count(), 1);
|
||||
assert_eq!(BondedPools::<T>::count(), 1);
|
||||
let (_, new_pool) = BondedPools::<T>::iter().next().unwrap();
|
||||
assert_eq!(
|
||||
new_pool,
|
||||
BondedPoolInner {
|
||||
points: min_create_bond,
|
||||
state: PoolState::Open,
|
||||
member_counter: 1,
|
||||
roles: PoolRoles {
|
||||
depositor: depositor.clone(),
|
||||
root: depositor.clone(),
|
||||
nominator: depositor.clone(),
|
||||
state_toggler: depositor.clone(),
|
||||
},
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&Pools::<T>::create_bonded_account(1)),
|
||||
Some(min_create_bond)
|
||||
);
|
||||
}
|
||||
|
||||
nominate {
|
||||
let n in 1 .. T::MaxNominations::get();
|
||||
|
||||
// Create a pool
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, min_create_bond);
|
||||
|
||||
// Create some accounts to nominate. For the sake of benchmarking they don't need to be
|
||||
// actual validators
|
||||
let validators: Vec<_> = (0..n)
|
||||
.map(|i| account("stash", USER_SEED, i))
|
||||
.collect();
|
||||
|
||||
whitelist_account!(depositor);
|
||||
}:_(Origin::Signed(depositor.clone()), 1, validators)
|
||||
verify {
|
||||
assert_eq!(RewardPools::<T>::count(), 1);
|
||||
assert_eq!(BondedPools::<T>::count(), 1);
|
||||
let (_, new_pool) = BondedPools::<T>::iter().next().unwrap();
|
||||
assert_eq!(
|
||||
new_pool,
|
||||
BondedPoolInner {
|
||||
points: min_create_bond,
|
||||
state: PoolState::Open,
|
||||
member_counter: 1,
|
||||
roles: PoolRoles {
|
||||
depositor: depositor.clone(),
|
||||
root: depositor.clone(),
|
||||
nominator: depositor.clone(),
|
||||
state_toggler: depositor.clone(),
|
||||
}
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
T::StakingInterface::active_stake(&Pools::<T>::create_bonded_account(1)),
|
||||
Some(min_create_bond)
|
||||
);
|
||||
}
|
||||
|
||||
set_state {
|
||||
// Create a pool
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, min_create_bond);
|
||||
BondedPools::<T>::mutate(&1, |maybe_pool| {
|
||||
// Force the pool into an invalid state
|
||||
maybe_pool.as_mut().map(|mut pool| pool.points = min_create_bond * 10u32.into());
|
||||
});
|
||||
|
||||
let caller = account("caller", 0, USER_SEED);
|
||||
whitelist_account!(caller);
|
||||
}:_(Origin::Signed(caller), 1, PoolState::Destroying)
|
||||
verify {
|
||||
assert_eq!(BondedPools::<T>::get(1).unwrap().state, PoolState::Destroying);
|
||||
}
|
||||
|
||||
set_metadata {
|
||||
let n in 1 .. <T as pallet_nomination_pools::Config>::MaxMetadataLen::get();
|
||||
|
||||
// Create a pool
|
||||
let min_create_bond = MinCreateBond::<T>::get()
|
||||
.max(T::StakingInterface::minimum_bond())
|
||||
.max(CurrencyOf::<T>::minimum_balance());
|
||||
let (depositor, pool_account) = create_pool_account::<T>(0, min_create_bond);
|
||||
|
||||
// Create metadata of the max possible size
|
||||
let metadata: Vec<u8> = (0..n).map(|_| 42).collect();
|
||||
|
||||
whitelist_account!(depositor);
|
||||
}:_(Origin::Signed(depositor), 1, metadata.clone())
|
||||
verify {
|
||||
assert_eq!(Metadata::<T>::get(&1), metadata);
|
||||
}
|
||||
|
||||
set_configs {
|
||||
}:_(
|
||||
Origin::Root,
|
||||
ConfigOp::Set(BalanceOf::<T>::max_value()),
|
||||
ConfigOp::Set(BalanceOf::<T>::max_value()),
|
||||
ConfigOp::Set(u32::MAX),
|
||||
ConfigOp::Set(u32::MAX),
|
||||
ConfigOp::Set(u32::MAX)
|
||||
) verify {
|
||||
assert_eq!(MinJoinBond::<T>::get(), BalanceOf::<T>::max_value());
|
||||
assert_eq!(MinCreateBond::<T>::get(), BalanceOf::<T>::max_value());
|
||||
assert_eq!(MaxPools::<T>::get(), Some(u32::MAX));
|
||||
assert_eq!(MaxPoolMembers::<T>::get(), Some(u32::MAX));
|
||||
assert_eq!(MaxPoolMembersPerPool::<T>::get(), Some(u32::MAX));
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::mock::new_test_ext(),
|
||||
crate::mock::Runtime
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use frame_election_provider_support::VoteWeight;
|
||||
use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId};
|
||||
use sp_runtime::traits::{Convert, IdentityLookup};
|
||||
|
||||
type AccountId = u128;
|
||||
type AccountIndex = u32;
|
||||
type BlockNumber = u64;
|
||||
type Balance = u128;
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type Origin = Origin;
|
||||
type Index = AccountIndex;
|
||||
type BlockNumber = BlockNumber;
|
||||
type Call = Call;
|
||||
type Hash = sp_core::H256;
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = sp_runtime::testing::Header;
|
||||
type Event = Event;
|
||||
type BlockHashCount = ();
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pallet_balances::AccountData<Balance>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
impl pallet_timestamp::Config for Runtime {
|
||||
type Moment = u64;
|
||||
type OnTimestampSet = ();
|
||||
type MinimumPeriod = ConstU64<5>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ExistentialDeposit: Balance = 10;
|
||||
}
|
||||
impl pallet_balances::Config for Runtime {
|
||||
type MaxLocks = ();
|
||||
type MaxReserves = ();
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type Balance = Balance;
|
||||
type Event = Event;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
impl pallet_staking::Config for Runtime {
|
||||
type MaxNominations = ConstU32<16>;
|
||||
type Currency = Balances;
|
||||
type CurrencyBalance = Balance;
|
||||
type UnixTime = pallet_timestamp::Pallet<Self>;
|
||||
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
||||
type RewardRemainder = ();
|
||||
type Event = Event;
|
||||
type Slash = ();
|
||||
type Reward = ();
|
||||
type SessionsPerEra = ();
|
||||
type SlashDeferDuration = ();
|
||||
type SlashCancelOrigin = frame_system::EnsureRoot<Self::AccountId>;
|
||||
type BondingDuration = ConstU32<3>;
|
||||
type SessionInterface = ();
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type NextNewSession = ();
|
||||
type MaxNominatorRewardedPerValidator = ConstU32<64>;
|
||||
type OffendingValidatorsThreshold = ();
|
||||
type ElectionProvider =
|
||||
frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>;
|
||||
type GenesisElectionProvider = Self::ElectionProvider;
|
||||
type VoterList = pallet_bags_list::Pallet<Self>;
|
||||
type MaxUnlockingChunks = ConstU32<32>;
|
||||
type OnStakerSlash = Pools;
|
||||
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000];
|
||||
}
|
||||
|
||||
impl pallet_bags_list::Config for Runtime {
|
||||
type Event = Event;
|
||||
type WeightInfo = ();
|
||||
type BagThresholds = BagThresholds;
|
||||
type ScoreProvider = Staking;
|
||||
type Score = VoteWeight;
|
||||
}
|
||||
|
||||
pub struct BalanceToU256;
|
||||
impl Convert<Balance, sp_core::U256> for BalanceToU256 {
|
||||
fn convert(n: Balance) -> sp_core::U256 {
|
||||
n.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct U256ToBalance;
|
||||
impl Convert<sp_core::U256, Balance> for U256ToBalance {
|
||||
fn convert(n: sp_core::U256) -> Balance {
|
||||
n.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static PostUnbondingPoolsWindow: u32 = 10;
|
||||
pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
|
||||
}
|
||||
|
||||
impl pallet_nomination_pools::Config for Runtime {
|
||||
type Event = Event;
|
||||
type WeightInfo = ();
|
||||
type Currency = Balances;
|
||||
type BalanceToU256 = BalanceToU256;
|
||||
type U256ToBalance = U256ToBalance;
|
||||
type StakingInterface = Staking;
|
||||
type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
|
||||
type MaxMetadataLen = ConstU32<256>;
|
||||
type MaxUnbonding = ConstU32<8>;
|
||||
type PalletId = PoolsPalletId;
|
||||
}
|
||||
|
||||
impl crate::Config for Runtime {}
|
||||
|
||||
impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Runtime
|
||||
where
|
||||
Call: From<LocalCall>,
|
||||
{
|
||||
type OverarchingCall = Call;
|
||||
type Extrinsic = UncheckedExtrinsic;
|
||||
}
|
||||
|
||||
type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Event<T>},
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
BagsList: pallet_bags_list::{Pallet, Call, Storage, Event<T>},
|
||||
Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event<T>},
|
||||
}
|
||||
);
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let mut storage = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||
let _ = pallet_nomination_pools::GenesisConfig::<Runtime> {
|
||||
min_join_bond: 2,
|
||||
min_create_bond: 2,
|
||||
max_pools: Some(3),
|
||||
max_members_per_pool: Some(3),
|
||||
max_members: Some(3 * 3),
|
||||
}
|
||||
.assimilate_storage(&mut storage);
|
||||
sp_io::TestExternalities::from(storage)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,309 @@
|
||||
use super::*;
|
||||
use crate::{self as pools};
|
||||
use frame_support::{assert_ok, parameter_types, PalletId};
|
||||
use frame_system::RawOrigin;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub type AccountId = u128;
|
||||
pub type Balance = u128;
|
||||
|
||||
// Ext builder creates a pool with id 1.
|
||||
pub fn default_bonded_account() -> AccountId {
|
||||
Pools::create_bonded_account(1)
|
||||
}
|
||||
|
||||
// Ext builder creates a pool with id 1.
|
||||
pub fn default_reward_account() -> AccountId {
|
||||
Pools::create_reward_account(1)
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static CurrentEra: EraIndex = 0;
|
||||
pub static BondingDuration: EraIndex = 3;
|
||||
static BondedBalanceMap: HashMap<AccountId, Balance> = Default::default();
|
||||
static UnbondingBalanceMap: HashMap<AccountId, Balance> = Default::default();
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub static MaxUnbonding: u32 = 8;
|
||||
pub static Nominations: Vec<AccountId> = vec![];
|
||||
}
|
||||
|
||||
pub struct StakingMock;
|
||||
impl StakingMock {
|
||||
pub(crate) fn set_bonded_balance(who: AccountId, bonded: Balance) {
|
||||
BONDED_BALANCE_MAP.with(|m| m.borrow_mut().insert(who, bonded));
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_staking::StakingInterface for StakingMock {
|
||||
type Balance = Balance;
|
||||
type AccountId = AccountId;
|
||||
|
||||
fn minimum_bond() -> Self::Balance {
|
||||
10
|
||||
}
|
||||
|
||||
fn current_era() -> EraIndex {
|
||||
CurrentEra::get()
|
||||
}
|
||||
|
||||
fn bonding_duration() -> EraIndex {
|
||||
BondingDuration::get()
|
||||
}
|
||||
|
||||
fn active_stake(who: &Self::AccountId) -> Option<Self::Balance> {
|
||||
BondedBalanceMap::get().get(who).map(|v| *v)
|
||||
}
|
||||
|
||||
fn total_stake(who: &Self::AccountId) -> Option<Self::Balance> {
|
||||
match (
|
||||
UnbondingBalanceMap::get().get(who).map(|v| *v),
|
||||
BondedBalanceMap::get().get(who).map(|v| *v),
|
||||
) {
|
||||
(None, None) => None,
|
||||
(Some(v), None) | (None, Some(v)) => Some(v),
|
||||
(Some(a), Some(b)) => Some(a + b),
|
||||
}
|
||||
}
|
||||
|
||||
fn bond_extra(who: Self::AccountId, extra: Self::Balance) -> DispatchResult {
|
||||
BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() += extra);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unbond(who: Self::AccountId, amount: Self::Balance) -> DispatchResult {
|
||||
BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() -= amount);
|
||||
UNBONDING_BALANCE_MAP
|
||||
.with(|m| *m.borrow_mut().entry(who).or_insert(Self::Balance::zero()) += amount);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result<u64, DispatchError> {
|
||||
// Simulates removing unlocking chunks and only having the bonded balance locked
|
||||
let _maybe_new_free = UNBONDING_BALANCE_MAP.with(|m| m.borrow_mut().remove(&who));
|
||||
|
||||
Ok(100)
|
||||
}
|
||||
|
||||
fn bond(
|
||||
stash: Self::AccountId,
|
||||
_: Self::AccountId,
|
||||
value: Self::Balance,
|
||||
_: Self::AccountId,
|
||||
) -> DispatchResult {
|
||||
StakingMock::set_bonded_balance(stash, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn nominate(_: Self::AccountId, nominations: Vec<Self::AccountId>) -> DispatchResult {
|
||||
Nominations::set(nominations);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type SS58Prefix = ();
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Call = Call;
|
||||
type Hash = sp_core::H256;
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
|
||||
type Header = sp_runtime::testing::Header;
|
||||
type Event = Event;
|
||||
type BlockHashCount = ();
|
||||
type DbWeight = ();
|
||||
type BlockLength = ();
|
||||
type BlockWeights = ();
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pallet_balances::AccountData<Balance>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = frame_support::traits::ConstU32<16>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static ExistentialDeposit: Balance = 5;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for Runtime {
|
||||
type MaxLocks = frame_support::traits::ConstU32<1024>;
|
||||
type MaxReserves = ();
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type Balance = Balance;
|
||||
type Event = Event;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
pub struct BalanceToU256;
|
||||
impl Convert<Balance, U256> for BalanceToU256 {
|
||||
fn convert(n: Balance) -> U256 {
|
||||
n.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct U256ToBalance;
|
||||
impl Convert<U256, Balance> for U256ToBalance {
|
||||
fn convert(n: U256) -> Balance {
|
||||
n.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static PostUnbondingPoolsWindow: u32 = 2;
|
||||
pub static MaxMetadataLen: u32 = 2;
|
||||
pub static CheckLevel: u8 = 255;
|
||||
pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
|
||||
}
|
||||
impl pools::Config for Runtime {
|
||||
type Event = Event;
|
||||
type WeightInfo = ();
|
||||
type Currency = Balances;
|
||||
type BalanceToU256 = BalanceToU256;
|
||||
type U256ToBalance = U256ToBalance;
|
||||
type StakingInterface = StakingMock;
|
||||
type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow;
|
||||
type PalletId = PoolsPalletId;
|
||||
type MaxMetadataLen = MaxMetadataLen;
|
||||
type MaxUnbonding = MaxUnbonding;
|
||||
}
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
|
||||
type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Storage, Event<T>, Config},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Pools: pools::{Pallet, Call, Storage, Event<T>},
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExtBuilder {
|
||||
members: Vec<(AccountId, Balance)>,
|
||||
}
|
||||
|
||||
impl ExtBuilder {
|
||||
// Add members to pool 0.
|
||||
pub(crate) fn add_members(mut self, members: Vec<(AccountId, Balance)>) -> Self {
|
||||
self.members = members;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn ed(self, ed: Balance) -> Self {
|
||||
ExistentialDeposit::set(ed);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_check(self, level: u8) -> Self {
|
||||
CheckLevel::set(level);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> sp_io::TestExternalities {
|
||||
let mut storage =
|
||||
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||
|
||||
let _ = crate::GenesisConfig::<Runtime> {
|
||||
min_join_bond: 2,
|
||||
min_create_bond: 2,
|
||||
max_pools: Some(2),
|
||||
max_members_per_pool: Some(3),
|
||||
max_members: Some(4),
|
||||
}
|
||||
.assimilate_storage(&mut storage);
|
||||
|
||||
let mut ext = sp_io::TestExternalities::from(storage);
|
||||
|
||||
ext.execute_with(|| {
|
||||
// for events to be deposited.
|
||||
frame_system::Pallet::<Runtime>::set_block_number(1);
|
||||
|
||||
// make a pool
|
||||
let amount_to_bond = <Runtime as pools::Config>::StakingInterface::minimum_bond();
|
||||
Balances::make_free_balance_be(&10, amount_to_bond * 2);
|
||||
assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902));
|
||||
|
||||
let last_pool = LastPoolId::<Runtime>::get();
|
||||
for (account_id, bonded) in self.members {
|
||||
Balances::make_free_balance_be(&account_id, bonded * 2);
|
||||
assert_ok!(Pools::join(RawOrigin::Signed(account_id).into(), bonded, last_pool));
|
||||
}
|
||||
});
|
||||
|
||||
ext
|
||||
}
|
||||
|
||||
pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
|
||||
self.build().execute_with(|| {
|
||||
test();
|
||||
Pools::sanity_checks(CheckLevel::get()).unwrap();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) -> Result<(), ()> {
|
||||
BondedPools::<Runtime>::try_mutate(pool_id, |maybe_bonded_pool| {
|
||||
maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| {
|
||||
bonded_pool.state = state;
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
static ObservedEvents: usize = 0;
|
||||
}
|
||||
|
||||
/// All events of this pallet.
|
||||
pub(crate) fn pool_events_since_last_call() -> Vec<super::Event<Runtime>> {
|
||||
let events = System::events()
|
||||
.into_iter()
|
||||
.map(|r| r.event)
|
||||
.filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None })
|
||||
.collect::<Vec<_>>();
|
||||
let already_seen = ObservedEvents::get();
|
||||
ObservedEvents::set(events.len());
|
||||
events.into_iter().skip(already_seen).collect()
|
||||
}
|
||||
|
||||
/// Same as `fully_unbond`, in permissioned setting.
|
||||
pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult {
|
||||
let points = PoolMembers::<Runtime>::get(&member)
|
||||
.map(|d| d.active_points())
|
||||
.unwrap_or_default();
|
||||
Pools::unbond(Origin::signed(member), member, points)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn u256_to_balance_convert_works() {
|
||||
assert_eq!(U256ToBalance::convert(0u32.into()), Zero::zero());
|
||||
assert_eq!(U256ToBalance::convert(Balance::max_value().into()), Balance::max_value())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn u256_to_balance_convert_panics_correctly() {
|
||||
U256ToBalance::convert(U256::from(Balance::max_value()).saturating_add(1u32.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn balance_to_u256_convert_works() {
|
||||
assert_eq!(BalanceToU256::convert(0u32.into()), U256::zero());
|
||||
assert_eq!(BalanceToU256::convert(Balance::max_value()), Balance::max_value().into())
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,482 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Autogenerated weights for pallet_nomination_pools
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-04-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// target/production/substrate
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=pallet_nomination_pools
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./frame/nomination-pools/src/weights.rs
|
||||
// --template=./.maintain/frame-weight-template.hbs
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_nomination_pools.
|
||||
pub trait WeightInfo {
|
||||
fn join() -> Weight;
|
||||
fn bond_extra_transfer() -> Weight;
|
||||
fn bond_extra_reward() -> Weight;
|
||||
fn claim_payout() -> Weight;
|
||||
fn unbond() -> Weight;
|
||||
fn pool_withdraw_unbonded(s: u32, ) -> Weight;
|
||||
fn withdraw_unbonded_update(s: u32, ) -> Weight;
|
||||
fn withdraw_unbonded_kill(s: u32, ) -> Weight;
|
||||
fn create() -> Weight;
|
||||
fn nominate(n: u32, ) -> Weight;
|
||||
fn set_state() -> Weight;
|
||||
fn set_metadata(n: u32, ) -> Weight;
|
||||
fn set_configs() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for pallet_nomination_pools using the Substrate node and recommended hardware.
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools MinJoinBond (r:1 w:0)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:0)
|
||||
// Storage: System Account (r:2 w:1)
|
||||
// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0)
|
||||
// Storage: NominationPools MaxPoolMembers (r:1 w:0)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:3 w:3)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
fn join() -> Weight {
|
||||
(117_870_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(18 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(12 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:2 w:2)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:3 w:3)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
fn bond_extra_transfer() -> Weight {
|
||||
(110_176_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(14 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(13 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:3 w:3)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:2 w:2)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
fn bond_extra_reward() -> Weight {
|
||||
(122_829_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(14 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(13 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:1 w:1)
|
||||
fn claim_payout() -> Weight {
|
||||
(50_094_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(5 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:2 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Nominators (r:1 w:0)
|
||||
// Storage: Staking MinNominatorBond (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:3 w:3)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
// Storage: NominationPools SubPoolsStorage (r:1 w:1)
|
||||
// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1)
|
||||
fn unbond() -> Weight {
|
||||
(119_288_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(19 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:0)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
fn pool_withdraw_unbonded(s: u32, ) -> Weight {
|
||||
(39_986_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((50_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools SubPoolsStorage (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: System Account (r:1 w:1)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
fn withdraw_unbonded_update(s: u32, ) -> Weight {
|
||||
(76_897_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((48_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(9 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(8 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools SubPoolsStorage (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:1)
|
||||
// Storage: Staking SlashingSpans (r:1 w:0)
|
||||
// Storage: Staking Validators (r:1 w:0)
|
||||
// Storage: Staking Nominators (r:1 w:0)
|
||||
// Storage: System Account (r:2 w:2)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools ReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: NominationPools CounterForRewardPools (r:1 w:1)
|
||||
// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1)
|
||||
// Storage: NominationPools CounterForBondedPools (r:1 w:1)
|
||||
// Storage: Staking Payee (r:0 w:1)
|
||||
fn withdraw_unbonded_kill(_s: u32, ) -> Weight {
|
||||
(135_837_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(20 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(17 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: Staking MinNominatorBond (r:1 w:0)
|
||||
// Storage: NominationPools MinCreateBond (r:1 w:0)
|
||||
// Storage: NominationPools MinJoinBond (r:1 w:0)
|
||||
// Storage: NominationPools MaxPools (r:1 w:0)
|
||||
// Storage: NominationPools CounterForBondedPools (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools LastPoolId (r:1 w:1)
|
||||
// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0)
|
||||
// Storage: NominationPools MaxPoolMembers (r:1 w:0)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
// Storage: System Account (r:2 w:2)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Staking HistoryDepth (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: NominationPools CounterForRewardPools (r:1 w:1)
|
||||
// Storage: NominationPools ReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: Staking Payee (r:0 w:1)
|
||||
fn create() -> Weight {
|
||||
(129_265_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(16 as Weight))
|
||||
}
|
||||
// Storage: NominationPools BondedPools (r:1 w:0)
|
||||
// Storage: Staking Ledger (r:1 w:0)
|
||||
// Storage: Staking MinNominatorBond (r:1 w:0)
|
||||
// Storage: Staking Nominators (r:1 w:1)
|
||||
// Storage: Staking MaxNominatorsCount (r:1 w:0)
|
||||
// Storage: Staking Validators (r:2 w:0)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: BagsList ListNodes (r:1 w:1)
|
||||
// Storage: BagsList ListBags (r:1 w:1)
|
||||
// Storage: BagsList CounterForListNodes (r:1 w:1)
|
||||
// Storage: Staking CounterForNominators (r:1 w:1)
|
||||
fn nominate(n: u32, ) -> Weight {
|
||||
(45_546_000 as Weight)
|
||||
// Standard Error: 11_000
|
||||
.saturating_add((2_075_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(12 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(5 as Weight))
|
||||
}
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:0)
|
||||
fn set_state() -> Weight {
|
||||
(23_256_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
// Storage: NominationPools BondedPools (r:1 w:0)
|
||||
// Storage: NominationPools Metadata (r:1 w:1)
|
||||
// Storage: NominationPools CounterForMetadata (r:1 w:1)
|
||||
fn set_metadata(n: u32, ) -> Weight {
|
||||
(10_893_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((1_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
// Storage: NominationPools MinJoinBond (r:0 w:1)
|
||||
// Storage: NominationPools MaxPoolMembers (r:0 w:1)
|
||||
// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1)
|
||||
// Storage: NominationPools MinCreateBond (r:0 w:1)
|
||||
// Storage: NominationPools MaxPools (r:0 w:1)
|
||||
fn set_configs() -> Weight {
|
||||
(2_793_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().writes(5 as Weight))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools MinJoinBond (r:1 w:0)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:0)
|
||||
// Storage: System Account (r:2 w:1)
|
||||
// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0)
|
||||
// Storage: NominationPools MaxPoolMembers (r:1 w:0)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:3 w:3)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
fn join() -> Weight {
|
||||
(117_870_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(18 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(12 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:2 w:2)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:3 w:3)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
fn bond_extra_transfer() -> Weight {
|
||||
(110_176_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(14 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(13 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:3 w:3)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:2 w:2)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
fn bond_extra_reward() -> Weight {
|
||||
(122_829_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(14 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(13 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:1 w:1)
|
||||
fn claim_payout() -> Weight {
|
||||
(50_094_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: System Account (r:2 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Nominators (r:1 w:0)
|
||||
// Storage: Staking MinNominatorBond (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: BagsList ListNodes (r:3 w:3)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: BagsList ListBags (r:2 w:2)
|
||||
// Storage: NominationPools SubPoolsStorage (r:1 w:1)
|
||||
// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1)
|
||||
fn unbond() -> Weight {
|
||||
(119_288_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(19 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:0)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
fn pool_withdraw_unbonded(s: u32, ) -> Weight {
|
||||
(39_986_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((50_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools SubPoolsStorage (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: System Account (r:1 w:1)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
fn withdraw_unbonded_update(s: u32, ) -> Weight {
|
||||
(76_897_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((48_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(9 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(8 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: NominationPools SubPoolsStorage (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:1)
|
||||
// Storage: Staking SlashingSpans (r:1 w:0)
|
||||
// Storage: Staking Validators (r:1 w:0)
|
||||
// Storage: Staking Nominators (r:1 w:0)
|
||||
// Storage: System Account (r:2 w:2)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools ReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: NominationPools CounterForRewardPools (r:1 w:1)
|
||||
// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1)
|
||||
// Storage: NominationPools CounterForBondedPools (r:1 w:1)
|
||||
// Storage: Staking Payee (r:0 w:1)
|
||||
fn withdraw_unbonded_kill(_s: u32, ) -> Weight {
|
||||
(135_837_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(20 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(17 as Weight))
|
||||
}
|
||||
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
|
||||
// Storage: Staking MinNominatorBond (r:1 w:0)
|
||||
// Storage: NominationPools MinCreateBond (r:1 w:0)
|
||||
// Storage: NominationPools MinJoinBond (r:1 w:0)
|
||||
// Storage: NominationPools MaxPools (r:1 w:0)
|
||||
// Storage: NominationPools CounterForBondedPools (r:1 w:1)
|
||||
// Storage: NominationPools PoolMembers (r:1 w:1)
|
||||
// Storage: NominationPools LastPoolId (r:1 w:1)
|
||||
// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0)
|
||||
// Storage: NominationPools MaxPoolMembers (r:1 w:0)
|
||||
// Storage: NominationPools CounterForPoolMembers (r:1 w:1)
|
||||
// Storage: System Account (r:2 w:2)
|
||||
// Storage: Staking Ledger (r:1 w:1)
|
||||
// Storage: Staking Bonded (r:1 w:1)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Staking HistoryDepth (r:1 w:0)
|
||||
// Storage: Balances Locks (r:1 w:1)
|
||||
// Storage: NominationPools RewardPools (r:1 w:1)
|
||||
// Storage: NominationPools CounterForRewardPools (r:1 w:1)
|
||||
// Storage: NominationPools ReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1)
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: Staking Payee (r:0 w:1)
|
||||
fn create() -> Weight {
|
||||
(129_265_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(16 as Weight))
|
||||
}
|
||||
// Storage: NominationPools BondedPools (r:1 w:0)
|
||||
// Storage: Staking Ledger (r:1 w:0)
|
||||
// Storage: Staking MinNominatorBond (r:1 w:0)
|
||||
// Storage: Staking Nominators (r:1 w:1)
|
||||
// Storage: Staking MaxNominatorsCount (r:1 w:0)
|
||||
// Storage: Staking Validators (r:2 w:0)
|
||||
// Storage: Staking CurrentEra (r:1 w:0)
|
||||
// Storage: Staking Bonded (r:1 w:0)
|
||||
// Storage: BagsList ListNodes (r:1 w:1)
|
||||
// Storage: BagsList ListBags (r:1 w:1)
|
||||
// Storage: BagsList CounterForListNodes (r:1 w:1)
|
||||
// Storage: Staking CounterForNominators (r:1 w:1)
|
||||
fn nominate(n: u32, ) -> Weight {
|
||||
(45_546_000 as Weight)
|
||||
// Standard Error: 11_000
|
||||
.saturating_add((2_075_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(12 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
|
||||
}
|
||||
// Storage: NominationPools BondedPools (r:1 w:1)
|
||||
// Storage: Staking Ledger (r:1 w:0)
|
||||
fn set_state() -> Weight {
|
||||
(23_256_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
// Storage: NominationPools BondedPools (r:1 w:0)
|
||||
// Storage: NominationPools Metadata (r:1 w:1)
|
||||
// Storage: NominationPools CounterForMetadata (r:1 w:1)
|
||||
fn set_metadata(n: u32, ) -> Weight {
|
||||
(10_893_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((1_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
// Storage: NominationPools MinJoinBond (r:0 w:1)
|
||||
// Storage: NominationPools MaxPoolMembers (r:0 w:1)
|
||||
// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1)
|
||||
// Storage: NominationPools MinCreateBond (r:0 w:1)
|
||||
// Storage: NominationPools MaxPools (r:0 w:1)
|
||||
fn set_configs() -> Weight {
|
||||
(2_793_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
|
||||
}
|
||||
}
|
||||
@@ -71,5 +71,6 @@ runtime-benchmarks = [
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-election-provider-support/runtime-benchmarks",
|
||||
"rand_chacha",
|
||||
"sp-staking/runtime-benchmarks"
|
||||
]
|
||||
try-runtime = ["frame-support/try-runtime"]
|
||||
|
||||
@@ -49,7 +49,7 @@ type MaxNominators<T> = <<T as Config>::BenchmarkingConfig as BenchmarkingConfig
|
||||
|
||||
// Add slashing spans to a user account. Not relevant for actual use, only to benchmark
|
||||
// read and write operations.
|
||||
fn add_slashing_spans<T: Config>(who: &T::AccountId, spans: u32) {
|
||||
pub fn add_slashing_spans<T: Config>(who: &T::AccountId, spans: u32) {
|
||||
if spans == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -737,6 +737,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<AccountId> SessionInterface<AccountId> for () {
|
||||
fn disable_validator(_: u32) -> bool {
|
||||
true
|
||||
}
|
||||
fn validators() -> Vec<AccountId> {
|
||||
Vec::new()
|
||||
}
|
||||
fn prune_historical_up_to(_: SessionIndex) {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler for determining how much of a balance should be paid out on the current era.
|
||||
pub trait EraPayout<Balance> {
|
||||
/// Determine the payout for this era.
|
||||
|
||||
@@ -323,7 +323,7 @@ pub struct ExtBuilder {
|
||||
invulnerables: Vec<AccountId>,
|
||||
has_stakers: bool,
|
||||
initialize_first_session: bool,
|
||||
min_nominator_bond: Balance,
|
||||
pub min_nominator_bond: Balance,
|
||||
min_validator_bond: Balance,
|
||||
balance_factor: Balance,
|
||||
status: BTreeMap<AccountId, StakerStatus<AccountId>>,
|
||||
|
||||
@@ -29,15 +29,15 @@ use frame_support::{
|
||||
},
|
||||
weights::{Weight, WithPostDispatchInfo},
|
||||
};
|
||||
use frame_system::pallet_prelude::BlockNumberFor;
|
||||
use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
|
||||
use pallet_session::historical;
|
||||
use sp_runtime::{
|
||||
traits::{Bounded, Convert, SaturatedConversion, Saturating, Zero},
|
||||
traits::{Bounded, Convert, SaturatedConversion, Saturating, StaticLookup, Zero},
|
||||
Perbill,
|
||||
};
|
||||
use sp_staking::{
|
||||
offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
|
||||
EraIndex, SessionIndex,
|
||||
EraIndex, SessionIndex, StakingInterface,
|
||||
};
|
||||
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
|
||||
@@ -1367,3 +1367,68 @@ impl<T: Config> SortedListProvider<T::AccountId> for UseNominatorsAndValidatorsM
|
||||
Validators::<T>::remove_all();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> StakingInterface for Pallet<T> {
|
||||
type AccountId = T::AccountId;
|
||||
type Balance = BalanceOf<T>;
|
||||
|
||||
fn minimum_bond() -> Self::Balance {
|
||||
MinNominatorBond::<T>::get()
|
||||
}
|
||||
|
||||
fn bonding_duration() -> EraIndex {
|
||||
T::BondingDuration::get()
|
||||
}
|
||||
|
||||
fn current_era() -> EraIndex {
|
||||
Self::current_era().unwrap_or(Zero::zero())
|
||||
}
|
||||
|
||||
fn active_stake(controller: &Self::AccountId) -> Option<Self::Balance> {
|
||||
Self::ledger(controller).map(|l| l.active)
|
||||
}
|
||||
|
||||
fn total_stake(controller: &Self::AccountId) -> Option<Self::Balance> {
|
||||
Self::ledger(controller).map(|l| l.total)
|
||||
}
|
||||
|
||||
fn bond_extra(stash: Self::AccountId, extra: Self::Balance) -> DispatchResult {
|
||||
Self::bond_extra(RawOrigin::Signed(stash).into(), extra)
|
||||
}
|
||||
|
||||
fn unbond(controller: Self::AccountId, value: Self::Balance) -> DispatchResult {
|
||||
Self::unbond(RawOrigin::Signed(controller).into(), value)
|
||||
}
|
||||
|
||||
fn withdraw_unbonded(
|
||||
controller: Self::AccountId,
|
||||
num_slashing_spans: u32,
|
||||
) -> Result<u64, DispatchError> {
|
||||
Self::withdraw_unbonded(RawOrigin::Signed(controller).into(), num_slashing_spans)
|
||||
.map(|post_info| {
|
||||
post_info
|
||||
.actual_weight
|
||||
.unwrap_or(T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans))
|
||||
})
|
||||
.map_err(|err_with_post_info| err_with_post_info.error)
|
||||
}
|
||||
|
||||
fn bond(
|
||||
stash: Self::AccountId,
|
||||
controller: Self::AccountId,
|
||||
value: Self::Balance,
|
||||
payee: Self::AccountId,
|
||||
) -> DispatchResult {
|
||||
Self::bond(
|
||||
RawOrigin::Signed(stash).into(),
|
||||
T::Lookup::unlookup(controller),
|
||||
value,
|
||||
RewardDestination::Account(payee),
|
||||
)
|
||||
}
|
||||
|
||||
fn nominate(controller: Self::AccountId, targets: Vec<Self::AccountId>) -> DispatchResult {
|
||||
let targets = targets.into_iter().map(T::Lookup::unlookup).collect::<Vec<_>>();
|
||||
Self::nominate(RawOrigin::Signed(controller).into(), targets)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use frame_support::{
|
||||
use frame_system::{ensure_root, ensure_signed, offchain::SendTransactionTypes, pallet_prelude::*};
|
||||
use sp_runtime::{
|
||||
traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero},
|
||||
DispatchError, Perbill, Percent,
|
||||
Perbill, Percent,
|
||||
};
|
||||
use sp_staking::{EraIndex, SessionIndex};
|
||||
use sp_std::{cmp::max, prelude::*};
|
||||
|
||||
@@ -87,6 +87,8 @@ pub use self::{
|
||||
StorageHasher, Twox128, Twox256, Twox64Concat,
|
||||
},
|
||||
storage::{
|
||||
bounded_btree_map::BoundedBTreeMap,
|
||||
bounded_btree_set::BoundedBTreeSet,
|
||||
bounded_vec::{BoundedSlice, BoundedVec},
|
||||
migration,
|
||||
weak_bounded_vec::WeakBoundedVec,
|
||||
@@ -138,6 +140,25 @@ macro_rules! bounded_vec {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a bounded btree-map from the given literals.
|
||||
///
|
||||
/// The type of the outcome must be known.
|
||||
///
|
||||
/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding
|
||||
/// bounded vec type. Thus, this is only suitable for testing and non-consensus code.
|
||||
#[macro_export]
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! bounded_btree_map {
|
||||
($ ( $key:expr => $value:expr ),* $(,)?) => {
|
||||
{
|
||||
$crate::traits::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect(
|
||||
$crate::sp_std::vec![$(($key, $value)),*].into_iter()
|
||||
).unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// Generate a new type alias for [`storage::types::StorageValue`],
|
||||
/// [`storage::types::StorageMap`], [`storage::types::StorageDoubleMap`]
|
||||
/// and [`storage::types::StorageNMap`].
|
||||
|
||||
@@ -74,6 +74,14 @@ where
|
||||
Self(t, Default::default())
|
||||
}
|
||||
|
||||
/// Exactly the same semantics as `BTreeMap::retain`.
|
||||
///
|
||||
/// The is a safe `&mut self` borrow because `retain` can only ever decrease the length of the
|
||||
/// inner map.
|
||||
pub fn retain<F: FnMut(&K, &mut V) -> bool>(&mut self, f: F) {
|
||||
self.0.retain(f)
|
||||
}
|
||||
|
||||
/// Create a new `BoundedBTreeMap`.
|
||||
///
|
||||
/// Does not allocate.
|
||||
|
||||
@@ -129,9 +129,13 @@ pub trait DefensiveOption<T> {
|
||||
/// if `None`, which should never happen.
|
||||
fn defensive_map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U;
|
||||
|
||||
/// Defensively transform this option to a result.
|
||||
/// Defensively transform this option to a result, mapping `None` to the return value of an
|
||||
/// error closure.
|
||||
fn defensive_ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E>;
|
||||
|
||||
/// Defensively transform this option to a result, mapping `None` to a default value.
|
||||
fn defensive_ok_or<E>(self, err: E) -> Result<T, E>;
|
||||
|
||||
/// Exactly the same as `map`, but it prints the appropriate warnings if the value being mapped
|
||||
/// is `None`.
|
||||
fn defensive_map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U>;
|
||||
@@ -284,6 +288,13 @@ impl<T> DefensiveOption<T> for Option<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn defensive_ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
self.ok_or_else(|| {
|
||||
defensive!();
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
fn defensive_map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
|
||||
match self {
|
||||
Some(inner) => Some(f(inner)),
|
||||
|
||||
@@ -26,3 +26,4 @@ std = [
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
]
|
||||
runtime-benchmarks = []
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
//! A crate which contains primitives that are useful for implementation that uses staking
|
||||
//! approaches in general. Definitions related to sessions, slashing, etc go here.
|
||||
use sp_runtime::{DispatchError, DispatchResult};
|
||||
use sp_std::collections::btree_map::BTreeMap;
|
||||
|
||||
pub mod offence;
|
||||
@@ -38,7 +39,7 @@ pub trait OnStakerSlash<AccountId, Balance> {
|
||||
///
|
||||
/// * `stash` - The stash of the staker whom the slash was applied to.
|
||||
/// * `slashed_active` - The new bonded balance of the staker after the slash was applied.
|
||||
/// * `slashed_unlocking` - a map of slashed eras, and the balance of that unlocking chunk after
|
||||
/// * `slashed_unlocking` - A map of slashed eras, and the balance of that unlocking chunk after
|
||||
/// the slash is applied. Any era not present in the map is not affected at all.
|
||||
fn on_slash(
|
||||
stash: &AccountId,
|
||||
@@ -52,3 +53,80 @@ impl<AccountId, Balance> OnStakerSlash<AccountId, Balance> for () {
|
||||
// Nothing to do here
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for communication with the staking pallet.
|
||||
pub trait StakingInterface {
|
||||
/// Balance type used by the staking system.
|
||||
type Balance;
|
||||
|
||||
/// AccountId type used by the staking system
|
||||
type AccountId;
|
||||
|
||||
/// The minimum amount required to bond in order to be a nominator. This does not necessarily
|
||||
/// mean the nomination will be counted in an election, but instead just enough to be stored as
|
||||
/// a nominator. In other words, this is the minimum amount to register the intention to
|
||||
/// nominate.
|
||||
fn minimum_bond() -> Self::Balance;
|
||||
|
||||
/// Number of eras that staked funds must remain bonded for.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This must be strictly greater than the staking systems slash deffer duration.
|
||||
fn bonding_duration() -> EraIndex;
|
||||
|
||||
/// The current era index.
|
||||
///
|
||||
/// This should be the latest planned era that the staking system knows about.
|
||||
fn current_era() -> EraIndex;
|
||||
|
||||
/// The amount of active stake that `controller` has in the staking system.
|
||||
fn active_stake(controller: &Self::AccountId) -> Option<Self::Balance>;
|
||||
|
||||
/// The total stake that `controller` has in the staking system. This includes the
|
||||
/// [`Self::active_stake`], and any funds currently in the process of unbonding via
|
||||
/// [`Self::unbond`].
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is only guaranteed to reflect the amount locked by the staking system. If there are
|
||||
/// non-staking locks on the bonded pair's balance this may not be accurate.
|
||||
fn total_stake(controller: &Self::AccountId) -> Option<Self::Balance>;
|
||||
|
||||
/// Bond (lock) `value` of `stash`'s balance. `controller` will be set as the account
|
||||
/// controlling `stash`. This creates what is referred to as "bonded pair".
|
||||
fn bond(
|
||||
stash: Self::AccountId,
|
||||
controller: Self::AccountId,
|
||||
value: Self::Balance,
|
||||
payee: Self::AccountId,
|
||||
) -> DispatchResult;
|
||||
|
||||
/// Have `controller` nominate `validators`.
|
||||
fn nominate(
|
||||
controller: Self::AccountId,
|
||||
validators: sp_std::vec::Vec<Self::AccountId>,
|
||||
) -> DispatchResult;
|
||||
|
||||
/// Bond some extra amount in the _Stash_'s free balance against the active bonded balance of
|
||||
/// the account. The amount extra actually bonded will never be more than the _Stash_'s free
|
||||
/// balance.
|
||||
fn bond_extra(controller: Self::AccountId, extra: Self::Balance) -> DispatchResult;
|
||||
|
||||
/// Schedule a portion of the active bonded balance to be unlocked at era
|
||||
/// [Self::current_era] + [`Self::bonding_duration`].
|
||||
///
|
||||
/// Once the unlock era has been reached, [`Self::withdraw_unbonded`] can be called to unlock
|
||||
/// the funds.
|
||||
///
|
||||
/// The amount of times this can be successfully called is limited based on how many distinct
|
||||
/// eras funds are schedule to unlock in. Calling [`Self::withdraw_unbonded`] after some unlock
|
||||
/// schedules have reached their unlocking era should allow more calls to this function.
|
||||
fn unbond(controller: Self::AccountId, value: Self::Balance) -> DispatchResult;
|
||||
|
||||
/// Unlock any funds schedule to unlock before or at the current era.
|
||||
fn withdraw_unbonded(
|
||||
controller: Self::AccountId,
|
||||
num_slashing_spans: u32,
|
||||
) -> Result<u64, DispatchError>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user