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,62 @@
|
||||
[package]
|
||||
name = "pezpallet-conviction-voting"
|
||||
version = "28.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "FRAME pallet for conviction voting in referenda"
|
||||
readme = "README.md"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
assert_matches = { workspace = true }
|
||||
codec = { features = ["derive", "max-encoded-len"], workspace = true }
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
scale-info = { features = ["derive"], workspace = true }
|
||||
serde = { features = [
|
||||
"derive",
|
||||
], optional = true, workspace = true, default-features = true }
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezpallet-balances = { workspace = true, default-features = true }
|
||||
pezsp-core = { workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"pezpallet-balances/std",
|
||||
"scale-info/std",
|
||||
"serde",
|
||||
"pezsp-core/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
# Voting Pallet
|
||||
|
||||
- [`assembly::Config`](https://docs.rs/pezpallet-assembly/latest/pallet_assembly/trait.Config.html)
|
||||
- [`Call`](https://docs.rs/pezpallet-assembly/latest/pallet_assembly/enum.Call.html)
|
||||
|
||||
## Overview
|
||||
|
||||
Pallet for voting in referenda.
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user