Referenda and Conviction Voting pallets (#10195)

* Initial draft of new referendum state machine.

* Docs

* Fixes

* Fixes

* Add conviction-voting pallet

* Basic build

* Building

* Some TODOs

* Tests building

* Add missing file

* Basic lifecycle test

* Add couple of tests

* Another test

* More tests

* Fixes

* Fixes

* Formatting

* Fixes

* Tests

* Fixes

* Fixes

* More tests

* Formatting

* First few benchmarks

* First few benchmarks

* Defered queue servicing

* More testing

* Benchmarks

* Fiddly benchmark

* Final nudge benchmarks

* Formatting

* Formatting

* Finished up benchmarks

* cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_referenda --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/referenda/src/weights.rs --template=./.maintain/frame-weight-template.hbs

* Events finished

* Missing file

* No GenesisConfig for Referenda

* Formatting

* Docs

* Docs

* Docs

* Per-class conviction voting

* New test & mock utils

* More tests

* Tests

* Tests finished 🎉

* Benchmarking stuff

* Fixes

* Test harness

* Test harness

* Benchmarks for Conviction=Voting

* Benchmarking pipeline complete

* Docs

* Formatting

* Remove unneeded warning

* Fix UI tests

* cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_conviction_voting --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/conviction-voting/src/weights.rs --template=./.maintain/frame-weight-template.hbs

* Docs

* Update frame/conviction-voting/src/vote.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* update sp-runtime version

* MEL Fixes for Referenda and Conviction Voting (#10725)

* free maxencodedlen

* more maxencodedlen

* more MEL

* more mel

* disable storage info

* More Referenda Patches (#10760)

* basic fixes

* fix benchmarking

* fix license

* prevent panic in curve math

* fmt

* bump crate versions

* Update mock.rs

Co-authored-by: Parity Bot <admin@parity.io>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Gavin Wood
2022-02-06 12:51:12 +01:00
committed by GitHub
parent 074ff19dbc
commit a6891951fb
34 changed files with 6542 additions and 106 deletions
@@ -0,0 +1,520 @@
// This file is part of Substrate.
// Copyright (C) 2020-2021 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.
//! Democracy pallet benchmarking.
use super::*;
use crate::Pallet as Referenda;
use assert_matches::assert_matches;
use frame_benchmarking::{account, benchmarks, whitelist_account};
use frame_support::{
assert_ok,
traits::{Currency, EnsureOrigin},
};
use frame_system::RawOrigin;
use sp_runtime::traits::{Bounded, Hash};
const SEED: u32 = 0;
#[allow(dead_code)]
fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
}
fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
let caller: T::AccountId = account(name, index, SEED);
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
caller
}
fn create_referendum<T: Config>() -> (T::AccountId, ReferendumIndex) {
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
assert_ok!(Referenda::<T>::submit(
RawOrigin::Signed(caller.clone()).into(),
RawOrigin::Root.into(),
T::Hashing::hash_of(&0),
AtOrAfter::After(0u32.into())
));
let index = ReferendumCount::<T>::get() - 1;
(caller, index)
}
fn place_deposit<T: Config>(index: ReferendumIndex) {
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
assert_ok!(Referenda::<T>::place_decision_deposit(
RawOrigin::Signed(caller.clone()).into(),
index,
));
}
fn nudge<T: Config>(index: ReferendumIndex) {
assert_ok!(Referenda::<T>::nudge_referendum(RawOrigin::Root.into(), index));
}
fn fill_queue<T: Config>(
index: ReferendumIndex,
spaces: u32,
pass_after: u32,
) -> Vec<ReferendumIndex> {
// First, create enough other referendums to fill the track.
let mut others = vec![];
for _ in 0..info::<T>(index).max_deciding {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
others.push(index);
}
// We will also need enough referenda which are queued and passing, we want `MaxQueued - 1`
// in order to force the maximum amount of work to insert ours into the queue.
for _ in spaces..T::MaxQueued::get() {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
make_passing_after::<T>(index, Perbill::from_percent(pass_after));
others.push(index);
}
// Skip to when they can start being decided.
skip_prepare_period::<T>(index);
// Manually nudge the other referenda first to ensure that they begin.
others.iter().for_each(|&i| nudge::<T>(i));
others
}
fn info<T: Config>(index: ReferendumIndex) -> &'static TrackInfoOf<T> {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
T::Tracks::info(status.track).expect("Id value returned from T::Tracks")
}
fn make_passing_after<T: Config>(index: ReferendumIndex, period_portion: Perbill) {
let turnout = info::<T>(index).min_turnout.threshold(period_portion);
let approval = info::<T>(index).min_approval.threshold(period_portion);
Referenda::<T>::access_poll(index, |status| {
if let PollStatus::Ongoing(tally, ..) = status {
*tally = T::Tally::from_requirements(turnout, approval);
}
});
}
fn make_passing<T: Config>(index: ReferendumIndex) {
Referenda::<T>::access_poll(index, |status| {
if let PollStatus::Ongoing(tally, ..) = status {
*tally = T::Tally::unanimity();
}
});
}
fn make_failing<T: Config>(index: ReferendumIndex) {
Referenda::<T>::access_poll(index, |status| {
if let PollStatus::Ongoing(tally, ..) = status {
*tally = T::Tally::default();
}
});
}
fn skip_prepare_period<T: Config>(index: ReferendumIndex) {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
let prepare_period_over = status.submitted + info::<T>(index).prepare_period;
frame_system::Pallet::<T>::set_block_number(prepare_period_over);
}
fn skip_decision_period<T: Config>(index: ReferendumIndex) {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
let decision_period_over = status.deciding.unwrap().since + info::<T>(index).decision_period;
frame_system::Pallet::<T>::set_block_number(decision_period_over);
}
fn skip_confirm_period<T: Config>(index: ReferendumIndex) {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
let confirm_period_over = status.deciding.unwrap().confirming.unwrap();
frame_system::Pallet::<T>::set_block_number(confirm_period_over);
}
fn skip_timeout_period<T: Config>(index: ReferendumIndex) {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
let timeout_period_over = status.submitted + T::UndecidingTimeout::get();
frame_system::Pallet::<T>::set_block_number(timeout_period_over);
}
fn alarm_time<T: Config>(index: ReferendumIndex) -> T::BlockNumber {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
status.alarm.unwrap().0
}
fn is_confirming<T: Config>(index: ReferendumIndex) -> bool {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
matches!(
status,
ReferendumStatus { deciding: Some(DecidingStatus { confirming: Some(_), .. }), .. }
)
}
fn is_not_confirming<T: Config>(index: ReferendumIndex) -> bool {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
matches!(
status,
ReferendumStatus { deciding: Some(DecidingStatus { confirming: None, .. }), .. }
)
}
benchmarks! {
submit {
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
}: _(
RawOrigin::Signed(caller),
RawOrigin::Root.into(),
T::Hashing::hash_of(&0),
AtOrAfter::After(0u32.into())
) verify {
let index = ReferendumCount::<T>::get().checked_sub(1).unwrap();
assert_matches!(ReferendumInfoFor::<T>::get(index), Some(ReferendumInfo::Ongoing(_)));
}
place_decision_deposit_preparing {
let (caller, index) = create_referendum::<T>();
}: place_decision_deposit(RawOrigin::Signed(caller), index)
verify {
assert!(Referenda::<T>::ensure_ongoing(index).unwrap().decision_deposit.is_some());
}
place_decision_deposit_queued {
let (caller, index) = create_referendum::<T>();
fill_queue::<T>(index, 1, 90);
}: place_decision_deposit(RawOrigin::Signed(caller), index)
verify {
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
assert_eq!(TrackQueue::<T>::get(&track)[0], (index, 0u32.into()));
}
place_decision_deposit_not_queued {
let (caller, index) = create_referendum::<T>();
fill_queue::<T>(index, 0, 90);
}: place_decision_deposit(RawOrigin::Signed(caller), index)
verify {
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
assert!(TrackQueue::<T>::get(&track).into_iter().all(|(i, _)| i != index));
}
place_decision_deposit_passing {
let (caller, index) = create_referendum::<T>();
skip_prepare_period::<T>(index);
make_passing::<T>(index);
}: place_decision_deposit(RawOrigin::Signed(caller), index)
verify {
assert!(is_confirming::<T>(index));
}
place_decision_deposit_failing {
let (caller, index) = create_referendum::<T>();
skip_prepare_period::<T>(index);
}: place_decision_deposit(RawOrigin::Signed(caller), index)
verify {
assert!(is_not_confirming::<T>(index));
}
refund_decision_deposit {
let (caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
assert_ok!(Referenda::<T>::cancel(T::CancelOrigin::successful_origin(), index));
}: _(RawOrigin::Signed(caller), index)
verify {
assert_matches!(ReferendumInfoFor::<T>::get(index), Some(ReferendumInfo::Cancelled(_, _, None)));
}
cancel {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
}: _<T::Origin>(T::CancelOrigin::successful_origin(), index)
verify {
assert_matches!(ReferendumInfoFor::<T>::get(index), Some(ReferendumInfo::Cancelled(..)));
}
kill {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
}: _<T::Origin>(T::KillOrigin::successful_origin(), index)
verify {
assert_matches!(ReferendumInfoFor::<T>::get(index), Some(ReferendumInfo::Killed(..)));
}
one_fewer_deciding_queue_empty {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
nudge::<T>(index);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_ok!(Referenda::<T>::cancel(T::CancelOrigin::successful_origin(), index));
assert_eq!(DecidingCount::<T>::get(&track), 1);
}: one_fewer_deciding(RawOrigin::Root, track.clone())
verify {
assert_eq!(DecidingCount::<T>::get(&track), 0);
}
one_fewer_deciding_failing {
let (_caller, index) = create_referendum::<T>();
// No spaces free in the queue.
let queued = fill_queue::<T>(index, 0, 90);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_ok!(Referenda::<T>::cancel(T::CancelOrigin::successful_origin(), queued[0]));
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
let deciding_count = DecidingCount::<T>::get(&track);
}: one_fewer_deciding(RawOrigin::Root, track.clone())
verify {
assert_eq!(DecidingCount::<T>::get(&track), deciding_count);
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get() - 1);
assert!(queued.into_iter().skip(1).all(|i| Referenda::<T>::ensure_ongoing(i)
.unwrap()
.deciding
.map_or(true, |d| d.confirming.is_none())
));
}
one_fewer_deciding_passing {
let (_caller, index) = create_referendum::<T>();
// No spaces free in the queue.
let queued = fill_queue::<T>(index, 0, 0);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_ok!(Referenda::<T>::cancel(T::CancelOrigin::successful_origin(), queued[0]));
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
let deciding_count = DecidingCount::<T>::get(&track);
}: one_fewer_deciding(RawOrigin::Root, track.clone())
verify {
assert_eq!(DecidingCount::<T>::get(&track), deciding_count);
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get() - 1);
assert!(queued.into_iter().skip(1).all(|i| Referenda::<T>::ensure_ongoing(i)
.unwrap()
.deciding
.map_or(true, |d| d.confirming.is_some())
));
}
nudge_referendum_requeued_insertion {
// First create our referendum and place the deposit. It will be failing.
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
fill_queue::<T>(index, 0, 90);
// Now nudge ours, with the track now full and the queue full of referenda with votes,
// ours will not be in the queue.
nudge::<T>(index);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert!(TrackQueue::<T>::get(&track).into_iter().all(|(i, _)| i != index));
// Now alter the voting, so that ours goes into pole-position and shifts others down.
make_passing::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let t = TrackQueue::<T>::get(&track);
assert_eq!(t.len() as u32, T::MaxQueued::get());
assert_eq!(t[t.len() - 1].0, index);
}
nudge_referendum_requeued_slide {
// First create our referendum and place the deposit. It will be failing.
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
fill_queue::<T>(index, 1, 90);
// Now nudge ours, with the track now full, ours will be queued, but with no votes, it
// will have the worst position.
nudge::<T>(index);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
assert_eq!(TrackQueue::<T>::get(&track)[0], (index, 0u32.into()));
// Now alter the voting, so that ours leap-frogs all into the best position.
make_passing::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let t = TrackQueue::<T>::get(&track);
assert_eq!(t.len() as u32, T::MaxQueued::get());
assert_eq!(t[t.len() - 1].0, index);
}
nudge_referendum_queued {
// NOTE: worst possible queue situation is with a queue full of passing refs with one slot
// free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the
// insertion at the beginning.
// First create our referendum and place the deposit. It will be failing.
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
fill_queue::<T>(index, 1, 0);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get() - 1);
assert!(TrackQueue::<T>::get(&track).into_iter().all(|(_, v)| v > 0u32.into()));
// Then nudge ours, with the track now full, ours will be queued.
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
assert_eq!(TrackQueue::<T>::get(&track)[0], (index, 0u32.into()));
}
nudge_referendum_not_queued {
// First create our referendum and place the deposit. It will be failing.
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
fill_queue::<T>(index, 0, 0);
let track = Referenda::<T>::ensure_ongoing(index).unwrap().track;
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
assert!(TrackQueue::<T>::get(&track).into_iter().all(|(_, v)| v > 0u32.into()));
// Then nudge ours, with the track now full, ours will be queued.
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert_eq!(TrackQueue::<T>::get(&track).len() as u32, T::MaxQueued::get());
assert!(TrackQueue::<T>::get(&track).into_iter().all(|(i, _)| i != index));
}
nudge_referendum_no_deposit {
let (_caller, index) = create_referendum::<T>();
skip_prepare_period::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
assert_matches!(status, ReferendumStatus { deciding: None, .. });
}
nudge_referendum_preparing {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let status = Referenda::<T>::ensure_ongoing(index).unwrap();
assert_matches!(status, ReferendumStatus { deciding: None, .. });
}
nudge_referendum_timed_out {
let (_caller, index) = create_referendum::<T>();
skip_timeout_period::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let info = ReferendumInfoFor::<T>::get(index).unwrap();
assert_matches!(info, ReferendumInfo::TimedOut(..));
}
nudge_referendum_begin_deciding_failing {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert!(is_not_confirming::<T>(index));
}
nudge_referendum_begin_deciding_passing {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
make_passing::<T>(index);
skip_prepare_period::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert!(is_confirming::<T>(index));
}
nudge_referendum_begin_confirming {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
nudge::<T>(index);
assert!(!is_confirming::<T>(index));
make_passing::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert!(is_confirming::<T>(index));
}
nudge_referendum_end_confirming {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
make_passing::<T>(index);
nudge::<T>(index);
assert!(is_confirming::<T>(index));
make_failing::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert!(!is_confirming::<T>(index));
}
nudge_referendum_continue_not_confirming {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
nudge::<T>(index);
assert!(!is_confirming::<T>(index));
let old_alarm = alarm_time::<T>(index);
make_passing_after::<T>(index, Perbill::from_percent(50));
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert_ne!(old_alarm, alarm_time::<T>(index));
assert!(!is_confirming::<T>(index));
}
nudge_referendum_continue_confirming {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
make_passing::<T>(index);
skip_prepare_period::<T>(index);
nudge::<T>(index);
assert!(is_confirming::<T>(index));
let old_alarm = alarm_time::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
assert!(is_confirming::<T>(index));
}
nudge_referendum_approved {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
make_passing::<T>(index);
nudge::<T>(index);
skip_confirm_period::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let info = ReferendumInfoFor::<T>::get(index).unwrap();
assert_matches!(info, ReferendumInfo::Approved(..));
}
nudge_referendum_rejected {
let (_caller, index) = create_referendum::<T>();
place_deposit::<T>(index);
skip_prepare_period::<T>(index);
nudge::<T>(index);
skip_decision_period::<T>(index);
}: nudge_referendum(RawOrigin::Root, index)
verify {
let info = ReferendumInfoFor::<T>::get(index).unwrap();
assert_matches!(info, ReferendumInfo::Rejected(..));
}
impl_benchmark_test_suite!(
Referenda,
crate::mock::new_test_ext(),
crate::mock::Test
);
}
+172
View File
@@ -0,0 +1,172 @@
// This file is part of Substrate.
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Helpers for managing the different weights in various algorithmic branches.
use super::Config;
use crate::weights::WeightInfo;
/// Branches within the `begin_deciding` function.
pub enum BeginDecidingBranch {
Passing,
Failing,
}
/// Branches within the `service_referendum` function.
pub enum ServiceBranch {
Fail,
NoDeposit,
Preparing,
Queued,
NotQueued,
RequeuedInsertion,
RequeuedSlide,
BeginDecidingPassing,
BeginDecidingFailing,
BeginConfirming,
ContinueConfirming,
EndConfirming,
ContinueNotConfirming,
Approved,
Rejected,
TimedOut,
}
impl From<BeginDecidingBranch> for ServiceBranch {
fn from(x: BeginDecidingBranch) -> Self {
use BeginDecidingBranch::*;
use ServiceBranch::*;
match x {
Passing => BeginDecidingPassing,
Failing => BeginDecidingFailing,
}
}
}
impl ServiceBranch {
/// Return the weight of the `nudge` function when it takes the branch denoted by `self`.
pub fn weight_of_nudge<T: Config>(self) -> frame_support::weights::Weight {
use ServiceBranch::*;
match self {
NoDeposit => T::WeightInfo::nudge_referendum_no_deposit(),
Preparing => T::WeightInfo::nudge_referendum_preparing(),
Queued => T::WeightInfo::nudge_referendum_queued(),
NotQueued => T::WeightInfo::nudge_referendum_not_queued(),
RequeuedInsertion => T::WeightInfo::nudge_referendum_requeued_insertion(),
RequeuedSlide => T::WeightInfo::nudge_referendum_requeued_slide(),
BeginDecidingPassing => T::WeightInfo::nudge_referendum_begin_deciding_passing(),
BeginDecidingFailing => T::WeightInfo::nudge_referendum_begin_deciding_failing(),
BeginConfirming => T::WeightInfo::nudge_referendum_begin_confirming(),
ContinueConfirming => T::WeightInfo::nudge_referendum_continue_confirming(),
EndConfirming => T::WeightInfo::nudge_referendum_end_confirming(),
ContinueNotConfirming => T::WeightInfo::nudge_referendum_continue_not_confirming(),
Approved => T::WeightInfo::nudge_referendum_approved(),
Rejected => T::WeightInfo::nudge_referendum_rejected(),
TimedOut | Fail => T::WeightInfo::nudge_referendum_timed_out(),
}
}
/// Return the maximum possible weight of the `nudge` function.
pub fn max_weight_of_nudge<T: Config>() -> frame_support::weights::Weight {
0.max(T::WeightInfo::nudge_referendum_no_deposit())
.max(T::WeightInfo::nudge_referendum_preparing())
.max(T::WeightInfo::nudge_referendum_queued())
.max(T::WeightInfo::nudge_referendum_not_queued())
.max(T::WeightInfo::nudge_referendum_requeued_insertion())
.max(T::WeightInfo::nudge_referendum_requeued_slide())
.max(T::WeightInfo::nudge_referendum_begin_deciding_passing())
.max(T::WeightInfo::nudge_referendum_begin_deciding_failing())
.max(T::WeightInfo::nudge_referendum_begin_confirming())
.max(T::WeightInfo::nudge_referendum_continue_confirming())
.max(T::WeightInfo::nudge_referendum_end_confirming())
.max(T::WeightInfo::nudge_referendum_continue_not_confirming())
.max(T::WeightInfo::nudge_referendum_approved())
.max(T::WeightInfo::nudge_referendum_rejected())
.max(T::WeightInfo::nudge_referendum_timed_out())
}
/// Return the weight of the `place_decision_deposit` function when it takes the branch denoted
/// by `self`.
pub fn weight_of_deposit<T: Config>(self) -> Option<frame_support::weights::Weight> {
use ServiceBranch::*;
Some(match self {
Preparing => T::WeightInfo::place_decision_deposit_preparing(),
Queued => T::WeightInfo::place_decision_deposit_queued(),
NotQueued => T::WeightInfo::place_decision_deposit_not_queued(),
BeginDecidingPassing => T::WeightInfo::place_decision_deposit_passing(),
BeginDecidingFailing => T::WeightInfo::place_decision_deposit_failing(),
BeginConfirming |
ContinueConfirming |
EndConfirming |
ContinueNotConfirming |
Approved |
Rejected |
RequeuedInsertion |
RequeuedSlide |
TimedOut |
Fail |
NoDeposit => return None,
})
}
/// Return the maximum possible weight of the `place_decision_deposit` function.
pub fn max_weight_of_deposit<T: Config>() -> frame_support::weights::Weight {
0.max(T::WeightInfo::place_decision_deposit_preparing())
.max(T::WeightInfo::place_decision_deposit_queued())
.max(T::WeightInfo::place_decision_deposit_not_queued())
.max(T::WeightInfo::place_decision_deposit_passing())
.max(T::WeightInfo::place_decision_deposit_failing())
}
}
/// Branches that the `one_fewer_deciding` function may take.
pub enum OneFewerDecidingBranch {
QueueEmpty,
BeginDecidingPassing,
BeginDecidingFailing,
}
impl From<BeginDecidingBranch> for OneFewerDecidingBranch {
fn from(x: BeginDecidingBranch) -> Self {
use BeginDecidingBranch::*;
use OneFewerDecidingBranch::*;
match x {
Passing => BeginDecidingPassing,
Failing => BeginDecidingFailing,
}
}
}
impl OneFewerDecidingBranch {
/// Return the weight of the `one_fewer_deciding` function when it takes the branch denoted
/// by `self`.
pub fn weight<T: Config>(self) -> frame_support::weights::Weight {
use OneFewerDecidingBranch::*;
match self {
QueueEmpty => T::WeightInfo::one_fewer_deciding_queue_empty(),
BeginDecidingPassing => T::WeightInfo::one_fewer_deciding_passing(),
BeginDecidingFailing => T::WeightInfo::one_fewer_deciding_failing(),
}
}
/// Return the maximum possible weight of the `one_fewer_deciding` function.
pub fn max_weight<T: Config>() -> frame_support::weights::Weight {
0.max(T::WeightInfo::one_fewer_deciding_queue_empty())
.max(T::WeightInfo::one_fewer_deciding_passing())
.max(T::WeightInfo::one_fewer_deciding_failing())
}
}
File diff suppressed because it is too large Load Diff
+460
View File
@@ -0,0 +1,460 @@
// This file is part of Substrate.
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The crate's tests.
use super::*;
use crate as pallet_referenda;
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{
assert_ok, ord_parameter_types, parameter_types,
traits::{
ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling,
PreimageRecipient, SortedMembers,
},
weights::Weight,
};
use frame_system::{EnsureRoot, EnsureSignedBy};
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, Hash, IdentityLookup},
DispatchResult, Perbill,
};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
frame_support::construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system,
Balances: pallet_balances,
Preimage: pallet_preimage,
Scheduler: pallet_scheduler,
Referenda: pallet_referenda,
}
);
// Test that a fitlered call can be dispatched.
pub struct BaseFilter;
impl Contains<Call> for BaseFilter {
fn contains(call: &Call) -> bool {
!matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. }))
}
}
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(1_000_000);
}
impl frame_system::Config for Test {
type BaseCallFilter = BaseFilter;
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Call = Call;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}
impl pallet_preimage::Config for Test {
type Event = Event;
type WeightInfo = ();
type Currency = Balances;
type ManagerOrigin = EnsureRoot<u64>;
type MaxSize = ConstU32<4096>;
type BaseDeposit = ();
type ByteDeposit = ();
}
parameter_types! {
pub MaximumSchedulerWeight: Weight = 2_000_000_000_000;
}
impl pallet_scheduler::Config for Test {
type Event = Event;
type Origin = Origin;
type PalletsOrigin = OriginCaller;
type Call = Call;
type MaximumWeight = MaximumSchedulerWeight;
type ScheduleOrigin = EnsureRoot<u64>;
type MaxScheduledPerBlock = ConstU32<100>;
type WeightInfo = ();
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type PreimageProvider = Preimage;
type NoPreimagePostponement = ConstU64<10>;
}
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
pub const MaxLocks: u32 = 10;
}
impl pallet_balances::Config for Test {
type MaxReserves = ();
type ReserveIdentifier = [u8; 8];
type MaxLocks = MaxLocks;
type Balance = u64;
type Event = Event;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
}
parameter_types! {
pub static AlarmInterval: u64 = 1;
pub const SubmissionDeposit: u64 = 2;
pub const MaxQueued: u32 = 3;
pub const UndecidingTimeout: u64 = 20;
}
ord_parameter_types! {
pub const One: u64 = 1;
pub const Two: u64 = 2;
pub const Three: u64 = 3;
pub const Four: u64 = 4;
pub const Five: u64 = 5;
pub const Six: u64 = 6;
}
pub struct OneToFive;
impl SortedMembers<u64> for OneToFive {
fn sorted_members() -> Vec<u64> {
vec![1, 2, 3, 4, 5]
}
#[cfg(feature = "runtime-benchmarks")]
fn add(_m: &u64) {}
}
pub struct TestTracksInfo;
impl TracksInfo<u64, u64> for TestTracksInfo {
type Id = u8;
type Origin = <Origin as OriginTrait>::PalletsOrigin;
fn tracks() -> &'static [(Self::Id, TrackInfo<u64, u64>)] {
static DATA: [(u8, TrackInfo<u64, u64>); 2] = [
(
0u8,
TrackInfo {
name: "root",
max_deciding: 1,
decision_deposit: 10,
prepare_period: 4,
decision_period: 4,
confirm_period: 2,
min_enactment_period: 4,
min_approval: Curve::LinearDecreasing {
begin: Perbill::from_percent(100),
delta: Perbill::from_percent(50),
},
min_turnout: Curve::LinearDecreasing {
begin: Perbill::from_percent(100),
delta: Perbill::from_percent(100),
},
},
),
(
1u8,
TrackInfo {
name: "none",
max_deciding: 3,
decision_deposit: 1,
prepare_period: 2,
decision_period: 2,
confirm_period: 1,
min_enactment_period: 2,
min_approval: Curve::LinearDecreasing {
begin: Perbill::from_percent(55),
delta: Perbill::from_percent(5),
},
min_turnout: Curve::LinearDecreasing {
begin: Perbill::from_percent(10),
delta: Perbill::from_percent(10),
},
},
),
];
&DATA[..]
}
fn track_for(id: &Self::Origin) -> Result<Self::Id, ()> {
if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) {
match system_origin {
frame_system::RawOrigin::Root => Ok(0),
frame_system::RawOrigin::None => Ok(1),
_ => Err(()),
}
} else {
Err(())
}
}
}
impl Config for Test {
type WeightInfo = ();
type Call = Call;
type Event = Event;
type Scheduler = Scheduler;
type Currency = pallet_balances::Pallet<Self>;
type CancelOrigin = EnsureSignedBy<Four, u64>;
type KillOrigin = EnsureRoot<u64>;
type Slash = ();
type Votes = u32;
type Tally = Tally;
type SubmissionDeposit = SubmissionDeposit;
type MaxQueued = MaxQueued;
type UndecidingTimeout = UndecidingTimeout;
type AlarmInterval = AlarmInterval;
type Tracks = TestTracksInfo;
}
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
let balances = vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)];
pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut t)
.unwrap();
let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| System::set_block_number(1));
ext
}
/// Execute the function two times, with `true` and with `false`.
#[allow(dead_code)]
pub fn new_test_ext_execute_with_cond(execute: impl FnOnce(bool) -> () + Clone) {
new_test_ext().execute_with(|| (execute.clone())(false));
new_test_ext().execute_with(|| execute(true));
}
#[derive(Encode, Debug, Decode, TypeInfo, Eq, PartialEq, Clone, Default, MaxEncodedLen)]
pub struct Tally {
pub ayes: u32,
pub nays: u32,
}
impl VoteTally<u32> for Tally {
fn ayes(&self) -> u32 {
self.ayes
}
fn turnout(&self) -> Perbill {
Perbill::from_percent(self.ayes + self.nays)
}
fn approval(&self) -> Perbill {
Perbill::from_rational(self.ayes, self.ayes + self.nays)
}
#[cfg(feature = "runtime-benchmarks")]
fn unanimity() -> Self {
Self { ayes: 100, nays: 0 }
}
#[cfg(feature = "runtime-benchmarks")]
fn from_requirements(turnout: Perbill, approval: Perbill) -> Self {
let turnout = turnout.mul_ceil(100u32);
let ayes = approval.mul_ceil(turnout);
Self { ayes, nays: turnout - ayes }
}
}
pub fn set_balance_proposal(value: u64) -> Vec<u8> {
Call::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 })
.encode()
}
pub fn set_balance_proposal_hash(value: u64) -> H256 {
let c = Call::Balances(pallet_balances::Call::set_balance {
who: 42,
new_free: value,
new_reserved: 0,
});
<Preimage as PreimageRecipient<_>>::note_preimage(c.encode().try_into().unwrap());
BlakeTwo256::hash_of(&c)
}
#[allow(dead_code)]
pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult {
Referenda::submit(
Origin::signed(who),
frame_system::RawOrigin::Root.into(),
set_balance_proposal_hash(value),
AtOrAfter::After(delay),
)
}
pub fn next_block() {
System::set_block_number(System::block_number() + 1);
Scheduler::on_initialize(System::block_number());
}
pub fn run_to(n: u64) {
while System::block_number() < n {
next_block();
}
}
#[allow(dead_code)]
pub fn begin_referendum() -> ReferendumIndex {
System::set_block_number(0);
assert_ok!(propose_set_balance(1, 2, 1));
run_to(2);
0
}
#[allow(dead_code)]
pub fn tally(r: ReferendumIndex) -> Tally {
Referenda::ensure_ongoing(r).unwrap().tally
}
pub fn set_tally(index: ReferendumIndex, ayes: u32, nays: u32) {
<Referenda as Polling<Tally>>::access_poll(index, |status| {
let tally = status.ensure_ongoing().unwrap().0;
tally.ayes = ayes;
tally.nays = nays;
});
}
pub fn waiting_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Ongoing(ReferendumStatus { submitted, deciding: None, .. }) => submitted,
_ => panic!("Not waiting"),
}
}
pub fn deciding_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Ongoing(ReferendumStatus {
deciding: Some(DecidingStatus { since, .. }),
..
}) => since,
_ => panic!("Not deciding"),
}
}
pub fn deciding_and_failing_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Ongoing(ReferendumStatus {
deciding: Some(DecidingStatus { since, confirming: None, .. }),
..
}) => since,
_ => panic!("Not deciding"),
}
}
pub fn confirming_until(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Ongoing(ReferendumStatus {
deciding: Some(DecidingStatus { confirming: Some(until), .. }),
..
}) => until,
_ => panic!("Not confirming"),
}
}
pub fn approved_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Approved(since, ..) => since,
_ => panic!("Not approved"),
}
}
pub fn rejected_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Rejected(since, ..) => since,
_ => panic!("Not rejected"),
}
}
pub fn cancelled_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Cancelled(since, ..) => since,
_ => panic!("Not cancelled"),
}
}
pub fn killed_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::Killed(since, ..) => since,
_ => panic!("Not killed"),
}
}
pub fn timed_out_since(i: ReferendumIndex) -> u64 {
match ReferendumInfoFor::<Test>::get(i).unwrap() {
ReferendumInfo::TimedOut(since, ..) => since,
_ => panic!("Not timed out"),
}
}
fn is_deciding(i: ReferendumIndex) -> bool {
matches!(
ReferendumInfoFor::<Test>::get(i),
Some(ReferendumInfo::Ongoing(ReferendumStatus { deciding: Some(_), .. }))
)
}
#[derive(Clone, Copy)]
pub enum RefState {
Failing,
Passing,
Confirming { immediate: bool },
}
impl RefState {
pub fn create(self) -> ReferendumIndex {
assert_ok!(Referenda::submit(
Origin::signed(1),
frame_support::dispatch::RawOrigin::Root.into(),
set_balance_proposal_hash(1),
AtOrAfter::At(10),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
if matches!(self, RefState::Confirming { immediate: true }) {
set_tally(0, 100, 0);
}
let index = ReferendumCount::<Test>::get() - 1;
while !is_deciding(index) {
run_to(System::block_number() + 1);
}
if matches!(self, RefState::Confirming { immediate: false }) {
set_tally(0, 100, 0);
run_to(System::block_number() + 1);
}
if matches!(self, RefState::Confirming { .. }) {
assert_eq!(confirming_until(index), System::block_number() + 2);
}
if matches!(self, RefState::Passing) {
set_tally(0, 100, 99);
run_to(System::block_number() + 1);
}
index
}
}
+511
View File
@@ -0,0 +1,511 @@
// This file is part of Substrate.
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The crate's tests.
use super::*;
use crate::mock::{RefState::*, *};
use assert_matches::assert_matches;
use codec::Decode;
use frame_support::{
assert_noop, assert_ok,
dispatch::{DispatchError::BadOrigin, RawOrigin},
traits::Contains,
};
use pallet_balances::Error as BalancesError;
// TODO: Scheduler should re-use `None` items in its `Agenda`.
#[test]
fn params_should_work() {
new_test_ext().execute_with(|| {
assert_eq!(ReferendumCount::<Test>::get(), 0);
assert_eq!(Balances::free_balance(42), 0);
assert_eq!(Balances::total_issuance(), 600);
});
}
#[test]
fn basic_happy_path_works() {
new_test_ext().execute_with(|| {
// #1: submit
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
set_balance_proposal_hash(1),
AtOrAfter::At(10),
));
assert_eq!(Balances::reserved_balance(&1), 2);
assert_eq!(ReferendumCount::<Test>::get(), 1);
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
run_to(4);
assert_eq!(DecidingCount::<Test>::get(0), 0);
run_to(5);
// #5: 4 blocks after submit - vote should now be deciding.
assert_eq!(DecidingCount::<Test>::get(0), 1);
run_to(6);
// #6: Lots of ayes. Should now be confirming.
set_tally(0, 100, 0);
run_to(7);
assert_eq!(confirming_until(0), 9);
run_to(9);
// #8: Should be confirmed & ended.
assert_eq!(approved_since(0), 9);
assert_ok!(Referenda::refund_decision_deposit(Origin::signed(2), 0));
run_to(12);
// #9: Should not yet be enacted.
assert_eq!(Balances::free_balance(&42), 0);
run_to(13);
// #10: Proposal should be executed.
assert_eq!(Balances::free_balance(&42), 1);
});
}
#[test]
fn insta_confirm_then_kill_works() {
new_test_ext().execute_with(|| {
let r = Confirming { immediate: true }.create();
run_to(6);
assert_ok!(Referenda::kill(Origin::root(), r));
assert_eq!(killed_since(r), 6);
});
}
#[test]
fn confirm_then_reconfirm_with_elapsed_trigger_works() {
new_test_ext().execute_with(|| {
let r = Confirming { immediate: false }.create();
assert_eq!(confirming_until(r), 8);
run_to(7);
set_tally(r, 100, 99);
run_to(8);
assert_eq!(deciding_and_failing_since(r), 5);
run_to(11);
assert_eq!(approved_since(r), 11);
});
}
#[test]
fn instaconfirm_then_reconfirm_with_elapsed_trigger_works() {
new_test_ext().execute_with(|| {
let r = Confirming { immediate: true }.create();
run_to(6);
assert_eq!(confirming_until(r), 7);
set_tally(r, 100, 99);
run_to(7);
assert_eq!(deciding_and_failing_since(r), 5);
run_to(11);
assert_eq!(approved_since(r), 11);
});
}
#[test]
fn instaconfirm_then_reconfirm_with_voting_trigger_works() {
new_test_ext().execute_with(|| {
let r = Confirming { immediate: true }.create();
run_to(6);
assert_eq!(confirming_until(r), 7);
set_tally(r, 100, 99);
run_to(7);
assert_eq!(deciding_and_failing_since(r), 5);
run_to(8);
set_tally(r, 100, 0);
run_to(9);
assert_eq!(confirming_until(r), 11);
run_to(11);
assert_eq!(approved_since(r), 11);
});
}
#[test]
fn voting_should_extend_for_late_confirmation() {
new_test_ext().execute_with(|| {
let r = Passing.create();
run_to(10);
assert_eq!(confirming_until(r), 11);
run_to(11);
assert_eq!(approved_since(r), 11);
});
}
#[test]
fn should_instafail_during_extension_confirmation() {
new_test_ext().execute_with(|| {
let r = Passing.create();
run_to(10);
assert_eq!(confirming_until(r), 11);
// Should insta-fail since it's now past the normal voting time.
set_tally(r, 100, 101);
run_to(11);
assert_eq!(rejected_since(r), 11);
});
}
#[test]
fn confirming_then_fail_works() {
new_test_ext().execute_with(|| {
let r = Failing.create();
// Normally ends at 5 + 4 (voting period) = 9.
assert_eq!(deciding_and_failing_since(r), 5);
set_tally(r, 100, 0);
run_to(6);
assert_eq!(confirming_until(r), 8);
set_tally(r, 100, 101);
run_to(9);
assert_eq!(rejected_since(r), 9);
});
}
#[test]
fn queueing_works() {
new_test_ext().execute_with(|| {
// Submit a proposal into a track with a queue len of 1.
assert_ok!(Referenda::submit(
Origin::signed(5),
RawOrigin::Root.into(),
set_balance_proposal_hash(0),
AtOrAfter::After(0),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(5), 0));
run_to(2);
// Submit 3 more proposals into the same queue.
for i in 1..=4 {
assert_ok!(Referenda::submit(
Origin::signed(i),
RawOrigin::Root.into(),
set_balance_proposal_hash(i),
AtOrAfter::After(0),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(i), i as u32));
// TODO: decision deposit after some initial votes with a non-highest voted coming
// first.
}
assert_eq!(ReferendumCount::<Test>::get(), 5);
run_to(5);
// One should be being decided.
assert_eq!(DecidingCount::<Test>::get(0), 1);
assert_eq!(deciding_and_failing_since(0), 5);
for i in 1..=4 {
assert_eq!(waiting_since(i), 2);
}
// Vote to set order.
set_tally(1, 1, 10);
set_tally(2, 2, 20);
set_tally(3, 3, 30);
set_tally(4, 100, 0);
println!("Agenda #6: {:?}", pallet_scheduler::Agenda::<Test>::get(6));
run_to(6);
println!("{:?}", Vec::<_>::from(TrackQueue::<Test>::get(0)));
// Cancel the first.
assert_ok!(Referenda::cancel(Origin::signed(4), 0));
assert_eq!(cancelled_since(0), 6);
// The other with the most approvals (#4) should be being decided.
run_to(7);
assert_eq!(DecidingCount::<Test>::get(0), 1);
assert_eq!(deciding_since(4), 7);
assert_eq!(confirming_until(4), 9);
// Vote on the remaining two to change order.
println!("Set tally #1");
set_tally(1, 30, 31);
println!("{:?}", Vec::<_>::from(TrackQueue::<Test>::get(0)));
println!("Set tally #2");
set_tally(2, 20, 20);
println!("{:?}", Vec::<_>::from(TrackQueue::<Test>::get(0)));
// Let confirmation period end.
run_to(9);
// #4 should have been confirmed.
assert_eq!(approved_since(4), 9);
// On to the next block to select the new referendum
run_to(10);
// #1 (the one with the most approvals) should now be being decided.
assert_eq!(deciding_since(1), 10);
// Let it end unsuccessfully.
run_to(14);
assert_eq!(rejected_since(1), 14);
// Service queue.
run_to(15);
// #2 should now be being decided. It will (barely) pass.
assert_eq!(deciding_and_failing_since(2), 15);
// #2 moves into confirming at the last moment with a 50% approval.
run_to(19);
assert_eq!(confirming_until(2), 21);
// #2 gets approved.
run_to(21);
assert_eq!(approved_since(2), 21);
// The final one has since timed out.
run_to(22);
assert_eq!(timed_out_since(3), 22);
});
}
#[test]
fn auto_timeout_should_happen_with_nothing_but_submit() {
new_test_ext().execute_with(|| {
// #1: submit
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
set_balance_proposal_hash(1),
AtOrAfter::At(20),
));
run_to(20);
assert_matches!(ReferendumInfoFor::<Test>::get(0), Some(ReferendumInfo::Ongoing(..)));
run_to(21);
// #11: Timed out - ended.
assert_matches!(
ReferendumInfoFor::<Test>::get(0),
Some(ReferendumInfo::TimedOut(21, _, None))
);
});
}
#[test]
fn tracks_are_distinguished() {
new_test_ext().execute_with(|| {
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
set_balance_proposal_hash(1),
AtOrAfter::At(10),
));
assert_ok!(Referenda::submit(
Origin::signed(2),
RawOrigin::None.into(),
set_balance_proposal_hash(2),
AtOrAfter::At(20),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(3), 0));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(4), 1));
let mut i = ReferendumInfoFor::<Test>::iter().collect::<Vec<_>>();
i.sort_by_key(|x| x.0);
assert_eq!(
i,
vec![
(
0,
ReferendumInfo::Ongoing(ReferendumStatus {
track: 0,
origin: OriginCaller::system(RawOrigin::Root),
proposal_hash: set_balance_proposal_hash(1),
enactment: AtOrAfter::At(10),
submitted: 1,
submission_deposit: Deposit { who: 1, amount: 2 },
decision_deposit: Some(Deposit { who: 3, amount: 10 }),
deciding: None,
tally: Tally { ayes: 0, nays: 0 },
in_queue: false,
alarm: Some((5, (5, 0))),
})
),
(
1,
ReferendumInfo::Ongoing(ReferendumStatus {
track: 1,
origin: OriginCaller::system(RawOrigin::None),
proposal_hash: set_balance_proposal_hash(2),
enactment: AtOrAfter::At(20),
submitted: 1,
submission_deposit: Deposit { who: 2, amount: 2 },
decision_deposit: Some(Deposit { who: 4, amount: 1 }),
deciding: None,
tally: Tally { ayes: 0, nays: 0 },
in_queue: false,
alarm: Some((3, (3, 0))),
})
),
]
);
});
}
#[test]
fn submit_errors_work() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
// No track for Signed origins.
assert_noop!(
Referenda::submit(Origin::signed(1), RawOrigin::Signed(2).into(), h, AtOrAfter::At(10),),
Error::<Test>::NoTrack
);
// No funds for deposit
assert_noop!(
Referenda::submit(Origin::signed(10), RawOrigin::Root.into(), h, AtOrAfter::At(10),),
BalancesError::<Test>::InsufficientBalance
);
});
}
#[test]
fn decision_deposit_errors_work() {
new_test_ext().execute_with(|| {
let e = Error::<Test>::NotOngoing;
assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e);
let h = set_balance_proposal_hash(1);
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
h,
AtOrAfter::At(10),
));
let e = BalancesError::<Test>::InsufficientBalance;
assert_noop!(Referenda::place_decision_deposit(Origin::signed(10), 0), e);
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
let e = Error::<Test>::HaveDeposit;
assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e);
});
}
#[test]
fn refund_deposit_works() {
new_test_ext().execute_with(|| {
let e = Error::<Test>::BadReferendum;
assert_noop!(Referenda::refund_decision_deposit(Origin::signed(1), 0), e);
let h = set_balance_proposal_hash(1);
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
h,
AtOrAfter::At(10),
));
let e = Error::<Test>::NoDeposit;
assert_noop!(Referenda::refund_decision_deposit(Origin::signed(2), 0), e);
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
let e = Error::<Test>::Unfinished;
assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e);
run_to(11);
assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0));
});
}
#[test]
fn cancel_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
h,
AtOrAfter::At(10),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
run_to(8);
assert_ok!(Referenda::cancel(Origin::signed(4), 0));
assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0));
assert_eq!(cancelled_since(0), 8);
});
}
#[test]
fn cancel_errors_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
h,
AtOrAfter::At(10),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
assert_noop!(Referenda::cancel(Origin::signed(1), 0), BadOrigin);
run_to(11);
assert_noop!(Referenda::cancel(Origin::signed(4), 0), Error::<Test>::NotOngoing);
});
}
#[test]
fn kill_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
h,
AtOrAfter::At(10),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
run_to(8);
assert_ok!(Referenda::kill(Origin::root(), 0));
let e = Error::<Test>::NoDeposit;
assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e);
assert_eq!(killed_since(0), 8);
});
}
#[test]
fn kill_errors_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
assert_ok!(Referenda::submit(
Origin::signed(1),
RawOrigin::Root.into(),
h,
AtOrAfter::At(10),
));
assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0));
assert_noop!(Referenda::kill(Origin::signed(4), 0), BadOrigin);
run_to(11);
assert_noop!(Referenda::kill(Origin::root(), 0), Error::<Test>::NotOngoing);
});
}
#[test]
fn set_balance_proposal_is_correctly_filtered_out() {
for i in 0..10 {
let call = crate::mock::Call::decode(&mut &set_balance_proposal(i)[..]).unwrap();
assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
}
}
#[test]
fn curve_handles_all_inputs() {
let test_curve = Curve::LinearDecreasing { begin: Perbill::zero(), delta: Perbill::zero() };
let delay = test_curve.delay(Perbill::zero());
assert_eq!(delay, Perbill::zero());
let test_curve = Curve::LinearDecreasing { begin: Perbill::zero(), delta: Perbill::one() };
let threshold = test_curve.threshold(Perbill::one());
assert_eq!(threshold, Perbill::zero());
}
+358
View File
@@ -0,0 +1,358 @@
// This file is part of Substrate.
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Miscellaneous additional datatypes.
use super::*;
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use frame_support::{traits::schedule::Anon, Parameter};
use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug;
use sp_std::fmt::Debug;
pub type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;
pub type CallOf<T> = <T as Config>::Call;
pub type VotesOf<T> = <T as Config>::Votes;
pub type TallyOf<T> = <T as Config>::Tally;
pub type PalletsOriginOf<T> = <<T as frame_system::Config>::Origin as OriginTrait>::PalletsOrigin;
pub type ReferendumInfoOf<T> = ReferendumInfo<
TrackIdOf<T>,
PalletsOriginOf<T>,
<T as frame_system::Config>::BlockNumber,
<T as frame_system::Config>::Hash,
BalanceOf<T>,
TallyOf<T>,
<T as frame_system::Config>::AccountId,
ScheduleAddressOf<T>,
>;
pub type ReferendumStatusOf<T> = ReferendumStatus<
TrackIdOf<T>,
PalletsOriginOf<T>,
<T as frame_system::Config>::BlockNumber,
<T as frame_system::Config>::Hash,
BalanceOf<T>,
TallyOf<T>,
<T as frame_system::Config>::AccountId,
ScheduleAddressOf<T>,
>;
pub type DecidingStatusOf<T> = DecidingStatus<<T as frame_system::Config>::BlockNumber>;
pub type TrackInfoOf<T> = TrackInfo<BalanceOf<T>, <T as frame_system::Config>::BlockNumber>;
pub type TrackIdOf<T> = <<T as Config>::Tracks as TracksInfo<
BalanceOf<T>,
<T as frame_system::Config>::BlockNumber,
>>::Id;
pub type ScheduleAddressOf<T> = <<T as Config>::Scheduler as Anon<
<T as frame_system::Config>::BlockNumber,
CallOf<T>,
PalletsOriginOf<T>,
>>::Address;
/// A referendum index.
pub type ReferendumIndex = u32;
pub trait InsertSorted<T> {
/// Inserts an item into a sorted series.
///
/// Returns `true` if it was inserted, `false` if it would belong beyond the bound of the
/// series.
fn insert_sorted_by_key<F: FnMut(&T) -> K, K: PartialOrd<K> + Ord>(
&mut self,
t: T,
f: F,
) -> bool;
}
impl<T: Ord, S: Get<u32>> InsertSorted<T> for BoundedVec<T, S> {
fn insert_sorted_by_key<F: FnMut(&T) -> K, K: PartialOrd<K> + Ord>(
&mut self,
t: T,
mut f: F,
) -> bool {
let index = self.binary_search_by_key::<K, F>(&f(&t), f).unwrap_or_else(|x| x);
self.force_insert_keep_right(index, t)
}
}
#[cfg(test)]
mod tests {
use super::*;
use frame_support::traits::ConstU32;
#[test]
fn insert_sorted_works() {
let mut b: BoundedVec<u32, ConstU32<6>> = vec![20, 30, 40].try_into().unwrap();
assert!(b.insert_sorted_by_key(10, |&x| x));
assert_eq!(&b[..], &[10, 20, 30, 40][..]);
assert!(b.insert_sorted_by_key(60, |&x| x));
assert_eq!(&b[..], &[10, 20, 30, 40, 60][..]);
assert!(b.insert_sorted_by_key(50, |&x| x));
assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]);
assert!(!b.insert_sorted_by_key(9, |&x| x));
assert_eq!(&b[..], &[10, 20, 30, 40, 50, 60][..]);
assert!(b.insert_sorted_by_key(11, |&x| x));
assert_eq!(&b[..], &[11, 20, 30, 40, 50, 60][..]);
assert!(b.insert_sorted_by_key(21, |&x| x));
assert_eq!(&b[..], &[20, 21, 30, 40, 50, 60][..]);
assert!(b.insert_sorted_by_key(61, |&x| x));
assert_eq!(&b[..], &[21, 30, 40, 50, 60, 61][..]);
assert!(b.insert_sorted_by_key(51, |&x| x));
assert_eq!(&b[..], &[30, 40, 50, 51, 60, 61][..]);
}
}
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct DecidingStatus<BlockNumber> {
/// When this referendum began being "decided". If confirming, then the
/// end will actually be delayed until the end of the confirmation period.
pub(crate) since: BlockNumber,
/// If `Some`, then the referendum has entered confirmation stage and will end at
/// the block number as long as it doesn't lose its approval in the meantime.
pub(crate) confirming: Option<BlockNumber>,
}
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct Deposit<AccountId, Balance> {
pub(crate) who: AccountId,
pub(crate) amount: Balance,
}
#[derive(Clone, Encode, TypeInfo)]
pub struct TrackInfo<Balance, Moment> {
/// Name of this track. TODO was &'static str
pub name: &'static str,
/// A limit for the number of referenda on this track that can be being decided at once.
/// For Root origin this should generally be just one.
pub max_deciding: u32,
/// Amount that must be placed on deposit before a decision can be made.
pub decision_deposit: Balance,
/// Amount of time this must be submitted for before a decision can be made.
pub prepare_period: Moment,
/// Amount of time that a decision may take to be approved prior to cancellation.
pub decision_period: Moment,
/// Amount of time that the approval criteria must hold before it can be approved.
pub confirm_period: Moment,
/// Minimum amount of time that an approved proposal must be in the dispatch queue.
pub min_enactment_period: Moment,
/// Minimum aye votes as percentage of overall conviction-weighted votes needed for
/// approval as a function of time into decision period.
pub min_approval: Curve,
/// Minimum turnout as percentage of overall population that is needed for
/// approval as a function of time into decision period.
pub min_turnout: Curve,
}
/// Information on the voting tracks.
pub trait TracksInfo<Balance, Moment> {
/// The identifier for a track.
type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static;
/// The origin type from which a track is implied.
type Origin;
/// Return the array of known tracks and their information.
fn tracks() -> &'static [(Self::Id, TrackInfo<Balance, Moment>)];
/// Determine the voting track for the given `origin`.
fn track_for(origin: &Self::Origin) -> Result<Self::Id, ()>;
/// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`.
fn info(id: Self::Id) -> Option<&'static TrackInfo<Balance, Moment>> {
Self::tracks().iter().find(|x| &x.0 == &id).map(|x| &x.1)
}
}
/// Indication of either a specific moment or a delay from a implicitly defined moment.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub enum AtOrAfter<Moment: Parameter> {
/// Indiciates that the event should occur at the moment given.
At(Moment),
/// Indiciates that the event should occur some period of time (defined by the parameter) after
/// a prior event. The prior event is defined by the context, but for the purposes of
/// referendum proposals, the "prior event" is the passing of the referendum.
After(Moment),
}
impl<Moment: AtLeast32BitUnsigned + Copy + Parameter> AtOrAfter<Moment> {
pub fn evaluate(&self, since: Moment) -> Moment {
match &self {
Self::At(m) => *m,
Self::After(m) => m.saturating_add(since),
}
}
}
/// Info regarding an ongoing referendum.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct ReferendumStatus<
TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
> {
/// The track of this referendum.
pub(crate) track: TrackId,
/// The origin for this referendum.
pub(crate) origin: Origin,
/// The hash of the proposal up for referendum.
pub(crate) proposal_hash: Hash,
/// The time the proposal should be scheduled for enactment.
pub(crate) enactment: AtOrAfter<Moment>,
/// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it
/// `deciding` is `None`.
pub(crate) submitted: Moment,
/// The deposit reserved for the submission of this referendum.
pub(crate) submission_deposit: Deposit<AccountId, Balance>,
/// The deposit reserved for this referendum to be decided.
pub(crate) decision_deposit: Option<Deposit<AccountId, Balance>>,
/// The status of a decision being made. If `None`, it has not entered the deciding period.
pub(crate) deciding: Option<DecidingStatus<Moment>>,
/// The current tally of votes in this referendum.
pub(crate) tally: Tally,
/// Whether we have been placed in the queue for being decided or not.
pub(crate) in_queue: bool,
/// The next scheduled wake-up, if `Some`.
pub(crate) alarm: Option<(Moment, ScheduleAddress)>,
}
/// Info regarding a referendum, present or past.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub enum ReferendumInfo<
TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
> {
/// Referendum has been submitted and is being voted on.
Ongoing(
ReferendumStatus<TrackId, Origin, Moment, Hash, Balance, Tally, AccountId, ScheduleAddress>,
),
/// Referendum finished with approval. Submission deposit is held.
Approved(Moment, Deposit<AccountId, Balance>, Option<Deposit<AccountId, Balance>>),
/// Referendum finished with rejection. Submission deposit is held.
Rejected(Moment, Deposit<AccountId, Balance>, Option<Deposit<AccountId, Balance>>),
/// Referendum finished with cancelation. Submission deposit is held.
Cancelled(Moment, Deposit<AccountId, Balance>, Option<Deposit<AccountId, Balance>>),
/// Referendum finished and was never decided. Submission deposit is held.
TimedOut(Moment, Deposit<AccountId, Balance>, Option<Deposit<AccountId, Balance>>),
/// Referendum finished with a kill.
Killed(Moment),
}
impl<
TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
> ReferendumInfo<TrackId, Origin, Moment, Hash, Balance, Tally, AccountId, ScheduleAddress>
{
/// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not
/// in a valid state for the Decision Deposit to be refunded.
pub fn take_decision_deposit(&mut self) -> Result<Option<Deposit<AccountId, Balance>>, ()> {
use ReferendumInfo::*;
match self {
Ongoing(x) if x.decision_deposit.is_none() => Ok(None),
// Cannot refund deposit if Ongoing as this breaks assumptions.
Ongoing(_) => Err(()),
Approved(_, _, d) | Rejected(_, _, d) | TimedOut(_, _, d) | Cancelled(_, _, d) =>
Ok(d.take()),
Killed(_) => Ok(None),
}
}
}
/// Type for describing a curve over the 2-dimensional space of axes between 0-1, as represented
/// by `(Perbill, Perbill)`.
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)]
#[cfg_attr(not(feature = "std"), derive(RuntimeDebug))]
pub enum Curve {
/// Linear curve starting at `(0, begin)`, ending at `(period, begin - delta)`.
LinearDecreasing { begin: Perbill, delta: Perbill },
}
impl Curve {
/// Determine the `y` value for the given `x` value.
pub(crate) fn threshold(&self, x: Perbill) -> Perbill {
match self {
Self::LinearDecreasing { begin, delta } => *begin - (*delta * x).min(*begin),
}
}
/// Determine the smallest `x` value such that `passing` returns `true` when passed along with
/// the given `y` value.
///
/// ```nocompile
/// let c = Curve::LinearDecreasing { begin: Perbill::one(), delta: Perbill::one() };
/// // ^^^ Can be any curve.
/// let y = Perbill::from_percent(50);
/// // ^^^ Can be any value.
/// let x = c.delay(y);
/// assert!(c.passing(x, y));
/// ```
pub fn delay(&self, y: Perbill) -> Perbill {
match self {
Self::LinearDecreasing { begin, delta } =>
if delta.is_zero() {
return *delta
} else {
return (*begin - y.min(*begin)).min(*delta) / *delta
},
}
}
/// Return `true` iff the `y` value is greater than the curve at the `x`.
pub fn passing(&self, x: Perbill, y: Perbill) -> bool {
y >= self.threshold(x)
}
}
#[cfg(feature = "std")]
impl Debug for Curve {
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
match self {
Self::LinearDecreasing { begin, delta } => {
write!(
f,
"Linear[(0%, {}%) -> (100%, {}%)]",
*begin * 100u32,
(*begin - *delta) * 100u32,
)
},
}
}
}
+491
View File
@@ -0,0 +1,491 @@
// This file is part of Substrate.
// Copyright (C) 2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Autogenerated weights for pallet_referenda
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2021-12-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
// Executed Command:
// target/release/substrate
// benchmark
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet_referenda
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --heap-pages=4096
// --output=./frame/referenda/src/weights.rs
// --template=./.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use sp_std::marker::PhantomData;
/// Weight functions needed for pallet_referenda.
pub trait WeightInfo {
fn submit() -> Weight;
fn place_decision_deposit_preparing() -> Weight;
fn place_decision_deposit_queued() -> Weight;
fn place_decision_deposit_not_queued() -> Weight;
fn place_decision_deposit_passing() -> Weight;
fn place_decision_deposit_failing() -> Weight;
fn refund_decision_deposit() -> Weight;
fn cancel() -> Weight;
fn kill() -> Weight;
fn one_fewer_deciding_queue_empty() -> Weight;
fn one_fewer_deciding_failing() -> Weight;
fn one_fewer_deciding_passing() -> Weight;
fn nudge_referendum_requeued_insertion() -> Weight;
fn nudge_referendum_requeued_slide() -> Weight;
fn nudge_referendum_queued() -> Weight;
fn nudge_referendum_not_queued() -> Weight;
fn nudge_referendum_no_deposit() -> Weight;
fn nudge_referendum_preparing() -> Weight;
fn nudge_referendum_timed_out() -> Weight;
fn nudge_referendum_begin_deciding_failing() -> Weight;
fn nudge_referendum_begin_deciding_passing() -> Weight;
fn nudge_referendum_begin_confirming() -> Weight;
fn nudge_referendum_end_confirming() -> Weight;
fn nudge_referendum_continue_not_confirming() -> Weight;
fn nudge_referendum_continue_confirming() -> Weight;
fn nudge_referendum_approved() -> Weight;
fn nudge_referendum_rejected() -> Weight;
}
/// Weights for pallet_referenda using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Storage: Referenda ReferendumCount (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Referenda ReferendumInfoFor (r:0 w:1)
fn submit() -> Weight {
(42_395_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn place_decision_deposit_preparing() -> Weight {
(48_113_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
fn place_decision_deposit_queued() -> Weight {
(53_624_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
fn place_decision_deposit_not_queued() -> Weight {
(52_560_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn place_decision_deposit_passing() -> Weight {
(54_067_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(4 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn place_decision_deposit_failing() -> Weight {
(52_457_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(4 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
fn refund_decision_deposit() -> Weight {
(28_504_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn cancel() -> Weight {
(40_425_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn kill() -> Weight {
(65_974_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda TrackQueue (r:1 w:0)
// Storage: Referenda DecidingCount (r:1 w:1)
fn one_fewer_deciding_queue_empty() -> Weight {
(8_904_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn one_fewer_deciding_failing() -> Weight {
(181_387_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(4 as Weight))
}
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn one_fewer_deciding_passing() -> Weight {
(179_753_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(4 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_requeued_insertion() -> Weight {
(53_592_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_requeued_slide() -> Weight {
(53_173_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_queued() -> Weight {
(55_770_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_not_queued() -> Weight {
(53_922_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_no_deposit() -> Weight {
(26_906_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_preparing() -> Weight {
(27_943_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
fn nudge_referendum_timed_out() -> Weight {
(20_256_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_begin_deciding_failing() -> Weight {
(30_964_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_begin_deciding_passing() -> Weight {
(31_763_000 as Weight)
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_begin_confirming() -> Weight {
(28_892_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_end_confirming() -> Weight {
(29_666_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_continue_not_confirming() -> Weight {
(29_740_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_continue_confirming() -> Weight {
(29_661_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
fn nudge_referendum_approved() -> Weight {
(55_736_000 as Weight)
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_rejected() -> Weight {
(32_726_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
}
// For backwards compatibility and tests
impl WeightInfo for () {
// Storage: Referenda ReferendumCount (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Referenda ReferendumInfoFor (r:0 w:1)
fn submit() -> Weight {
(42_395_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn place_decision_deposit_preparing() -> Weight {
(48_113_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
fn place_decision_deposit_queued() -> Weight {
(53_624_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
fn place_decision_deposit_not_queued() -> Weight {
(52_560_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn place_decision_deposit_passing() -> Weight {
(54_067_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn place_decision_deposit_failing() -> Weight {
(52_457_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
fn refund_decision_deposit() -> Weight {
(28_504_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn cancel() -> Weight {
(40_425_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn kill() -> Weight {
(65_974_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda TrackQueue (r:1 w:0)
// Storage: Referenda DecidingCount (r:1 w:1)
fn one_fewer_deciding_queue_empty() -> Weight {
(8_904_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn one_fewer_deciding_failing() -> Weight {
(181_387_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
}
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
fn one_fewer_deciding_passing() -> Weight {
(179_753_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_requeued_insertion() -> Weight {
(53_592_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_requeued_slide() -> Weight {
(53_173_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_queued() -> Weight {
(55_770_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:0)
// Storage: Referenda TrackQueue (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_not_queued() -> Weight {
(53_922_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_no_deposit() -> Weight {
(26_906_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_preparing() -> Weight {
(27_943_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
fn nudge_referendum_timed_out() -> Weight {
(20_256_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_begin_deciding_failing() -> Weight {
(30_964_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Referenda DecidingCount (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_begin_deciding_passing() -> Weight {
(31_763_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_begin_confirming() -> Weight {
(28_892_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_end_confirming() -> Weight {
(29_666_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_continue_not_confirming() -> Weight {
(29_740_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_continue_confirming() -> Weight {
(29_661_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
fn nudge_referendum_approved() -> Weight {
(55_736_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
}
// Storage: Referenda ReferendumInfoFor (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn nudge_referendum_rejected() -> Weight {
(32_726_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
}
}