feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarking for pezpallet-fast-unstake.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use crate::{types::*, *};
|
||||
use alloc::vec::Vec;
|
||||
use pezframe_benchmarking::v2::*;
|
||||
use pezframe_support::{
|
||||
assert_ok,
|
||||
traits::{Currency, EnsureOrigin, Get, Hooks},
|
||||
};
|
||||
use pezframe_system::RawOrigin;
|
||||
use pezsp_runtime::traits::Zero;
|
||||
use pezsp_staking::{EraIndex, StakingInterface};
|
||||
|
||||
const USER_SEED: u32 = 0;
|
||||
|
||||
type CurrencyOf<T> = <T as Config>::Currency;
|
||||
|
||||
fn create_unexposed_batch<T: Config>(batch_size: u32) -> Vec<T::AccountId> {
|
||||
(0..batch_size)
|
||||
.map(|i| {
|
||||
let account =
|
||||
pezframe_benchmarking::account::<T::AccountId>("unexposed_nominator", i, USER_SEED);
|
||||
fund_and_bond_account::<T>(&account);
|
||||
account
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn fund_and_bond_account<T: Config>(account: &T::AccountId) {
|
||||
let stake = CurrencyOf::<T>::minimum_balance() * 100u32.into();
|
||||
CurrencyOf::<T>::make_free_balance_be(&account, stake * 100u32.into());
|
||||
|
||||
// bond without nominating - fast-unstake works with non-nominating bonded accounts.
|
||||
// Note that if we want to nominate a validator, we must first create a valid one; otherwise,
|
||||
// `nominate()` will fail with a BadTarget error. However, fast-unstaking is intended for
|
||||
// accounts that are bonded but not actively nominating, making this an unnecessary complication
|
||||
// for our needs.
|
||||
assert_ok!(T::Staking::bond(account, stake, account));
|
||||
}
|
||||
|
||||
pub(crate) fn fast_unstake_events<T: Config>() -> Vec<crate::Event<T>> {
|
||||
pezframe_system::Pallet::<T>::events()
|
||||
.into_iter()
|
||||
.map(|r| r.event)
|
||||
.filter_map(|e| <T as Config>::RuntimeEvent::from(e).try_into().ok())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn setup_staking<T: Config>(v: u32, until: EraIndex) {
|
||||
let ed = CurrencyOf::<T>::minimum_balance();
|
||||
|
||||
log!(debug, "registering {} validators and {} eras.", v, until);
|
||||
|
||||
// our validators don't actually need to registered in staking -- just generate `v` random
|
||||
// accounts.
|
||||
let validators = (0..v)
|
||||
.map(|x| pezframe_benchmarking::account::<T::AccountId>("validator", x, USER_SEED))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for era in 0..=until {
|
||||
let others = (0..T::Staking::max_exposure_page_size())
|
||||
.map(|s| {
|
||||
let who = pezframe_benchmarking::account::<T::AccountId>("nominator", era, s.into());
|
||||
let value = ed;
|
||||
(who, value)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
validators.iter().for_each(|v| {
|
||||
T::Staking::add_era_stakers(&era, &v, others.clone());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn on_idle_full_block<T: Config>() {
|
||||
let remaining_weight = <T as pezframe_system::Config>::BlockWeights::get().max_block;
|
||||
Pallet::<T>::on_idle(Zero::zero(), remaining_weight);
|
||||
}
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
// on_idle, we don't check anyone, but fully unbond them.
|
||||
#[benchmark]
|
||||
fn on_idle_unstake(b: Linear<1, { T::BatchSize::get() }>) {
|
||||
ErasToCheckPerBlock::<T>::put(1);
|
||||
for who in create_unexposed_batch::<T>(b).into_iter() {
|
||||
assert_ok!(Pallet::<T>::register_fast_unstake(RawOrigin::Signed(who.clone()).into(),));
|
||||
}
|
||||
|
||||
// Run on_idle once. This will check era 0.
|
||||
assert_eq!(Head::<T>::get(), None);
|
||||
on_idle_full_block::<T>();
|
||||
|
||||
assert!(matches!(
|
||||
Head::<T>::get(),
|
||||
Some(UnstakeRequest {
|
||||
checked,
|
||||
stashes,
|
||||
..
|
||||
}) if checked.len() == 1 && stashes.len() as u32 == b
|
||||
));
|
||||
|
||||
#[block]
|
||||
{
|
||||
on_idle_full_block::<T>();
|
||||
}
|
||||
|
||||
assert_eq!(fast_unstake_events::<T>().last(), Some(&Event::BatchFinished { size: b }));
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn on_idle_check(v: Linear<1, 256>, b: Linear<1, { T::BatchSize::get() }>) {
|
||||
// on_idle: When we check some number of eras and the queue is already set.
|
||||
|
||||
let u = T::MaxErasToCheckPerBlock::get().min(T::Staking::bonding_duration());
|
||||
|
||||
ErasToCheckPerBlock::<T>::put(u);
|
||||
T::Staking::set_current_era(u);
|
||||
|
||||
// setup staking with v validators and u eras of data (0..=u+1)
|
||||
setup_staking::<T>(v, u);
|
||||
|
||||
let stashes = create_unexposed_batch::<T>(b)
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
assert_ok!(
|
||||
Pallet::<T>::register_fast_unstake(RawOrigin::Signed(s.clone()).into(),)
|
||||
);
|
||||
(s, T::Deposit::get())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// no one is queued thus far.
|
||||
assert_eq!(Head::<T>::get(), None);
|
||||
|
||||
Head::<T>::put(UnstakeRequest {
|
||||
stashes: stashes.clone().try_into().unwrap(),
|
||||
checked: Default::default(),
|
||||
});
|
||||
|
||||
#[block]
|
||||
{
|
||||
on_idle_full_block::<T>();
|
||||
}
|
||||
|
||||
let checked = (1..=u).rev().collect::<Vec<EraIndex>>();
|
||||
let request = Head::<T>::get().unwrap();
|
||||
assert_eq!(checked, request.checked.into_inner());
|
||||
assert!(matches!(fast_unstake_events::<T>().last(), Some(Event::BatchChecked { .. })));
|
||||
assert!(stashes.iter().all(|(s, _)| request.stashes.iter().any(|(ss, _)| ss == s)));
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn register_fast_unstake() {
|
||||
ErasToCheckPerBlock::<T>::put(1);
|
||||
let who = create_unexposed_batch::<T>(1).get(0).cloned().unwrap();
|
||||
whitelist_account!(who);
|
||||
assert_eq!(Queue::<T>::count(), 0);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(who.clone()));
|
||||
|
||||
assert_eq!(Queue::<T>::count(), 1);
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn deregister() {
|
||||
ErasToCheckPerBlock::<T>::put(1);
|
||||
let who = create_unexposed_batch::<T>(1).get(0).cloned().unwrap();
|
||||
assert_ok!(Pallet::<T>::register_fast_unstake(RawOrigin::Signed(who.clone()).into(),));
|
||||
assert_eq!(Queue::<T>::count(), 1);
|
||||
whitelist_account!(who);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(who.clone()));
|
||||
|
||||
assert_eq!(Queue::<T>::count(), 0);
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn control() -> Result<(), BenchmarkError> {
|
||||
let origin = <T as Config>::ControlOrigin::try_successful_origin()
|
||||
.map_err(|_| BenchmarkError::Weightless)?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(origin as T::RuntimeOrigin, T::MaxErasToCheckPerBlock::get());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Pallet, mock::ExtBuilder::default().build(), mock::Runtime);
|
||||
}
|
||||
@@ -0,0 +1,630 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! > Made with *Bizinikiwi*, for *Pezkuwi*.
|
||||
//!
|
||||
//! [![github]](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/bizinikiwi/pezframe/fast-unstake) -
|
||||
//! [![pezkuwi]](https://pezkuwichain.io)
|
||||
//!
|
||||
//! [pezkuwi]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white
|
||||
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
|
||||
//!
|
||||
//! # Fast Unstake Pallet
|
||||
//!
|
||||
//! A pallet to allow participants of the staking system (represented by [`Config::Staking`], being
|
||||
//! [`StakingInterface`]) to unstake quicker, if and only if they meet the condition of not being
|
||||
//! exposed to any slashes.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! If a nominator is not exposed anywhere in the staking system, checked via
|
||||
//! [`StakingInterface::is_exposed_in_era`] (i.e. "has not actively backed any validators in the
|
||||
//! last [`StakingInterface::bonding_duration`] days"), then they can register themselves in this
|
||||
//! pallet and unstake faster than having to wait an entire bonding duration.
|
||||
//!
|
||||
//! *Being exposed with validator* from the point of view of the staking system means earning
|
||||
//! rewards with the validator, and also being at the risk of slashing with the validator. This is
|
||||
//! equivalent to the "Active Nominator" role explained in
|
||||
//! [here](https://pezkuwichain.io/blog/staking-update-february-2022/).
|
||||
//!
|
||||
//! Stakers who are certain about NOT being exposed can register themselves with
|
||||
//! [`Pallet::register_fast_unstake`]. This will chill, fully unbond the staker and place them
|
||||
//! in the queue to be checked.
|
||||
//!
|
||||
//! A successful registration implies being fully unbonded and chilled in the staking system. These
|
||||
//! effects persist even if the fast-unstake registration is retracted (see [`Pallet::deregister`]
|
||||
//! and further).
|
||||
//!
|
||||
//! Once registered as a fast-unstaker, the staker will be queued and checked by the system. This
|
||||
//! can take a variable number of blocks based on demand, but will almost certainly be "faster" (as
|
||||
//! the name suggest) than waiting the standard bonding duration.
|
||||
//!
|
||||
//! A fast-unstaker is either in [`Queue`] or actively being checked, at which point it lives in
|
||||
//! [`Head`]. Once in [`Head`], the request cannot be retracted anymore. But, once in [`Queue`], it
|
||||
//! can, via [`Pallet::deregister`].
|
||||
//!
|
||||
//! A deposit equal to [`Config::Deposit`] is collected for this process, and is returned in case a
|
||||
//! successful unstake occurs (`Event::Unstaked` signals that).
|
||||
//!
|
||||
//! Once processed, if successful, no additional fee for the checking process is taken, and the
|
||||
//! staker is instantly unbonded.
|
||||
//!
|
||||
//! If unsuccessful, meaning that the staker was exposed, the aforementioned deposit will be slashed
|
||||
//! for the amount of wasted work they have inflicted on the chain.
|
||||
//!
|
||||
//! All in all, this pallet is meant to provide an easy off-ramp for some stakers.
|
||||
//!
|
||||
//! ### Example
|
||||
//!
|
||||
//! 1. Fast-unstake with multiple participants in the queue.
|
||||
#![doc = docify::embed!("src/tests.rs", successful_multi_queue)]
|
||||
//!
|
||||
//! 2. Fast unstake failing because a nominator is exposed.
|
||||
#![doc = docify::embed!("src/tests.rs", exposed_nominator_cannot_unstake)]
|
||||
//!
|
||||
//! ## Pallet API
|
||||
//!
|
||||
//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
|
||||
//! including its configuration trait, dispatchables, storage items, events and errors.
|
||||
//!
|
||||
//! ## Low Level / Implementation Details
|
||||
//!
|
||||
//! This pallet works off the basis of `on_idle`, meaning that it provides no guarantee about when
|
||||
//! it will succeed, if at all. Moreover, the queue implementation is unordered. In case of
|
||||
//! congestion, no FIFO ordering is provided.
|
||||
//!
|
||||
//! A few important considerations can be concluded based on the `on_idle`-based implementation:
|
||||
//!
|
||||
//! * It is crucial for the weights of this pallet to be correct. The code inside
|
||||
//! [`Pallet::on_idle`] MUST be able to measure itself and report the remaining weight correctly
|
||||
//! after execution.
|
||||
//!
|
||||
//! * If the weight measurement is incorrect, it can lead to perpetual overweight (consequently
|
||||
//! slow) blocks.
|
||||
//!
|
||||
//! * The amount of weight that `on_idle` consumes is a direct function of [`ErasToCheckPerBlock`].
|
||||
//!
|
||||
//! * Thus, a correct value of [`ErasToCheckPerBlock`] (which can be set via [`Pallet::control`])
|
||||
//! should be chosen, such that a reasonable amount of weight is used `on_idle`. If
|
||||
//! [`ErasToCheckPerBlock`] is too large, `on_idle` will always conclude that it has not enough
|
||||
//! weight to proceed, and will early-return. Nonetheless, this should also be *safe* as long as
|
||||
//! the benchmarking/weights are *accurate*.
|
||||
//!
|
||||
//! * See the inline code-comments on `do_on_idle` (private) for more details.
|
||||
//!
|
||||
//! * For further safety, in case of any unforeseen errors, the pallet will emit
|
||||
//! [`Event::InternalError`] and set [`ErasToCheckPerBlock`] back to 0, which essentially means
|
||||
//! the pallet will halt/disable itself.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// NOTE: enable benchmarking in tests as well.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
pub mod migrations;
|
||||
pub mod types;
|
||||
pub mod weights;
|
||||
|
||||
// some extra imports for docs to link properly.
|
||||
#[cfg(doc)]
|
||||
pub use pezframe_support::traits::Hooks;
|
||||
#[cfg(doc)]
|
||||
pub use pezsp_staking::StakingInterface;
|
||||
|
||||
/// The logging target of this pallet.
|
||||
pub const LOG_TARGET: &'static str = "runtime::fast-unstake";
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log {
|
||||
($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
|
||||
log::$level!(
|
||||
target: crate::LOG_TARGET,
|
||||
concat!("[{:?}] 💨 ", $patter), pezframe_system::Pallet::<T>::block_number() $(, $values)*
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use crate::types::*;
|
||||
use alloc::vec::Vec;
|
||||
use pezframe_support::{
|
||||
pezpallet_prelude::*,
|
||||
traits::{Defensive, ReservableCurrency, StorageVersion},
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::*;
|
||||
use pezsp_runtime::{traits::Zero, DispatchResult};
|
||||
use pezsp_staking::{EraIndex, StakingInterface};
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use pezsp_runtime::TryRuntimeError;
|
||||
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// The overarching event type.
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: From<Event<Self>>
|
||||
+ IsType<<Self as pezframe_system::Config>::RuntimeEvent>
|
||||
+ TryInto<Event<Self>>;
|
||||
|
||||
/// The currency used for deposits.
|
||||
type Currency: ReservableCurrency<Self::AccountId>;
|
||||
|
||||
/// Deposit to take for unstaking, to make sure we're able to slash the it in order to cover
|
||||
/// the costs of resources on unsuccessful unstake.
|
||||
#[pallet::constant]
|
||||
type Deposit: Get<BalanceOf<Self>>;
|
||||
|
||||
/// The origin that can control this pallet, in other words invoke [`Pallet::control`].
|
||||
type ControlOrigin: pezframe_support::traits::EnsureOrigin<Self::RuntimeOrigin>;
|
||||
|
||||
/// Batch size.
|
||||
///
|
||||
/// This many stashes are processed in each unstake request.
|
||||
type BatchSize: Get<u32>;
|
||||
|
||||
/// The access to staking functionality.
|
||||
type Staking: StakingInterface<Balance = BalanceOf<Self>, AccountId = Self::AccountId>;
|
||||
|
||||
/// Maximum value for `ErasToCheckPerBlock`, checked in [`Pallet::control`].
|
||||
///
|
||||
/// This should be slightly bigger than the actual value in order to have accurate
|
||||
/// benchmarks.
|
||||
type MaxErasToCheckPerBlock: Get<u32>;
|
||||
|
||||
/// The weight information of this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// The current "head of the queue" being unstaked.
|
||||
///
|
||||
/// The head in itself can be a batch of up to [`Config::BatchSize`] stakers.
|
||||
#[pallet::storage]
|
||||
pub type Head<T: Config> = StorageValue<_, UnstakeRequest<T>, OptionQuery>;
|
||||
|
||||
/// The map of all accounts wishing to be unstaked.
|
||||
///
|
||||
/// Keeps track of `AccountId` wishing to unstake and it's corresponding deposit.
|
||||
// Hasher: Twox safe since `AccountId` is a secure hash.
|
||||
#[pallet::storage]
|
||||
pub type Queue<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, BalanceOf<T>>;
|
||||
|
||||
/// Number of eras to check per block.
|
||||
///
|
||||
/// If set to 0, this pallet does absolutely nothing. Cannot be set to more than
|
||||
/// [`Config::MaxErasToCheckPerBlock`].
|
||||
///
|
||||
/// Based on the amount of weight available at [`Pallet::on_idle`], up to this many eras are
|
||||
/// checked. The checking is represented by updating [`UnstakeRequest::checked`], which is
|
||||
/// stored in [`Head`].
|
||||
#[pallet::storage]
|
||||
pub type ErasToCheckPerBlock<T: Config> = StorageValue<_, u32, ValueQuery>;
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A staker was unstaked.
|
||||
Unstaked { stash: T::AccountId, result: DispatchResult },
|
||||
/// A staker was slashed for requesting fast-unstake whilst being exposed.
|
||||
Slashed { stash: T::AccountId, amount: BalanceOf<T> },
|
||||
/// A batch was partially checked for the given eras, but the process did not finish.
|
||||
BatchChecked { eras: Vec<EraIndex> },
|
||||
/// A batch of a given size was terminated.
|
||||
///
|
||||
/// This is always follows by a number of `Unstaked` or `Slashed` events, marking the end
|
||||
/// of the batch. A new batch will be created upon next block.
|
||||
BatchFinished { size: u32 },
|
||||
/// An internal error happened. Operations will be paused now.
|
||||
InternalError,
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub enum Error<T> {
|
||||
/// The provided Controller account was not found.
|
||||
///
|
||||
/// This means that the given account is not bonded.
|
||||
NotController,
|
||||
/// The bonded account has already been queued.
|
||||
AlreadyQueued,
|
||||
/// The bonded account has active unlocking chunks.
|
||||
NotFullyBonded,
|
||||
/// The provided un-staker is not in the `Queue`.
|
||||
NotQueued,
|
||||
/// The provided un-staker is already in Head, and cannot deregister.
|
||||
AlreadyHead,
|
||||
/// The call is not allowed at this point because the pallet is not active.
|
||||
CallNotAllowed,
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_idle(_: BlockNumberFor<T>, remaining_weight: Weight) -> Weight {
|
||||
if remaining_weight.any_lt(T::DbWeight::get().reads(2)) {
|
||||
return Weight::from_parts(0, 0);
|
||||
}
|
||||
|
||||
Self::do_on_idle(remaining_weight)
|
||||
}
|
||||
|
||||
fn integrity_test() {
|
||||
// Ensure that the value of `ErasToCheckPerBlock` is less or equal to
|
||||
// `T::MaxErasToCheckPerBlock`.
|
||||
assert!(
|
||||
ErasToCheckPerBlock::<T>::get() <= T::MaxErasToCheckPerBlock::get(),
|
||||
"the value of `ErasToCheckPerBlock` is greater than `T::MaxErasToCheckPerBlock`",
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn try_state(_n: BlockNumberFor<T>) -> Result<(), TryRuntimeError> {
|
||||
// ensure that the value of `ErasToCheckPerBlock` is less than
|
||||
// `T::MaxErasToCheckPerBlock`.
|
||||
ensure!(
|
||||
ErasToCheckPerBlock::<T>::get() <= T::MaxErasToCheckPerBlock::get(),
|
||||
"the value of `ErasToCheckPerBlock` is greater than `T::MaxErasToCheckPerBlock`",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Register oneself for fast-unstake.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// The dispatch origin of this call must be *signed* by whoever is permitted to call
|
||||
/// unbond funds by the staking system. See [`Config::Staking`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// The stash associated with the origin must have no ongoing unlocking chunks. If
|
||||
/// successful, this will fully unbond and chill the stash. Then, it will enqueue the stash
|
||||
/// to be checked in further blocks.
|
||||
///
|
||||
/// If by the time this is called, the stash is actually eligible for fast-unstake, then
|
||||
/// they are guaranteed to remain eligible, because the call will chill them as well.
|
||||
///
|
||||
/// If the check works, the entire staking data is removed, i.e. the stash is fully
|
||||
/// unstaked.
|
||||
///
|
||||
/// If the check fails, the stash remains chilled and waiting for being unbonded as in with
|
||||
/// the normal staking system, but they lose part of their unbonding chunks due to consuming
|
||||
/// the chain's resources.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Some events from the staking and currency system might be emitted.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::register_fast_unstake())]
|
||||
pub fn register_fast_unstake(origin: OriginFor<T>) -> DispatchResult {
|
||||
let ctrl = ensure_signed(origin)?;
|
||||
|
||||
ensure!(ErasToCheckPerBlock::<T>::get() != 0, Error::<T>::CallNotAllowed);
|
||||
let stash_account =
|
||||
T::Staking::stash_by_ctrl(&ctrl).map_err(|_| Error::<T>::NotController)?;
|
||||
ensure!(!Queue::<T>::contains_key(&stash_account), Error::<T>::AlreadyQueued);
|
||||
ensure!(!Self::is_head(&stash_account), Error::<T>::AlreadyHead);
|
||||
ensure!(!T::Staking::is_unbonding(&stash_account)?, Error::<T>::NotFullyBonded);
|
||||
|
||||
// chill and fully unstake.
|
||||
T::Staking::chill(&stash_account)?;
|
||||
T::Staking::fully_unbond(&stash_account)?;
|
||||
|
||||
T::Currency::reserve(&stash_account, T::Deposit::get())?;
|
||||
|
||||
// enqueue them.
|
||||
Queue::<T>::insert(stash_account, T::Deposit::get());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deregister oneself from the fast-unstake.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// The dispatch origin of this call must be *signed* by whoever is permitted to call
|
||||
/// unbond funds by the staking system. See [`Config::Staking`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// This is useful if one is registered, they are still waiting, and they change their mind.
|
||||
///
|
||||
/// Note that the associated stash is still fully unbonded and chilled as a consequence of
|
||||
/// calling [`Pallet::register_fast_unstake`]. Therefore, this should probably be followed
|
||||
/// by a call to `rebond` in the staking system.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Some events from the staking and currency system might be emitted.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::deregister())]
|
||||
pub fn deregister(origin: OriginFor<T>) -> DispatchResult {
|
||||
let ctrl = ensure_signed(origin)?;
|
||||
|
||||
ensure!(ErasToCheckPerBlock::<T>::get() != 0, Error::<T>::CallNotAllowed);
|
||||
|
||||
let stash_account =
|
||||
T::Staking::stash_by_ctrl(&ctrl).map_err(|_| Error::<T>::NotController)?;
|
||||
ensure!(Queue::<T>::contains_key(&stash_account), Error::<T>::NotQueued);
|
||||
ensure!(!Self::is_head(&stash_account), Error::<T>::AlreadyHead);
|
||||
let deposit = Queue::<T>::take(stash_account.clone());
|
||||
|
||||
if let Some(deposit) = deposit.defensive() {
|
||||
let remaining = T::Currency::unreserve(&stash_account, deposit);
|
||||
if !remaining.is_zero() {
|
||||
Self::halt("not enough balance to unreserve");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Control the operation of this pallet.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// The dispatch origin of this call must be [`Config::ControlOrigin`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// Can set the number of eras to check per block, and potentially other admin work.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// No events are emitted from this dispatch.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(<T as Config>::WeightInfo::control())]
|
||||
pub fn control(origin: OriginFor<T>, eras_to_check: EraIndex) -> DispatchResult {
|
||||
T::ControlOrigin::ensure_origin(origin)?;
|
||||
ensure!(eras_to_check <= T::MaxErasToCheckPerBlock::get(), Error::<T>::CallNotAllowed);
|
||||
ErasToCheckPerBlock::<T>::put(eras_to_check);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Returns `true` if `staker` is anywhere to be found in the `head`.
|
||||
pub(crate) fn is_head(staker: &T::AccountId) -> bool {
|
||||
Head::<T>::get().map_or(false, |UnstakeRequest { stashes, .. }| {
|
||||
stashes.iter().any(|(stash, _)| stash == staker)
|
||||
})
|
||||
}
|
||||
|
||||
/// Halt the operations of this pallet.
|
||||
pub(crate) fn halt(reason: &'static str) {
|
||||
pezframe_support::defensive!(reason);
|
||||
ErasToCheckPerBlock::<T>::put(0);
|
||||
Self::deposit_event(Event::<T>::InternalError)
|
||||
}
|
||||
|
||||
/// process up to `remaining_weight`.
|
||||
///
|
||||
/// Returns the actual weight consumed.
|
||||
///
|
||||
/// Written for readability in mind, not efficiency. For example:
|
||||
///
|
||||
/// 1. We assume this is only ever called once per `on_idle`. This is because we know that
|
||||
/// in all use cases, even a single nominator cannot be unbonded in a single call. Multiple
|
||||
/// calls to this function are thus not needed.
|
||||
///
|
||||
/// 2. We will only mark a staker as unstaked if at the beginning of a check cycle, they are
|
||||
/// found out to have no eras to check. At the end of a check cycle, even if they are fully
|
||||
/// checked, we don't finish the process.
|
||||
pub(crate) fn do_on_idle(remaining_weight: Weight) -> Weight {
|
||||
// any weight that is unaccounted for
|
||||
let mut unaccounted_weight = Weight::from_parts(0, 0);
|
||||
|
||||
let eras_to_check_per_block = ErasToCheckPerBlock::<T>::get();
|
||||
if eras_to_check_per_block.is_zero() {
|
||||
return T::DbWeight::get().reads(1).saturating_add(unaccounted_weight);
|
||||
}
|
||||
|
||||
// NOTE: here we're assuming that the number of validators has only ever increased,
|
||||
// meaning that the number of exposures to check is either this per era, or less.
|
||||
let validator_count = T::Staking::desired_validator_count();
|
||||
let (next_batch_size, reads_from_queue) = Head::<T>::get()
|
||||
.map_or((Queue::<T>::count().min(T::BatchSize::get()), true), |head| {
|
||||
(head.stashes.len() as u32, false)
|
||||
});
|
||||
|
||||
// determine the number of eras to check. This is based on both `ErasToCheckPerBlock`
|
||||
// and `remaining_weight` passed on to us from the runtime executive.
|
||||
let max_weight = |v, b| {
|
||||
// NOTE: this potentially under-counts by up to `BatchSize` reads from the queue.
|
||||
<T as Config>::WeightInfo::on_idle_check(v, b)
|
||||
.max(<T as Config>::WeightInfo::on_idle_unstake(b))
|
||||
.saturating_add(if reads_from_queue {
|
||||
T::DbWeight::get().reads(next_batch_size.into())
|
||||
} else {
|
||||
Zero::zero()
|
||||
})
|
||||
};
|
||||
|
||||
if max_weight(validator_count, next_batch_size).any_gt(remaining_weight) {
|
||||
log!(debug, "early exit because eras_to_check_per_block is zero");
|
||||
return T::DbWeight::get().reads(3).saturating_add(unaccounted_weight);
|
||||
}
|
||||
|
||||
if T::Staking::election_ongoing() {
|
||||
// NOTE: we assume `ongoing` does not consume any weight.
|
||||
// there is an ongoing election -- we better not do anything. Imagine someone is not
|
||||
// exposed anywhere in the last era, and the snapshot for the election is already
|
||||
// taken. In this time period, we don't want to accidentally unstake them.
|
||||
return T::DbWeight::get().reads(4).saturating_add(unaccounted_weight);
|
||||
}
|
||||
|
||||
let UnstakeRequest { stashes, mut checked } = match Head::<T>::take().or_else(|| {
|
||||
// NOTE: there is no order guarantees in `Queue`.
|
||||
let stashes: BoundedVec<_, T::BatchSize> = Queue::<T>::drain()
|
||||
.take(T::BatchSize::get() as usize)
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.expect("take ensures bound is met; qed");
|
||||
unaccounted_weight.saturating_accrue(
|
||||
T::DbWeight::get().reads_writes(stashes.len() as u64, stashes.len() as u64),
|
||||
);
|
||||
if stashes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(UnstakeRequest { stashes, checked: Default::default() })
|
||||
}
|
||||
}) {
|
||||
None => {
|
||||
// There's no `Head` and nothing in the `Queue`, nothing to do here.
|
||||
return T::DbWeight::get().reads(4);
|
||||
},
|
||||
Some(head) => head,
|
||||
};
|
||||
|
||||
log!(
|
||||
debug,
|
||||
"checking {:?} stashes, eras_to_check_per_block = {:?}, checked {:?}, remaining_weight = {:?}",
|
||||
stashes.len(),
|
||||
eras_to_check_per_block,
|
||||
checked,
|
||||
remaining_weight,
|
||||
);
|
||||
|
||||
// the range that we're allowed to check in this round.
|
||||
let current_era = T::Staking::current_era();
|
||||
let bonding_duration = T::Staking::bonding_duration();
|
||||
|
||||
// prune all the old eras that we don't care about. This will help us keep the bound
|
||||
// of `checked`.
|
||||
checked.retain(|e| *e >= current_era.saturating_sub(bonding_duration));
|
||||
|
||||
let unchecked_eras_to_check = {
|
||||
// get the last available `bonding_duration` eras up to current era in reverse
|
||||
// order.
|
||||
let total_check_range = (current_era.saturating_sub(bonding_duration)..=
|
||||
current_era)
|
||||
.rev()
|
||||
.collect::<Vec<_>>();
|
||||
debug_assert!(
|
||||
total_check_range.len() <= (bonding_duration + 1) as usize,
|
||||
"{:?}",
|
||||
total_check_range
|
||||
);
|
||||
|
||||
// remove eras that have already been checked, take a maximum of
|
||||
// eras_to_check_per_block.
|
||||
total_check_range
|
||||
.into_iter()
|
||||
.filter(|e| !checked.contains(e))
|
||||
.take(eras_to_check_per_block as usize)
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
log!(
|
||||
debug,
|
||||
"{} eras to check: {:?}",
|
||||
unchecked_eras_to_check.len(),
|
||||
unchecked_eras_to_check
|
||||
);
|
||||
|
||||
let unstake_stash = |stash: T::AccountId, deposit| {
|
||||
let result = T::Staking::force_unstake(stash.clone());
|
||||
let remaining = T::Currency::unreserve(&stash, deposit);
|
||||
if !remaining.is_zero() {
|
||||
Self::halt("not enough balance to unreserve");
|
||||
} else {
|
||||
log!(debug, "unstaked {:?}, outcome: {:?}", stash, result);
|
||||
Self::deposit_event(Event::<T>::Unstaked { stash, result });
|
||||
}
|
||||
};
|
||||
|
||||
let check_stash = |stash, deposit| {
|
||||
let is_exposed = unchecked_eras_to_check
|
||||
.iter()
|
||||
.any(|e| T::Staking::is_exposed_in_era(&stash, e));
|
||||
|
||||
if is_exposed {
|
||||
let _ = T::Currency::slash_reserved(&stash, deposit);
|
||||
log!(info, "slashed {:?} by {:?}", stash, deposit);
|
||||
Self::deposit_event(Event::<T>::Slashed { stash, amount: deposit });
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
if unchecked_eras_to_check.is_empty() {
|
||||
// `stashes` are not exposed in any era now -- we can let go of them now.
|
||||
let size = stashes.len() as u32;
|
||||
stashes.into_iter().for_each(|(stash, deposit)| unstake_stash(stash, deposit));
|
||||
Self::deposit_event(Event::<T>::BatchFinished { size });
|
||||
<T as Config>::WeightInfo::on_idle_unstake(size).saturating_add(unaccounted_weight)
|
||||
} else {
|
||||
let pre_length = stashes.len();
|
||||
let stashes: BoundedVec<(T::AccountId, BalanceOf<T>), T::BatchSize> = stashes
|
||||
.into_iter()
|
||||
.filter(|(stash, deposit)| check_stash(stash.clone(), *deposit))
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.expect("filter can only lessen the length; still in bound; qed");
|
||||
let post_length = stashes.len();
|
||||
|
||||
log!(
|
||||
debug,
|
||||
"checked {:?}, pre stashes: {:?}, post: {:?}",
|
||||
unchecked_eras_to_check,
|
||||
pre_length,
|
||||
post_length,
|
||||
);
|
||||
|
||||
match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) {
|
||||
Ok(_) =>
|
||||
if stashes.is_empty() {
|
||||
Self::deposit_event(Event::<T>::BatchFinished { size: 0 });
|
||||
} else {
|
||||
Head::<T>::put(UnstakeRequest { stashes, checked });
|
||||
Self::deposit_event(Event::<T>::BatchChecked {
|
||||
eras: unchecked_eras_to_check,
|
||||
});
|
||||
},
|
||||
Err(_) => {
|
||||
// don't put the head back in -- there is an internal error in the pallet.
|
||||
Self::halt("checked is pruned via retain above")
|
||||
},
|
||||
}
|
||||
|
||||
<T as Config>::WeightInfo::on_idle_check(validator_count, pre_length as u32)
|
||||
.saturating_add(unaccounted_weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub mod v1 {
|
||||
use crate::{types::BalanceOf, *};
|
||||
use alloc::vec::Vec;
|
||||
use pezframe_support::{
|
||||
storage::unhashed,
|
||||
traits::{Defensive, Get, GetStorageVersion, OnRuntimeUpgrade},
|
||||
weights::Weight,
|
||||
};
|
||||
use pezsp_staking::EraIndex;
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use pezframe_support::ensure;
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use pezsp_runtime::TryRuntimeError;
|
||||
|
||||
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
|
||||
if current == 1 && onchain == 0 {
|
||||
// update the version nonetheless.
|
||||
current.put::<Pallet<T>>();
|
||||
|
||||
// if a head exists, then we put them back into the queue.
|
||||
if Head::<T>::exists() {
|
||||
if let Some((stash, _, deposit)) =
|
||||
unhashed::take::<(T::AccountId, Vec<EraIndex>, BalanceOf<T>)>(
|
||||
&Head::<T>::hashed_key(),
|
||||
)
|
||||
.defensive()
|
||||
{
|
||||
Queue::<T>::insert(stash, deposit);
|
||||
} else {
|
||||
// not much we can do here -- head is already deleted.
|
||||
}
|
||||
T::DbWeight::get().reads_writes(2, 3)
|
||||
} else {
|
||||
T::DbWeight::get().reads(2)
|
||||
}
|
||||
} else {
|
||||
log!(info, "Migration did not execute. This probably should be removed");
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
ensure!(
|
||||
Pallet::<T>::on_chain_storage_version() == 0,
|
||||
"The onchain storage version must be zero for the migration to execute."
|
||||
);
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
|
||||
ensure!(
|
||||
Pallet::<T>::on_chain_storage_version() == 1,
|
||||
"The onchain version must be updated after the migration."
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{self as fast_unstake};
|
||||
use pezframe_election_provider_support::PageIndex;
|
||||
use pezframe_support::{
|
||||
assert_ok, derive_impl,
|
||||
pezpallet_prelude::*,
|
||||
parameter_types,
|
||||
traits::{ConstU64, Currency},
|
||||
weights::constants::WEIGHT_REF_TIME_PER_SECOND,
|
||||
};
|
||||
use pezsp_runtime::{traits::IdentityLookup, BuildStorage};
|
||||
|
||||
use pezpallet_staking::{Exposure, IndividualExposure, StakerStatus};
|
||||
|
||||
pub type AccountId = u128;
|
||||
pub type BlockNumber = u64;
|
||||
pub type Balance = u128;
|
||||
pub type T = Runtime;
|
||||
|
||||
parameter_types! {
|
||||
pub BlockWeights: pezframe_system::limits::BlockWeights =
|
||||
pezframe_system::limits::BlockWeights::simple_max(
|
||||
Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = Block;
|
||||
type AccountData = pezpallet_balances::AccountData<Balance>;
|
||||
// we use U128 account id in order to get a better iteration order out of a map.
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
}
|
||||
|
||||
impl pezpallet_timestamp::Config for Runtime {
|
||||
type Moment = u64;
|
||||
type OnTimestampSet = ();
|
||||
type MinimumPeriod = ConstU64<5>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static ExistentialDeposit: Balance = 1;
|
||||
}
|
||||
|
||||
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_balances::Config for Runtime {
|
||||
type Balance = Balance;
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
}
|
||||
|
||||
pezpallet_staking_reward_curve::build! {
|
||||
const I_NPOS: pezsp_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 pezsp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS;
|
||||
pub static BondingDuration: u32 = 3;
|
||||
pub static CurrentEra: u32 = 0;
|
||||
pub static Ongoing: bool = false;
|
||||
}
|
||||
|
||||
pub struct MockElection;
|
||||
|
||||
impl pezframe_election_provider_support::ElectionProvider for MockElection {
|
||||
type BlockNumber = BlockNumber;
|
||||
type AccountId = AccountId;
|
||||
type DataProvider = Staking;
|
||||
type MaxBackersPerWinner = ConstU32<100>;
|
||||
type MaxWinnersPerPage = ConstU32<100>;
|
||||
type Pages = ConstU32<1>;
|
||||
type MaxBackersPerWinnerFinal = Self::MaxBackersPerWinner;
|
||||
type Error = ();
|
||||
|
||||
fn elect(
|
||||
_remaining_pages: PageIndex,
|
||||
) -> Result<pezframe_election_provider_support::BoundedSupportsOf<Self>, Self::Error> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn start() -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn duration() -> Self::BlockNumber {
|
||||
0
|
||||
}
|
||||
|
||||
fn status() -> Result<bool, ()> {
|
||||
if Ongoing::get() {
|
||||
Ok(false)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive_impl(pezpallet_staking::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_staking::Config for Runtime {
|
||||
type OldCurrency = Balances;
|
||||
type Currency = Balances;
|
||||
type UnixTime = pezpallet_timestamp::Pallet<Self>;
|
||||
type AdminOrigin = pezframe_system::EnsureRoot<Self::AccountId>;
|
||||
type BondingDuration = BondingDuration;
|
||||
type EraPayout = pezpallet_staking::ConvertCurve<RewardCurve>;
|
||||
type ElectionProvider = MockElection;
|
||||
type GenesisElectionProvider = Self::ElectionProvider;
|
||||
type VoterList = pezpallet_staking::UseNominatorsAndValidatorsMap<Self>;
|
||||
type TargetList = pezpallet_staking::UseValidatorsMap<Self>;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static Deposit: u128 = 7;
|
||||
pub static BatchSize: u32 = 1;
|
||||
}
|
||||
|
||||
impl fast_unstake::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Deposit = Deposit;
|
||||
type Currency = Balances;
|
||||
type Staking = Staking;
|
||||
type ControlOrigin = pezframe_system::EnsureRoot<Self::AccountId>;
|
||||
type BatchSize = BatchSize;
|
||||
type WeightInfo = ();
|
||||
type MaxErasToCheckPerBlock = ConstU32<16>;
|
||||
}
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<Runtime>;
|
||||
|
||||
pezframe_support::construct_runtime!(
|
||||
pub enum Runtime {
|
||||
System: pezframe_system,
|
||||
Timestamp: pezpallet_timestamp,
|
||||
Balances: pezpallet_balances,
|
||||
Staking: pezpallet_staking,
|
||||
FastUnstake: fast_unstake,
|
||||
}
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
static FastUnstakeEvents: u32 = 0;
|
||||
}
|
||||
|
||||
pub(crate) fn fast_unstake_events_since_last_call() -> Vec<super::Event<Runtime>> {
|
||||
let events = System::events()
|
||||
.into_iter()
|
||||
.map(|r| r.event)
|
||||
.filter_map(|e| if let RuntimeEvent::FastUnstake(inner) = e { Some(inner) } else { None })
|
||||
.collect::<Vec<_>>();
|
||||
let already_seen = FastUnstakeEvents::get();
|
||||
FastUnstakeEvents::set(events.len() as u32);
|
||||
events.into_iter().skip(already_seen as usize).collect()
|
||||
}
|
||||
|
||||
pub struct ExtBuilder {
|
||||
unexposed: Vec<(AccountId, AccountId, Balance)>,
|
||||
}
|
||||
|
||||
impl Default for ExtBuilder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
unexposed: vec![
|
||||
(1, 1, 7 + 100),
|
||||
(3, 3, 7 + 100),
|
||||
(5, 5, 7 + 100),
|
||||
(7, 7, 7 + 100),
|
||||
(9, 9, 7 + 100),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const VALIDATORS_PER_ERA: AccountId = 32;
|
||||
pub(crate) const VALIDATOR_PREFIX: AccountId = 100;
|
||||
pub(crate) const NOMINATORS_PER_VALIDATOR_PER_ERA: AccountId = 4;
|
||||
pub(crate) const NOMINATOR_PREFIX: AccountId = 1000;
|
||||
|
||||
impl ExtBuilder {
|
||||
pub(crate) fn register_stakers_for_era(era: u32) {
|
||||
// validators are prefixed with 100 and nominators with 1000 to prevent conflict. Make sure
|
||||
// all the other accounts used in tests are below 100. Also ensure here that we don't
|
||||
// overlap.
|
||||
assert!(VALIDATOR_PREFIX + VALIDATORS_PER_ERA < NOMINATOR_PREFIX);
|
||||
|
||||
(VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA)
|
||||
.map(|v| {
|
||||
// for the sake of sanity, let's register this taker as an actual validator.
|
||||
let others = (NOMINATOR_PREFIX..
|
||||
(NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA))
|
||||
.map(|n| IndividualExposure { who: n, value: 0 as Balance })
|
||||
.collect::<Vec<_>>();
|
||||
(v, Exposure { total: 0, own: 0, others })
|
||||
})
|
||||
.for_each(|(validator, exposure)| {
|
||||
pezpallet_staking::EraInfo::<T>::set_exposure(era, &validator, exposure);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn batch(self, size: u32) -> Self {
|
||||
BatchSize::set(size);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> pezsp_io::TestExternalities {
|
||||
pezsp_tracing::try_init_simple();
|
||||
let mut storage =
|
||||
pezframe_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
|
||||
|
||||
let validators_range = VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA;
|
||||
let nominators_range =
|
||||
NOMINATOR_PREFIX..NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA;
|
||||
|
||||
let _ = pezpallet_balances::GenesisConfig::<Runtime> {
|
||||
balances: self
|
||||
.unexposed
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(stash, _, balance)| (stash, balance * 2))
|
||||
// give stakers enough balance for stake, ed and fast unstake deposit.
|
||||
.chain(validators_range.clone().map(|x| (x, 7 + 1 + 100)))
|
||||
.chain(nominators_range.clone().map(|x| (x, 7 + 1 + 100)))
|
||||
.collect::<Vec<_>>(),
|
||||
..Default::default()
|
||||
}
|
||||
.assimilate_storage(&mut storage);
|
||||
|
||||
let _ = pezpallet_staking::GenesisConfig::<Runtime> {
|
||||
stakers: self
|
||||
.unexposed
|
||||
.into_iter()
|
||||
.map(|(x, y, z)| (x, y, z, pezpallet_staking::StakerStatus::Nominator(vec![42])))
|
||||
.chain(validators_range.map(|x| (x, x, 100, StakerStatus::Validator)))
|
||||
.chain(nominators_range.map(|x| (x, x, 100, StakerStatus::Nominator(vec![x]))))
|
||||
.collect::<Vec<_>>(),
|
||||
..Default::default()
|
||||
}
|
||||
.assimilate_storage(&mut storage);
|
||||
|
||||
let mut ext = pezsp_io::TestExternalities::from(storage);
|
||||
|
||||
ext.execute_with(|| {
|
||||
// for events to be deposited.
|
||||
pezframe_system::Pallet::<Runtime>::set_block_number(1);
|
||||
|
||||
for era in 0..=(BondingDuration::get()) {
|
||||
Self::register_stakers_for_era(era);
|
||||
}
|
||||
|
||||
// because we read this value as a measure of how many validators we have.
|
||||
pezpallet_staking::ValidatorCount::<Runtime>::put(VALIDATORS_PER_ERA as u32);
|
||||
});
|
||||
|
||||
ext
|
||||
}
|
||||
|
||||
pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
|
||||
self.build().execute_with(|| {
|
||||
test();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_to_block(n: u64, on_idle: bool) {
|
||||
System::run_to_block_with::<AllPalletsWithSystem>(
|
||||
n,
|
||||
pezframe_system::RunToBlockHooks::default()
|
||||
.before_finalize(|_| {
|
||||
// Satisfy the timestamp pallet.
|
||||
Timestamp::set_timestamp(0);
|
||||
})
|
||||
.after_initialize(|bn| {
|
||||
if on_idle {
|
||||
FastUnstake::on_idle(bn, BlockWeights::get().max_block);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn next_block(on_idle: bool) {
|
||||
let current = System::block_number();
|
||||
run_to_block(current + 1, on_idle);
|
||||
}
|
||||
|
||||
pub fn assert_unstaked(stash: &AccountId) {
|
||||
assert!(!pezpallet_staking::Bonded::<T>::contains_key(stash));
|
||||
assert!(!pezpallet_staking::Payee::<T>::contains_key(stash));
|
||||
assert!(!pezpallet_staking::Validators::<T>::contains_key(stash));
|
||||
assert!(!pezpallet_staking::Nominators::<T>::contains_key(stash));
|
||||
}
|
||||
|
||||
pub fn create_exposed_nominator(exposed: AccountId, era: u32) {
|
||||
// create an exposed nominator in passed era
|
||||
let mut exposure = pezpallet_staking::EraInfo::<T>::get_full_exposure(era, &VALIDATORS_PER_ERA);
|
||||
exposure.others.push(IndividualExposure { who: exposed, value: 0 as Balance });
|
||||
pezpallet_staking::EraInfo::<T>::set_exposure(era, &VALIDATORS_PER_ERA, exposure);
|
||||
|
||||
Balances::make_free_balance_be(&exposed, 100);
|
||||
assert_ok!(Staking::bond(
|
||||
RuntimeOrigin::signed(exposed),
|
||||
10,
|
||||
pezpallet_staking::RewardDestination::Staked
|
||||
));
|
||||
assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed]));
|
||||
// register the exposed one.
|
||||
assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed)));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types used in the Fast Unstake pallet.
|
||||
|
||||
use crate::Config;
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use pezframe_support::{
|
||||
traits::Currency, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use pezsp_staking::{EraIndex, StakingInterface};
|
||||
|
||||
/// Maximum number of eras that we might check for a single staker.
|
||||
///
|
||||
/// In effect, it is the bonding duration, coming from [`Config::Staking`], plus one.
|
||||
#[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)]
|
||||
#[codec(mel_bound(T: Config))]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct MaxChecking<T: Config>(core::marker::PhantomData<T>);
|
||||
impl<T: Config> pezframe_support::traits::Get<u32> for MaxChecking<T> {
|
||||
fn get() -> u32 {
|
||||
T::Staking::bonding_duration() + 1
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
pub type BalanceOf<T> =
|
||||
<<T as Config>::Currency as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
|
||||
/// An unstake request.
|
||||
///
|
||||
/// This is stored in [`crate::Head`] storage item and points to the current unstake request that is
|
||||
/// being processed.
|
||||
#[derive(
|
||||
Encode,
|
||||
Decode,
|
||||
EqNoBound,
|
||||
PartialEqNoBound,
|
||||
CloneNoBound,
|
||||
TypeInfo,
|
||||
RuntimeDebugNoBound,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct UnstakeRequest<T: Config> {
|
||||
/// This list of stashes are being processed in this request, and their corresponding deposit.
|
||||
pub stashes: BoundedVec<(T::AccountId, BalanceOf<T>), T::BatchSize>,
|
||||
/// The list of eras for which they have been checked.
|
||||
pub checked: BoundedVec<EraIndex, MaxChecking<T>>,
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Autogenerated weights for `pezpallet_fast_unstake`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `4563561839a5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
|
||||
|
||||
// Executed Command:
|
||||
// frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --extrinsic=*
|
||||
// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm
|
||||
// --pallet=pezpallet_fast_unstake
|
||||
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
|
||||
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/fast-unstake/src/weights.rs
|
||||
// --wasm-execution=compiled
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --heap-pages=4096
|
||||
// --template=bizinikiwi/.maintain/frame-weight-template.hbs
|
||||
// --no-storage-info
|
||||
// --no-min-squares
|
||||
// --no-median-slopes
|
||||
// --genesis-builder-policy=none
|
||||
// --exclude-pallets=pezpallet_xcm,pezpallet_xcm_benchmarks::fungible,pezpallet_xcm_benchmarks::generic,pezpallet_nomination_pools,pezpallet_remark,pezpallet_transaction_storage,pezpallet_election_provider_multi_block,pezpallet_election_provider_multi_block::signed,pezpallet_election_provider_multi_block::unsigned,pezpallet_election_provider_multi_block::verifier
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use pezframe_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for `pezpallet_fast_unstake`.
|
||||
pub trait WeightInfo {
|
||||
fn on_idle_unstake(b: u32, ) -> Weight;
|
||||
fn on_idle_check(v: u32, b: u32, ) -> Weight;
|
||||
fn register_fast_unstake() -> Weight;
|
||||
fn deregister() -> Weight;
|
||||
fn control() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_fast_unstake` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::ValidatorCount` (r:1 w:0)
|
||||
/// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `MultiBlock::CurrentPhase` (r:1 w:0)
|
||||
/// Proof: `MultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CurrentEra` (r:1 w:0)
|
||||
/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::SlashingSpans` (r:64 w:0)
|
||||
/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `Staking::Bonded` (r:64 w:64)
|
||||
/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Ledger` (r:64 w:64)
|
||||
/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::VirtualStakers` (r:64 w:64)
|
||||
/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:64 w:64)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:64 w:64)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Validators` (r:64 w:0)
|
||||
/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Nominators` (r:64 w:0)
|
||||
/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Payee` (r:0 w:64)
|
||||
/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// The range of component `b` is `[1, 64]`.
|
||||
fn on_idle_unstake(b: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `57 + b * (443 ±0)`
|
||||
// Estimated: `7253 + b * (3566 ±0)`
|
||||
// Minimum execution time: 86_174_000 picoseconds.
|
||||
Weight::from_parts(9_455_381, 7253)
|
||||
// Standard Error: 41_683
|
||||
.saturating_add(Weight::from_parts(72_236_736, 0).saturating_mul(b.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(b.into())))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(b.into())))
|
||||
.saturating_add(Weight::from_parts(0, 3566).saturating_mul(b.into()))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::ValidatorCount` (r:1 w:0)
|
||||
/// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `MultiBlock::CurrentPhase` (r:1 w:0)
|
||||
/// Proof: `MultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CurrentEra` (r:1 w:0)
|
||||
/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::ErasStakersPaged` (r:257 w:0)
|
||||
/// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `v` is `[1, 256]`.
|
||||
/// The range of component `b` is `[1, 64]`.
|
||||
fn on_idle_check(v: u32, b: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `850 + b * (48 ±0) + v * (1318 ±0)`
|
||||
// Estimated: `7253 + b * (49 ±0) + v * (3794 ±0)`
|
||||
// Minimum execution time: 517_331_000 picoseconds.
|
||||
Weight::from_parts(530_541_000, 7253)
|
||||
// Standard Error: 2_918_095
|
||||
.saturating_add(Weight::from_parts(95_402_277, 0).saturating_mul(v.into()))
|
||||
// Standard Error: 11_675_633
|
||||
.saturating_add(Weight::from_parts(365_913_743, 0).saturating_mul(b.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(7_u64))
|
||||
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into())))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
.saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into()))
|
||||
.saturating_add(Weight::from_parts(0, 3794).saturating_mul(v.into()))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Ledger` (r:1 w:1)
|
||||
/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Bonded` (r:1 w:0)
|
||||
/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Queue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Validators` (r:1 w:0)
|
||||
/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Nominators` (r:1 w:1)
|
||||
/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CounterForNominators` (r:1 w:1)
|
||||
/// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `VoterList::ListNodes` (r:1 w:1)
|
||||
/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
|
||||
/// Storage: `VoterList::ListBags` (r:1 w:1)
|
||||
/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
|
||||
/// Storage: `VoterList::CounterForListNodes` (r:1 w:1)
|
||||
/// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CurrentEra` (r:1 w:0)
|
||||
/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::VirtualStakers` (r:1 w:0)
|
||||
/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:1 w:0)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
fn register_fast_unstake() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `702`
|
||||
// Estimated: `7253`
|
||||
// Minimum execution time: 115_559_000 picoseconds.
|
||||
Weight::from_parts(118_297_000, 7253)
|
||||
.saturating_add(T::DbWeight::get().reads(15_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(8_u64))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Ledger` (r:1 w:0)
|
||||
/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Bonded` (r:1 w:0)
|
||||
/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Queue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
fn deregister() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `428`
|
||||
// Estimated: `7253`
|
||||
// Minimum execution time: 38_629_000 picoseconds.
|
||||
Weight::from_parts(39_404_000, 7253)
|
||||
.saturating_add(T::DbWeight::get().reads(6_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:0 w:1)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
fn control() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 1_730_000 picoseconds.
|
||||
Weight::from_parts(1_802_000, 0)
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::ValidatorCount` (r:1 w:0)
|
||||
/// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `MultiBlock::CurrentPhase` (r:1 w:0)
|
||||
/// Proof: `MultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CurrentEra` (r:1 w:0)
|
||||
/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::SlashingSpans` (r:64 w:0)
|
||||
/// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `Staking::Bonded` (r:64 w:64)
|
||||
/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Ledger` (r:64 w:64)
|
||||
/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::VirtualStakers` (r:64 w:64)
|
||||
/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:64 w:64)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:64 w:64)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Validators` (r:64 w:0)
|
||||
/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Nominators` (r:64 w:0)
|
||||
/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Payee` (r:0 w:64)
|
||||
/// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`)
|
||||
/// The range of component `b` is `[1, 64]`.
|
||||
fn on_idle_unstake(b: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `57 + b * (443 ±0)`
|
||||
// Estimated: `7253 + b * (3566 ±0)`
|
||||
// Minimum execution time: 86_174_000 picoseconds.
|
||||
Weight::from_parts(9_455_381, 7253)
|
||||
// Standard Error: 41_683
|
||||
.saturating_add(Weight::from_parts(72_236_736, 0).saturating_mul(b.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().reads((8_u64).saturating_mul(b.into())))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(b.into())))
|
||||
.saturating_add(Weight::from_parts(0, 3566).saturating_mul(b.into()))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::ValidatorCount` (r:1 w:0)
|
||||
/// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `MultiBlock::CurrentPhase` (r:1 w:0)
|
||||
/// Proof: `MultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CurrentEra` (r:1 w:0)
|
||||
/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::ErasStakersPaged` (r:257 w:0)
|
||||
/// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `v` is `[1, 256]`.
|
||||
/// The range of component `b` is `[1, 64]`.
|
||||
fn on_idle_check(v: u32, b: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `850 + b * (48 ±0) + v * (1318 ±0)`
|
||||
// Estimated: `7253 + b * (49 ±0) + v * (3794 ±0)`
|
||||
// Minimum execution time: 517_331_000 picoseconds.
|
||||
Weight::from_parts(530_541_000, 7253)
|
||||
// Standard Error: 2_918_095
|
||||
.saturating_add(Weight::from_parts(95_402_277, 0).saturating_mul(v.into()))
|
||||
// Standard Error: 11_675_633
|
||||
.saturating_add(Weight::from_parts(365_913_743, 0).saturating_mul(b.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(7_u64))
|
||||
.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into())))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
.saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into()))
|
||||
.saturating_add(Weight::from_parts(0, 3794).saturating_mul(v.into()))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Ledger` (r:1 w:1)
|
||||
/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Bonded` (r:1 w:0)
|
||||
/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Queue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Validators` (r:1 w:0)
|
||||
/// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Nominators` (r:1 w:1)
|
||||
/// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CounterForNominators` (r:1 w:1)
|
||||
/// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `VoterList::ListNodes` (r:1 w:1)
|
||||
/// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`)
|
||||
/// Storage: `VoterList::ListBags` (r:1 w:1)
|
||||
/// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`)
|
||||
/// Storage: `VoterList::CounterForListNodes` (r:1 w:1)
|
||||
/// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::CurrentEra` (r:1 w:0)
|
||||
/// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::VirtualStakers` (r:1 w:0)
|
||||
/// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Balances::Holds` (r:1 w:0)
|
||||
/// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
fn register_fast_unstake() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `702`
|
||||
// Estimated: `7253`
|
||||
// Minimum execution time: 115_559_000 picoseconds.
|
||||
Weight::from_parts(118_297_000, 7253)
|
||||
.saturating_add(RocksDbWeight::get().reads(15_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(8_u64))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Ledger` (r:1 w:0)
|
||||
/// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Staking::Bonded` (r:1 w:0)
|
||||
/// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Queue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::Head` (r:1 w:0)
|
||||
/// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`)
|
||||
/// Storage: `FastUnstake::CounterForQueue` (r:1 w:1)
|
||||
/// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
fn deregister() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `428`
|
||||
// Estimated: `7253`
|
||||
// Minimum execution time: 38_629_000 picoseconds.
|
||||
Weight::from_parts(39_404_000, 7253)
|
||||
.saturating_add(RocksDbWeight::get().reads(6_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: `FastUnstake::ErasToCheckPerBlock` (r:0 w:1)
|
||||
/// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
fn control() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 1_730_000 picoseconds.
|
||||
Weight::from_parts(1_802_000, 0)
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user