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:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
@@ -0,0 +1,295 @@
// 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.
//! ConvictionVoting pallet benchmarking.
use super::*;
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use assert_matches::assert_matches;
use pezframe_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist_account};
use pezframe_support::{
dispatch::RawOrigin,
traits::{
fungible,
tokens::{Fortitude::Polite, Preservation::Expendable},
Currency, Get,
},
};
use pezsp_runtime::traits::Bounded;
use crate::Pallet as ConvictionVoting;
const SEED: u32 = 0;
/// Fill all classes as much as possible up to `MaxVotes` and return the Class with the most votes
/// ongoing.
fn fill_voting<T: Config<I>, I: 'static>(
) -> (ClassOf<T, I>, BTreeMap<ClassOf<T, I>, Vec<IndexOf<T, I>>>) {
let mut r = BTreeMap::<ClassOf<T, I>, Vec<IndexOf<T, I>>>::new();
for class in T::Polls::classes().into_iter() {
for _ in 0..T::MaxVotes::get() {
match T::Polls::create_ongoing(class.clone()) {
Ok(i) => r.entry(class.clone()).or_default().push(i),
Err(()) => break,
}
}
}
let c = r.iter().max_by_key(|(_, v)| v.len()).unwrap().0.clone();
(c, r)
}
fn funded_account<T: Config<I>, I: 'static>(name: &'static str, index: u32) -> T::AccountId {
let caller: T::AccountId = account(name, index, SEED);
T::Currency::make_free_balance_be(&caller, BalanceOf::<T, I>::max_value());
caller
}
fn account_vote<T: Config<I>, I: 'static>(b: BalanceOf<T, I>) -> AccountVote<BalanceOf<T, I>> {
let v = Vote { aye: true, conviction: Conviction::Locked1x };
AccountVote::Standard { vote: v, balance: b }
}
benchmarks_instance_pallet! {
where_clause { where T::MaxVotes: core::fmt::Debug }
vote_new {
let caller = funded_account::<T, I>("caller", 0);
whitelist_account!(caller);
let account_vote = account_vote::<T, I>(100u32.into());
T::VotingHooks::on_vote_worst_case(&caller);
let (class, all_polls) = fill_voting::<T, I>();
let polls = &all_polls[&class];
let r = polls.len() - 1;
// We need to create existing votes
for i in polls.iter().skip(1) {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote)?;
}
let votes = match VotingFor::<T, I>::get(&caller, &class) {
Voting::Casting(Casting { votes, .. }) => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), r as usize, "Votes were not recorded.");
let index = polls[0];
}: vote(RawOrigin::Signed(caller.clone()), index, account_vote)
verify {
assert_matches!(
VotingFor::<T, I>::get(&caller, &class),
Voting::Casting(Casting { votes, .. }) if votes.len() == (r + 1) as usize
);
}
vote_existing {
let caller = funded_account::<T, I>("caller", 0);
whitelist_account!(caller);
let old_account_vote = account_vote::<T, I>(100u32.into());
T::VotingHooks::on_vote_worst_case(&caller);
let (class, all_polls) = fill_voting::<T, I>();
let polls = &all_polls[&class];
let r = polls.len();
// We need to create existing votes
for i in polls.iter() {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?;
}
let votes = match VotingFor::<T, I>::get(&caller, &class) {
Voting::Casting(Casting { votes, .. }) => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), r, "Votes were not recorded.");
let new_account_vote = account_vote::<T, I>(200u32.into());
let index = polls[0];
}: vote(RawOrigin::Signed(caller.clone()), index, new_account_vote)
verify {
assert_matches!(
VotingFor::<T, I>::get(&caller, &class),
Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize
);
}
remove_vote {
let caller = funded_account::<T, I>("caller", 0);
whitelist_account!(caller);
let old_account_vote = account_vote::<T, I>(100u32.into());
T::VotingHooks::on_vote_worst_case(&caller);
let (class, all_polls) = fill_voting::<T, I>();
let polls = &all_polls[&class];
let r = polls.len();
// We need to create existing votes
for i in polls.iter() {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?;
}
let votes = match VotingFor::<T, I>::get(&caller, &class) {
Voting::Casting(Casting { votes, .. }) => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), r, "Votes were not recorded.");
let index = polls[0];
}: _(RawOrigin::Signed(caller.clone()), Some(class.clone()), index)
verify {
assert_matches!(
VotingFor::<T, I>::get(&caller, &class),
Voting::Casting(Casting { votes, .. }) if votes.len() == (r - 1) as usize
);
}
remove_other_vote {
let caller = funded_account::<T, I>("caller", 0);
let voter = funded_account::<T, I>("caller", 0);
let voter_lookup = T::Lookup::unlookup(voter.clone());
whitelist_account!(caller);
let old_account_vote = account_vote::<T, I>(100u32.into());
T::VotingHooks::on_vote_worst_case(&caller);
let (class, all_polls) = fill_voting::<T, I>();
let polls = &all_polls[&class];
let r = polls.len();
// We need to create existing votes
for i in polls.iter() {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote)?;
}
let votes = match VotingFor::<T, I>::get(&caller, &class) {
Voting::Casting(Casting { votes, .. }) => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), r, "Votes were not recorded.");
let index = polls[0];
assert!(T::Polls::end_ongoing(index, false).is_ok());
}: _(RawOrigin::Signed(caller.clone()), voter_lookup, class.clone(), index)
verify {
assert_matches!(
VotingFor::<T, I>::get(&voter, &class),
Voting::Casting(Casting { votes, .. }) if votes.len() == (r - 1) as usize
);
}
delegate {
let r in 0 .. T::MaxVotes::get().min(T::Polls::max_ongoing().1);
let all_polls = fill_voting::<T, I>().1;
let class = T::Polls::max_ongoing().0;
let polls = &all_polls[&class];
let voter = funded_account::<T, I>("voter", 0);
let voter_lookup = T::Lookup::unlookup(voter.clone());
let caller = funded_account::<T, I>("caller", 0);
whitelist_account!(caller);
let delegated_balance: BalanceOf<T, I> = 1000u32.into();
let delegate_vote = account_vote::<T, I>(delegated_balance);
// We need to create existing delegations
for i in polls.iter().take(r as usize) {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?;
}
assert_matches!(
VotingFor::<T, I>::get(&voter, &class),
Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize
);
}: _(RawOrigin::Signed(caller.clone()), class.clone(), voter_lookup, Conviction::Locked1x, delegated_balance)
verify {
assert_matches!(VotingFor::<T, I>::get(&caller, &class), Voting::Delegating(_));
}
undelegate {
let r in 0 .. T::MaxVotes::get().min(T::Polls::max_ongoing().1);
let all_polls = fill_voting::<T, I>().1;
let class = T::Polls::max_ongoing().0;
let polls = &all_polls[&class];
let voter = funded_account::<T, I>("voter", 0);
let voter_lookup = T::Lookup::unlookup(voter.clone());
let caller = funded_account::<T, I>("caller", 0);
whitelist_account!(caller);
let delegated_balance: BalanceOf<T, I> = 1000u32.into();
let delegate_vote = account_vote::<T, I>(delegated_balance);
ConvictionVoting::<T, I>::delegate(
RawOrigin::Signed(caller.clone()).into(),
class.clone(),
voter_lookup,
Conviction::Locked1x,
delegated_balance,
)?;
// We need to create delegations
for i in polls.iter().take(r as usize) {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?;
}
assert_matches!(
VotingFor::<T, I>::get(&voter, &class),
Voting::Casting(Casting { votes, .. }) if votes.len() == r as usize
);
assert_matches!(VotingFor::<T, I>::get(&caller, &class), Voting::Delegating(_));
}: _(RawOrigin::Signed(caller.clone()), class.clone())
verify {
assert_matches!(VotingFor::<T, I>::get(&caller, &class), Voting::Casting(_));
}
unlock {
let caller = funded_account::<T, I>("caller", 0);
let caller_lookup = T::Lookup::unlookup(caller.clone());
whitelist_account!(caller);
let normal_account_vote = account_vote::<T, I>(T::Currency::free_balance(&caller) - 100u32.into());
let big_account_vote = account_vote::<T, I>(T::Currency::free_balance(&caller));
// Fill everything up to the max by filling all classes with votes and voting on them all.
let (class, all_polls) = fill_voting::<T, I>();
assert!(all_polls.len() > 0);
for (class, polls) in all_polls.iter() {
assert!(polls.len() > 0);
for i in polls.iter() {
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote)?;
}
}
let orig_usable = <T::Currency as fungible::Inspect<T::AccountId>>::reducible_balance(&caller, Expendable, Polite);
let polls = &all_polls[&class];
// Vote big on the class with the most ongoing votes of them to bump the lock and make it
// hard to recompute when removed.
ConvictionVoting::<T, I>::vote(RawOrigin::Signed(caller.clone()).into(), polls[0], big_account_vote)?;
let now_usable = <T::Currency as fungible::Inspect<T::AccountId>>::reducible_balance(&caller, Expendable, Polite);
assert_eq!(orig_usable - now_usable, 100u32.into());
// Remove the vote
ConvictionVoting::<T, I>::remove_vote(RawOrigin::Signed(caller.clone()).into(), Some(class.clone()), polls[0])?;
// We can now unlock on `class` from 200 to 100...
}: _(RawOrigin::Signed(caller.clone()), class, caller_lookup)
verify {
assert_eq!(orig_usable, <T::Currency as fungible::Inspect<T::AccountId>>::reducible_balance(&caller, Expendable, Polite));
}
impl_benchmark_test_suite!(
ConvictionVoting,
crate::tests::new_test_ext(),
crate::tests::Test
);
}
@@ -0,0 +1,132 @@
// 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.
//! The conviction datatype.
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use pezsp_runtime::{
traits::{Bounded, CheckedDiv, CheckedMul, Zero},
RuntimeDebug,
};
use crate::types::Delegations;
/// A value denoting the strength of conviction of a vote.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Copy,
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub enum Conviction {
/// 0.1x votes, unlocked.
None,
/// 1x votes, locked for an enactment period following a successful vote.
Locked1x,
/// 2x votes, locked for 2x enactment periods following a successful vote.
Locked2x,
/// 3x votes, locked for 4x...
Locked3x,
/// 4x votes, locked for 8x...
Locked4x,
/// 5x votes, locked for 16x...
Locked5x,
/// 6x votes, locked for 32x...
Locked6x,
}
impl Default for Conviction {
fn default() -> Self {
Conviction::None
}
}
impl From<Conviction> for u8 {
fn from(c: Conviction) -> u8 {
match c {
Conviction::None => 0,
Conviction::Locked1x => 1,
Conviction::Locked2x => 2,
Conviction::Locked3x => 3,
Conviction::Locked4x => 4,
Conviction::Locked5x => 5,
Conviction::Locked6x => 6,
}
}
}
impl TryFrom<u8> for Conviction {
type Error = ();
fn try_from(i: u8) -> Result<Conviction, ()> {
Ok(match i {
0 => Conviction::None,
1 => Conviction::Locked1x,
2 => Conviction::Locked2x,
3 => Conviction::Locked3x,
4 => Conviction::Locked4x,
5 => Conviction::Locked5x,
6 => Conviction::Locked6x,
_ => return Err(()),
})
}
}
impl Conviction {
/// The amount of time (in number of periods) that our conviction implies a successful voter's
/// balance should be locked for.
pub fn lock_periods(self) -> u32 {
match self {
Conviction::None => 0,
Conviction::Locked1x => 1,
Conviction::Locked2x => 2,
Conviction::Locked3x => 4,
Conviction::Locked4x => 8,
Conviction::Locked5x => 16,
Conviction::Locked6x => 32,
}
}
/// The votes of a voter of the given `balance` with our conviction.
pub fn votes<B: From<u8> + Zero + Copy + CheckedMul + CheckedDiv + Bounded>(
self,
capital: B,
) -> Delegations<B> {
let votes = match self {
Conviction::None => capital.checked_div(&10u8.into()).unwrap_or_else(Zero::zero),
x => capital.checked_mul(&u8::from(x).into()).unwrap_or_else(B::max_value),
};
Delegations { votes, capital }
}
}
impl Bounded for Conviction {
fn min_value() -> Self {
Conviction::None
}
fn max_value() -> Self {
Conviction::Locked6x
}
}
@@ -0,0 +1,761 @@
// 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.
//! # Voting Pallet
//!
//! - [`Config`]
//! - [`Call`]
//!
//! ## Overview
//!
//! Pallet for managing actual voting in polls.
#![recursion_limit = "256"]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use pezframe_support::{
dispatch::DispatchResult,
ensure,
traits::{
fungible, Currency, Get, LockIdentifier, LockableCurrency, PollStatus, Polling,
ReservableCurrency, WithdrawReasons,
},
};
use pezsp_runtime::{
traits::{AtLeast32BitUnsigned, Saturating, StaticLookup, Zero},
ArithmeticError, DispatchError, Perbill,
};
mod conviction;
mod traits;
mod types;
mod vote;
pub mod weights;
pub use self::{
conviction::Conviction,
pallet::*,
traits::{Status, VotingHooks},
types::{Delegations, Tally, UnvoteScope},
vote::{AccountVote, Casting, Delegating, Vote, Voting},
weights::WeightInfo,
};
use pezsp_runtime::traits::BlockNumberProvider;
#[cfg(test)]
mod tests;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot";
pub type BlockNumberFor<T, I> =
<<T as Config<I>>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
type AccountIdLookupOf<T> = <<T as pezframe_system::Config>::Lookup as StaticLookup>::Source;
pub type BalanceOf<T, I = ()> =
<<T as Config<I>>::Currency as Currency<<T as pezframe_system::Config>::AccountId>>::Balance;
pub type VotingOf<T, I = ()> = Voting<
BalanceOf<T, I>,
<T as pezframe_system::Config>::AccountId,
BlockNumberFor<T, I>,
PollIndexOf<T, I>,
<T as Config<I>>::MaxVotes,
>;
#[allow(dead_code)]
type DelegatingOf<T, I = ()> =
Delegating<BalanceOf<T, I>, <T as pezframe_system::Config>::AccountId, BlockNumberFor<T, I>>;
pub type TallyOf<T, I = ()> = Tally<BalanceOf<T, I>, <T as Config<I>>::MaxTurnout>;
pub type VotesOf<T, I = ()> = BalanceOf<T, I>;
pub type PollIndexOf<T, I = ()> = <<T as Config<I>>::Polls as Polling<TallyOf<T, I>>>::Index;
#[cfg(feature = "runtime-benchmarks")]
pub type IndexOf<T, I = ()> = <<T as Config<I>>::Polls as Polling<TallyOf<T, I>>>::Index;
pub type ClassOf<T, I = ()> = <<T as Config<I>>::Polls as Polling<TallyOf<T, I>>>::Class;
#[pezframe_support::pallet]
pub mod pallet {
use super::*;
use pezframe_support::{
pezpallet_prelude::{
DispatchResultWithPostInfo, IsType, StorageDoubleMap, StorageMap, ValueQuery,
},
traits::ClassCountOf,
Twox64Concat,
};
use pezframe_system::pezpallet_prelude::{ensure_signed, OriginFor};
use pezsp_runtime::BoundedVec;
#[pallet::pallet]
pub struct Pallet<T, I = ()>(_);
#[pallet::config]
pub trait Config<I: 'static = ()>: pezframe_system::Config + Sized {
// System level stuff.
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
/// Currency type with which voting happens.
type Currency: ReservableCurrency<Self::AccountId>
+ LockableCurrency<Self::AccountId, Moment = BlockNumberFor<Self, I>>
+ fungible::Inspect<Self::AccountId>;
/// The implementation of the logic which conducts polls.
type Polls: Polling<
TallyOf<Self, I>,
Votes = BalanceOf<Self, I>,
Moment = BlockNumberFor<Self, I>,
>;
/// The maximum amount of tokens which may be used for voting. May just be
/// `Currency::total_issuance`, but you might want to reduce this in order to account for
/// funds in the system which are unable to vote (e.g. teyrchain auction deposits).
type MaxTurnout: Get<BalanceOf<Self, I>>;
/// The maximum number of concurrent votes an account may have.
///
/// Also used to compute weight, an overly large value can lead to extrinsics with large
/// weight estimation: see `delegate` for instance.
#[pallet::constant]
type MaxVotes: Get<u32>;
/// The minimum period of vote locking.
///
/// It should be no shorter than enactment period to ensure that in the case of an approval,
/// those successful voters are locked into the consequences that their votes entail.
#[pallet::constant]
type VoteLockingPeriod: Get<BlockNumberFor<Self, I>>;
/// Provider for the block number. Normally this is the `pezframe_system` pallet.
type BlockNumberProvider: BlockNumberProvider;
/// Hooks are called when a new vote is registered or an existing vote is removed.
///
/// The trait does not expose weight information.
/// The weight of each hook is assumed to be benchmarked as part of the function that calls
/// it. Hooks should never recursively call into functions that called,
/// directly or indirectly, the function that called them.
/// This could lead to infinite recursion and stack overflow.
/// Note that this also means to not call into other generic functionality like batch or
/// similar. Also, anything that a hook did will be subject to the transactional semantics
/// of the calling function. This means that if the calling function fails, the hook will
/// be rolled back without further notice.
type VotingHooks: VotingHooks<Self::AccountId, PollIndexOf<Self, I>, BalanceOf<Self, I>>;
}
/// All voting for a particular voter in a particular voting class. We store the balance for the
/// number of votes that we have recorded.
#[pallet::storage]
pub type VotingFor<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
_,
Twox64Concat,
T::AccountId,
Twox64Concat,
ClassOf<T, I>,
VotingOf<T, I>,
ValueQuery,
>;
/// The voting classes which have a non-zero lock requirement and the lock amounts which they
/// require. The actual amount locked on behalf of this pallet should always be the maximum of
/// this list.
#[pallet::storage]
pub type ClassLocksFor<T: Config<I>, I: 'static = ()> = StorageMap<
_,
Twox64Concat,
T::AccountId,
BoundedVec<(ClassOf<T, I>, BalanceOf<T, I>), ClassCountOf<T::Polls, TallyOf<T, I>>>,
ValueQuery,
>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
/// An account has delegated their vote to another account. \[who, target\]
Delegated(T::AccountId, T::AccountId, ClassOf<T, I>),
/// An \[account\] has cancelled a previous delegation operation.
Undelegated(T::AccountId, ClassOf<T, I>),
/// An account has voted
Voted {
who: T::AccountId,
vote: AccountVote<BalanceOf<T, I>>,
poll_index: PollIndexOf<T, I>,
},
/// A vote has been removed
VoteRemoved {
who: T::AccountId,
vote: AccountVote<BalanceOf<T, I>>,
poll_index: PollIndexOf<T, I>,
},
/// The lockup period of a conviction vote expired, and the funds have been unlocked.
VoteUnlocked { who: T::AccountId, class: ClassOf<T, I> },
}
#[pallet::error]
pub enum Error<T, I = ()> {
/// Poll is not ongoing.
NotOngoing,
/// The given account did not vote on the poll.
NotVoter,
/// The actor has no permission to conduct the action.
NoPermission,
/// The actor has no permission to conduct the action right now but will do in the future.
NoPermissionYet,
/// The account is already delegating.
AlreadyDelegating,
/// The account currently has votes attached to it and the operation cannot succeed until
/// these are removed through `remove_vote`.
AlreadyVoting,
/// Too high a balance was provided that the account cannot afford.
InsufficientFunds,
/// The account is not currently delegating.
NotDelegating,
/// Delegation to oneself makes no sense.
Nonsense,
/// Maximum number of votes reached.
MaxVotesReached,
/// The class must be supplied since it is not easily determinable from the state.
ClassNeeded,
/// The class ID supplied is invalid.
BadClass,
}
#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Vote in a poll. If `vote.is_aye()`, the vote is to enact the proposal;
/// otherwise it is a vote to keep the status quo.
///
/// The dispatch origin of this call must be _Signed_.
///
/// - `poll_index`: The index of the poll to vote for.
/// - `vote`: The vote configuration.
///
/// Weight: `O(R)` where R is the number of polls the voter has voted on.
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))]
pub fn vote(
origin: OriginFor<T>,
#[pallet::compact] poll_index: PollIndexOf<T, I>,
vote: AccountVote<BalanceOf<T, I>>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::try_vote(&who, poll_index, vote)
}
/// Delegate the voting power (with some given conviction) of the sending account for a
/// particular class of polls.
///
/// The balance delegated is locked for as long as it's delegated, and thereafter for the
/// time appropriate for the conviction's lock period.
///
/// The dispatch origin of this call must be _Signed_, and the signing account must either:
/// - be delegating already; or
/// - have no voting activity (if there is, then it will need to be removed through
/// `remove_vote`).
///
/// - `to`: The account whose voting the `target` account's voting power will follow.
/// - `class`: The class of polls to delegate. To delegate multiple classes, multiple calls
/// to this function are required.
/// - `conviction`: The conviction that will be attached to the delegated votes. When the
/// account is undelegated, the funds will be locked for the corresponding period.
/// - `balance`: The amount of the account's balance to be used in delegating. This must not
/// be more than the account's current balance.
///
/// Emits `Delegated`.
///
/// Weight: `O(R)` where R is the number of polls the voter delegating to has
/// voted on. Weight is initially charged as if maximum votes, but is refunded later.
// NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure
// because a valid delegation cover decoding a direct voting with max votes.
#[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::delegate(T::MaxVotes::get()))]
pub fn delegate(
origin: OriginFor<T>,
class: ClassOf<T, I>,
to: AccountIdLookupOf<T>,
conviction: Conviction,
balance: BalanceOf<T, I>,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
let to = T::Lookup::lookup(to)?;
let votes = Self::try_delegate(who, class, to, conviction, balance)?;
Ok(Some(T::WeightInfo::delegate(votes)).into())
}
/// Undelegate the voting power of the sending account for a particular class of polls.
///
/// Tokens may be unlocked following once an amount of time consistent with the lock period
/// of the conviction with which the delegation was issued has passed.
///
/// The dispatch origin of this call must be _Signed_ and the signing account must be
/// currently delegating.
///
/// - `class`: The class of polls to remove the delegation from.
///
/// Emits `Undelegated`.
///
/// Weight: `O(R)` where R is the number of polls the voter delegating to has
/// voted on. Weight is initially charged as if maximum votes, but is refunded later.
// NOTE: weight must cover an incorrect voting of origin with max votes, this is ensure
// because a valid delegation cover decoding a direct voting with max votes.
#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::undelegate(T::MaxVotes::get().into()))]
pub fn undelegate(
origin: OriginFor<T>,
class: ClassOf<T, I>,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
let votes = Self::try_undelegate(who, class)?;
Ok(Some(T::WeightInfo::undelegate(votes)).into())
}
/// Remove the lock caused by prior voting/delegating which has expired within a particular
/// class.
///
/// The dispatch origin of this call must be _Signed_.
///
/// - `class`: The class of polls to unlock.
/// - `target`: The account to remove the lock on.
///
/// Weight: `O(R)` with R number of vote of target.
#[pallet::call_index(3)]
#[pallet::weight(T::WeightInfo::unlock())]
pub fn unlock(
origin: OriginFor<T>,
class: ClassOf<T, I>,
target: AccountIdLookupOf<T>,
) -> DispatchResult {
ensure_signed(origin)?;
let target = T::Lookup::lookup(target)?;
Self::update_lock(&class, &target);
Self::deposit_event(Event::VoteUnlocked { who: target, class });
Ok(())
}
/// Remove a vote for a poll.
///
/// If:
/// - the poll was cancelled, or
/// - the poll is ongoing, or
/// - the poll has ended such that
/// - the vote of the account was in opposition to the result; or
/// - there was no conviction to the account's vote; or
/// - the account made a split vote
/// ...then the vote is removed cleanly and a following call to `unlock` may result in more
/// funds being available.
///
/// If, however, the poll has ended and:
/// - it finished corresponding to the vote of the account, and
/// - the account made a standard vote with conviction, and
/// - the lock period of the conviction is not over
/// ...then the lock will be aggregated into the overall account's lock, which may involve
/// *overlocking* (where the two locks are combined into a single lock that is the maximum
/// of both the amount locked and the time is it locked for).
///
/// The dispatch origin of this call must be _Signed_, and the signer must have a vote
/// registered for poll `index`.
///
/// - `index`: The index of poll of the vote to be removed.
/// - `class`: Optional parameter, if given it indicates the class of the poll. For polls
/// which have finished or are cancelled, this must be `Some`.
///
/// Weight: `O(R + log R)` where R is the number of polls that `target` has voted on.
/// Weight is calculated for the maximum number of vote.
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::remove_vote())]
pub fn remove_vote(
origin: OriginFor<T>,
class: Option<ClassOf<T, I>>,
index: PollIndexOf<T, I>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::try_remove_vote(&who, index, class, UnvoteScope::Any)
}
/// Remove a vote for a poll.
///
/// If the `target` is equal to the signer, then this function is exactly equivalent to
/// `remove_vote`. If not equal to the signer, then the vote must have expired,
/// either because the poll was cancelled, because the voter lost the poll or
/// because the conviction period is over.
///
/// The dispatch origin of this call must be _Signed_.
///
/// - `target`: The account of the vote to be removed; this account must have voted for poll
/// `index`.
/// - `index`: The index of poll of the vote to be removed.
/// - `class`: The class of the poll.
///
/// Weight: `O(R + log R)` where R is the number of polls that `target` has voted on.
/// Weight is calculated for the maximum number of vote.
#[pallet::call_index(5)]
#[pallet::weight(T::WeightInfo::remove_other_vote())]
pub fn remove_other_vote(
origin: OriginFor<T>,
target: AccountIdLookupOf<T>,
class: ClassOf<T, I>,
index: PollIndexOf<T, I>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
let target = T::Lookup::lookup(target)?;
let scope = if target == who { UnvoteScope::Any } else { UnvoteScope::OnlyExpired };
Self::try_remove_vote(&target, index, Some(class), scope)?;
Ok(())
}
}
}
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Actually enact a vote, if legit.
fn try_vote(
who: &T::AccountId,
poll_index: PollIndexOf<T, I>,
vote: AccountVote<BalanceOf<T, I>>,
) -> DispatchResult {
ensure!(
vote.balance() <= T::Currency::total_balance(who),
Error::<T, I>::InsufficientFunds
);
// Call on_vote hook
T::VotingHooks::on_before_vote(who, poll_index, vote)?;
T::Polls::try_access_poll(poll_index, |poll_status| {
let (tally, class) = poll_status.ensure_ongoing().ok_or(Error::<T, I>::NotOngoing)?;
VotingFor::<T, I>::try_mutate(who, &class, |voting| {
if let Voting::Casting(Casting { ref mut votes, delegations, .. }) = voting {
match votes.binary_search_by_key(&poll_index, |i| i.0) {
Ok(i) => {
// Shouldn't be possible to fail, but we handle it gracefully.
tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?;
if let Some(approve) = votes[i].1.as_standard() {
tally.reduce(approve, *delegations);
}
votes[i].1 = vote;
},
Err(i) => {
votes
.try_insert(i, (poll_index, vote))
.map_err(|_| Error::<T, I>::MaxVotesReached)?;
},
}
// Shouldn't be possible to fail, but we handle it gracefully.
tally.add(vote).ok_or(ArithmeticError::Overflow)?;
if let Some(approve) = vote.as_standard() {
tally.increase(approve, *delegations);
}
} else {
return Err(Error::<T, I>::AlreadyDelegating.into());
}
// Extend the lock to `balance` (rather than setting it) since we don't know what
// other votes are in place.
Self::extend_lock(who, &class, vote.balance());
Self::deposit_event(Event::Voted { who: who.clone(), vote, poll_index });
Ok(())
})
})
}
/// Remove the account's vote for the given poll if possible. This is possible when:
/// - The poll has not finished.
/// - The poll has finished and the voter lost their direction.
/// - The poll has finished and the voter's lock period is up.
///
/// This will generally be combined with a call to `unlock`.
fn try_remove_vote(
who: &T::AccountId,
poll_index: PollIndexOf<T, I>,
class_hint: Option<ClassOf<T, I>>,
scope: UnvoteScope,
) -> DispatchResult {
let class = class_hint
.or_else(|| Some(T::Polls::as_ongoing(poll_index)?.1))
.ok_or(Error::<T, I>::ClassNeeded)?;
VotingFor::<T, I>::try_mutate(who, class, |voting| {
if let Voting::Casting(Casting { ref mut votes, delegations, ref mut prior }) = voting {
let i = votes
.binary_search_by_key(&poll_index, |i| i.0)
.map_err(|_| Error::<T, I>::NotVoter)?;
let v = votes.remove(i);
T::Polls::try_access_poll(poll_index, |poll_status| match poll_status {
PollStatus::Ongoing(tally, _) => {
ensure!(matches!(scope, UnvoteScope::Any), Error::<T, I>::NoPermission);
// Shouldn't be possible to fail, but we handle it gracefully.
tally.remove(v.1).ok_or(ArithmeticError::Underflow)?;
if let Some(approve) = v.1.as_standard() {
tally.reduce(approve, *delegations);
}
Self::deposit_event(Event::VoteRemoved {
who: who.clone(),
vote: v.1,
poll_index,
});
T::VotingHooks::on_remove_vote(who, poll_index, Status::Ongoing);
Ok(())
},
PollStatus::Completed(end, approved) => {
if let Some((lock_periods, balance)) =
v.1.locked_if(vote::LockedIf::Status(approved))
{
let unlock_at = end.saturating_add(
T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()),
);
let now = T::BlockNumberProvider::current_block_number();
if now < unlock_at {
ensure!(
matches!(scope, UnvoteScope::Any),
Error::<T, I>::NoPermissionYet
);
prior.accumulate(unlock_at, balance)
}
} else if v.1.as_standard().is_some_and(|vote| vote != approved) {
// Unsuccessful vote, use special hook to lock the funds too in case of
// conviction.
if let Some(to_lock) =
T::VotingHooks::lock_balance_on_unsuccessful_vote(who, poll_index)
{
if let AccountVote::Standard { vote, .. } = v.1 {
let unlock_at = end.saturating_add(
T::VoteLockingPeriod::get()
.saturating_mul(vote.conviction.lock_periods().into()),
);
let now = T::BlockNumberProvider::current_block_number();
if now < unlock_at {
ensure!(
matches!(scope, UnvoteScope::Any),
Error::<T, I>::NoPermissionYet
);
prior.accumulate(unlock_at, to_lock)
}
}
}
}
// Call on_remove_vote hook
T::VotingHooks::on_remove_vote(who, poll_index, Status::Completed);
Ok(())
},
PollStatus::None => {
// Poll was cancelled.
T::VotingHooks::on_remove_vote(who, poll_index, Status::None);
Ok(())
},
})
} else {
Ok(())
}
})
}
/// Return the number of votes for `who`.
fn increase_upstream_delegation(
who: &T::AccountId,
class: &ClassOf<T, I>,
amount: Delegations<BalanceOf<T, I>>,
) -> u32 {
VotingFor::<T, I>::mutate(who, class, |voting| match voting {
Voting::Delegating(Delegating { delegations, .. }) => {
// We don't support second level delegating, so we don't need to do anything more.
*delegations = delegations.saturating_add(amount);
1
},
Voting::Casting(Casting { votes, delegations, .. }) => {
*delegations = delegations.saturating_add(amount);
for &(poll_index, account_vote) in votes.iter() {
if let AccountVote::Standard { vote, .. } = account_vote {
T::Polls::access_poll(poll_index, |poll_status| {
if let PollStatus::Ongoing(tally, _) = poll_status {
tally.increase(vote.aye, amount);
}
});
}
}
votes.len() as u32
},
})
}
/// Return the number of votes for `who`.
fn reduce_upstream_delegation(
who: &T::AccountId,
class: &ClassOf<T, I>,
amount: Delegations<BalanceOf<T, I>>,
) -> u32 {
VotingFor::<T, I>::mutate(who, class, |voting| match voting {
Voting::Delegating(Delegating { delegations, .. }) => {
// We don't support second level delegating, so we don't need to do anything more.
*delegations = delegations.saturating_sub(amount);
1
},
Voting::Casting(Casting { votes, delegations, .. }) => {
*delegations = delegations.saturating_sub(amount);
for &(poll_index, account_vote) in votes.iter() {
if let AccountVote::Standard { vote, .. } = account_vote {
T::Polls::access_poll(poll_index, |poll_status| {
if let PollStatus::Ongoing(tally, _) = poll_status {
tally.reduce(vote.aye, amount);
}
});
}
}
votes.len() as u32
},
})
}
/// Attempt to delegate `balance` times `conviction` of voting power from `who` to `target`.
///
/// Return the upstream number of votes.
fn try_delegate(
who: T::AccountId,
class: ClassOf<T, I>,
target: T::AccountId,
conviction: Conviction,
balance: BalanceOf<T, I>,
) -> Result<u32, DispatchError> {
ensure!(who != target, Error::<T, I>::Nonsense);
T::Polls::classes().binary_search(&class).map_err(|_| Error::<T, I>::BadClass)?;
ensure!(balance <= T::Currency::total_balance(&who), Error::<T, I>::InsufficientFunds);
let votes =
VotingFor::<T, I>::try_mutate(&who, &class, |voting| -> Result<u32, DispatchError> {
let old = core::mem::replace(
voting,
Voting::Delegating(Delegating {
balance,
target: target.clone(),
conviction,
delegations: Default::default(),
prior: Default::default(),
}),
);
match old {
Voting::Delegating(Delegating { .. }) =>
return Err(Error::<T, I>::AlreadyDelegating.into()),
Voting::Casting(Casting { votes, delegations, prior }) => {
// here we just ensure that we're currently idling with no votes recorded.
ensure!(votes.is_empty(), Error::<T, I>::AlreadyVoting);
voting.set_common(delegations, prior);
},
}
let votes =
Self::increase_upstream_delegation(&target, &class, conviction.votes(balance));
// Extend the lock to `balance` (rather than setting it) since we don't know what
// other votes are in place.
Self::extend_lock(&who, &class, balance);
Ok(votes)
})?;
Self::deposit_event(Event::<T, I>::Delegated(who, target, class));
Ok(votes)
}
/// Attempt to end the current delegation.
///
/// Return the number of votes of upstream.
fn try_undelegate(who: T::AccountId, class: ClassOf<T, I>) -> Result<u32, DispatchError> {
let votes =
VotingFor::<T, I>::try_mutate(&who, &class, |voting| -> Result<u32, DispatchError> {
match core::mem::replace(voting, Voting::default()) {
Voting::Delegating(Delegating {
balance,
target,
conviction,
delegations,
mut prior,
}) => {
// remove any delegation votes to our current target.
let votes = Self::reduce_upstream_delegation(
&target,
&class,
conviction.votes(balance),
);
let now = T::BlockNumberProvider::current_block_number();
let lock_periods = conviction.lock_periods().into();
prior.accumulate(
now.saturating_add(
T::VoteLockingPeriod::get().saturating_mul(lock_periods),
),
balance,
);
voting.set_common(delegations, prior);
Ok(votes)
},
Voting::Casting(_) => Err(Error::<T, I>::NotDelegating.into()),
}
})?;
Self::deposit_event(Event::<T, I>::Undelegated(who, class));
Ok(votes)
}
fn extend_lock(who: &T::AccountId, class: &ClassOf<T, I>, amount: BalanceOf<T, I>) {
ClassLocksFor::<T, I>::mutate(who, |locks| {
match locks.iter().position(|x| &x.0 == class) {
Some(i) => locks[i].1 = locks[i].1.max(amount),
None => {
let ok = locks.try_push((class.clone(), amount)).is_ok();
debug_assert!(
ok,
"Vec bounded by number of classes; \
all items in Vec associated with a unique class; \
qed"
);
},
}
});
T::Currency::extend_lock(
CONVICTION_VOTING_ID,
who,
amount,
WithdrawReasons::except(WithdrawReasons::RESERVE),
);
}
/// Rejig the lock on an account. It will never get more stringent (since that would indicate
/// a security hole) but may be reduced from what they are currently.
fn update_lock(class: &ClassOf<T, I>, who: &T::AccountId) {
let class_lock_needed = VotingFor::<T, I>::mutate(who, class, |voting| {
voting.rejig(T::BlockNumberProvider::current_block_number());
voting.locked_balance()
});
let lock_needed = ClassLocksFor::<T, I>::mutate(who, |locks| {
locks.retain(|x| &x.0 != class);
if !class_lock_needed.is_zero() {
let ok = locks.try_push((class.clone(), class_lock_needed)).is_ok();
debug_assert!(
ok,
"Vec bounded by number of classes; \
all items in Vec associated with a unique class; \
qed"
);
}
locks.iter().map(|x| x.1).max().unwrap_or(Zero::zero())
});
if lock_needed.is_zero() {
T::Currency::remove_lock(CONVICTION_VOTING_ID, who);
} else {
T::Currency::set_lock(
CONVICTION_VOTING_ID,
who,
lock_needed,
WithdrawReasons::except(WithdrawReasons::RESERVE),
);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,121 @@
// 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::AccountVote;
//! Traits for conviction voting.
use crate::AccountVote;
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use pezframe_support::dispatch::DispatchResult;
use scale_info::TypeInfo;
use pezsp_runtime::RuntimeDebug;
/// Represents the differents states of a referendum.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Copy,
Clone,
Eq,
PartialEq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub enum Status {
/// The referendum is not started.
None,
/// The referendum is ongoing.
Ongoing,
/// The referendum is finished.
Completed,
}
/// Trait for voting hooks that are called during various stages of the voting process.
///
/// # Important Note
/// These hooks are called BEFORE the actual vote is recorded in storage. This means:
/// - If `on_vote` returns an error, the entire voting operation will be reverted
/// - If `on_vote` succeeds but the voting operation fails later, any storage modifications made by
/// `on_vote` will still persist
///
/// # Hook Methods
/// - `on_vote`: Called before a vote is recorded. Returns `Err` to prevent the vote from being
/// recorded. Storage modifications made by this hook will persist even if the vote fails later.
///
/// - `on_remove_vote`: Called before a vote is removed. Cannot fail.
/// - `lock_balance_on_unsuccessful_vote`: Called when a vote fails to be recorded (e.g. due to
/// insufficient balance). Returns optionally locked balance amount.
///
/// # Benchmarking Hooks
/// The following methods are only used during runtime benchmarking:
/// - `on_vote_worst_case`: Sets up worst-case state for `on_vote` benchmarking
/// - `on_remove_vote_worst_case`: Sets up worst-case state for `on_remove_vote` benchmarking
///
/// # Generic Parameters
/// - `AccountId`: The type used to identify accounts in the system
/// - `Index`: The type used for referendum indices
/// - `Balance`: The type used for balance values
pub trait VotingHooks<AccountId, Index, Balance> {
// Called before a vote is recorded.
// Returns `Err` to prevent the vote from being recorded.
fn on_before_vote(
who: &AccountId,
ref_index: Index,
vote: AccountVote<Balance>,
) -> DispatchResult;
// Called when removed vote is executed.
fn on_remove_vote(who: &AccountId, ref_index: Index, status: Status);
// Called when a vote is unsuccessful.
// Returns the amount of locked balance, which is `None` in the default implementation.
fn lock_balance_on_unsuccessful_vote(who: &AccountId, ref_index: Index) -> Option<Balance>;
/// Will be called by benchmarking before calling `on_vote` in a benchmark.
///
/// Should setup the state in such a way that when `on_vote` is called it will
/// take the worst case path performance wise.
#[cfg(feature = "runtime-benchmarks")]
fn on_vote_worst_case(who: &AccountId);
/// Will be called by benchmarking before calling `on_remove_vote` in a benchmark.
///
/// Should setup the state in such a way that when `on_remove_vote` is called it will
/// take the worst case path performance wise.
#[cfg(feature = "runtime-benchmarks")]
fn on_remove_vote_worst_case(who: &AccountId);
}
// Default implementation for VotingHooks
impl<A, I, B> VotingHooks<A, I, B> for () {
fn on_before_vote(_who: &A, _ref_index: I, _vote: AccountVote<B>) -> DispatchResult {
Ok(())
}
fn on_remove_vote(_who: &A, _ref_index: I, _status: Status) {}
fn lock_balance_on_unsuccessful_vote(_who: &A, _ref_index: I) -> Option<B> {
None
}
#[cfg(feature = "runtime-benchmarks")]
fn on_vote_worst_case(_who: &A) {}
#[cfg(feature = "runtime-benchmarks")]
fn on_remove_vote_worst_case(_who: &A) {}
}
@@ -0,0 +1,270 @@
// 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.
//! Miscellaneous additional datatypes.
use codec::{Codec, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use core::{fmt::Debug, marker::PhantomData};
use pezframe_support::{
traits::VoteTally, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
};
use scale_info::TypeInfo;
use pezsp_runtime::{
traits::{Saturating, Zero},
RuntimeDebug,
};
use super::*;
use crate::{AccountVote, Conviction, Vote};
/// Info regarding an ongoing referendum.
#[derive(
CloneNoBound,
PartialEqNoBound,
EqNoBound,
RuntimeDebugNoBound,
TypeInfo,
Encode,
Decode,
DecodeWithMemTracking,
MaxEncodedLen,
)]
#[scale_info(skip_type_params(Total))]
#[codec(mel_bound(Votes: MaxEncodedLen))]
pub struct Tally<Votes: Clone + PartialEq + Eq + Debug + TypeInfo + Codec, Total> {
/// The number of aye votes, expressed in terms of post-conviction lock-vote.
pub ayes: Votes,
/// The number of nay votes, expressed in terms of post-conviction lock-vote.
pub nays: Votes,
/// The basic number of aye votes, expressed pre-conviction.
pub support: Votes,
/// Dummy.
dummy: PhantomData<Total>,
}
impl<
Votes: Clone + Default + PartialEq + Eq + Debug + Copy + AtLeast32BitUnsigned + TypeInfo + Codec,
Total: Get<Votes>,
Class,
> VoteTally<Votes, Class> for Tally<Votes, Total>
{
fn new(_: Class) -> Self {
Self { ayes: Zero::zero(), nays: Zero::zero(), support: Zero::zero(), dummy: PhantomData }
}
fn ayes(&self, _: Class) -> Votes {
self.ayes
}
fn support(&self, _: Class) -> Perbill {
Perbill::from_rational(self.support, Total::get())
}
fn approval(&self, _: Class) -> Perbill {
Perbill::from_rational(self.ayes, self.ayes.saturating_add(self.nays))
}
#[cfg(feature = "runtime-benchmarks")]
fn unanimity(_: Class) -> Self {
Self { ayes: Total::get(), nays: Zero::zero(), support: Total::get(), dummy: PhantomData }
}
#[cfg(feature = "runtime-benchmarks")]
fn rejection(_: Class) -> Self {
Self { ayes: Zero::zero(), nays: Total::get(), support: Total::get(), dummy: PhantomData }
}
#[cfg(feature = "runtime-benchmarks")]
fn from_requirements(support: Perbill, approval: Perbill, _: Class) -> Self {
let support = support.mul_ceil(Total::get());
let ayes = approval.mul_ceil(support);
Self { ayes, nays: support - ayes, support, dummy: PhantomData }
}
#[cfg(feature = "runtime-benchmarks")]
fn setup(_: Class, _: Perbill) {}
}
impl<
Votes: Clone + Default + PartialEq + Eq + Debug + Copy + AtLeast32BitUnsigned + TypeInfo + Codec,
Total: Get<Votes>,
> Tally<Votes, Total>
{
/// Create a new tally.
pub fn from_vote(vote: Vote, balance: Votes) -> Self {
let Delegations { votes, capital } = vote.conviction.votes(balance);
Self {
ayes: if vote.aye { votes } else { Zero::zero() },
nays: if vote.aye { Zero::zero() } else { votes },
support: capital,
dummy: PhantomData,
}
}
pub fn from_parts(
ayes_with_conviction: Votes,
nays_with_conviction: Votes,
support: Votes,
) -> Self {
Self { ayes: ayes_with_conviction, nays: nays_with_conviction, support, dummy: PhantomData }
}
/// Add an account's vote into the tally.
pub fn add(&mut self, vote: AccountVote<Votes>) -> Option<()> {
match vote {
AccountVote::Standard { vote, balance } => {
let Delegations { votes, capital } = vote.conviction.votes(balance);
match vote.aye {
true => {
self.support = self.support.checked_add(&capital)?;
self.ayes = self.ayes.checked_add(&votes)?
},
false => self.nays = self.nays.checked_add(&votes)?,
}
},
AccountVote::Split { aye, nay } => {
let aye = Conviction::None.votes(aye);
let nay = Conviction::None.votes(nay);
self.support = self.support.checked_add(&aye.capital)?;
self.ayes = self.ayes.checked_add(&aye.votes)?;
self.nays = self.nays.checked_add(&nay.votes)?;
},
AccountVote::SplitAbstain { aye, nay, abstain } => {
let aye = Conviction::None.votes(aye);
let nay = Conviction::None.votes(nay);
let abstain = Conviction::None.votes(abstain);
self.support =
self.support.checked_add(&aye.capital)?.checked_add(&abstain.capital)?;
self.ayes = self.ayes.checked_add(&aye.votes)?;
self.nays = self.nays.checked_add(&nay.votes)?;
},
}
Some(())
}
/// Remove an account's vote from the tally.
pub fn remove(&mut self, vote: AccountVote<Votes>) -> Option<()> {
match vote {
AccountVote::Standard { vote, balance } => {
let Delegations { votes, capital } = vote.conviction.votes(balance);
match vote.aye {
true => {
self.support = self.support.checked_sub(&capital)?;
self.ayes = self.ayes.checked_sub(&votes)?
},
false => self.nays = self.nays.checked_sub(&votes)?,
}
},
AccountVote::Split { aye, nay } => {
let aye = Conviction::None.votes(aye);
let nay = Conviction::None.votes(nay);
self.support = self.support.checked_sub(&aye.capital)?;
self.ayes = self.ayes.checked_sub(&aye.votes)?;
self.nays = self.nays.checked_sub(&nay.votes)?;
},
AccountVote::SplitAbstain { aye, nay, abstain } => {
let aye = Conviction::None.votes(aye);
let nay = Conviction::None.votes(nay);
let abstain = Conviction::None.votes(abstain);
self.support =
self.support.checked_sub(&aye.capital)?.checked_sub(&abstain.capital)?;
self.ayes = self.ayes.checked_sub(&aye.votes)?;
self.nays = self.nays.checked_sub(&nay.votes)?;
},
}
Some(())
}
/// Increment some amount of votes.
pub fn increase(&mut self, approve: bool, delegations: Delegations<Votes>) {
match approve {
true => {
self.support = self.support.saturating_add(delegations.capital);
self.ayes = self.ayes.saturating_add(delegations.votes);
},
false => self.nays = self.nays.saturating_add(delegations.votes),
}
}
/// Decrement some amount of votes.
pub fn reduce(&mut self, approve: bool, delegations: Delegations<Votes>) {
match approve {
true => {
self.support = self.support.saturating_sub(delegations.capital);
self.ayes = self.ayes.saturating_sub(delegations.votes);
},
false => self.nays = self.nays.saturating_sub(delegations.votes),
}
}
}
/// Amount of votes and capital placed in delegation for an account.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Default,
Copy,
Clone,
PartialEq,
Eq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub struct Delegations<Balance> {
/// The number of votes (this is post-conviction).
pub votes: Balance,
/// The amount of raw capital, used for the support.
pub capital: Balance,
}
impl<Balance: Saturating> Saturating for Delegations<Balance> {
fn saturating_add(self, o: Self) -> Self {
Self {
votes: self.votes.saturating_add(o.votes),
capital: self.capital.saturating_add(o.capital),
}
}
fn saturating_sub(self, o: Self) -> Self {
Self {
votes: self.votes.saturating_sub(o.votes),
capital: self.capital.saturating_sub(o.capital),
}
}
fn saturating_mul(self, o: Self) -> Self {
Self {
votes: self.votes.saturating_mul(o.votes),
capital: self.capital.saturating_mul(o.capital),
}
}
fn saturating_pow(self, exp: usize) -> Self {
Self { votes: self.votes.saturating_pow(exp), capital: self.capital.saturating_pow(exp) }
}
}
/// Whether an `unvote` operation is able to make actions that are not strictly always in the
/// interest of an account.
pub enum UnvoteScope {
/// Permitted to do everything.
Any,
/// Permitted to do only the changes that do not need the owner's permission.
OnlyExpired,
}
@@ -0,0 +1,330 @@
// 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.
//! The vote datatype.
use crate::{Conviction, Delegations};
use codec::{Decode, DecodeWithMemTracking, Encode, EncodeLike, Input, MaxEncodedLen, Output};
use pezframe_support::{pezpallet_prelude::Get, BoundedVec};
use scale_info::TypeInfo;
use pezsp_runtime::{
traits::{Saturating, Zero},
RuntimeDebug,
};
/// A number of lock periods, plus a vote, one way or the other.
#[derive(
DecodeWithMemTracking, Copy, Clone, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen,
)]
pub struct Vote {
pub aye: bool,
pub conviction: Conviction,
}
impl Encode for Vote {
fn encode_to<T: Output + ?Sized>(&self, output: &mut T) {
output.push_byte(u8::from(self.conviction) | if self.aye { 0b1000_0000 } else { 0 });
}
}
impl EncodeLike for Vote {}
impl Decode for Vote {
fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
let b = input.read_byte()?;
Ok(Vote {
aye: (b & 0b1000_0000) == 0b1000_0000,
conviction: Conviction::try_from(b & 0b0111_1111)
.map_err(|_| codec::Error::from("Invalid conviction"))?,
})
}
}
impl TypeInfo for Vote {
type Identity = Self;
fn type_info() -> scale_info::Type {
scale_info::Type::builder()
.path(scale_info::Path::new("Vote", module_path!()))
.composite(
scale_info::build::Fields::unnamed()
.field(|f| f.ty::<u8>().docs(&["Raw vote byte, encodes aye + conviction"])),
)
}
}
/// A vote for a referendum of a particular account.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Copy,
Clone,
Eq,
PartialEq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub enum AccountVote<Balance> {
/// A standard vote, one-way (approve or reject) with a given amount of conviction.
Standard { vote: Vote, balance: Balance },
/// A split vote with balances given for both ways, and with no conviction, useful for
/// teyrchains when voting.
Split { aye: Balance, nay: Balance },
/// A split vote with balances given for both ways as well as abstentions, and with no
/// conviction, useful for teyrchains when voting, other off-chain aggregate accounts and
/// individuals who wish to abstain.
SplitAbstain { aye: Balance, nay: Balance, abstain: Balance },
}
/// Present the conditions under which an account's Funds are locked after a voting action.
#[derive(Copy, Clone, Eq, PartialEq, RuntimeDebug)]
pub enum LockedIf {
/// Lock the funds if the outcome of the referendum matches the voting behavior of the user.
///
/// `true` means they voted `aye` and `false` means `nay`.
Status(bool),
/// Always lock the funds.
Always,
}
impl<Balance: Saturating> AccountVote<Balance> {
/// Returns `Some` of the lock periods that the account is locked for, assuming that the
/// referendum passed if `approved` is `true`.
pub fn locked_if(self, approved: LockedIf) -> Option<(u32, Balance)> {
// winning side: can only be removed after the lock period ends.
match (self, approved) {
// If the vote has no conviction, always return None
(AccountVote::Standard { vote: Vote { conviction: Conviction::None, .. }, .. }, _) =>
None,
// For Standard votes, check the approval condition
(AccountVote::Standard { vote, balance }, LockedIf::Status(is_approved))
if vote.aye == is_approved =>
Some((vote.conviction.lock_periods(), balance)),
// If LockedIf::Always, return the lock period regardless of the vote
(AccountVote::Standard { vote, balance }, LockedIf::Always) =>
Some((vote.conviction.lock_periods(), balance)),
// All other cases return None
_ => None,
}
}
/// The total balance involved in this vote.
pub fn balance(self) -> Balance {
match self {
AccountVote::Standard { balance, .. } => balance,
AccountVote::Split { aye, nay } => aye.saturating_add(nay),
AccountVote::SplitAbstain { aye, nay, abstain } =>
aye.saturating_add(nay).saturating_add(abstain),
}
}
/// Returns `Some` with whether the vote is an aye vote if it is standard, otherwise `None` if
/// it is split.
pub fn as_standard(self) -> Option<bool> {
match self {
AccountVote::Standard { vote, .. } => Some(vote.aye),
_ => None,
}
}
}
/// A "prior" lock, i.e. a lock for some now-forgotten reason.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Default,
Copy,
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub struct PriorLock<BlockNumber, Balance>(BlockNumber, Balance);
impl<BlockNumber: Ord + Copy + Zero, Balance: Ord + Copy + Zero> PriorLock<BlockNumber, Balance> {
/// Accumulates an additional lock.
pub fn accumulate(&mut self, until: BlockNumber, amount: Balance) {
self.0 = self.0.max(until);
self.1 = self.1.max(amount);
}
pub fn locked(&self) -> Balance {
self.1
}
pub fn rejig(&mut self, now: BlockNumber) {
if now >= self.0 {
self.0 = Zero::zero();
self.1 = Zero::zero();
}
}
}
/// Information concerning the delegation of some voting power.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Clone,
Eq,
PartialEq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub struct Delegating<Balance, AccountId, BlockNumber> {
/// The amount of balance delegated.
pub balance: Balance,
/// The account to which the voting power is delegated.
pub target: AccountId,
/// The conviction with which the voting power is delegated. When this gets undelegated, the
/// relevant lock begins.
pub conviction: Conviction,
/// The total amount of delegations that this account has received, post-conviction-weighting.
pub delegations: Delegations<Balance>,
/// Any pre-existing locks from past voting/delegating activity.
pub prior: PriorLock<BlockNumber, Balance>,
}
/// Information concerning the direct vote-casting of some voting power.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Clone,
Eq,
PartialEq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
#[scale_info(skip_type_params(MaxVotes))]
#[codec(mel_bound(Balance: MaxEncodedLen, BlockNumber: MaxEncodedLen, PollIndex: MaxEncodedLen))]
pub struct Casting<Balance, BlockNumber, PollIndex, MaxVotes>
where
MaxVotes: Get<u32>,
{
/// The current votes of the account.
pub votes: BoundedVec<(PollIndex, AccountVote<Balance>), MaxVotes>,
/// The total amount of delegations that this account has received, post-conviction-weighting.
pub delegations: Delegations<Balance>,
/// Any pre-existing locks from past voting/delegating activity.
pub prior: PriorLock<BlockNumber, Balance>,
}
/// An indicator for what an account is doing; it can either be delegating or voting.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Clone,
Eq,
PartialEq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
#[scale_info(skip_type_params(MaxVotes))]
#[codec(mel_bound(
Balance: MaxEncodedLen, AccountId: MaxEncodedLen, BlockNumber: MaxEncodedLen,
PollIndex: MaxEncodedLen,
))]
pub enum Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
where
MaxVotes: Get<u32>,
{
/// The account is voting directly.
Casting(Casting<Balance, BlockNumber, PollIndex, MaxVotes>),
/// The account is delegating `balance` of its balance to a `target` account with `conviction`.
Delegating(Delegating<Balance, AccountId, BlockNumber>),
}
impl<Balance: Default, AccountId, BlockNumber: Zero, PollIndex, MaxVotes> Default
for Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
where
MaxVotes: Get<u32>,
{
fn default() -> Self {
Voting::Casting(Casting {
votes: Default::default(),
delegations: Default::default(),
prior: PriorLock(Zero::zero(), Default::default()),
})
}
}
impl<Balance, AccountId, BlockNumber, PollIndex, MaxVotes> AsMut<PriorLock<BlockNumber, Balance>>
for Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
where
MaxVotes: Get<u32>,
{
fn as_mut(&mut self) -> &mut PriorLock<BlockNumber, Balance> {
match self {
Voting::Casting(Casting { prior, .. }) => prior,
Voting::Delegating(Delegating { prior, .. }) => prior,
}
}
}
impl<
Balance: Saturating + Ord + Zero + Copy,
BlockNumber: Ord + Copy + Zero,
AccountId,
PollIndex,
MaxVotes,
> Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
where
MaxVotes: Get<u32>,
{
pub fn rejig(&mut self, now: BlockNumber) {
AsMut::<PriorLock<BlockNumber, Balance>>::as_mut(self).rejig(now);
}
/// The amount of this account's balance that must currently be locked due to voting.
pub fn locked_balance(&self) -> Balance {
match self {
Voting::Casting(Casting { votes, prior, .. }) =>
votes.iter().map(|i| i.1.balance()).fold(prior.locked(), |a, i| a.max(i)),
Voting::Delegating(Delegating { balance, prior, .. }) => *balance.max(&prior.locked()),
}
}
pub fn set_common(
&mut self,
delegations: Delegations<Balance>,
prior: PriorLock<BlockNumber, Balance>,
) {
let (d, p) = match self {
Voting::Casting(Casting { ref mut delegations, ref mut prior, .. }) =>
(delegations, prior),
Voting::Delegating(Delegating { ref mut delegations, ref mut prior, .. }) =>
(delegations, prior),
};
*d = delegations;
*p = prior;
}
}
@@ -0,0 +1,397 @@
// 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_conviction_voting`
//!
//! 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_conviction_voting
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/conviction-voting/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_conviction_voting`.
pub trait WeightInfo {
fn vote_new() -> Weight;
fn vote_existing() -> Weight;
fn remove_vote() -> Weight;
fn remove_other_vote() -> Weight;
fn delegate(r: u32, ) -> Weight;
fn undelegate(r: u32, ) -> Weight;
fn unlock() -> Weight;
}
/// Weights for `pezpallet_conviction_voting` using the Bizinikiwi node and recommended hardware.
pub struct BizinikiwiWeight<T>(PhantomData<T>);
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
fn vote_new() -> Weight {
// Proof Size summary in bytes:
// Measured: `12820`
// Estimated: `219984`
// Minimum execution time: 122_673_000 picoseconds.
Weight::from_parts(132_468_000, 219984)
.saturating_add(T::DbWeight::get().reads(8_u64))
.saturating_add(T::DbWeight::get().writes(7_u64))
}
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
fn vote_existing() -> Weight {
// Proof Size summary in bytes:
// Measured: `19983`
// Estimated: `219984`
// Minimum execution time: 318_133_000 picoseconds.
Weight::from_parts(333_487_000, 219984)
.saturating_add(T::DbWeight::get().reads(8_u64))
.saturating_add(T::DbWeight::get().writes(7_u64))
}
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
fn remove_vote() -> Weight {
// Proof Size summary in bytes:
// Measured: `19820`
// Estimated: `219984`
// Minimum execution time: 288_951_000 picoseconds.
Weight::from_parts(305_052_000, 219984)
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(5_u64))
}
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
fn remove_other_vote() -> Weight {
// Proof Size summary in bytes:
// Measured: `12599`
// Estimated: `30706`
// Minimum execution time: 60_940_000 picoseconds.
Weight::from_parts(65_626_000, 30706)
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::VotingFor` (r:2 w:2)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
/// The range of component `r` is `[0, 1]`.
fn delegate(r: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `146 + r * (1516 ±0)`
// Estimated: `109992 + r * (109992 ±0)`
// Minimum execution time: 53_837_000 picoseconds.
Weight::from_parts(57_424_161, 109992)
// Standard Error: 349_816
.saturating_add(Weight::from_parts(45_427_938, 0).saturating_mul(r.into()))
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into())))
.saturating_add(T::DbWeight::get().writes(4_u64))
.saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(r.into())))
.saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into()))
}
/// Storage: `ConvictionVoting::VotingFor` (r:2 w:2)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
/// The range of component `r` is `[0, 1]`.
fn undelegate(r: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `350 + r * (1264 ±0)`
// Estimated: `109992 + r * (109992 ±0)`
// Minimum execution time: 26_552_000 picoseconds.
Weight::from_parts(28_629_093, 109992)
// Standard Error: 178_796
.saturating_add(Weight::from_parts(38_342_206, 0).saturating_mul(r.into()))
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into())))
.saturating_add(T::DbWeight::get().writes(2_u64))
.saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(r.into())))
.saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into()))
}
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
fn unlock() -> Weight {
// Proof Size summary in bytes:
// Measured: `11593`
// Estimated: `30706`
// Minimum execution time: 83_405_000 picoseconds.
Weight::from_parts(92_198_000, 30706)
.saturating_add(T::DbWeight::get().reads(5_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
fn vote_new() -> Weight {
// Proof Size summary in bytes:
// Measured: `12820`
// Estimated: `219984`
// Minimum execution time: 122_673_000 picoseconds.
Weight::from_parts(132_468_000, 219984)
.saturating_add(RocksDbWeight::get().reads(8_u64))
.saturating_add(RocksDbWeight::get().writes(7_u64))
}
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
fn vote_existing() -> Weight {
// Proof Size summary in bytes:
// Measured: `19983`
// Estimated: `219984`
// Minimum execution time: 318_133_000 picoseconds.
Weight::from_parts(333_487_000, 219984)
.saturating_add(RocksDbWeight::get().reads(8_u64))
.saturating_add(RocksDbWeight::get().writes(7_u64))
}
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
fn remove_vote() -> Weight {
// Proof Size summary in bytes:
// Measured: `19820`
// Estimated: `219984`
// Minimum execution time: 288_951_000 picoseconds.
Weight::from_parts(305_052_000, 219984)
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(5_u64))
}
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
fn remove_other_vote() -> Weight {
// Proof Size summary in bytes:
// Measured: `12599`
// Estimated: `30706`
// Minimum execution time: 60_940_000 picoseconds.
Weight::from_parts(65_626_000, 30706)
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::VotingFor` (r:2 w:2)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
/// The range of component `r` is `[0, 1]`.
fn delegate(r: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `146 + r * (1516 ±0)`
// Estimated: `109992 + r * (109992 ±0)`
// Minimum execution time: 53_837_000 picoseconds.
Weight::from_parts(57_424_161, 109992)
// Standard Error: 349_816
.saturating_add(Weight::from_parts(45_427_938, 0).saturating_mul(r.into()))
.saturating_add(RocksDbWeight::get().reads(6_u64))
.saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into())))
.saturating_add(RocksDbWeight::get().writes(4_u64))
.saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(r.into())))
.saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into()))
}
/// Storage: `ConvictionVoting::VotingFor` (r:2 w:2)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1)
/// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Agenda` (r:2 w:2)
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`)
/// Storage: `Scheduler::Retries` (r:0 w:1)
/// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`)
/// The range of component `r` is `[0, 1]`.
fn undelegate(r: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `350 + r * (1264 ±0)`
// Estimated: `109992 + r * (109992 ±0)`
// Minimum execution time: 26_552_000 picoseconds.
Weight::from_parts(28_629_093, 109992)
// Standard Error: 178_796
.saturating_add(Weight::from_parts(38_342_206, 0).saturating_mul(r.into()))
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into())))
.saturating_add(RocksDbWeight::get().writes(2_u64))
.saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(r.into())))
.saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into()))
}
/// Storage: `ConvictionVoting::VotingFor` (r:1 w:1)
/// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`)
/// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1)
/// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`)
/// Storage: `Parameters::Parameters` (r:1 w:0)
/// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(11322), added: 13797, mode: `MaxEncodedLen`)
/// Storage: `Balances::Locks` (r:1 w:1)
/// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`)
/// Storage: `Balances::Freezes` (r:1 w:0)
/// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`)
fn unlock() -> Weight {
// Proof Size summary in bytes:
// Measured: `11593`
// Estimated: `30706`
// Minimum execution time: 83_405_000 picoseconds.
Weight::from_parts(92_198_000, 30706)
.saturating_add(RocksDbWeight::get().reads(5_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
}