Bound uses of Call (#11649)

* Introduce preimages module in traits

* Multisize Preimages

* Len not actually necessary

* Tweaks to the preimage API

* Fixes

* Get Scheduler building with new API

* Scheduler tests pass

* Bounded Scheduler 🎉

* Use Agenda holes and introduce IncompleteSince to avoid need to reschedule

* Tests pass with new weight system

* New benchmarks

* Add missing file

* Drop preimage when permenantly overeight

* Drop preimage when permenantly overeight

* Referenda uses latest preimage API

* Testing ok

* Adding tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add preimage migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Docs

* Remove dbg

* Refactor Democracy

* Refactor Democracy

* Add final MEL

* Remove silly maps

* Fixes

* Minor refactor

* Formatting

* Fixes

* Fixes

* Fixes

* Update frame/preimage/src/lib.rs

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

* Add migrations to Democracy

* WIP

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Resolve conflicts

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Resolve conflicts"

This reverts commit 734d66d69e54553471ffa54fa52e3e304dc8f106.

* Undo wrong resolves...

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* WIP

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Make compile

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* massage clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clippy annoyance

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clippy annoyance

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix benchmarks

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* add missing file

* Test <Preimage as QueryPreimage>

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Clippy harassment

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixup tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove old stuff

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Test <Scheduler as Anon> trait functions

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update pallet-ui tests

Why is this needed? Should not be the case unless master is broken...

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More scheduler trait test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Apply review suggestion

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Beauty fixes

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add Scheduler test migration_v3_to_v4_works

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Merge fixup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Keep referenda benchmarks instantiatable

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update weights

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use new scheduler weight functions

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use new democracy weight functions

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use weight compare functions

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update pallet-ui tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More renaming…

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More renaming…

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add comment

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Implement OnRuntimeUpgrade for scheduler::v3_to_v4 migration

Put the migration into a proper `MigrateToV4` struct and implement
the OnRuntimeUpgrade hooks for it. Also move the test to use that
instead.

This should make it easier for adding it to Polkadot.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Handle undecodable Agendas

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove trash

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use new OnRuntimeUpgrade functions

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fix test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix BoundedSlice::truncate_from

Co-authored-by: jakoblell

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix pre_upgrade hook return values

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add more error logging

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Find too large preimages in the pre_upgrade hook

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Test that too large Calls in agendas are ignored

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use new OnRuntimeUpgrade hooks

Why did the CI not catch this?!

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* works fine - just more logs

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix staking migration

Causing issues on Kusama...

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix UI tests

No idea why this is needed. This is actually undoing an earlier change.
Maybe the CI has different rustc versions!?

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove multisig's Calls (#12072)

* Remove multisig's Calls

* Multisig: Fix tests and re-introduce reserve logic (#12241)

* Fix tests and re-introduce reserve logic

* fix benches

* add todo

* remove irrelevant bench

* [Feature] Add a migration that drains and refunds stored calls (#12313)

* [Feature] Add a migration that drains and refunds stored calls

* migration fixes

* fixes

* address review comments

* consume the whole block weight

* fix assertions

* license header

* fix interface

Co-authored-by: parity-processbot <>

Co-authored-by: parity-processbot <>
Co-authored-by: Roman Useinov <roman.useinov@gmail.com>

* Fix test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix multisig benchmarks

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy

* ".git/.scripts/bench-bot.sh" pallet dev pallet_scheduler

* ".git/.scripts/bench-bot.sh" pallet dev pallet_preimage

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: parity-processbot <>
Co-authored-by: Roman Useinov <roman.useinov@gmail.com>
This commit is contained in:
Gavin Wood
2022-10-05 19:21:37 +01:00
committed by GitHub
parent 24f0c3601c
commit 93e8ffed55
67 changed files with 5089 additions and 3488 deletions
+4
View File
@@ -5581,7 +5581,9 @@ dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
"pallet-balances",
"pallet-preimage",
"pallet-scheduler",
"parity-scale-codec",
"scale-info",
@@ -5899,6 +5901,7 @@ dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
"pallet-balances",
"parity-scale-codec",
"scale-info",
@@ -6065,6 +6068,7 @@ dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
"pallet-balances",
"parity-scale-codec",
"scale-info",
+7 -9
View File
@@ -340,8 +340,6 @@ impl pallet_proxy::Config for Runtime {
parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
RuntimeBlockWeights::get().max_block;
// Retry a scheduled item every 10 blocks (1 minute) until the preimage exists.
pub const NoPreimagePostponement: Option<u32> = Some(10);
}
impl pallet_scheduler::Config for Runtime {
@@ -351,11 +349,10 @@ impl pallet_scheduler::Config for Runtime {
type RuntimeCall = RuntimeCall;
type MaximumWeight = MaximumSchedulerWeight;
type ScheduleOrigin = EnsureRoot<AccountId>;
type MaxScheduledPerBlock = ConstU32<50>;
type MaxScheduledPerBlock = ConstU32<512>;
type WeightInfo = pallet_scheduler::weights::SubstrateWeight<Runtime>;
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type PreimageProvider = Preimage;
type NoPreimagePostponement = NoPreimagePostponement;
type Preimages = Preimage;
}
parameter_types! {
@@ -370,7 +367,6 @@ impl pallet_preimage::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type ManagerOrigin = EnsureRoot<AccountId>;
type MaxSize = PreimageMaxSize;
type BaseDeposit = PreimageBaseDeposit;
type ByteDeposit = PreimageByteDeposit;
}
@@ -862,6 +858,7 @@ impl pallet_referenda::Config for Runtime {
type UndecidingTimeout = UndecidingTimeout;
type AlarmInterval = AlarmInterval;
type Tracks = TracksInfo;
type Preimages = Preimage;
}
impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
@@ -881,6 +878,7 @@ impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
type UndecidingTimeout = UndecidingTimeout;
type AlarmInterval = AlarmInterval;
type Tracks = TracksInfo;
type Preimages = Preimage;
}
impl pallet_ranked_collective::Config for Runtime {
@@ -909,7 +907,6 @@ parameter_types! {
}
impl pallet_democracy::Config for Runtime {
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type EnactmentPeriod = EnactmentPeriod;
@@ -949,14 +946,15 @@ impl pallet_democracy::Config for Runtime {
// only do it once and it lasts only for the cool-off period.
type VetoOrigin = pallet_collective::EnsureMember<AccountId, TechnicalCollective>;
type CooloffPeriod = CooloffPeriod;
type PreimageByteDeposit = PreimageByteDeposit;
type OperationalPreimageOrigin = pallet_collective::EnsureMember<AccountId, CouncilCollective>;
type Slash = Treasury;
type Scheduler = Scheduler;
type PalletsOrigin = OriginCaller;
type MaxVotes = ConstU32<100>;
type WeightInfo = pallet_democracy::weights::SubstrateWeight<Runtime>;
type MaxProposals = MaxProposals;
type Preimages = Preimage;
type MaxDeposits = ConstU32<100>;
type MaxBlacklisted = ConstU32<100>;
}
parameter_types! {
+1 -1
View File
@@ -819,7 +819,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
value: BalanceOf<T, I>,
) -> DispatchResult {
let bounded_description: BoundedVec<_, _> =
description.try_into().map_err(|()| Error::<T, I>::ReasonTooBig)?;
description.try_into().map_err(|_| Error::<T, I>::ReasonTooBig)?;
ensure!(value >= T::BountyValueMinimum::get(), Error::<T, I>::InvalidValue);
let index = Self::bounty_count();
+1 -1
View File
@@ -340,7 +340,7 @@ where
let queue: Vec<DeletedContract> = (0..T::DeletionQueueDepth::get())
.map(|_| DeletedContract { trie_id: TrieId::default() })
.collect();
let bounded: BoundedVec<_, _> = queue.try_into().unwrap();
let bounded: BoundedVec<_, _> = queue.try_into().map_err(|_| ()).unwrap();
<DeletionQueue<T>>::put(bounded);
}
}
+1 -1
View File
@@ -400,7 +400,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Err(i) => {
votes
.try_insert(i, (poll_index, vote))
.map_err(|()| Error::<T, I>::MaxVotesReached)?;
.map_err(|_| Error::<T, I>::MaxVotesReached)?;
},
}
// Shouldn't be possible to fail, but we handle it gracefully.
+5 -2
View File
@@ -24,11 +24,13 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys
sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" }
log = { version = "0.4.17", default-features = false }
[dev-dependencies]
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" }
sp-core = { version = "6.0.0", path = "../../primitives/core" }
pallet-preimage = { version = "4.0.0-dev", path = "../preimage" }
[features]
default = ["std"]
@@ -42,6 +44,7 @@ std = [
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"sp-core/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
@@ -49,4 +52,4 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = ["frame-support/try-runtime"]
try-runtime = ["frame-support/try-runtime",]
+123 -275
View File
@@ -22,24 +22,16 @@ use super::*;
use frame_benchmarking::{account, benchmarks, whitelist_account};
use frame_support::{
assert_noop, assert_ok,
codec::Decode,
traits::{
schedule::DispatchTime, Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable,
},
traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable},
};
use frame_system::{Pallet as System, RawOrigin};
use sp_runtime::traits::{BadOrigin, Bounded, One};
use frame_system::RawOrigin;
use sp_core::H256;
use sp_runtime::{traits::Bounded, BoundedVec};
use crate::Pallet as Democracy;
const REFERENDUM_COUNT_HINT: u32 = 10;
const SEED: u32 = 0;
const MAX_REFERENDUMS: u32 = 99;
const MAX_SECONDERS: u32 = 100;
const MAX_BYTES: u32 = 16_384;
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
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);
@@ -49,37 +41,32 @@ fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
caller
}
fn add_proposal<T: Config>(n: u32) -> Result<T::Hash, &'static str> {
let other = funded_account::<T>("proposer", n);
let value = T::MinimumDeposit::get();
let proposal_hash: T::Hash = T::Hashing::hash_of(&n);
Democracy::<T>::propose(RawOrigin::Signed(other).into(), proposal_hash, value)?;
Ok(proposal_hash)
fn make_proposal<T: Config>(n: u32) -> BoundedCallOf<T> {
let call: CallOf<T> = frame_system::Call::remark { remark: n.encode() }.into();
<T as Config>::Preimages::bound(call).unwrap()
}
fn add_referendum<T: Config>(n: u32) -> Result<ReferendumIndex, &'static str> {
let proposal_hash: T::Hash = T::Hashing::hash_of(&n);
let vote_threshold = VoteThreshold::SimpleMajority;
fn add_proposal<T: Config>(n: u32) -> Result<H256, &'static str> {
let other = funded_account::<T>("proposer", n);
let value = T::MinimumDeposit::get();
let proposal = make_proposal::<T>(n);
Democracy::<T>::propose(RawOrigin::Signed(other).into(), proposal.clone(), value)?;
Ok(proposal.hash())
}
Democracy::<T>::inject_referendum(
T::LaunchPeriod::get(),
proposal_hash,
vote_threshold,
0u32.into(),
);
let referendum_index: ReferendumIndex = ReferendumCount::<T>::get() - 1;
T::Scheduler::schedule_named(
(DEMOCRACY_ID, referendum_index).encode(),
DispatchTime::At(2u32.into()),
None,
63,
frame_system::RawOrigin::Root.into(),
Call::enact_proposal { proposal_hash, index: referendum_index }.into(),
fn add_referendum<T: Config>(n: u32) -> (ReferendumIndex, H256) {
let vote_threshold = VoteThreshold::SimpleMajority;
let proposal = make_proposal::<T>(n);
let hash = proposal.hash();
(
Democracy::<T>::inject_referendum(
T::LaunchPeriod::get(),
proposal,
vote_threshold,
0u32.into(),
),
hash,
)
.map_err(|_| "failed to schedule named")?;
Ok(referendum_index)
}
fn account_vote<T: Config>(b: BalanceOf<T>) -> AccountVote<BalanceOf<T>> {
@@ -97,95 +84,90 @@ benchmarks! {
}
let caller = funded_account::<T>("caller", 0);
let proposal_hash: T::Hash = T::Hashing::hash_of(&0);
let proposal = make_proposal::<T>(0);
let value = T::MinimumDeposit::get();
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller), proposal_hash, value)
}: _(RawOrigin::Signed(caller), proposal, value)
verify {
assert_eq!(Democracy::<T>::public_props().len(), p as usize, "Proposals not created.");
}
second {
let s in 0 .. MAX_SECONDERS;
let caller = funded_account::<T>("caller", 0);
let proposal_hash = add_proposal::<T>(s)?;
add_proposal::<T>(0)?;
// Create s existing "seconds"
for i in 0 .. s {
// we must reserve one deposit for the `proposal` and one for our benchmarked `second` call.
for i in 0 .. T::MaxDeposits::get() - 2 {
let seconder = funded_account::<T>("seconder", i);
Democracy::<T>::second(RawOrigin::Signed(seconder).into(), 0, u32::MAX)?;
Democracy::<T>::second(RawOrigin::Signed(seconder).into(), 0)?;
}
let deposits = Democracy::<T>::deposit_of(0).ok_or("Proposal not created")?;
assert_eq!(deposits.0.len(), (s + 1) as usize, "Seconds not recorded");
assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded");
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller), 0, u32::MAX)
}: _(RawOrigin::Signed(caller), 0)
verify {
let deposits = Democracy::<T>::deposit_of(0).ok_or("Proposal not created")?;
assert_eq!(deposits.0.len(), (s + 2) as usize, "`second` benchmark did not work");
assert_eq!(deposits.0.len(), (T::MaxDeposits::get()) as usize, "`second` benchmark did not work");
}
vote_new {
let r in 1 .. MAX_REFERENDUMS;
let caller = funded_account::<T>("caller", 0);
let account_vote = account_vote::<T>(100u32.into());
// We need to create existing direct votes
for i in 0 .. r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
for i in 0 .. T::MaxVotes::get() - 1 {
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
}
let votes = match VotingOf::<T>::get(&caller) {
Voting::Direct { votes, .. } => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), r as usize, "Votes were not recorded.");
assert_eq!(votes.len(), (T::MaxVotes::get() - 1) as usize, "Votes were not recorded.");
let referendum_index = add_referendum::<T>(r)?;
let ref_index = add_referendum::<T>(T::MaxVotes::get() - 1).0;
whitelist_account!(caller);
}: vote(RawOrigin::Signed(caller.clone()), referendum_index, account_vote)
}: vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote)
verify {
let votes = match VotingOf::<T>::get(&caller) {
Voting::Direct { votes, .. } => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), (r + 1) as usize, "Vote was not recorded.");
assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was not recorded.");
}
vote_existing {
let r in 1 .. MAX_REFERENDUMS;
let caller = funded_account::<T>("caller", 0);
let account_vote = account_vote::<T>(100u32.into());
// We need to create existing direct votes
for i in 0 ..=r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
for i in 0..T::MaxVotes::get() {
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
}
let votes = match VotingOf::<T>::get(&caller) {
Voting::Direct { votes, .. } => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), (r + 1) as usize, "Votes were not recorded.");
assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Votes were not recorded.");
// Change vote from aye to nay
let nay = Vote { aye: false, conviction: Conviction::Locked1x };
let new_vote = AccountVote::Standard { vote: nay, balance: 1000u32.into() };
let referendum_index = Democracy::<T>::referendum_count() - 1;
let ref_index = Democracy::<T>::referendum_count() - 1;
// This tests when a user changes a vote
whitelist_account!(caller);
}: vote(RawOrigin::Signed(caller.clone()), referendum_index, new_vote)
}: vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote)
verify {
let votes = match VotingOf::<T>::get(&caller) {
Voting::Direct { votes, .. } => votes,
_ => return Err("Votes are not direct".into()),
};
assert_eq!(votes.len(), (r + 1) as usize, "Vote was incorrectly added");
let referendum_info = Democracy::<T>::referendum_info(referendum_index)
assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added");
let referendum_info = Democracy::<T>::referendum_info(ref_index)
.ok_or("referendum doesn't exist")?;
let tally = match referendum_info {
ReferendumInfo::Ongoing(r) => r.tally,
@@ -196,61 +178,55 @@ benchmarks! {
emergency_cancel {
let origin = T::CancellationOrigin::successful_origin();
let referendum_index = add_referendum::<T>(0)?;
assert_ok!(Democracy::<T>::referendum_status(referendum_index));
}: _<T::RuntimeOrigin>(origin, referendum_index)
let ref_index = add_referendum::<T>(0).0;
assert_ok!(Democracy::<T>::referendum_status(ref_index));
}: _<T::RuntimeOrigin>(origin, ref_index)
verify {
// Referendum has been canceled
assert_noop!(
Democracy::<T>::referendum_status(referendum_index),
Democracy::<T>::referendum_status(ref_index),
Error::<T>::ReferendumInvalid,
);
}
blacklist {
let p in 1 .. T::MaxProposals::get();
// Place our proposal at the end to make sure it's worst case.
for i in 0 .. p - 1 {
for i in 0 .. T::MaxProposals::get() - 1 {
add_proposal::<T>(i)?;
}
// We should really add a lot of seconds here, but we're not doing it elsewhere.
// Add a referendum of our proposal.
let (ref_index, hash) = add_referendum::<T>(0);
assert_ok!(Democracy::<T>::referendum_status(ref_index));
// Place our proposal in the external queue, too.
let hash = T::Hashing::hash_of(&0);
assert_ok!(
Democracy::<T>::external_propose(T::ExternalOrigin::successful_origin(), hash)
Democracy::<T>::external_propose(T::ExternalOrigin::successful_origin(), make_proposal::<T>(0))
);
let origin = T::BlacklistOrigin::successful_origin();
// Add a referendum of our proposal.
let referendum_index = add_referendum::<T>(0)?;
assert_ok!(Democracy::<T>::referendum_status(referendum_index));
}: _<T::RuntimeOrigin>(origin, hash, Some(referendum_index))
}: _<T::RuntimeOrigin>(origin, hash, Some(ref_index))
verify {
// Referendum has been canceled
assert_noop!(
Democracy::<T>::referendum_status(referendum_index),
Democracy::<T>::referendum_status(ref_index),
Error::<T>::ReferendumInvalid
);
}
// Worst case scenario, we external propose a previously blacklisted proposal
external_propose {
let v in 1 .. MAX_VETOERS as u32;
let origin = T::ExternalOrigin::successful_origin();
let proposal_hash = T::Hashing::hash_of(&0);
let proposal = make_proposal::<T>(0);
// Add proposal to blacklist with block number 0
let addresses = (0..v)
let addresses: BoundedVec<_, _> = (0..(T::MaxBlacklisted::get() - 1))
.into_iter()
.map(|i| account::<T::AccountId>("blacklist", i, SEED))
.collect::<Vec<_>>();
Blacklist::<T>::insert(
proposal_hash,
(T::BlockNumber::zero(), addresses),
);
}: _<T::RuntimeOrigin>(origin, proposal_hash)
.collect::<Vec<_>>()
.try_into()
.unwrap();
Blacklist::<T>::insert(proposal.hash(), (T::BlockNumber::zero(), addresses));
}: _<T::RuntimeOrigin>(origin, proposal)
verify {
// External proposal created
ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -258,8 +234,8 @@ benchmarks! {
external_propose_majority {
let origin = T::ExternalMajorityOrigin::successful_origin();
let proposal_hash = T::Hashing::hash_of(&0);
}: _<T::RuntimeOrigin>(origin, proposal_hash)
let proposal = make_proposal::<T>(0);
}: _<T::RuntimeOrigin>(origin, proposal)
verify {
// External proposal created
ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -267,8 +243,8 @@ benchmarks! {
external_propose_default {
let origin = T::ExternalDefaultOrigin::successful_origin();
let proposal_hash = T::Hashing::hash_of(&0);
}: _<T::RuntimeOrigin>(origin, proposal_hash)
let proposal = make_proposal::<T>(0);
}: _<T::RuntimeOrigin>(origin, proposal)
verify {
// External proposal created
ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -276,8 +252,9 @@ benchmarks! {
fast_track {
let origin_propose = T::ExternalDefaultOrigin::successful_origin();
let proposal_hash: T::Hash = T::Hashing::hash_of(&0);
Democracy::<T>::external_propose_default(origin_propose, proposal_hash)?;
let proposal = make_proposal::<T>(0);
let proposal_hash = proposal.hash();
Democracy::<T>::external_propose_default(origin_propose, proposal)?;
// NOTE: Instant origin may invoke a little bit more logic, but may not always succeed.
let origin_fast_track = T::FastTrackOrigin::successful_origin();
@@ -289,17 +266,15 @@ benchmarks! {
}
veto_external {
// Existing veto-ers
let v in 0 .. MAX_VETOERS as u32;
let proposal_hash: T::Hash = T::Hashing::hash_of(&v);
let proposal = make_proposal::<T>(0);
let proposal_hash = proposal.hash();
let origin_propose = T::ExternalDefaultOrigin::successful_origin();
Democracy::<T>::external_propose_default(origin_propose, proposal_hash)?;
Democracy::<T>::external_propose_default(origin_propose, proposal)?;
let mut vetoers: Vec<T::AccountId> = Vec::new();
for i in 0 .. v {
vetoers.push(account::<T::AccountId>("vetoer", i, SEED));
let mut vetoers: BoundedVec<T::AccountId, _> = Default::default();
for i in 0 .. (T::MaxBlacklisted::get() - 1) {
vetoers.try_push(account::<T::AccountId>("vetoer", i, SEED)).unwrap();
}
vetoers.sort();
Blacklist::<T>::insert(proposal_hash, (T::BlockNumber::zero(), vetoers));
@@ -310,42 +285,27 @@ benchmarks! {
verify {
assert!(NextExternal::<T>::get().is_none());
let (_, new_vetoers) = <Blacklist<T>>::get(&proposal_hash).ok_or("no blacklist")?;
assert_eq!(new_vetoers.len(), (v + 1) as usize, "vetoers not added");
assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added");
}
cancel_proposal {
let p in 1 .. T::MaxProposals::get();
// Place our proposal at the end to make sure it's worst case.
for i in 0 .. p {
for i in 0 .. T::MaxProposals::get() {
add_proposal::<T>(i)?;
}
let cancel_origin = T::CancelProposalOrigin::successful_origin();
}: _<T::RuntimeOrigin>(cancel_origin, 0)
cancel_referendum {
let referendum_index = add_referendum::<T>(0)?;
}: _(RawOrigin::Root, referendum_index)
let ref_index = add_referendum::<T>(0).0;
}: _(RawOrigin::Root, ref_index)
cancel_queued {
let r in 1 .. MAX_REFERENDUMS;
for i in 0..r {
add_referendum::<T>(i)?; // This add one element in the scheduler
}
let referendum_index = add_referendum::<T>(r)?;
}: _(RawOrigin::Root, referendum_index)
// This measures the path of `launch_next` external. Not currently used as we simply
// assume the weight is `MaxBlockWeight` when executing.
#[extra]
on_initialize_external {
let r in 0 .. MAX_REFERENDUMS;
let r in 0 .. REFERENDUM_COUNT_HINT;
for i in 0..r {
add_referendum::<T>(i)?;
add_referendum::<T>(i);
}
assert_eq!(Democracy::<T>::referendum_count(), r, "referenda not created");
@@ -354,8 +314,8 @@ benchmarks! {
LastTabledWasExternal::<T>::put(false);
let origin = T::ExternalMajorityOrigin::successful_origin();
let proposal_hash = T::Hashing::hash_of(&r);
let call = Call::<T>::external_propose_majority { proposal_hash };
let proposal = make_proposal::<T>(r);
let call = Call::<T>::external_propose_majority { proposal };
call.dispatch_bypass_filter(origin)?;
// External proposal created
ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -379,14 +339,12 @@ benchmarks! {
}
}
// This measures the path of `launch_next` public. Not currently used as we simply
// assume the weight is `MaxBlockWeight` when executing.
#[extra]
on_initialize_public {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
for i in 0..r {
add_referendum::<T>(i)?;
add_referendum::<T>(i);
}
assert_eq!(Democracy::<T>::referendum_count(), r, "referenda not created");
@@ -415,10 +373,10 @@ benchmarks! {
// No launch no maturing referenda.
on_initialize_base {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
for i in 0..r {
add_referendum::<T>(i)?;
add_referendum::<T>(i);
}
for (key, mut info) in ReferendumInfoOf::<T>::iter() {
@@ -445,10 +403,10 @@ benchmarks! {
}
on_initialize_base_with_launch_period {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
for i in 0..r {
add_referendum::<T>(i)?;
add_referendum::<T>(i);
}
for (key, mut info) in ReferendumInfoOf::<T>::iter() {
@@ -477,7 +435,7 @@ benchmarks! {
}
delegate {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
let initial_balance: BalanceOf<T> = 100u32.into();
let delegated_balance: BalanceOf<T> = 1000u32.into();
@@ -504,8 +462,8 @@ benchmarks! {
let account_vote = account_vote::<T>(initial_balance);
// We need to create existing direct votes for the `new_delegate`
for i in 0..r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_idx, account_vote)?;
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_index, account_vote)?;
}
let votes = match VotingOf::<T>::get(&new_delegate) {
Voting::Direct { votes, .. } => votes,
@@ -529,7 +487,7 @@ benchmarks! {
}
undelegate {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
let initial_balance: BalanceOf<T> = 100u32.into();
let delegated_balance: BalanceOf<T> = 1000u32.into();
@@ -553,10 +511,10 @@ benchmarks! {
// We need to create votes direct votes for the `delegate`
let account_vote = account_vote::<T>(initial_balance);
for i in 0..r {
let ref_idx = add_referendum::<T>(i)?;
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(
RawOrigin::Signed(the_delegate.clone()).into(),
ref_idx,
ref_index,
account_vote
)?;
}
@@ -580,71 +538,9 @@ benchmarks! {
}: _(RawOrigin::Root)
note_preimage {
// Num of bytes in encoded proposal
let b in 0 .. MAX_BYTES;
let caller = funded_account::<T>("caller", 0);
let encoded_proposal = vec![1; b as usize];
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller), encoded_proposal.clone())
verify {
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
match Preimages::<T>::get(proposal_hash) {
Some(PreimageStatus::Available { .. }) => (),
_ => return Err("preimage not available".into())
}
}
note_imminent_preimage {
// Num of bytes in encoded proposal
let b in 0 .. MAX_BYTES;
// d + 1 to include the one we are testing
let encoded_proposal = vec![1; b as usize];
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
let block_number = T::BlockNumber::one();
Preimages::<T>::insert(&proposal_hash, PreimageStatus::Missing(block_number));
let caller = funded_account::<T>("caller", 0);
let encoded_proposal = vec![1; b as usize];
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller), encoded_proposal.clone())
verify {
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
match Preimages::<T>::get(proposal_hash) {
Some(PreimageStatus::Available { .. }) => (),
_ => return Err("preimage not available".into())
}
}
reap_preimage {
// Num of bytes in encoded proposal
let b in 0 .. MAX_BYTES;
let encoded_proposal = vec![1; b as usize];
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
let submitter = funded_account::<T>("submitter", b);
Democracy::<T>::note_preimage(RawOrigin::Signed(submitter).into(), encoded_proposal.clone())?;
// We need to set this otherwise we get `Early` error.
let block_number = T::VotingPeriod::get() + T::EnactmentPeriod::get() + T::BlockNumber::one();
System::<T>::set_block_number(block_number);
assert!(Preimages::<T>::contains_key(proposal_hash));
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller), proposal_hash, u32::MAX)
verify {
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
assert!(!Preimages::<T>::contains_key(proposal_hash));
}
// Test when unlock will remove locks
unlock_remove {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
let locker = funded_account::<T>("locker", 0);
let locker_lookup = T::Lookup::unlookup(locker.clone());
@@ -653,9 +549,9 @@ benchmarks! {
let small_vote = account_vote::<T>(base_balance);
// Vote and immediately unvote
for i in 0 .. r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?;
Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_idx)?;
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?;
Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?;
}
let caller = funded_account::<T>("caller", 0);
@@ -669,7 +565,7 @@ benchmarks! {
// Test when unlock will set a new value
unlock_set {
let r in 1 .. MAX_REFERENDUMS;
let r in 0 .. (T::MaxVotes::get() - 1);
let locker = funded_account::<T>("locker", 0);
let locker_lookup = T::Lookup::unlookup(locker.clone());
@@ -677,14 +573,14 @@ benchmarks! {
let base_balance: BalanceOf<T> = 100u32.into();
let small_vote = account_vote::<T>(base_balance);
for i in 0 .. r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?;
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?;
}
// Create a big vote so lock increases
let big_vote = account_vote::<T>(base_balance * 10u32.into());
let referendum_index = add_referendum::<T>(r)?;
Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), referendum_index, big_vote)?;
let ref_index = add_referendum::<T>(r).0;
Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, big_vote)?;
let votes = match VotingOf::<T>::get(&locker) {
Voting::Direct { votes, .. } => votes,
@@ -695,7 +591,7 @@ benchmarks! {
let voting = VotingOf::<T>::get(&locker);
assert_eq!(voting.locked_balance(), base_balance * 10u32.into());
Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), referendum_index)?;
Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?;
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
@@ -709,18 +605,18 @@ benchmarks! {
let voting = VotingOf::<T>::get(&locker);
// Note that we may want to add a `get_lock` api to actually verify
assert_eq!(voting.locked_balance(), base_balance);
assert_eq!(voting.locked_balance(), if r > 0 { base_balance } else { 0u32.into() });
}
remove_vote {
let r in 1 .. MAX_REFERENDUMS;
let r in 1 .. T::MaxVotes::get();
let caller = funded_account::<T>("caller", 0);
let account_vote = account_vote::<T>(100u32.into());
for i in 0 .. r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
}
let votes = match VotingOf::<T>::get(&caller) {
@@ -729,9 +625,9 @@ benchmarks! {
};
assert_eq!(votes.len(), r as usize, "Votes not created");
let referendum_index = r - 1;
let ref_index = r - 1;
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller.clone()), referendum_index)
}: _(RawOrigin::Signed(caller.clone()), ref_index)
verify {
let votes = match VotingOf::<T>::get(&caller) {
Voting::Direct { votes, .. } => votes,
@@ -742,15 +638,15 @@ benchmarks! {
// Worst case is when target == caller and referendum is ongoing
remove_other_vote {
let r in 1 .. MAX_REFERENDUMS;
let r in 1 .. T::MaxVotes::get();
let caller = funded_account::<T>("caller", r);
let caller_lookup = T::Lookup::unlookup(caller.clone());
let account_vote = account_vote::<T>(100u32.into());
for i in 0 .. r {
let ref_idx = add_referendum::<T>(i)?;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
let ref_index = add_referendum::<T>(i).0;
Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
}
let votes = match VotingOf::<T>::get(&caller) {
@@ -759,9 +655,9 @@ benchmarks! {
};
assert_eq!(votes.len(), r as usize, "Votes not created");
let referendum_index = r - 1;
let ref_index = r - 1;
whitelist_account!(caller);
}: _(RawOrigin::Signed(caller.clone()), caller_lookup, referendum_index)
}: _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index)
verify {
let votes = match VotingOf::<T>::get(&caller) {
Voting::Direct { votes, .. } => votes,
@@ -770,54 +666,6 @@ benchmarks! {
assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed");
}
#[extra]
enact_proposal_execute {
// Num of bytes in encoded proposal
let b in 0 .. MAX_BYTES;
let proposer = funded_account::<T>("proposer", 0);
let raw_call = Call::note_preimage { encoded_proposal: vec![1; b as usize] };
let generic_call: T::Proposal = raw_call.into();
let encoded_proposal = generic_call.encode();
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
Democracy::<T>::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?;
match Preimages::<T>::get(proposal_hash) {
Some(PreimageStatus::Available { .. }) => (),
_ => return Err("preimage not available".into())
}
}: enact_proposal(RawOrigin::Root, proposal_hash, 0)
verify {
// Fails due to mismatched origin
assert_last_event::<T>(Event::<T>::Executed { ref_index: 0, result: Err(BadOrigin.into()) }.into());
}
#[extra]
enact_proposal_slash {
// Num of bytes in encoded proposal
let b in 0 .. MAX_BYTES;
let proposer = funded_account::<T>("proposer", 0);
// Random invalid bytes
let encoded_proposal = vec![200; b as usize];
let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
Democracy::<T>::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?;
match Preimages::<T>::get(proposal_hash) {
Some(PreimageStatus::Available { .. }) => (),
_ => return Err("preimage not available".into())
}
let origin = RawOrigin::Root.into();
let call = Call::<T>::enact_proposal { proposal_hash, index: 0 }.encode();
}: {
assert_eq!(
<Call<T> as Decode>::decode(&mut &*call)
.expect("call is encoded above, encoding must be correct")
.dispatch_bypass_filter(origin),
Err(Error::<T>::PreimageInvalid.into())
);
}
impl_benchmark_test_suite!(
Democracy,
crate::tests::new_test_ext(),
+14 -2
View File
@@ -18,7 +18,7 @@
//! The conviction datatype.
use crate::types::Delegations;
use codec::{Decode, Encode};
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{Bounded, CheckedDiv, CheckedMul, Zero},
@@ -27,7 +27,19 @@ use sp_runtime::{
use sp_std::{prelude::*, result::Result};
/// A value denoting the strength of conviction of a vote.
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)]
#[derive(
Encode,
MaxEncodedLen,
Decode,
Copy,
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
RuntimeDebug,
TypeInfo,
)]
pub enum Conviction {
/// 0.1x votes, unlocked.
None,
File diff suppressed because it is too large Load Diff
+236
View File
@@ -0,0 +1,236 @@
// This file is part of Substrate.
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Storage migrations for the preimage pallet.
use super::*;
use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, BoundedVec};
use sp_core::H256;
/// The log target.
const TARGET: &'static str = "runtime::democracy::migration::v1";
/// The original data layout of the democracy pallet without a specific version number.
mod v0 {
use super::*;
#[storage_alias]
pub type PublicProps<T: Config> = StorageValue<
Pallet<T>,
Vec<(PropIndex, <T as frame_system::Config>::Hash, <T as frame_system::Config>::AccountId)>,
ValueQuery,
>;
#[storage_alias]
pub type NextExternal<T: Config> =
StorageValue<Pallet<T>, (<T as frame_system::Config>::Hash, VoteThreshold)>;
#[cfg(feature = "try-runtime")]
#[storage_alias]
pub type ReferendumInfoOf<T: Config> = StorageMap<
Pallet<T>,
frame_support::Twox64Concat,
ReferendumIndex,
ReferendumInfo<
<T as frame_system::Config>::BlockNumber,
<T as frame_system::Config>::Hash,
BalanceOf<T>,
>,
>;
}
pub mod v1 {
use super::*;
/// Migration for translating bare `Hash`es into `Bounded<Call>`s.
pub struct Migration<T>(sp_std::marker::PhantomData<T>);
impl<T: Config + frame_system::Config<Hash = H256>> OnRuntimeUpgrade for Migration<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
let props_count = v0::PublicProps::<T>::get().len();
log::info!(target: TARGET, "{} public proposals will be migrated.", props_count,);
ensure!(props_count <= T::MaxProposals::get() as usize, "too many proposals");
let referenda_count = v0::ReferendumInfoOf::<T>::iter().count();
log::info!(target: TARGET, "{} referenda will be migrated.", referenda_count);
Ok((props_count as u32, referenda_count as u32).encode())
}
#[allow(deprecated)]
fn on_runtime_upgrade() -> Weight {
let mut weight = T::DbWeight::get().reads(1);
if StorageVersion::get::<Pallet<T>>() != 0 {
log::warn!(
target: TARGET,
"skipping on_runtime_upgrade: executed on wrong storage version.\
Expected version 0"
);
return weight
}
ReferendumInfoOf::<T>::translate(
|index, old: ReferendumInfo<T::BlockNumber, T::Hash, BalanceOf<T>>| {
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
log::info!(target: TARGET, "migrating referendum #{:?}", &index);
Some(match old {
ReferendumInfo::Ongoing(status) =>
ReferendumInfo::Ongoing(ReferendumStatus {
end: status.end,
proposal: Bounded::from_legacy_hash(status.proposal),
threshold: status.threshold,
delay: status.delay,
tally: status.tally,
}),
ReferendumInfo::Finished { approved, end } =>
ReferendumInfo::Finished { approved, end },
})
},
);
let props = v0::PublicProps::<T>::take()
.into_iter()
.map(|(i, hash, a)| (i, Bounded::from_legacy_hash(hash), a))
.collect::<Vec<_>>();
let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone());
PublicProps::<T>::put(bounded);
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
if props.len() as u32 > T::MaxProposals::get() {
log::error!(
target: TARGET,
"truncated {} public proposals to {}; continuing",
props.len(),
T::MaxProposals::get()
);
}
if let Some((hash, threshold)) = v0::NextExternal::<T>::take() {
log::info!(target: TARGET, "migrating next external proposal");
NextExternal::<T>::put((Bounded::from_legacy_hash(hash), threshold));
}
StorageVersion::new(1).put::<Pallet<T>>();
weight.saturating_add(T::DbWeight::get().reads_writes(1, 2))
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
let (old_props_count, old_ref_count): (u32, u32) =
Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
let new_props_count = crate::PublicProps::<T>::get().len() as u32;
assert_eq!(new_props_count, old_props_count, "must migrate all public proposals");
let new_ref_count = crate::ReferendumInfoOf::<T>::iter().count() as u32;
assert_eq!(new_ref_count, old_ref_count, "must migrate all referenda");
log::info!(
target: TARGET,
"{} public proposals migrated, {} referenda migrated",
new_props_count,
new_ref_count,
);
Ok(())
}
}
}
#[cfg(test)]
#[cfg(feature = "try-runtime")]
mod test {
use super::*;
use crate::{
tests::{Test as T, *},
types::*,
};
use frame_support::bounded_vec;
#[allow(deprecated)]
#[test]
fn migration_works() {
new_test_ext().execute_with(|| {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0);
// Insert some values into the v0 storage:
// Case 1: Ongoing referendum
let hash = H256::repeat_byte(1);
let status = ReferendumStatus {
end: 1u32.into(),
proposal: hash.clone(),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 1u32.into(),
tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
};
v0::ReferendumInfoOf::<T>::insert(1u32, ReferendumInfo::Ongoing(status));
// Case 2: Finished referendum
v0::ReferendumInfoOf::<T>::insert(
2u32,
ReferendumInfo::Finished { approved: true, end: 123u32.into() },
);
// Case 3: Public proposals
let hash2 = H256::repeat_byte(2);
v0::PublicProps::<T>::put(vec![
(3u32, hash.clone(), 123u64),
(4u32, hash2.clone(), 123u64),
]);
// Case 4: Next external
v0::NextExternal::<T>::put((hash.clone(), VoteThreshold::SuperMajorityApprove));
// Migrate.
let state = v1::Migration::<T>::pre_upgrade().unwrap();
let _weight = v1::Migration::<T>::on_runtime_upgrade();
v1::Migration::<T>::post_upgrade(state).unwrap();
// Check that all values got migrated.
// Case 1: Ongoing referendum
assert_eq!(
ReferendumInfoOf::<T>::get(1u32),
Some(ReferendumInfo::Ongoing(ReferendumStatus {
end: 1u32.into(),
proposal: Bounded::from_legacy_hash(hash),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 1u32.into(),
tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
}))
);
// Case 2: Finished referendum
assert_eq!(
ReferendumInfoOf::<T>::get(2u32),
Some(ReferendumInfo::Finished { approved: true, end: 123u32.into() })
);
// Case 3: Public proposals
let props: BoundedVec<_, <Test as Config>::MaxProposals> = bounded_vec![
(3u32, Bounded::from_legacy_hash(hash), 123u64),
(4u32, Bounded::from_legacy_hash(hash2), 123u64)
];
assert_eq!(PublicProps::<T>::get(), props);
// Case 4: Next external
assert_eq!(
NextExternal::<T>::get(),
Some((Bounded::from_legacy_hash(hash), VoteThreshold::SuperMajorityApprove))
);
});
}
}
+27 -49
View File
@@ -19,11 +19,11 @@
use super::*;
use crate as pallet_democracy;
use codec::Encode;
use frame_support::{
assert_noop, assert_ok, ord_parameter_types, parameter_types,
traits::{
ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers,
ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize,
SortedMembers, StorePreimage,
},
weights::Weight,
};
@@ -35,14 +35,12 @@ use sp_runtime::{
traits::{BadOrigin, BlakeTwo256, IdentityLookup},
Perbill,
};
mod cancellation;
mod decoders;
mod delegation;
mod external_proposing;
mod fast_tracking;
mod lock_voting;
mod preimage;
mod public_proposals;
mod scheduling;
mod voting;
@@ -63,6 +61,7 @@ frame_support::construct_runtime!(
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
Preimage: pallet_preimage,
Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>},
Democracy: pallet_democracy::{Pallet, Call, Storage, Config<T>, Event<T>},
}
@@ -78,13 +77,11 @@ impl Contains<RuntimeCall> for BaseFilter {
parameter_types! {
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(
Weight::from_ref_time(1_000_000).set_proof_size(u64::MAX),
);
frame_system::limits::BlockWeights::simple_max(frame_support::weights::constants::WEIGHT_PER_SECOND.set_proof_size(u64::MAX));
}
impl frame_system::Config for Test {
type BaseCallFilter = BaseFilter;
type BlockWeights = ();
type BlockWeights = BlockWeights;
type BlockLength = ();
type DbWeight = ();
type RuntimeOrigin = RuntimeOrigin;
@@ -111,6 +108,16 @@ impl frame_system::Config for Test {
parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;
}
impl pallet_preimage::Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type Currency = Balances;
type ManagerOrigin = EnsureRoot<u64>;
type BaseDeposit = ConstU64<0>;
type ByteDeposit = ConstU64<0>;
}
impl pallet_scheduler::Config for Test {
type RuntimeEvent = RuntimeEvent;
type RuntimeOrigin = RuntimeOrigin;
@@ -118,11 +125,10 @@ impl pallet_scheduler::Config for Test {
type RuntimeCall = RuntimeCall;
type MaximumWeight = MaximumSchedulerWeight;
type ScheduleOrigin = EnsureRoot<u64>;
type MaxScheduledPerBlock = ();
type MaxScheduledPerBlock = ConstU32<100>;
type WeightInfo = ();
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type PreimageProvider = ();
type NoPreimagePostponement = ();
type Preimages = ();
}
impl pallet_balances::Config for Test {
@@ -158,7 +164,6 @@ impl SortedMembers<u64> for OneToFive {
}
impl Config for Test {
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type Currency = pallet_balances::Pallet<Self>;
type EnactmentPeriod = ConstU64<2>;
@@ -167,6 +172,8 @@ impl Config for Test {
type VoteLockingPeriod = ConstU64<3>;
type FastTrackVotingPeriod = ConstU64<2>;
type MinimumDeposit = ConstU64<1>;
type MaxDeposits = ConstU32<1000>;
type MaxBlacklisted = ConstU32<5>;
type ExternalOrigin = EnsureSignedBy<Two, u64>;
type ExternalMajorityOrigin = EnsureSignedBy<Three, u64>;
type ExternalDefaultOrigin = EnsureSignedBy<One, u64>;
@@ -176,16 +183,15 @@ impl Config for Test {
type CancelProposalOrigin = EnsureRoot<u64>;
type VetoOrigin = EnsureSignedBy<OneToFive, u64>;
type CooloffPeriod = ConstU64<2>;
type PreimageByteDeposit = PreimageByteDeposit;
type Slash = ();
type InstantOrigin = EnsureSignedBy<Six, u64>;
type InstantAllowed = InstantAllowed;
type Scheduler = Scheduler;
type MaxVotes = ConstU32<100>;
type OperationalPreimageOrigin = EnsureSignedBy<Six, u64>;
type PalletsOrigin = OriginCaller;
type WeightInfo = ();
type MaxProposals = ConstU32<100>;
type Preimages = Preimage;
}
pub fn new_test_ext() -> sp_io::TestExternalities {
@@ -203,12 +209,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
ext
}
/// Execute the function two times, with `true` and with `false`.
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));
}
#[test]
fn params_should_work() {
new_test_ext().execute_with(|| {
@@ -218,44 +218,22 @@ fn params_should_work() {
});
}
fn set_balance_proposal(value: u64) -> Vec<u8> {
RuntimeCall::Balances(pallet_balances::Call::set_balance {
who: 42,
new_free: value,
new_reserved: 0,
})
.encode()
fn set_balance_proposal(value: u64) -> BoundedCallOf<Test> {
let inner = pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 };
let outer = RuntimeCall::Balances(inner);
Preimage::bound(outer).unwrap()
}
#[test]
fn set_balance_proposal_is_correctly_filtered_out() {
for i in 0..10 {
let call = RuntimeCall::decode(&mut &set_balance_proposal(i)[..]).unwrap();
let call = Preimage::realize(&set_balance_proposal(i)).unwrap().0;
assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
}
}
fn set_balance_proposal_hash(value: u64) -> H256 {
BlakeTwo256::hash(&set_balance_proposal(value)[..])
}
fn set_balance_proposal_hash_and_note(value: u64) -> H256 {
let p = set_balance_proposal(value);
let h = BlakeTwo256::hash(&p[..]);
match Democracy::note_preimage(RuntimeOrigin::signed(6), p) {
Ok(_) => (),
Err(x) if x == Error::<Test>::DuplicatePreimage.into() => (),
Err(x) => panic!("{:?}", x),
}
h
}
fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult {
Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash(value), delay)
}
fn propose_set_balance_and_note(who: u64, value: u64, delay: u64) -> DispatchResult {
Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash_and_note(value), delay)
Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal(value), delay)
}
fn next_block() {
@@ -272,7 +250,7 @@ fn fast_forward_to(n: u64) {
fn begin_referendum() -> ReferendumIndex {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
assert_ok!(propose_set_balance(1, 2, 1));
fast_forward_to(2);
0
}
@@ -24,7 +24,7 @@ fn cancel_referendum_should_work() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -42,37 +42,13 @@ fn cancel_referendum_should_work() {
});
}
#[test]
fn cancel_queued_should_work() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
// start of 2 => next referendum scheduled.
fast_forward_to(2);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1)));
fast_forward_to(4);
assert!(pallet_scheduler::Agenda::<Test>::get(6)[0].is_some());
assert_noop!(
Democracy::cancel_queued(RuntimeOrigin::root(), 1),
Error::<Test>::ProposalMissing
);
assert_ok!(Democracy::cancel_queued(RuntimeOrigin::root(), 0));
assert!(pallet_scheduler::Agenda::<Test>::get(6)[0].is_none());
});
}
#[test]
fn emergency_cancel_should_work() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
2,
);
@@ -86,7 +62,7 @@ fn emergency_cancel_should_work() {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
2,
);
@@ -18,7 +18,10 @@
//! The for various partial storage decoders
use super::*;
use frame_support::storage::{migration, unhashed};
use frame_support::{
storage::{migration, unhashed},
BoundedVec,
};
#[test]
fn test_decode_compact_u32_at() {
@@ -42,7 +45,8 @@ fn test_decode_compact_u32_at() {
fn len_of_deposit_of() {
new_test_ext().execute_with(|| {
for l in vec![0, 1, 200, 1000] {
let value: (Vec<u64>, u64) = ((0..l).map(|_| Default::default()).collect(), 3u64);
let value: (BoundedVec<u64, _>, u64) =
((0..l).map(|_| Default::default()).collect::<Vec<_>>().try_into().unwrap(), 3u64);
DepositOf::<Test>::insert(2, value);
assert_eq!(Democracy::len_of_deposit_of(2), Some(l));
}
@@ -51,35 +55,3 @@ fn len_of_deposit_of() {
assert_eq!(Democracy::len_of_deposit_of(2), None);
})
}
#[test]
fn pre_image() {
new_test_ext().execute_with(|| {
let key = Default::default();
let missing = PreimageStatus::Missing(0);
Preimages::<Test>::insert(key, missing);
assert_noop!(Democracy::pre_image_data_len(key), Error::<Test>::PreimageMissing);
assert_eq!(Democracy::check_pre_image_is_missing(key), Ok(()));
Preimages::<Test>::remove(key);
assert_noop!(Democracy::pre_image_data_len(key), Error::<Test>::PreimageMissing);
assert_noop!(Democracy::check_pre_image_is_missing(key), Error::<Test>::NotImminent);
for l in vec![0, 10, 100, 1000u32] {
let available = PreimageStatus::Available {
data: (0..l).map(|i| i as u8).collect(),
provider: 0,
deposit: 0,
since: 0,
expiry: None,
};
Preimages::<Test>::insert(key, available);
assert_eq!(Democracy::pre_image_data_len(key), Ok(l));
assert_noop!(
Democracy::check_pre_image_is_missing(key),
Error::<Test>::DuplicatePreimage
);
}
})
}
@@ -24,7 +24,7 @@ fn single_proposal_should_work_with_delegation() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
assert_ok!(propose_set_balance(1, 2, 1));
fast_forward_to(2);
@@ -75,7 +75,7 @@ fn cyclic_delegation_should_unwind() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
assert_ok!(propose_set_balance(1, 2, 1));
fast_forward_to(2);
@@ -100,7 +100,7 @@ fn single_proposal_should_work_with_vote_and_delegation() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
assert_ok!(propose_set_balance(1, 2, 1));
fast_forward_to(2);
@@ -122,7 +122,7 @@ fn single_proposal_should_work_with_undelegation() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
assert_ok!(propose_set_balance(1, 2, 1));
// Delegate and undelegate vote.
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
@@ -23,35 +23,29 @@ use super::*;
fn veto_external_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(2),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
assert!(<NextExternal<Test>>::exists());
let h = set_balance_proposal_hash_and_note(2);
let h = set_balance_proposal(2).hash();
assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h));
// cancelled.
assert!(!<NextExternal<Test>>::exists());
// fails - same proposal can't be resubmitted.
assert_noop!(
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),),
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),),
Error::<Test>::ProposalBlacklisted
);
fast_forward_to(1);
// fails as we're still in cooloff period.
assert_noop!(
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),),
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),),
Error::<Test>::ProposalBlacklisted
);
fast_forward_to(2);
// works; as we're out of the cooloff period.
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(2),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
assert!(<NextExternal<Test>>::exists());
// 3 can't veto the same thing twice.
@@ -68,14 +62,11 @@ fn veto_external_works() {
fast_forward_to(3);
// same proposal fails as we're still in cooloff
assert_noop!(
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),),
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)),
Error::<Test>::ProposalBlacklisted
);
// different proposal works fine.
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(3),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),));
});
}
@@ -84,22 +75,16 @@ fn external_blacklisting_should_work() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(2),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
let hash = set_balance_proposal_hash(2);
let hash = set_balance_proposal(2).hash();
assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None));
fast_forward_to(2);
assert_noop!(Democracy::referendum_status(0), Error::<Test>::ReferendumInvalid);
assert_noop!(
Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(2),
),
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)),
Error::<Test>::ProposalBlacklisted,
);
});
@@ -110,15 +95,12 @@ fn external_referendum_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_noop!(
Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal_hash(2),),
Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal(2),),
BadOrigin,
);
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(2),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
assert_noop!(
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(1),),
Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),),
Error::<Test>::DuplicateProposal
);
fast_forward_to(2);
@@ -126,7 +108,7 @@ fn external_referendum_works() {
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 4,
proposal_hash: set_balance_proposal_hash(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -140,22 +122,19 @@ fn external_majority_referendum_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_noop!(
Democracy::external_propose_majority(
RuntimeOrigin::signed(1),
set_balance_proposal_hash(2)
),
Democracy::external_propose_majority(RuntimeOrigin::signed(1), set_balance_proposal(2)),
BadOrigin,
);
assert_ok!(Democracy::external_propose_majority(
RuntimeOrigin::signed(3),
set_balance_proposal_hash_and_note(2)
set_balance_proposal(2)
));
fast_forward_to(2);
assert_eq!(
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 4,
proposal_hash: set_balance_proposal_hash(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SimpleMajority,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -169,22 +148,19 @@ fn external_default_referendum_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_noop!(
Democracy::external_propose_default(
RuntimeOrigin::signed(3),
set_balance_proposal_hash(2)
),
Democracy::external_propose_default(RuntimeOrigin::signed(3), set_balance_proposal(2)),
BadOrigin,
);
assert_ok!(Democracy::external_propose_default(
RuntimeOrigin::signed(1),
set_balance_proposal_hash_and_note(2)
set_balance_proposal(2)
));
fast_forward_to(2);
assert_eq!(
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 4,
proposal_hash: set_balance_proposal_hash(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SuperMajorityAgainst,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -197,11 +173,8 @@ fn external_default_referendum_works() {
fn external_and_public_interleaving_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(1),
));
assert_ok!(propose_set_balance_and_note(6, 2, 2));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),));
assert_ok!(propose_set_balance(6, 2, 2));
fast_forward_to(2);
@@ -210,17 +183,14 @@ fn external_and_public_interleaving_works() {
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 4,
proposal_hash: set_balance_proposal_hash_and_note(1),
proposal: set_balance_proposal(1),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
})
);
// replenish external
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(3),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),));
fast_forward_to(4);
@@ -229,7 +199,7 @@ fn external_and_public_interleaving_works() {
Democracy::referendum_status(1),
Ok(ReferendumStatus {
end: 6,
proposal_hash: set_balance_proposal_hash_and_note(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -244,17 +214,14 @@ fn external_and_public_interleaving_works() {
Democracy::referendum_status(2),
Ok(ReferendumStatus {
end: 8,
proposal_hash: set_balance_proposal_hash_and_note(3),
proposal: set_balance_proposal(3),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
})
);
// replenish external
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(5),
));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(5),));
fast_forward_to(8);
@@ -263,18 +230,15 @@ fn external_and_public_interleaving_works() {
Democracy::referendum_status(3),
Ok(ReferendumStatus {
end: 10,
proposal_hash: set_balance_proposal_hash_and_note(5),
proposal: set_balance_proposal(5),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
})
);
// replenish both
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(7),
));
assert_ok!(propose_set_balance_and_note(6, 4, 2));
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(7),));
assert_ok!(propose_set_balance(6, 4, 2));
fast_forward_to(10);
@@ -283,16 +247,16 @@ fn external_and_public_interleaving_works() {
Democracy::referendum_status(4),
Ok(ReferendumStatus {
end: 12,
proposal_hash: set_balance_proposal_hash_and_note(4),
proposal: set_balance_proposal(4),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
})
);
// replenish public again
assert_ok!(propose_set_balance_and_note(6, 6, 2));
assert_ok!(propose_set_balance(6, 6, 2));
// cancel external
let h = set_balance_proposal_hash_and_note(7);
let h = set_balance_proposal(7).hash();
assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h));
fast_forward_to(12);
@@ -302,7 +266,7 @@ fn external_and_public_interleaving_works() {
Democracy::referendum_status(5),
Ok(ReferendumStatus {
end: 14,
proposal_hash: set_balance_proposal_hash_and_note(6),
proposal: set_balance_proposal(6),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -23,14 +23,14 @@ use super::*;
fn fast_track_referendum_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
let h = set_balance_proposal_hash_and_note(2);
let h = set_balance_proposal(2).hash();
assert_noop!(
Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2),
Error::<Test>::ProposalMissing
);
assert_ok!(Democracy::external_propose_majority(
RuntimeOrigin::signed(3),
set_balance_proposal_hash_and_note(2)
set_balance_proposal(2)
));
assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin);
assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0));
@@ -38,7 +38,7 @@ fn fast_track_referendum_works() {
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 2,
proposal_hash: set_balance_proposal_hash_and_note(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SimpleMajority,
delay: 0,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -51,14 +51,14 @@ fn fast_track_referendum_works() {
fn instant_referendum_works() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
let h = set_balance_proposal_hash_and_note(2);
let h = set_balance_proposal(2).hash();
assert_noop!(
Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2),
Error::<Test>::ProposalMissing
);
assert_ok!(Democracy::external_propose_majority(
RuntimeOrigin::signed(3),
set_balance_proposal_hash_and_note(2)
set_balance_proposal(2)
));
assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin);
assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 1, 0), BadOrigin);
@@ -76,7 +76,7 @@ fn instant_referendum_works() {
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 1,
proposal_hash: set_balance_proposal_hash_and_note(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SimpleMajority,
delay: 0,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -93,7 +93,7 @@ fn instant_next_block_referendum_backed() {
let majority_origin_id = 3;
let instant_origin_id = 6;
let voting_period = 1;
let proposal_hash = set_balance_proposal_hash_and_note(2);
let proposal = set_balance_proposal(2);
let delay = 2; // has no effect on test
// init
@@ -103,13 +103,13 @@ fn instant_next_block_referendum_backed() {
// propose with majority origin
assert_ok!(Democracy::external_propose_majority(
RuntimeOrigin::signed(majority_origin_id),
proposal_hash
proposal.clone()
));
// fast track with instant origin and voting period pointing to the next block
assert_ok!(Democracy::fast_track(
RuntimeOrigin::signed(instant_origin_id),
proposal_hash,
proposal.hash(),
voting_period,
delay
));
@@ -119,7 +119,7 @@ fn instant_next_block_referendum_backed() {
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: start_block_number + voting_period,
proposal_hash,
proposal,
threshold: VoteThreshold::SimpleMajority,
delay,
tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -143,11 +143,8 @@ fn instant_next_block_referendum_backed() {
fn fast_track_referendum_fails_when_no_simple_majority() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
let h = set_balance_proposal_hash_and_note(2);
assert_ok!(Democracy::external_propose(
RuntimeOrigin::signed(2),
set_balance_proposal_hash_and_note(2)
));
let h = set_balance_proposal(2).hash();
assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)));
assert_noop!(
Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2),
Error::<Test>::NotSimpleMajority
@@ -43,7 +43,7 @@ fn lock_voting_should_work() {
System::set_block_number(0);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -59,7 +59,7 @@ fn lock_voting_should_work() {
assert_eq!(Balances::locks(i), vec![the_lock(i * 10)]);
}
fast_forward_to(2);
fast_forward_to(3);
// Referendum passed; 1 and 5 didn't get their way and can now reap and unlock.
assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r));
@@ -126,13 +126,13 @@ fn no_locks_without_conviction_should_work() {
System::set_block_number(0);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(0, 10)));
fast_forward_to(2);
fast_forward_to(3);
assert_eq!(Balances::free_balance(42), 2);
assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 1, r));
@@ -146,7 +146,7 @@ fn lock_voting_should_work_with_delegation() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -167,28 +167,16 @@ fn lock_voting_should_work_with_delegation() {
fn setup_three_referenda() -> (u32, u32, u32) {
System::set_block_number(0);
let r1 = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
VoteThreshold::SimpleMajority,
0,
);
let r1 =
Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r1, aye(4, 10)));
let r2 = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
VoteThreshold::SimpleMajority,
0,
);
let r2 =
Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r2, aye(3, 20)));
let r3 = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
VoteThreshold::SimpleMajority,
0,
);
let r3 =
Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r3, aye(2, 50)));
fast_forward_to(2);
@@ -306,7 +294,7 @@ fn locks_should_persist_from_voting_to_delegation() {
System::set_block_number(0);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SimpleMajority,
0,
);
@@ -1,237 +0,0 @@
// 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 preimage tests.
use super::*;
#[test]
fn missing_preimage_should_fail() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash(2),
VoteThreshold::SuperMajorityApprove,
0,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
next_block();
next_block();
assert_eq!(Balances::free_balance(42), 0);
});
}
#[test]
fn preimage_deposit_should_be_required_and_returned() {
new_test_ext_execute_with_cond(|operational| {
// fee of 100 is too much.
PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 100);
assert_noop!(
if operational {
Democracy::note_preimage_operational(RuntimeOrigin::signed(6), vec![0; 500])
} else {
Democracy::note_preimage(RuntimeOrigin::signed(6), vec![0; 500])
},
BalancesError::<Test, _>::InsufficientBalance,
);
// fee of 1 is reasonable.
PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
VoteThreshold::SuperMajorityApprove,
0,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_eq!(Balances::reserved_balance(6), 12);
next_block();
next_block();
assert_eq!(Balances::reserved_balance(6), 0);
assert_eq!(Balances::free_balance(6), 60);
assert_eq!(Balances::free_balance(42), 2);
});
}
#[test]
fn preimage_deposit_should_be_reapable_earlier_by_owner() {
new_test_ext_execute_with_cond(|operational| {
PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
assert_ok!(if operational {
Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2))
} else {
Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2))
});
assert_eq!(Balances::reserved_balance(6), 12);
next_block();
assert_noop!(
Democracy::reap_preimage(
RuntimeOrigin::signed(6),
set_balance_proposal_hash(2),
u32::MAX
),
Error::<Test>::TooEarly
);
next_block();
assert_ok!(Democracy::reap_preimage(
RuntimeOrigin::signed(6),
set_balance_proposal_hash(2),
u32::MAX
));
assert_eq!(Balances::free_balance(6), 60);
assert_eq!(Balances::reserved_balance(6), 0);
});
}
#[test]
fn preimage_deposit_should_be_reapable() {
new_test_ext_execute_with_cond(|operational| {
assert_noop!(
Democracy::reap_preimage(
RuntimeOrigin::signed(5),
set_balance_proposal_hash(2),
u32::MAX
),
Error::<Test>::PreimageMissing
);
PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
assert_ok!(if operational {
Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2))
} else {
Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2))
});
assert_eq!(Balances::reserved_balance(6), 12);
next_block();
next_block();
next_block();
assert_noop!(
Democracy::reap_preimage(
RuntimeOrigin::signed(5),
set_balance_proposal_hash(2),
u32::MAX
),
Error::<Test>::TooEarly
);
next_block();
assert_ok!(Democracy::reap_preimage(
RuntimeOrigin::signed(5),
set_balance_proposal_hash(2),
u32::MAX
));
assert_eq!(Balances::reserved_balance(6), 0);
assert_eq!(Balances::free_balance(6), 48);
assert_eq!(Balances::free_balance(5), 62);
});
}
#[test]
fn noting_imminent_preimage_for_free_should_work() {
new_test_ext_execute_with_cond(|operational| {
PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash(2),
VoteThreshold::SuperMajorityApprove,
1,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_noop!(
if operational {
Democracy::note_imminent_preimage_operational(
RuntimeOrigin::signed(6),
set_balance_proposal(2),
)
} else {
Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2))
},
Error::<Test>::NotImminent
);
next_block();
// Now we're in the dispatch queue it's all good.
assert_ok!(Democracy::note_imminent_preimage(
RuntimeOrigin::signed(6),
set_balance_proposal(2)
));
next_block();
assert_eq!(Balances::free_balance(42), 2);
});
}
#[test]
fn reaping_imminent_preimage_should_fail() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash_and_note(2);
let r = Democracy::inject_referendum(3, h, VoteThreshold::SuperMajorityApprove, 1);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
next_block();
next_block();
assert_noop!(
Democracy::reap_preimage(RuntimeOrigin::signed(6), h, u32::MAX),
Error::<Test>::Imminent
);
});
}
#[test]
fn note_imminent_preimage_can_only_be_successful_once() {
new_test_ext().execute_with(|| {
PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash(2),
VoteThreshold::SuperMajorityApprove,
1,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
next_block();
// First time works
assert_ok!(Democracy::note_imminent_preimage(
RuntimeOrigin::signed(6),
set_balance_proposal(2)
));
// Second time fails
assert_noop!(
Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)),
Error::<Test>::DuplicatePreimage
);
// Fails from any user
assert_noop!(
Democracy::note_imminent_preimage(RuntimeOrigin::signed(5), set_balance_proposal(2)),
Error::<Test>::DuplicatePreimage
);
});
}
@@ -22,9 +22,9 @@ use super::*;
#[test]
fn backing_for_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance_and_note(1, 2, 2));
assert_ok!(propose_set_balance_and_note(1, 4, 4));
assert_ok!(propose_set_balance_and_note(1, 3, 3));
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_ok!(propose_set_balance(1, 3, 3));
assert_eq!(Democracy::backing_for(0), Some(2));
assert_eq!(Democracy::backing_for(1), Some(4));
assert_eq!(Democracy::backing_for(2), Some(3));
@@ -34,11 +34,11 @@ fn backing_for_should_work() {
#[test]
fn deposit_for_proposals_should_be_taken() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance_and_note(1, 2, 5));
assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
assert_ok!(propose_set_balance(1, 2, 5));
assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
assert_eq!(Balances::free_balance(1), 5);
assert_eq!(Balances::free_balance(2), 15);
assert_eq!(Balances::free_balance(5), 35);
@@ -48,11 +48,11 @@ fn deposit_for_proposals_should_be_taken() {
#[test]
fn deposit_for_proposals_should_be_returned() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance_and_note(1, 2, 5));
assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
assert_ok!(propose_set_balance(1, 2, 5));
assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
fast_forward_to(3);
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 20);
@@ -77,30 +77,19 @@ fn poor_proposer_should_not_work() {
#[test]
fn poor_seconder_should_not_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance_and_note(2, 2, 11));
assert_ok!(propose_set_balance(2, 2, 11));
assert_noop!(
Democracy::second(RuntimeOrigin::signed(1), 0, u32::MAX),
Democracy::second(RuntimeOrigin::signed(1), 0),
BalancesError::<Test, _>::InsufficientBalance
);
});
}
#[test]
fn invalid_seconds_upper_bound_should_not_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance_and_note(1, 2, 5));
assert_noop!(
Democracy::second(RuntimeOrigin::signed(2), 0, 0),
Error::<Test>::WrongUpperBound
);
});
}
#[test]
fn cancel_proposal_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance_and_note(1, 2, 2));
assert_ok!(propose_set_balance_and_note(1, 4, 4));
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin);
assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0));
System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into());
@@ -113,10 +102,10 @@ fn cancel_proposal_should_work() {
fn blacklisting_should_work() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
let hash = set_balance_proposal_hash(2);
let hash = set_balance_proposal(2).hash();
assert_ok!(propose_set_balance_and_note(1, 2, 2));
assert_ok!(propose_set_balance_and_note(1, 4, 4));
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin);
assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None));
@@ -124,11 +113,11 @@ fn blacklisting_should_work() {
assert_eq!(Democracy::backing_for(0), None);
assert_eq!(Democracy::backing_for(1), Some(4));
assert_noop!(propose_set_balance_and_note(1, 2, 2), Error::<Test>::ProposalBlacklisted);
assert_noop!(propose_set_balance(1, 2, 2), Error::<Test>::ProposalBlacklisted);
fast_forward_to(2);
let hash = set_balance_proposal_hash(4);
let hash = set_balance_proposal(4).hash();
assert_ok!(Democracy::referendum_status(0));
assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, Some(0)));
assert_noop!(Democracy::referendum_status(0), Error::<Test>::ReferendumInvalid);
@@ -139,9 +128,9 @@ fn blacklisting_should_work() {
fn runners_up_should_come_after() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 2));
assert_ok!(propose_set_balance_and_note(1, 4, 4));
assert_ok!(propose_set_balance_and_note(1, 3, 3));
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_ok!(propose_set_balance(1, 3, 3));
fast_forward_to(2);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1)));
fast_forward_to(4);
@@ -24,7 +24,7 @@ fn simple_passing_should_work() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -43,7 +43,7 @@ fn simple_failing_should_work() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -62,13 +62,13 @@ fn ooo_inject_referendums_should_work() {
new_test_ext().execute_with(|| {
let r1 = Democracy::inject_referendum(
3,
set_balance_proposal_hash_and_note(3),
set_balance_proposal(3),
VoteThreshold::SuperMajorityApprove,
0,
);
let r2 = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -77,11 +77,13 @@ fn ooo_inject_referendums_should_work() {
assert_eq!(tally(r2), Tally { ayes: 1, nays: 0, turnout: 10 });
next_block();
assert_eq!(Balances::free_balance(42), 2);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1)));
assert_eq!(tally(r1), Tally { ayes: 1, nays: 0, turnout: 10 });
next_block();
assert_eq!(Balances::free_balance(42), 2);
next_block();
assert_eq!(Balances::free_balance(42), 3);
});
@@ -92,7 +94,7 @@ fn delayed_enactment_should_work() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
1,
);
@@ -118,19 +120,19 @@ fn lowest_unbaked_should_be_sensible() {
new_test_ext().execute_with(|| {
let r1 = Democracy::inject_referendum(
3,
set_balance_proposal_hash_and_note(1),
set_balance_proposal(1),
VoteThreshold::SuperMajorityApprove,
0,
);
let r2 = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
let r3 = Democracy::inject_referendum(
10,
set_balance_proposal_hash_and_note(3),
set_balance_proposal(3),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -141,16 +143,19 @@ fn lowest_unbaked_should_be_sensible() {
assert_eq!(Democracy::lowest_unbaked(), 0);
next_block();
// r2 is approved
assert_eq!(Balances::free_balance(42), 2);
// r2 ends with approval
assert_eq!(Democracy::lowest_unbaked(), 0);
next_block();
// r1 is approved
assert_eq!(Balances::free_balance(42), 1);
// r1 ends with approval
assert_eq!(Democracy::lowest_unbaked(), 3);
assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count());
// r2 is executed
assert_eq!(Balances::free_balance(42), 2);
next_block();
// r1 is executed
assert_eq!(Balances::free_balance(42), 1);
});
}
@@ -63,7 +63,7 @@ fn split_vote_cancellation_should_work() {
fn single_proposal_should_work() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance_and_note(1, 2, 1));
assert_ok!(propose_set_balance(1, 2, 1));
let r = 0;
assert!(Democracy::referendum_info(r).is_none());
@@ -76,7 +76,7 @@ fn single_proposal_should_work() {
Democracy::referendum_status(0),
Ok(ReferendumStatus {
end: 4,
proposal_hash: set_balance_proposal_hash_and_note(2),
proposal: set_balance_proposal(2),
threshold: VoteThreshold::SuperMajorityApprove,
delay: 2,
tally: Tally { ayes: 1, nays: 0, turnout: 10 },
@@ -106,7 +106,7 @@ fn controversial_voting_should_work() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -132,7 +132,7 @@ fn controversial_low_turnout_voting_should_work() {
new_test_ext().execute_with(|| {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
@@ -156,7 +156,7 @@ fn passing_low_turnout_voting_should_work() {
let r = Democracy::inject_referendum(
2,
set_balance_proposal_hash_and_note(2),
set_balance_proposal(2),
VoteThreshold::SuperMajorityApprove,
0,
);
+15 -13
View File
@@ -18,7 +18,7 @@
//! Miscellaneous additional datatypes.
use crate::{AccountVote, Conviction, Vote, VoteThreshold};
use codec::{Decode, Encode};
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Saturating, Zero},
@@ -26,7 +26,7 @@ use sp_runtime::{
};
/// Info regarding an ongoing referendum.
#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
#[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct Tally<Balance> {
/// The number of aye votes, expressed in terms of post-conviction lock-vote.
pub ayes: Balance,
@@ -37,7 +37,9 @@ pub struct Tally<Balance> {
}
/// Amount of votes and capital placed in delegation for an account.
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
#[derive(
Encode, MaxEncodedLen, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo,
)]
pub struct Delegations<Balance> {
/// The number of votes (this is post-conviction).
pub votes: Balance,
@@ -160,12 +162,12 @@ impl<
}
/// Info regarding an ongoing referendum.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct ReferendumStatus<BlockNumber, Hash, Balance> {
#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct ReferendumStatus<BlockNumber, Proposal, Balance> {
/// When voting on this referendum will end.
pub end: BlockNumber,
/// The hash of the proposal being voted on.
pub proposal_hash: Hash,
/// The proposal being voted on.
pub proposal: Proposal,
/// The thresholding mechanism to determine whether it passed.
pub threshold: VoteThreshold,
/// The delay (in blocks) to wait after a successful referendum before deploying.
@@ -175,23 +177,23 @@ pub struct ReferendumStatus<BlockNumber, Hash, Balance> {
}
/// Info regarding a referendum, present or past.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub enum ReferendumInfo<BlockNumber, Hash, Balance> {
#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub enum ReferendumInfo<BlockNumber, Proposal, Balance> {
/// Referendum is happening, the arg is the block number at which it will end.
Ongoing(ReferendumStatus<BlockNumber, Hash, Balance>),
Ongoing(ReferendumStatus<BlockNumber, Proposal, Balance>),
/// Referendum finished at `end`, and has been `approved` or rejected.
Finished { approved: bool, end: BlockNumber },
}
impl<BlockNumber, Hash, Balance: Default> ReferendumInfo<BlockNumber, Hash, Balance> {
impl<BlockNumber, Proposal, Balance: Default> ReferendumInfo<BlockNumber, Proposal, Balance> {
/// Create a new instance.
pub fn new(
end: BlockNumber,
proposal_hash: Hash,
proposal: Proposal,
threshold: VoteThreshold,
delay: BlockNumber,
) -> Self {
let s = ReferendumStatus { end, proposal_hash, threshold, delay, tally: Tally::default() };
let s = ReferendumStatus { end, proposal, threshold, delay, tally: Tally::default() };
ReferendumInfo::Ongoing(s)
}
}
+36 -12
View File
@@ -18,11 +18,12 @@
//! The vote datatype.
use crate::{Conviction, Delegations, ReferendumIndex};
use codec::{Decode, Encode, EncodeLike, Input, Output};
use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen, Output};
use frame_support::traits::Get;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{Saturating, Zero},
RuntimeDebug,
BoundedVec, RuntimeDebug,
};
use sp_std::prelude::*;
@@ -39,6 +40,12 @@ impl Encode for Vote {
}
}
impl MaxEncodedLen for Vote {
fn max_encoded_len() -> usize {
1
}
}
impl EncodeLike for Vote {}
impl Decode for Vote {
@@ -66,7 +73,7 @@ impl TypeInfo for Vote {
}
/// A vote for a referendum of a particular account.
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
#[derive(Encode, MaxEncodedLen, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub enum AccountVote<Balance> {
/// A standard vote, one-way (approve or reject) with a given amount of conviction.
Standard { vote: Vote, balance: Balance },
@@ -107,7 +114,18 @@ impl<Balance: Saturating> AccountVote<Balance> {
/// A "prior" lock, i.e. a lock for some now-forgotten reason.
#[derive(
Encode, Decode, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo,
Encode,
MaxEncodedLen,
Decode,
Default,
Copy,
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
RuntimeDebug,
TypeInfo,
)]
pub struct PriorLock<BlockNumber, Balance>(BlockNumber, Balance);
@@ -131,13 +149,15 @@ impl<BlockNumber: Ord + Copy + Zero, Balance: Ord + Copy + Zero> PriorLock<Block
}
/// An indicator for what an account is doing; it can either be delegating or voting.
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub enum Voting<Balance, AccountId, BlockNumber> {
#[derive(Clone, Encode, Decode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
#[codec(mel_bound(skip_type_params(MaxVotes)))]
#[scale_info(skip_type_params(MaxVotes))]
pub enum Voting<Balance, AccountId, BlockNumber, MaxVotes: Get<u32>> {
/// The account is voting directly. `delegations` is the total amount of post-conviction voting
/// weight that it controls from those that have delegated to it.
Direct {
/// The current votes of the account.
votes: Vec<(ReferendumIndex, AccountVote<Balance>)>,
votes: BoundedVec<(ReferendumIndex, AccountVote<Balance>), MaxVotes>,
/// The total amount of delegations that this account has received.
delegations: Delegations<Balance>,
/// Any pre-existing locks from past voting/delegating activity.
@@ -155,20 +175,24 @@ pub enum Voting<Balance, AccountId, BlockNumber> {
},
}
impl<Balance: Default, AccountId, BlockNumber: Zero> Default
for Voting<Balance, AccountId, BlockNumber>
impl<Balance: Default, AccountId, BlockNumber: Zero, MaxVotes: Get<u32>> Default
for Voting<Balance, AccountId, BlockNumber, MaxVotes>
{
fn default() -> Self {
Voting::Direct {
votes: Vec::new(),
votes: Default::default(),
delegations: Default::default(),
prior: PriorLock(Zero::zero(), Default::default()),
}
}
}
impl<Balance: Saturating + Ord + Zero + Copy, BlockNumber: Ord + Copy + Zero, AccountId>
Voting<Balance, AccountId, BlockNumber>
impl<
Balance: Saturating + Ord + Zero + Copy,
BlockNumber: Ord + Copy + Zero,
AccountId,
MaxVotes: Get<u32>,
> Voting<Balance, AccountId, BlockNumber, MaxVotes>
{
pub fn rejig(&mut self, now: BlockNumber) {
match self {
@@ -18,7 +18,7 @@
//! Voting thresholds.
use crate::Tally;
use codec::{Decode, Encode};
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
@@ -26,7 +26,9 @@ use sp_runtime::traits::{IntegerSquareRoot, Zero};
use sp_std::ops::{Add, Div, Mul, Rem};
/// A means of determining if a vote is past pass threshold.
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, TypeInfo)]
#[derive(
Clone, Copy, PartialEq, Eq, Encode, MaxEncodedLen, Decode, sp_runtime::RuntimeDebug, TypeInfo,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum VoteThreshold {
/// A supermajority of approvals is needed to pass this vote.
+132 -214
View File
@@ -18,22 +18,24 @@
//! Autogenerated weights for pallet_democracy
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/substrate
// /home/benchbot/cargo_target_dir/production/substrate
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet_democracy
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --template=./.maintain/frame-weight-template.hbs
// --heap-pages=4096
// --pallet=pallet_democracy
// --chain=dev
// --output=./frame/democracy/src/weights.rs
// --template=./.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
@@ -45,27 +47,23 @@ use sp_std::marker::PhantomData;
/// Weight functions needed for pallet_democracy.
pub trait WeightInfo {
fn propose() -> Weight;
fn second(s: u32, ) -> Weight;
fn vote_new(r: u32, ) -> Weight;
fn vote_existing(r: u32, ) -> Weight;
fn second() -> Weight;
fn vote_new() -> Weight;
fn vote_existing() -> Weight;
fn emergency_cancel() -> Weight;
fn blacklist(p: u32, ) -> Weight;
fn external_propose(v: u32, ) -> Weight;
fn blacklist() -> Weight;
fn external_propose() -> Weight;
fn external_propose_majority() -> Weight;
fn external_propose_default() -> Weight;
fn fast_track() -> Weight;
fn veto_external(v: u32, ) -> Weight;
fn cancel_proposal(p: u32, ) -> Weight;
fn veto_external() -> Weight;
fn cancel_proposal() -> Weight;
fn cancel_referendum() -> Weight;
fn cancel_queued(r: u32, ) -> Weight;
fn on_initialize_base(r: u32, ) -> Weight;
fn on_initialize_base_with_launch_period(r: u32, ) -> Weight;
fn delegate(r: u32, ) -> Weight;
fn undelegate(r: u32, ) -> Weight;
fn clear_public_proposals() -> Weight;
fn note_preimage(b: u32, ) -> Weight;
fn note_imminent_preimage(b: u32, ) -> Weight;
fn reap_preimage(b: u32, ) -> Weight;
fn unlock_remove(r: u32, ) -> Weight;
fn unlock_set(r: u32, ) -> Weight;
fn remove_vote(r: u32, ) -> Weight;
@@ -80,125 +78,103 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Storage: Democracy Blacklist (r:1 w:0)
// Storage: Democracy DepositOf (r:0 w:1)
fn propose() -> Weight {
Weight::from_ref_time(48_328_000 as u64)
Weight::from_ref_time(57_410_000 as u64)
.saturating_add(T::DbWeight::get().reads(3 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy DepositOf (r:1 w:1)
fn second(s: u32, ) -> Weight {
Weight::from_ref_time(30_923_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64))
fn second() -> Weight {
Weight::from_ref_time(49_224_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
fn vote_new(r: u32, ) -> Weight {
Weight::from_ref_time(40_345_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64))
fn vote_new() -> Weight {
Weight::from_ref_time(60_933_000 as u64)
.saturating_add(T::DbWeight::get().reads(3 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
fn vote_existing(r: u32, ) -> Weight {
Weight::from_ref_time(39_853_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64))
fn vote_existing() -> Weight {
Weight::from_ref_time(60_393_000 as u64)
.saturating_add(T::DbWeight::get().reads(3 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy Cancellations (r:1 w:1)
fn emergency_cancel() -> Weight {
Weight::from_ref_time(19_364_000 as u64)
Weight::from_ref_time(24_588_000 as u64)
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Democracy PublicProps (r:1 w:1)
// Storage: Democracy DepositOf (r:1 w:1)
// Storage: System Account (r:1 w:1)
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy Blacklist (r:0 w:1)
// Storage: Democracy DepositOf (r:1 w:1)
// Storage: System Account (r:1 w:1)
fn blacklist(p: u32, ) -> Weight {
Weight::from_ref_time(57_708_000 as u64)
// Standard Error: 4_000
.saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64))
fn blacklist() -> Weight {
Weight::from_ref_time(91_226_000 as u64)
.saturating_add(T::DbWeight::get().reads(5 as u64))
.saturating_add(T::DbWeight::get().writes(6 as u64))
}
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy Blacklist (r:1 w:0)
fn external_propose(v: u32, ) -> Weight {
Weight::from_ref_time(10_714_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64))
fn external_propose() -> Weight {
Weight::from_ref_time(18_898_000 as u64)
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy NextExternal (r:0 w:1)
fn external_propose_majority() -> Weight {
Weight::from_ref_time(3_697_000 as u64)
Weight::from_ref_time(5_136_000 as u64)
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy NextExternal (r:0 w:1)
fn external_propose_default() -> Weight {
Weight::from_ref_time(3_831_000 as u64)
Weight::from_ref_time(5_243_000 as u64)
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy ReferendumCount (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:0 w:1)
fn fast_track() -> Weight {
Weight::from_ref_time(20_271_000 as u64)
Weight::from_ref_time(24_275_000 as u64)
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy Blacklist (r:1 w:1)
fn veto_external(v: u32, ) -> Weight {
Weight::from_ref_time(21_319_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64))
fn veto_external() -> Weight {
Weight::from_ref_time(30_988_000 as u64)
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Democracy PublicProps (r:1 w:1)
// Storage: Democracy DepositOf (r:1 w:1)
// Storage: System Account (r:1 w:1)
fn cancel_proposal(p: u32, ) -> Weight {
Weight::from_ref_time(43_960_000 as u64)
// Standard Error: 2_000
.saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64))
fn cancel_proposal() -> Weight {
Weight::from_ref_time(78_515_000 as u64)
.saturating_add(T::DbWeight::get().reads(3 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:0 w:1)
fn cancel_referendum() -> Weight {
Weight::from_ref_time(13_475_000 as u64)
Weight::from_ref_time(16_155_000 as u64)
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn cancel_queued(r: u32, ) -> Weight {
Weight::from_ref_time(24_320_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Democracy LowestUnbaked (r:1 w:1)
// Storage: Democracy ReferendumCount (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:2 w:0)
/// The range of component `r` is `[0, 99]`.
fn on_initialize_base(r: u32, ) -> Weight {
Weight::from_ref_time(3_428_000 as u64)
// Standard Error: 2_000
.saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(7_007_000 as u64)
// Standard Error: 2_686
.saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
@@ -208,33 +184,36 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Storage: Democracy LastTabledWasExternal (r:1 w:0)
// Storage: Democracy NextExternal (r:1 w:0)
// Storage: Democracy PublicProps (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:2 w:0)
/// The range of component `r` is `[0, 99]`.
fn on_initialize_base_with_launch_period(r: u32, ) -> Weight {
Weight::from_ref_time(7_867_000 as u64)
// Standard Error: 2_000
.saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(9_528_000 as u64)
// Standard Error: 2_521
.saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(5 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy VotingOf (r:3 w:3)
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:2 w:2)
/// The range of component `r` is `[0, 99]`.
fn delegate(r: u32, ) -> Weight {
Weight::from_ref_time(37_902_000 as u64)
// Standard Error: 4_000
.saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(46_787_000 as u64)
// Standard Error: 2_943
.saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(4 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(T::DbWeight::get().writes(4 as u64))
.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64)))
}
// Storage: Democracy VotingOf (r:2 w:2)
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:2 w:2)
/// The range of component `r` is `[0, 99]`.
fn undelegate(r: u32, ) -> Weight {
Weight::from_ref_time(21_272_000 as u64)
// Standard Error: 3_000
.saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(29_789_000 as u64)
// Standard Error: 2_324
.saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(T::DbWeight::get().writes(2 as u64))
@@ -242,69 +221,48 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
}
// Storage: Democracy PublicProps (r:0 w:1)
fn clear_public_proposals() -> Weight {
Weight::from_ref_time(4_913_000 as u64)
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy Preimages (r:1 w:1)
fn note_preimage(b: u32, ) -> Weight {
Weight::from_ref_time(27_986_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy Preimages (r:1 w:1)
fn note_imminent_preimage(b: u32, ) -> Weight {
Weight::from_ref_time(20_058_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy Preimages (r:1 w:1)
// Storage: System Account (r:1 w:0)
fn reap_preimage(b: u32, ) -> Weight {
Weight::from_ref_time(28_619_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
Weight::from_ref_time(6_519_000 as u64)
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
// Storage: System Account (r:1 w:1)
/// The range of component `r` is `[0, 99]`.
fn unlock_remove(r: u32, ) -> Weight {
Weight::from_ref_time(26_619_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(28_884_000 as u64)
// Standard Error: 2_631
.saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(3 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
// Storage: System Account (r:1 w:1)
/// The range of component `r` is `[0, 99]`.
fn unlock_set(r: u32, ) -> Weight {
Weight::from_ref_time(25_373_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(33_498_000 as u64)
// Standard Error: 622
.saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(3 as u64))
.saturating_add(T::DbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
/// The range of component `r` is `[1, 100]`.
fn remove_vote(r: u32, ) -> Weight {
Weight::from_ref_time(15_961_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(18_201_000 as u64)
// Standard Error: 1_007
.saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
/// The range of component `r` is `[1, 100]`.
fn remove_other_vote(r: u32, ) -> Weight {
Weight::from_ref_time(15_992_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(18_455_000 as u64)
// Standard Error: 951
.saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
@@ -317,125 +275,103 @@ impl WeightInfo for () {
// Storage: Democracy Blacklist (r:1 w:0)
// Storage: Democracy DepositOf (r:0 w:1)
fn propose() -> Weight {
Weight::from_ref_time(48_328_000 as u64)
Weight::from_ref_time(57_410_000 as u64)
.saturating_add(RocksDbWeight::get().reads(3 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy DepositOf (r:1 w:1)
fn second(s: u32, ) -> Weight {
Weight::from_ref_time(30_923_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64))
fn second() -> Weight {
Weight::from_ref_time(49_224_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
fn vote_new(r: u32, ) -> Weight {
Weight::from_ref_time(40_345_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64))
fn vote_new() -> Weight {
Weight::from_ref_time(60_933_000 as u64)
.saturating_add(RocksDbWeight::get().reads(3 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
fn vote_existing(r: u32, ) -> Weight {
Weight::from_ref_time(39_853_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64))
fn vote_existing() -> Weight {
Weight::from_ref_time(60_393_000 as u64)
.saturating_add(RocksDbWeight::get().reads(3 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy Cancellations (r:1 w:1)
fn emergency_cancel() -> Weight {
Weight::from_ref_time(19_364_000 as u64)
Weight::from_ref_time(24_588_000 as u64)
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Democracy PublicProps (r:1 w:1)
// Storage: Democracy DepositOf (r:1 w:1)
// Storage: System Account (r:1 w:1)
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy Blacklist (r:0 w:1)
// Storage: Democracy DepositOf (r:1 w:1)
// Storage: System Account (r:1 w:1)
fn blacklist(p: u32, ) -> Weight {
Weight::from_ref_time(57_708_000 as u64)
// Standard Error: 4_000
.saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64))
fn blacklist() -> Weight {
Weight::from_ref_time(91_226_000 as u64)
.saturating_add(RocksDbWeight::get().reads(5 as u64))
.saturating_add(RocksDbWeight::get().writes(6 as u64))
}
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy Blacklist (r:1 w:0)
fn external_propose(v: u32, ) -> Weight {
Weight::from_ref_time(10_714_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64))
fn external_propose() -> Weight {
Weight::from_ref_time(18_898_000 as u64)
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy NextExternal (r:0 w:1)
fn external_propose_majority() -> Weight {
Weight::from_ref_time(3_697_000 as u64)
Weight::from_ref_time(5_136_000 as u64)
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy NextExternal (r:0 w:1)
fn external_propose_default() -> Weight {
Weight::from_ref_time(3_831_000 as u64)
Weight::from_ref_time(5_243_000 as u64)
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy ReferendumCount (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:0 w:1)
fn fast_track() -> Weight {
Weight::from_ref_time(20_271_000 as u64)
Weight::from_ref_time(24_275_000 as u64)
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy NextExternal (r:1 w:1)
// Storage: Democracy Blacklist (r:1 w:1)
fn veto_external(v: u32, ) -> Weight {
Weight::from_ref_time(21_319_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64))
fn veto_external() -> Weight {
Weight::from_ref_time(30_988_000 as u64)
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Democracy PublicProps (r:1 w:1)
// Storage: Democracy DepositOf (r:1 w:1)
// Storage: System Account (r:1 w:1)
fn cancel_proposal(p: u32, ) -> Weight {
Weight::from_ref_time(43_960_000 as u64)
// Standard Error: 2_000
.saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64))
fn cancel_proposal() -> Weight {
Weight::from_ref_time(78_515_000 as u64)
.saturating_add(RocksDbWeight::get().reads(3 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:0 w:1)
fn cancel_referendum() -> Weight {
Weight::from_ref_time(13_475_000 as u64)
Weight::from_ref_time(16_155_000 as u64)
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
fn cancel_queued(r: u32, ) -> Weight {
Weight::from_ref_time(24_320_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Democracy LowestUnbaked (r:1 w:1)
// Storage: Democracy ReferendumCount (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:2 w:0)
/// The range of component `r` is `[0, 99]`.
fn on_initialize_base(r: u32, ) -> Weight {
Weight::from_ref_time(3_428_000 as u64)
// Standard Error: 2_000
.saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(7_007_000 as u64)
// Standard Error: 2_686
.saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
@@ -445,33 +381,36 @@ impl WeightInfo for () {
// Storage: Democracy LastTabledWasExternal (r:1 w:0)
// Storage: Democracy NextExternal (r:1 w:0)
// Storage: Democracy PublicProps (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:1 w:0)
// Storage: Democracy ReferendumInfoOf (r:2 w:0)
/// The range of component `r` is `[0, 99]`.
fn on_initialize_base_with_launch_period(r: u32, ) -> Weight {
Weight::from_ref_time(7_867_000 as u64)
// Standard Error: 2_000
.saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(9_528_000 as u64)
// Standard Error: 2_521
.saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(5 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy VotingOf (r:3 w:3)
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:2 w:2)
/// The range of component `r` is `[0, 99]`.
fn delegate(r: u32, ) -> Weight {
Weight::from_ref_time(37_902_000 as u64)
// Standard Error: 4_000
.saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(46_787_000 as u64)
// Standard Error: 2_943
.saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(4 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(RocksDbWeight::get().writes(4 as u64))
.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64)))
}
// Storage: Democracy VotingOf (r:2 w:2)
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy ReferendumInfoOf (r:2 w:2)
/// The range of component `r` is `[0, 99]`.
fn undelegate(r: u32, ) -> Weight {
Weight::from_ref_time(21_272_000 as u64)
// Standard Error: 3_000
.saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(29_789_000 as u64)
// Standard Error: 2_324
.saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
@@ -479,69 +418,48 @@ impl WeightInfo for () {
}
// Storage: Democracy PublicProps (r:0 w:1)
fn clear_public_proposals() -> Weight {
Weight::from_ref_time(4_913_000 as u64)
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy Preimages (r:1 w:1)
fn note_preimage(b: u32, ) -> Weight {
Weight::from_ref_time(27_986_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy Preimages (r:1 w:1)
fn note_imminent_preimage(b: u32, ) -> Weight {
Weight::from_ref_time(20_058_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy Preimages (r:1 w:1)
// Storage: System Account (r:1 w:0)
fn reap_preimage(b: u32, ) -> Weight {
Weight::from_ref_time(28_619_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
Weight::from_ref_time(6_519_000 as u64)
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
// Storage: System Account (r:1 w:1)
/// The range of component `r` is `[0, 99]`.
fn unlock_remove(r: u32, ) -> Weight {
Weight::from_ref_time(26_619_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(28_884_000 as u64)
// Standard Error: 2_631
.saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(3 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy VotingOf (r:1 w:1)
// Storage: Balances Locks (r:1 w:1)
// Storage: System Account (r:1 w:1)
/// The range of component `r` is `[0, 99]`.
fn unlock_set(r: u32, ) -> Weight {
Weight::from_ref_time(25_373_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(33_498_000 as u64)
// Standard Error: 622
.saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(3 as u64))
.saturating_add(RocksDbWeight::get().writes(3 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
/// The range of component `r` is `[1, 100]`.
fn remove_vote(r: u32, ) -> Weight {
Weight::from_ref_time(15_961_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(18_201_000 as u64)
// Standard Error: 1_007
.saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Democracy ReferendumInfoOf (r:1 w:1)
// Storage: Democracy VotingOf (r:1 w:1)
/// The range of component `r` is `[1, 100]`.
fn remove_other_vote(r: u32, ) -> Weight {
Weight::from_ref_time(15_992_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64))
Weight::from_ref_time(18_455_000 as u64)
// Standard Error: 951
.saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
+1 -1
View File
@@ -268,7 +268,7 @@ fn registration_should_work() {
let mut three_fields = ten();
three_fields.additional.try_push(Default::default()).unwrap();
three_fields.additional.try_push(Default::default()).unwrap();
assert_eq!(three_fields.additional.try_push(Default::default()), Err(()));
assert!(three_fields.additional.try_push(Default::default()).is_err());
assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
assert_eq!(Identity::identity(10).unwrap().info, ten());
assert_eq!(Balances::free_balance(10), 90);
+3
View File
@@ -22,6 +22,9 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/
sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
# third party
log = { version = "0.4.17", default-features = false }
[dev-dependencies]
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
sp-core = { version = "6.0.0", path = "../../primitives/core" }
+17 -107
View File
@@ -31,7 +31,7 @@ const SEED: u32 = 0;
fn setup_multi<T: Config>(
s: u32,
z: u32,
) -> Result<(Vec<T::AccountId>, OpaqueCall<T>), &'static str> {
) -> Result<(Vec<T::AccountId>, Box<<T as Config>::RuntimeCall>), &'static str> {
let mut signatories: Vec<T::AccountId> = Vec::new();
for i in 0..s {
let signatory = account("signatory", i, SEED);
@@ -44,8 +44,7 @@ fn setup_multi<T: Config>(
// Must first convert to runtime call type.
let call: <T as Config>::RuntimeCall =
frame_system::Call::<T>::remark { remark: vec![0; z as usize] }.into();
let call_data = OpaqueCall::<T>::from_encoded(call.encode());
Ok((signatories, call_data))
Ok((signatories, Box::new(call)))
}
benchmarks! {
@@ -74,35 +73,15 @@ benchmarks! {
// Transaction Length
let z in 0 .. 10_000;
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let call_hash = blake2_256(call.encoded());
let call_hash = call.using_encoded(blake2_256);
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, false, Weight::zero())
}: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero())
verify {
assert!(Multisigs::<T>::contains_key(multi_account_id, call_hash));
assert!(!Calls::<T>::contains_key(call_hash));
}
as_multi_create_store {
// Signatories, need at least 2 total people
let s in 2 .. T::MaxSignatories::get() as u32;
// Transaction Length
let z in 0 .. 10_000;
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let call_hash = blake2_256(call.encoded());
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, true, Weight::zero())
verify {
assert!(Multisigs::<T>::contains_key(multi_account_id, call_hash));
assert!(Calls::<T>::contains_key(call_hash));
}
as_multi_approve {
@@ -111,78 +90,51 @@ benchmarks! {
// Transaction Length
let z in 0 .. 10_000;
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let call_hash = blake2_256(call.encoded());
let call_hash = call.using_encoded(blake2_256);
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let mut signatories2 = signatories.clone();
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
// before the call, get the timepoint
let timepoint = Multisig::<T>::timepoint();
// Create the multi, storing for worst case
Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?;
assert!(Calls::<T>::contains_key(call_hash));
// Create the multi
Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?;
let caller2 = signatories2.remove(0);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::zero())
}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::zero())
verify {
let multisig = Multisigs::<T>::get(multi_account_id, call_hash).ok_or("multisig not created")?;
assert_eq!(multisig.approvals.len(), 2);
}
as_multi_approve_store {
// Signatories, need at least 3 people (so we don't complete the multisig)
let s in 3 .. T::MaxSignatories::get() as u32;
// Transaction Length
let z in 0 .. 10_000;
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let call_hash = blake2_256(call.encoded());
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let mut signatories2 = signatories.clone();
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
// before the call, get the timepoint
let timepoint = Multisig::<T>::timepoint();
// Create the multi, not storing
Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), false, Weight::zero())?;
assert!(!Calls::<T>::contains_key(call_hash));
let caller2 = signatories2.remove(0);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, true, Weight::zero())
verify {
let multisig = Multisigs::<T>::get(multi_account_id, call_hash).ok_or("multisig not created")?;
assert_eq!(multisig.approvals.len(), 2);
assert!(Calls::<T>::contains_key(call_hash));
}
as_multi_complete {
// Signatories, need at least 2 people
let s in 2 .. T::MaxSignatories::get() as u32;
// Transaction Length
let z in 0 .. 10_000;
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let call_hash = blake2_256(call.encoded());
let call_hash = call.using_encoded(blake2_256);
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let mut signatories2 = signatories.clone();
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
// before the call, get the timepoint
let timepoint = Multisig::<T>::timepoint();
// Create the multi, storing it for worst case
Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?;
// Create the multi
Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?;
// Everyone except the first person approves
for i in 1 .. s - 1 {
let mut signatories_loop = signatories2.clone();
let caller_loop = signatories_loop.remove(i as usize);
let o = RawOrigin::Signed(caller_loop).into();
Multisig::<T>::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?;
Multisig::<T>::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), Weight::zero())?;
}
let caller2 = signatories2.remove(0);
assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::MAX)
}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::MAX)
verify {
assert!(!Multisigs::<T>::contains_key(&multi_account_id, call_hash));
}
@@ -195,7 +147,7 @@ benchmarks! {
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
let call_hash = blake2_256(call.encoded());
let call_hash = call.using_encoded(blake2_256);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
@@ -214,7 +166,7 @@ benchmarks! {
let mut signatories2 = signatories.clone();
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
let call_hash = blake2_256(call.encoded());
let call_hash = call.using_encoded(blake2_256);
// before the call, get the timepoint
let timepoint = Multisig::<T>::timepoint();
// Create the multi
@@ -224,7 +176,6 @@ benchmarks! {
signatories,
None,
call,
false,
Weight::zero()
)?;
let caller2 = signatories2.remove(0);
@@ -237,45 +188,6 @@ benchmarks! {
assert_eq!(multisig.approvals.len(), 2);
}
approve_as_multi_complete {
// Signatories, need at least 2 people
let s in 2 .. T::MaxSignatories::get() as u32;
// Transaction Length, not a component
let z = 10_000;
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let mut signatories2 = signatories.clone();
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
let call_hash = blake2_256(call.encoded());
// before the call, get the timepoint
let timepoint = Multisig::<T>::timepoint();
// Create the multi
Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?;
// Everyone except the first person approves
for i in 1 .. s - 1 {
let mut signatories_loop = signatories2.clone();
let caller_loop = signatories_loop.remove(i as usize);
let o = RawOrigin::Signed(caller_loop).into();
Multisig::<T>::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?;
}
let caller2 = signatories2.remove(0);
assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: approve_as_multi(
RawOrigin::Signed(caller2),
s as u16,
signatories2,
Some(timepoint),
call_hash,
Weight::MAX
)
verify {
assert!(!Multisigs::<T>::contains_key(multi_account_id, call_hash));
}
cancel_as_multi {
// Signatories, need at least 2 people
let s in 2 .. T::MaxSignatories::get() as u32;
@@ -284,20 +196,18 @@ benchmarks! {
let (mut signatories, call) = setup_multi::<T>(s, z)?;
let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
let call_hash = blake2_256(call.encoded());
let call_hash = call.using_encoded(blake2_256);
let timepoint = Multisig::<T>::timepoint();
// Create the multi
let o = RawOrigin::Signed(caller.clone()).into();
Multisig::<T>::as_multi(o, s as u16, signatories.clone(), None, call, true, Weight::zero())?;
Multisig::<T>::as_multi(o, s as u16, signatories.clone(), None, call, Weight::zero())?;
assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
assert!(Calls::<T>::contains_key(call_hash));
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash)
verify {
assert!(!Multisigs::<T>::contains_key(multi_account_id, call_hash));
assert!(!Calls::<T>::contains_key(call_hash));
}
impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test);
+40 -108
View File
@@ -47,6 +47,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
mod benchmarking;
pub mod migrations;
mod tests;
pub mod weights;
@@ -57,7 +58,7 @@ use frame_support::{
PostDispatchInfo,
},
ensure,
traits::{Currency, Get, ReservableCurrency, WrapperKeepOpaque},
traits::{Currency, Get, ReservableCurrency},
weights::Weight,
RuntimeDebug,
};
@@ -73,6 +74,20 @@ pub use weights::WeightInfo;
pub use pallet::*;
/// The log target of this pallet.
pub const LOG_TARGET: &'static str = "runtime::multisig";
// syntactic sugar for logging.
#[macro_export]
macro_rules! log {
($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
log::$level!(
target: crate::LOG_TARGET,
concat!("[{:?}] ✍️ ", $patter), <frame_system::Pallet<T>>::block_number() $(, $values)*
)
};
}
type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
@@ -100,12 +115,10 @@ pub struct Multisig<BlockNumber, Balance, AccountId> {
approvals: Vec<AccountId>,
}
type OpaqueCall<T> = WrapperKeepOpaque<<T as Config>::RuntimeCall>;
type CallHash = [u8; 32];
enum CallOrHash<T: Config> {
Call(OpaqueCall<T>, bool),
Call(<T as Config>::RuntimeCall),
Hash([u8; 32]),
}
@@ -152,9 +165,13 @@ pub mod pallet {
type WeightInfo: WeightInfo;
}
/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
#[pallet::without_storage_info]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);
/// The set of open multisig operations.
@@ -168,10 +185,6 @@ pub mod pallet {
Multisig<T::BlockNumber, BalanceOf<T>, T::AccountId>,
>;
#[pallet::storage]
pub type Calls<T: Config> =
StorageMap<_, Identity, [u8; 32], (OpaqueCall<T>, T::AccountId, BalanceOf<T>)>;
#[pallet::error]
pub enum Error<T> {
/// Threshold must be 2 or greater.
@@ -343,13 +356,13 @@ pub mod pallet {
/// taken for its lifetime of `DepositBase + threshold * DepositFactor`.
/// -------------------------------
/// - DB Weight:
/// - Reads: Multisig Storage, [Caller Account], Calls (if `store_call`)
/// - Writes: Multisig Storage, [Caller Account], Calls (if `store_call`)
/// - Reads: Multisig Storage, [Caller Account]
/// - Writes: Multisig Storage, [Caller Account]
/// - Plus Call Weight
/// # </weight>
#[pallet::weight({
let s = other_signatories.len() as u32;
let z = call.encoded_len() as u32;
let z = call.using_encoded(|d| d.len()) as u32;
T::WeightInfo::as_multi_create(s, z)
.max(T::WeightInfo::as_multi_create_store(s, z))
@@ -362,8 +375,7 @@ pub mod pallet {
threshold: u16,
other_signatories: Vec<T::AccountId>,
maybe_timepoint: Option<Timepoint<T::BlockNumber>>,
call: OpaqueCall<T>,
store_call: bool,
call: Box<<T as Config>::RuntimeCall>,
max_weight: Weight,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
@@ -372,7 +384,7 @@ pub mod pallet {
threshold,
other_signatories,
maybe_timepoint,
CallOrHash::Call(call, store_call),
CallOrHash::Call(*call),
max_weight,
)
}
@@ -462,8 +474,8 @@ pub mod pallet {
/// - Storage: removes one item.
/// ----------------------------------
/// - DB Weight:
/// - Read: Multisig Storage, [Caller Account], Refund Account, Calls
/// - Write: Multisig Storage, [Caller Account], Refund Account, Calls
/// - Read: Multisig Storage, [Caller Account], Refund Account
/// - Write: Multisig Storage, [Caller Account], Refund Account
/// # </weight>
#[pallet::weight(T::WeightInfo::cancel_as_multi(other_signatories.len() as u32))]
pub fn cancel_as_multi(
@@ -489,7 +501,6 @@ pub mod pallet {
let err_amount = T::Currency::unreserve(&m.depositor, m.deposit);
debug_assert!(err_amount.is_zero());
<Multisigs<T>>::remove(&id, &call_hash);
Self::clear_call(&call_hash);
Self::deposit_event(Event::MultisigCancelled {
cancelling: who,
@@ -531,13 +542,12 @@ impl<T: Config> Pallet<T> {
let id = Self::multi_account_id(&signatories, threshold);
// Threshold > 1; this means it's a multi-step operation. We extract the `call_hash`.
let (call_hash, call_len, maybe_call, store) = match call_or_hash {
CallOrHash::Call(call, should_store) => {
let call_hash = blake2_256(call.encoded());
let call_len = call.encoded_len();
(call_hash, call_len, Some(call), should_store)
let (call_hash, call_len, maybe_call) = match call_or_hash {
CallOrHash::Call(call) => {
let (call_hash, call_len) = call.using_encoded(|d| (blake2_256(d), d.len()));
(call_hash, call_len, Some(call))
},
CallOrHash::Hash(h) => (h, 0, None, false),
CallOrHash::Hash(h) => (h, 0, None),
};
// Branch on whether the operation has already started or not.
@@ -556,13 +566,7 @@ impl<T: Config> Pallet<T> {
}
// We only bother fetching/decoding call if we know that we're ready to execute.
let maybe_approved_call = if approvals >= threshold {
Self::get_call(&call_hash, maybe_call.as_ref())
} else {
None
};
if let Some((call, call_len)) = maybe_approved_call {
if let Some(call) = maybe_call.filter(|_| approvals >= threshold) {
// verify weight
ensure!(
call.get_dispatch_info().weight.all_lte(max_weight),
@@ -572,7 +576,6 @@ impl<T: Config> Pallet<T> {
// Clean up storage before executing call to avoid an possibility of reentrancy
// attack.
<Multisigs<T>>::remove(&id, call_hash);
Self::clear_call(&call_hash);
T::Currency::unreserve(&m.depositor, m.deposit);
let result = call.dispatch(RawOrigin::Signed(id.clone()).into());
@@ -596,19 +599,6 @@ impl<T: Config> Pallet<T> {
// We cannot dispatch the call now; either it isn't available, or it is, but we
// don't have threshold approvals even with our signature.
// Store the call if desired.
let stored = if let Some(data) = maybe_call.filter(|_| store) {
Self::store_call_and_reserve(
who.clone(),
&call_hash,
data,
BalanceOf::<T>::zero(),
)?;
true
} else {
false
};
if let Some(pos) = maybe_pos {
// Record approval.
m.approvals.insert(pos, who.clone());
@@ -622,17 +612,11 @@ impl<T: Config> Pallet<T> {
} else {
// If we already approved and didn't store the Call, then this was useless and
// we report an error.
ensure!(stored, Error::<T>::AlreadyApproved);
Err(Error::<T>::AlreadyApproved)?
}
let final_weight = if stored {
T::WeightInfo::as_multi_approve_store(
other_signatories_len as u32,
call_len as u32,
)
} else {
T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32)
};
let final_weight =
T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32);
// Call is not made, so the actual weight does not include call
Ok(Some(final_weight).into())
}
@@ -643,14 +627,7 @@ impl<T: Config> Pallet<T> {
// Just start the operation by recording it in storage.
let deposit = T::DepositBase::get() + T::DepositFactor::get() * threshold.into();
// Store the call if desired.
let stored = if let Some(data) = maybe_call.filter(|_| store) {
Self::store_call_and_reserve(who.clone(), &call_hash, data, deposit)?;
true
} else {
T::Currency::reserve(&who, deposit)?;
false
};
T::Currency::reserve(&who, deposit)?;
<Multisigs<T>>::insert(
&id,
@@ -664,58 +641,13 @@ impl<T: Config> Pallet<T> {
);
Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash });
let final_weight = if stored {
T::WeightInfo::as_multi_create_store(other_signatories_len as u32, call_len as u32)
} else {
T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32)
};
let final_weight =
T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32);
// Call is not made, so the actual weight does not include call
Ok(Some(final_weight).into())
}
}
/// Place a call's encoded data in storage, reserving funds as appropriate.
///
/// We store `data` here because storing `call` would result in needing another `.encode`.
///
/// Returns a `bool` indicating whether the data did end up being stored.
fn store_call_and_reserve(
who: T::AccountId,
hash: &[u8; 32],
data: OpaqueCall<T>,
other_deposit: BalanceOf<T>,
) -> DispatchResult {
ensure!(!Calls::<T>::contains_key(hash), Error::<T>::AlreadyStored);
let deposit = other_deposit +
T::DepositBase::get() +
T::DepositFactor::get() *
BalanceOf::<T>::from(((data.encoded_len() + 31) / 32) as u32);
T::Currency::reserve(&who, deposit)?;
Calls::<T>::insert(&hash, (data, who, deposit));
Ok(())
}
/// Attempt to decode and return the call, provided by the user or from storage.
fn get_call(
hash: &[u8; 32],
maybe_known: Option<&OpaqueCall<T>>,
) -> Option<(<T as Config>::RuntimeCall, usize)> {
maybe_known.map_or_else(
|| {
Calls::<T>::get(hash)
.and_then(|(data, ..)| Some((data.try_decode()?, data.encoded_len())))
},
|data| Some((data.try_decode()?, data.encoded_len())),
)
}
/// Attempt to remove a call from storage, returning any deposit on it to the owner.
fn clear_call(hash: &[u8; 32]) {
if let Some((_, who, deposit)) = Calls::<T>::take(hash) {
T::Currency::unreserve(&who, deposit);
}
}
/// The current `Timepoint`.
pub fn timepoint() -> Timepoint<T::BlockNumber> {
Timepoint {
@@ -0,0 +1,86 @@
// This file is part of Substrate.
// Copyright (C) 2019-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.
// Migrations for Multisig Pallet
use super::*;
use frame_support::{
dispatch::GetStorageVersion,
traits::{OnRuntimeUpgrade, WrapperKeepOpaque},
Identity,
};
#[cfg(feature = "try-runtime")]
use frame_support::ensure;
pub mod v1 {
use super::*;
type OpaqueCall<T> = WrapperKeepOpaque<<T as Config>::RuntimeCall>;
#[frame_support::storage_alias]
type Calls<T: Config> = StorageMap<
Pallet<T>,
Identity,
[u8; 32],
(OpaqueCall<T>, <T as frame_system::Config>::AccountId, BalanceOf<T>),
>;
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
let onchain = Pallet::<T>::on_chain_storage_version();
ensure!(onchain < 1, "this migration can be deleted");
log!(info, "Number of calls to refund and delete: {}", Calls::<T>::iter().count());
Ok(Vec::new())
}
fn on_runtime_upgrade() -> Weight {
let current = Pallet::<T>::current_storage_version();
let onchain = Pallet::<T>::on_chain_storage_version();
if onchain > 0 {
log!(info, "MigrateToV1 should be removed");
return T::DbWeight::get().reads(1)
}
Calls::<T>::drain().for_each(|(_call_hash, (_data, caller, deposit))| {
T::Currency::unreserve(&caller, deposit);
});
current.put::<Pallet<T>>();
<T as frame_system::Config>::BlockWeights::get().max_block
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
let onchain = Pallet::<T>::on_chain_storage_version();
ensure!(onchain < 2, "this migration needs to be removed");
ensure!(onchain == 1, "this migration needs to be run");
ensure!(
Calls::<T>::iter().count() == 0,
"there are some dangling calls that need to be destroyed and refunded"
);
Ok(())
}
}
}
+36 -257
View File
@@ -34,7 +34,6 @@ use sp_runtime::{
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
type OpaqueCall = super::OpaqueCall<Test>;
frame_support::construct_runtime!(
pub enum Test where
@@ -130,8 +129,8 @@ fn now() -> Timepoint<u64> {
Multisig::timepoint()
}
fn call_transfer(dest: u64, value: u64) -> RuntimeCall {
RuntimeCall::Balances(BalancesCall::transfer { dest, value })
fn call_transfer(dest: u64, value: u64) -> Box<RuntimeCall> {
Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest, value }))
}
#[test]
@@ -144,14 +143,12 @@ fn multisig_deposit_is_taken_and_returned() {
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data.clone()),
false,
call.clone(),
Weight::zero()
));
assert_eq!(Balances::free_balance(1), 2);
@@ -162,8 +159,7 @@ fn multisig_deposit_is_taken_and_returned() {
2,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call,
call_weight
));
assert_eq!(Balances::free_balance(1), 5);
@@ -171,96 +167,6 @@ fn multisig_deposit_is_taken_and_returned() {
});
}
#[test]
fn multisig_deposit_is_taken_and_returned_with_call_storage() {
new_test_ext().execute_with(|| {
let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2);
assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data),
true,
Weight::zero()
));
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 5);
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(2),
2,
vec![1, 3],
Some(now()),
hash,
call_weight
));
assert_eq!(Balances::free_balance(1), 5);
assert_eq!(Balances::reserved_balance(1), 0);
});
}
#[test]
fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() {
new_test_ext().execute_with(|| {
let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3);
assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(1),
3,
vec![2, 3],
None,
hash,
Weight::zero()
));
assert_eq!(Balances::free_balance(1), 1);
assert_eq!(Balances::reserved_balance(1), 4);
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(2),
3,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(data),
true,
Weight::zero()
));
assert_eq!(Balances::free_balance(2), 3);
assert_eq!(Balances::reserved_balance(2), 2);
assert_eq!(Balances::free_balance(1), 1);
assert_eq!(Balances::reserved_balance(1), 4);
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(3),
3,
vec![1, 2],
Some(now()),
hash,
call_weight
));
assert_eq!(Balances::free_balance(1), 5);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(Balances::free_balance(2), 5);
assert_eq!(Balances::reserved_balance(2), 0);
});
}
#[test]
fn cancel_multisig_returns_deposit() {
new_test_ext().execute_with(|| {
@@ -298,8 +204,8 @@ fn timepoint_checking_works() {
assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
let call = call_transfer(6, 15).encode();
let hash = blake2_256(&call);
let call = call_transfer(6, 15);
let hash = blake2_256(&call.encode());
assert_noop!(
Multisig::approve_as_multi(
@@ -328,8 +234,7 @@ fn timepoint_checking_works() {
2,
vec![1, 3],
None,
OpaqueCall::from_encoded(call.clone()),
false,
call.clone(),
Weight::zero()
),
Error::<Test>::NoTimepoint,
@@ -341,8 +246,7 @@ fn timepoint_checking_works() {
2,
vec![1, 3],
Some(later),
OpaqueCall::from_encoded(call),
false,
call,
Weight::zero()
),
Error::<Test>::WrongTimepoint,
@@ -350,41 +254,6 @@ fn timepoint_checking_works() {
});
}
#[test]
fn multisig_2_of_3_works_with_call_storing() {
new_test_ext().execute_with(|| {
let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2);
assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data),
true,
Weight::zero()
));
assert_eq!(Balances::free_balance(6), 0);
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(2),
2,
vec![1, 3],
Some(now()),
hash,
call_weight
));
assert_eq!(Balances::free_balance(6), 15);
});
}
#[test]
fn multisig_2_of_3_works() {
new_test_ext().execute_with(|| {
@@ -395,8 +264,7 @@ fn multisig_2_of_3_works() {
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
let hash = blake2_256(&call.encode());
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(1),
2,
@@ -412,8 +280,7 @@ fn multisig_2_of_3_works() {
2,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call,
call_weight
));
assert_eq!(Balances::free_balance(6), 15);
@@ -430,8 +297,7 @@ fn multisig_3_of_3_works() {
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
let hash = blake2_256(&call.encode());
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(1),
3,
@@ -455,8 +321,7 @@ fn multisig_3_of_3_works() {
3,
vec![1, 2],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call,
call_weight
));
assert_eq!(Balances::free_balance(6), 15);
@@ -492,68 +357,6 @@ fn cancel_multisig_works() {
});
}
#[test]
fn cancel_multisig_with_call_storage_works() {
new_test_ext().execute_with(|| {
let call = call_transfer(6, 15).encode();
let hash = blake2_256(&call);
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
3,
vec![2, 3],
None,
OpaqueCall::from_encoded(call),
true,
Weight::zero()
));
assert_eq!(Balances::free_balance(1), 4);
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(2),
3,
vec![1, 3],
Some(now()),
hash,
Weight::zero()
));
assert_noop!(
Multisig::cancel_as_multi(RuntimeOrigin::signed(2), 3, vec![1, 3], now(), hash),
Error::<Test>::NotOwner,
);
assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash),);
assert_eq!(Balances::free_balance(1), 10);
});
}
#[test]
fn cancel_multisig_with_alt_call_storage_works() {
new_test_ext().execute_with(|| {
let call = call_transfer(6, 15).encode();
let hash = blake2_256(&call);
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(1),
3,
vec![2, 3],
None,
hash,
Weight::zero()
));
assert_eq!(Balances::free_balance(1), 6);
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(2),
3,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(call),
true,
Weight::zero()
));
assert_eq!(Balances::free_balance(2), 8);
assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash));
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 10);
});
}
#[test]
fn multisig_2_of_3_as_multi_works() {
new_test_ext().execute_with(|| {
@@ -564,14 +367,12 @@ fn multisig_2_of_3_as_multi_works() {
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data.clone()),
false,
call.clone(),
Weight::zero()
));
assert_eq!(Balances::free_balance(6), 0);
@@ -581,8 +382,7 @@ fn multisig_2_of_3_as_multi_works() {
2,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call,
call_weight
));
assert_eq!(Balances::free_balance(6), 15);
@@ -599,18 +399,15 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
let call1 = call_transfer(6, 10);
let call1_weight = call1.get_dispatch_info().weight;
let data1 = call1.encode();
let call2 = call_transfer(7, 5);
let call2_weight = call2.get_dispatch_info().weight;
let data2 = call2.encode();
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data1.clone()),
false,
call1.clone(),
Weight::zero()
));
assert_ok!(Multisig::as_multi(
@@ -618,8 +415,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
2,
vec![1, 3],
None,
OpaqueCall::from_encoded(data2.clone()),
false,
call2.clone(),
Weight::zero()
));
assert_ok!(Multisig::as_multi(
@@ -627,8 +423,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
2,
vec![1, 2],
Some(now()),
OpaqueCall::from_encoded(data1),
false,
call1,
call1_weight
));
assert_ok!(Multisig::as_multi(
@@ -636,8 +431,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
2,
vec![1, 2],
Some(now()),
OpaqueCall::from_encoded(data2),
false,
call2,
call2_weight
));
@@ -656,15 +450,13 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
let call = call_transfer(6, 10);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
let hash = blake2_256(&call.encode());
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data.clone()),
false,
call.clone(),
Weight::zero()
));
assert_ok!(Multisig::as_multi(
@@ -672,8 +464,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
2,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(data.clone()),
false,
call.clone(),
call_weight
));
assert_eq!(Balances::free_balance(multi), 5);
@@ -683,8 +474,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data.clone()),
false,
call.clone(),
Weight::zero()
));
assert_ok!(Multisig::as_multi(
@@ -692,8 +482,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
2,
vec![1, 2],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call.clone(),
call_weight
));
@@ -714,15 +503,14 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
#[test]
fn minimum_threshold_check_works() {
new_test_ext().execute_with(|| {
let call = call_transfer(6, 15).encode();
let call = call_transfer(6, 15);
assert_noop!(
Multisig::as_multi(
RuntimeOrigin::signed(1),
0,
vec![2],
None,
OpaqueCall::from_encoded(call.clone()),
false,
call.clone(),
Weight::zero()
),
Error::<Test>::MinimumThreshold,
@@ -733,8 +521,7 @@ fn minimum_threshold_check_works() {
1,
vec![2],
None,
OpaqueCall::from_encoded(call.clone()),
false,
call.clone(),
Weight::zero()
),
Error::<Test>::MinimumThreshold,
@@ -745,15 +532,14 @@ fn minimum_threshold_check_works() {
#[test]
fn too_many_signatories_fails() {
new_test_ext().execute_with(|| {
let call = call_transfer(6, 15).encode();
let call = call_transfer(6, 15);
assert_noop!(
Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3, 4],
None,
OpaqueCall::from_encoded(call),
false,
call.clone(),
Weight::zero()
),
Error::<Test>::TooManySignatories,
@@ -815,8 +601,8 @@ fn multisig_1_of_3_works() {
assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
let call = call_transfer(6, 15).encode();
let hash = blake2_256(&call);
let call = call_transfer(6, 15);
let hash = blake2_256(&call.encode());
assert_noop!(
Multisig::approve_as_multi(
RuntimeOrigin::signed(1),
@@ -834,17 +620,15 @@ fn multisig_1_of_3_works() {
1,
vec![2, 3],
None,
OpaqueCall::from_encoded(call),
false,
call.clone(),
Weight::zero()
),
Error::<Test>::MinimumThreshold,
);
let boxed_call = Box::new(call_transfer(6, 15));
assert_ok!(Multisig::as_multi_threshold_1(
RuntimeOrigin::signed(1),
vec![2, 3],
boxed_call
call_transfer(6, 15)
));
assert_eq!(Balances::free_balance(6), 15);
@@ -871,14 +655,12 @@ fn weight_check_works() {
assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
let call = call_transfer(6, 15);
let data = call.encode();
assert_ok!(Multisig::as_multi(
RuntimeOrigin::signed(1),
2,
vec![2, 3],
None,
OpaqueCall::from_encoded(data.clone()),
false,
call.clone(),
Weight::zero()
));
assert_eq!(Balances::free_balance(6), 0);
@@ -889,8 +671,7 @@ fn weight_check_works() {
2,
vec![1, 3],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call,
Weight::zero()
),
Error::<Test>::MaxWeightTooLow,
@@ -911,8 +692,7 @@ fn multisig_handles_no_preimage_after_all_approve() {
let call = call_transfer(6, 15);
let call_weight = call.get_dispatch_info().weight;
let data = call.encode();
let hash = blake2_256(&data);
let hash = blake2_256(&call.encode());
assert_ok!(Multisig::approve_as_multi(
RuntimeOrigin::signed(1),
3,
@@ -944,8 +724,7 @@ fn multisig_handles_no_preimage_after_all_approve() {
3,
vec![1, 2],
Some(now()),
OpaqueCall::from_encoded(data),
false,
call,
call_weight
));
assert_eq!(Balances::free_balance(6), 15);
+2 -2
View File
@@ -140,7 +140,7 @@ pub mod pallet {
let sender = ensure_signed(origin)?;
let bounded_name: BoundedVec<_, _> =
name.try_into().map_err(|()| Error::<T>::TooLong)?;
name.try_into().map_err(|_| Error::<T>::TooLong)?;
ensure!(bounded_name.len() >= T::MinLength::get() as usize, Error::<T>::TooShort);
let deposit = if let Some((_, deposit)) = <NameOf<T>>::get(&sender) {
@@ -229,7 +229,7 @@ pub mod pallet {
T::ForceOrigin::ensure_origin(origin)?;
let bounded_name: BoundedVec<_, _> =
name.try_into().map_err(|()| Error::<T>::TooLong)?;
name.try_into().map_err(|_| Error::<T>::TooLong)?;
let target = T::Lookup::lookup(target)?;
let deposit = <NameOf<T>>::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero);
<NameOf<T>>::insert(&target, (bounded_name, deposit));
+5 -1
View File
@@ -19,6 +19,7 @@ sp-core = { version = "6.0.0", default-features = false, optional = true, path =
sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
log = { version = "0.4.17", default-features = false }
[dev-dependencies]
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
@@ -36,10 +37,13 @@ std = [
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"log/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
]
try-runtime = ["frame-support/try-runtime"]
try-runtime = [
"frame-support/try-runtime",
]
+16 -10
View File
@@ -35,7 +35,7 @@ fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
}
fn preimage_and_hash<T: Config>() -> (Vec<u8>, T::Hash) {
sized_preimage_and_hash::<T>(T::MaxSize::get())
sized_preimage_and_hash::<T>(MAX_SIZE)
}
fn sized_preimage_and_hash<T: Config>(size: u32) -> (Vec<u8>, T::Hash) {
@@ -48,7 +48,7 @@ fn sized_preimage_and_hash<T: Config>(size: u32) -> (Vec<u8>, T::Hash) {
benchmarks! {
// Expensive note - will reserve.
note_preimage {
let s in 0 .. T::MaxSize::get();
let s in 0 .. MAX_SIZE;
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
let (preimage, hash) = sized_preimage_and_hash::<T>(s);
@@ -58,7 +58,7 @@ benchmarks! {
}
// Cheap note - will not reserve since it was requested.
note_requested_preimage {
let s in 0 .. T::MaxSize::get();
let s in 0 .. MAX_SIZE;
let caller = funded_account::<T>("caller", 0);
whitelist_account!(caller);
let (preimage, hash) = sized_preimage_and_hash::<T>(s);
@@ -69,7 +69,7 @@ benchmarks! {
}
// Cheap note - will not reserve since it's the manager.
note_no_deposit_preimage {
let s in 0 .. T::MaxSize::get();
let s in 0 .. MAX_SIZE;
let (preimage, hash) = sized_preimage_and_hash::<T>(s);
assert_ok!(Preimage::<T>::request_preimage(T::ManagerOrigin::successful_origin(), hash));
}: note_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), preimage)
@@ -101,10 +101,12 @@ benchmarks! {
let (preimage, hash) = preimage_and_hash::<T>();
let noter = funded_account::<T>("noter", 0);
whitelist_account!(noter);
assert_ok!(Preimage::<T>::note_preimage(RawOrigin::Signed(noter).into(), preimage));
assert_ok!(Preimage::<T>::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage));
}: _<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
verify {
assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into();
let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) };
assert_eq!(StatusFor::<T>::get(&hash), Some(s));
}
// Cheap request - would unreserve the deposit but none was held.
request_no_deposit_preimage {
@@ -112,14 +114,16 @@ benchmarks! {
assert_ok!(Preimage::<T>::note_preimage(T::ManagerOrigin::successful_origin(), preimage));
}: request_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
verify {
assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) };
assert_eq!(StatusFor::<T>::get(&hash), Some(s));
}
// Cheap request - the preimage is not yet noted, so deposit to unreserve.
request_unnoted_preimage {
let (_, hash) = preimage_and_hash::<T>();
}: request_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
verify {
assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
let s = RequestStatus::Requested { deposit: None, count: 1, len: None };
assert_eq!(StatusFor::<T>::get(&hash), Some(s));
}
// Cheap request - the preimage is already requested, so just a counter bump.
request_requested_preimage {
@@ -127,7 +131,8 @@ benchmarks! {
assert_ok!(Preimage::<T>::request_preimage(T::ManagerOrigin::successful_origin(), hash));
}: request_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
verify {
assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(2)));
let s = RequestStatus::Requested { deposit: None, count: 2, len: None };
assert_eq!(StatusFor::<T>::get(&hash), Some(s));
}
// Expensive unrequest - last reference and it's noted, so will destroy the preimage.
@@ -154,7 +159,8 @@ benchmarks! {
assert_ok!(Preimage::<T>::request_preimage(T::ManagerOrigin::successful_origin(), hash));
}: unrequest_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
verify {
assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
let s = RequestStatus::Requested { deposit: None, count: 1, len: None };
assert_eq!(StatusFor::<T>::get(&hash), Some(s));
}
impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test);
+173 -64
View File
@@ -30,6 +30,7 @@
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod migration;
#[cfg(test)]
mod mock;
#[cfg(test)]
@@ -37,15 +38,18 @@ mod tests;
pub mod weights;
use sp_runtime::traits::{BadOrigin, Hash, Saturating};
use sp_std::prelude::*;
use sp_std::{borrow::Cow, prelude::*};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{
dispatch::Pays,
ensure,
pallet_prelude::Get,
traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency},
BoundedVec,
traits::{
Currency, Defensive, FetchResult, Hash as PreimageHash, PreimageProvider,
PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage,
},
BoundedSlice, BoundedVec,
};
use scale_info::TypeInfo;
pub use weights::WeightInfo;
@@ -59,20 +63,27 @@ pub use pallet::*;
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)]
pub enum RequestStatus<AccountId, Balance> {
/// The associated preimage has not yet been requested by the system. The given deposit (if
/// some) is being held until either it becomes requested or the user retracts the primage.
Unrequested(Option<(AccountId, Balance)>),
/// some) is being held until either it becomes requested or the user retracts the preimage.
Unrequested { deposit: (AccountId, Balance), len: u32 },
/// There are a non-zero number of outstanding requests for this hash by this chain. If there
/// is a preimage registered, then it may be removed iff this counter becomes zero.
Requested(u32),
/// is a preimage registered, then `len` is `Some` and it may be removed iff this counter
/// becomes zero.
Requested { deposit: Option<(AccountId, Balance)>, count: u32, len: Option<u32> },
}
type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
/// Maximum size of preimage we can store is 4mb.
const MAX_SIZE: u32 = 4 * 1024 * 1024;
#[frame_support::pallet]
pub mod pallet {
use super::*;
/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching event type.
@@ -88,9 +99,6 @@ pub mod pallet {
/// manage existing preimages.
type ManagerOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// Max size allowed for a preimage.
type MaxSize: Get<u32>;
/// The base deposit for placing a preimage on chain.
type BaseDeposit: Get<BalanceOf<Self>>;
@@ -100,6 +108,7 @@ pub mod pallet {
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(PhantomData<T>);
#[pallet::event]
@@ -116,7 +125,7 @@ pub mod pallet {
#[pallet::error]
pub enum Error<T> {
/// Preimage is too large to store on-chain.
TooLarge,
TooBig,
/// Preimage has already been noted on-chain.
AlreadyNoted,
/// The user is not authorized to perform this action.
@@ -134,10 +143,9 @@ pub mod pallet {
pub(super) type StatusFor<T: Config> =
StorageMap<_, Identity, T::Hash, RequestStatus<T::AccountId, BalanceOf<T>>>;
/// The preimages stored by this pallet.
#[pallet::storage]
pub(super) type PreimageFor<T: Config> =
StorageMap<_, Identity, T::Hash, BoundedVec<u8, T::MaxSize>>;
StorageMap<_, Identity, (T::Hash, u32), BoundedVec<u8, ConstU32<MAX_SIZE>>>;
#[pallet::call]
impl<T: Config> Pallet<T> {
@@ -150,9 +158,7 @@ pub mod pallet {
// We accept a signed origin which will pay a deposit, or a root origin where a deposit
// is not taken.
let maybe_sender = Self::ensure_signed_or_manager(origin)?;
let bounded_vec =
BoundedVec::<u8, T::MaxSize>::try_from(bytes).map_err(|()| Error::<T>::TooLarge)?;
let system_requested = Self::note_bytes(bounded_vec, maybe_sender.as_ref())?;
let (system_requested, _) = Self::note_bytes(bytes.into(), maybe_sender.as_ref())?;
if system_requested || maybe_sender.is_none() {
Ok(Pays::No.into())
} else {
@@ -161,6 +167,11 @@ pub mod pallet {
}
/// Clear an unrequested preimage from the runtime storage.
///
/// If `len` is provided, then it will be a much cheaper operation.
///
/// - `hash`: The hash of the preimage to be removed from the store.
/// - `len`: The length of the preimage of `hash`.
#[pallet::weight(T::WeightInfo::unnote_preimage())]
pub fn unnote_preimage(origin: OriginFor<T>, hash: T::Hash) -> DispatchResult {
let maybe_sender = Self::ensure_signed_or_manager(origin)?;
@@ -203,41 +214,46 @@ impl<T: Config> Pallet<T> {
/// Store some preimage on chain.
///
/// If `maybe_depositor` is `None` then it is also requested. If `Some`, then it is not.
///
/// We verify that the preimage is within the bounds of what the pallet supports.
///
/// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees.
fn note_bytes(
preimage: BoundedVec<u8, T::MaxSize>,
preimage: Cow<[u8]>,
maybe_depositor: Option<&T::AccountId>,
) -> Result<bool, DispatchError> {
) -> Result<(bool, T::Hash), DispatchError> {
let hash = T::Hashing::hash(&preimage);
ensure!(!PreimageFor::<T>::contains_key(hash), Error::<T>::AlreadyNoted);
let len = preimage.len() as u32;
ensure!(len <= MAX_SIZE, Error::<T>::TooBig);
// We take a deposit only if there is a provided depositor, and the preimage was not
// We take a deposit only if there is a provided depositor and the preimage was not
// previously requested. This also allows the tx to pay no fee.
let was_requested = match (StatusFor::<T>::get(hash), maybe_depositor) {
(Some(RequestStatus::Requested(..)), _) => true,
(Some(RequestStatus::Unrequested(..)), _) =>
let status = match (StatusFor::<T>::get(hash), maybe_depositor) {
(Some(RequestStatus::Requested { count, deposit, .. }), _) =>
RequestStatus::Requested { count, deposit, len: Some(len) },
(Some(RequestStatus::Unrequested { .. }), Some(_)) =>
return Err(Error::<T>::AlreadyNoted.into()),
(None, None) => {
StatusFor::<T>::insert(hash, RequestStatus::Unrequested(None));
false
},
(Some(RequestStatus::Unrequested { len, deposit }), None) =>
RequestStatus::Requested { deposit: Some(deposit), count: 1, len: Some(len) },
(None, None) => RequestStatus::Requested { count: 1, len: Some(len), deposit: None },
(None, Some(depositor)) => {
let length = preimage.len() as u32;
let deposit = T::BaseDeposit::get()
.saturating_add(T::ByteDeposit::get().saturating_mul(length.into()));
T::Currency::reserve(depositor, deposit)?;
let status = RequestStatus::Unrequested(Some((depositor.clone(), deposit)));
StatusFor::<T>::insert(hash, status);
false
RequestStatus::Unrequested { deposit: (depositor.clone(), deposit), len }
},
};
let was_requested = matches!(status, RequestStatus::Requested { .. });
StatusFor::<T>::insert(hash, status);
let _ = Self::insert(&hash, preimage)
.defensive_proof("Unable to insert. Logic error in `note_bytes`?");
PreimageFor::<T>::insert(hash, preimage);
Self::deposit_event(Event::Noted { hash });
Ok(was_requested)
Ok((was_requested, hash))
}
// This function will add a hash to the list of requested preimages.
@@ -245,19 +261,15 @@ impl<T: Config> Pallet<T> {
// If the preimage already exists before the request is made, the deposit for the preimage is
// returned to the user, and removed from their management.
fn do_request_preimage(hash: &T::Hash) {
let count = StatusFor::<T>::get(hash).map_or(1, |x| match x {
RequestStatus::Requested(mut count) => {
count.saturating_inc();
count
},
RequestStatus::Unrequested(None) => 1,
RequestStatus::Unrequested(Some((owner, deposit))) => {
// Return the deposit - the preimage now has outstanding requests.
T::Currency::unreserve(&owner, deposit);
1
},
});
StatusFor::<T>::insert(hash, RequestStatus::Requested(count));
let (count, len, deposit) =
StatusFor::<T>::get(hash).map_or((1, None, None), |x| match x {
RequestStatus::Requested { mut count, len, deposit } => {
count.saturating_inc();
(count, len, deposit)
},
RequestStatus::Unrequested { deposit, len } => (1, Some(len), Some(deposit)),
});
StatusFor::<T>::insert(hash, RequestStatus::Requested { count, len, deposit });
if count == 1 {
Self::deposit_event(Event::Requested { hash: *hash });
}
@@ -265,6 +277,8 @@ impl<T: Config> Pallet<T> {
// Clear a preimage from the storage of the chain, returning any deposit that may be reserved.
//
// If `len` is provided, it will be a much cheaper operation.
//
// If `maybe_owner` is provided, we verify that it is the correct owner before clearing the
// data.
fn do_unnote_preimage(
@@ -272,51 +286,101 @@ impl<T: Config> Pallet<T> {
maybe_check_owner: Option<T::AccountId>,
) -> DispatchResult {
match StatusFor::<T>::get(hash).ok_or(Error::<T>::NotNoted)? {
RequestStatus::Unrequested(Some((owner, deposit))) => {
RequestStatus::Requested { deposit: Some((owner, deposit)), count, len } => {
ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::<T>::NotAuthorized);
T::Currency::unreserve(&owner, deposit);
StatusFor::<T>::insert(
hash,
RequestStatus::Requested { deposit: None, count, len },
);
Ok(())
},
RequestStatus::Unrequested(None) => {
RequestStatus::Requested { deposit: None, .. } => {
ensure!(maybe_check_owner.is_none(), Error::<T>::NotAuthorized);
Self::do_unrequest_preimage(hash)
},
RequestStatus::Unrequested { deposit: (owner, deposit), len } => {
ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::<T>::NotAuthorized);
T::Currency::unreserve(&owner, deposit);
StatusFor::<T>::remove(hash);
Self::remove(hash, len);
Self::deposit_event(Event::Cleared { hash: *hash });
Ok(())
},
RequestStatus::Requested(_) => return Err(Error::<T>::Requested.into()),
}
StatusFor::<T>::remove(hash);
PreimageFor::<T>::remove(hash);
Self::deposit_event(Event::Cleared { hash: *hash });
Ok(())
}
/// Clear a preimage request.
fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult {
match StatusFor::<T>::get(hash).ok_or(Error::<T>::NotRequested)? {
RequestStatus::Requested(mut count) if count > 1 => {
RequestStatus::Requested { mut count, len, deposit } if count > 1 => {
count.saturating_dec();
StatusFor::<T>::insert(hash, RequestStatus::Requested(count));
StatusFor::<T>::insert(hash, RequestStatus::Requested { count, len, deposit });
},
RequestStatus::Requested(count) => {
RequestStatus::Requested { count, len, deposit } => {
debug_assert!(count == 1, "preimage request counter at zero?");
PreimageFor::<T>::remove(hash);
StatusFor::<T>::remove(hash);
Self::deposit_event(Event::Cleared { hash: *hash });
match (len, deposit) {
// Preimage was never noted.
(None, _) => StatusFor::<T>::remove(hash),
// Preimage was noted without owner - just remove it.
(Some(len), None) => {
Self::remove(hash, len);
StatusFor::<T>::remove(hash);
Self::deposit_event(Event::Cleared { hash: *hash });
},
// Preimage was noted with owner - move to unrequested so they can get refund.
(Some(len), Some(deposit)) => {
StatusFor::<T>::insert(hash, RequestStatus::Unrequested { deposit, len });
},
}
},
RequestStatus::Unrequested(_) => return Err(Error::<T>::NotRequested.into()),
RequestStatus::Unrequested { .. } => return Err(Error::<T>::NotRequested.into()),
}
Ok(())
}
fn insert(hash: &T::Hash, preimage: Cow<[u8]>) -> Result<(), ()> {
BoundedSlice::<u8, ConstU32<MAX_SIZE>>::try_from(preimage.as_ref())
.map(|s| PreimageFor::<T>::insert((hash, s.len() as u32), s))
}
fn remove(hash: &T::Hash, len: u32) {
PreimageFor::<T>::remove((hash, len))
}
fn have(hash: &T::Hash) -> bool {
Self::len(hash).is_some()
}
fn len(hash: &T::Hash) -> Option<u32> {
use RequestStatus::*;
match StatusFor::<T>::get(hash) {
Some(Requested { len: Some(len), .. }) | Some(Unrequested { len, .. }) => Some(len),
_ => None,
}
}
fn fetch(hash: &T::Hash, len: Option<u32>) -> FetchResult {
let len = len.or_else(|| Self::len(hash)).ok_or(DispatchError::Unavailable)?;
PreimageFor::<T>::get((hash, len))
.map(|p| p.into_inner())
.map(Into::into)
.ok_or(DispatchError::Unavailable)
}
}
impl<T: Config> PreimageProvider<T::Hash> for Pallet<T> {
fn have_preimage(hash: &T::Hash) -> bool {
PreimageFor::<T>::contains_key(hash)
Self::have(hash)
}
fn preimage_requested(hash: &T::Hash) -> bool {
matches!(StatusFor::<T>::get(hash), Some(RequestStatus::Requested(..)))
matches!(StatusFor::<T>::get(hash), Some(RequestStatus::Requested { .. }))
}
fn get_preimage(hash: &T::Hash) -> Option<Vec<u8>> {
PreimageFor::<T>::get(hash).map(|preimage| preimage.to_vec())
Self::fetch(hash, None).ok().map(Cow::into_owned)
}
fn request_preimage(hash: &T::Hash) {
@@ -330,15 +394,60 @@ impl<T: Config> PreimageProvider<T::Hash> for Pallet<T> {
}
impl<T: Config> PreimageRecipient<T::Hash> for Pallet<T> {
type MaxSize = T::MaxSize;
type MaxSize = ConstU32<MAX_SIZE>; // 2**22
fn note_preimage(bytes: BoundedVec<u8, Self::MaxSize>) {
// We don't really care if this fails, since that's only the case if someone else has
// already noted it.
let _ = Self::note_bytes(bytes, None);
let _ = Self::note_bytes(bytes.into_inner().into(), None);
}
fn unnote_preimage(hash: &T::Hash) {
// Should never fail if authorization check is skipped.
let res = Self::do_unrequest_preimage(hash);
debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?");
}
}
impl<T: Config<Hash = PreimageHash>> QueryPreimage for Pallet<T> {
fn len(hash: &T::Hash) -> Option<u32> {
Pallet::<T>::len(hash)
}
fn fetch(hash: &T::Hash, len: Option<u32>) -> FetchResult {
Pallet::<T>::fetch(hash, len)
}
fn is_requested(hash: &T::Hash) -> bool {
matches!(StatusFor::<T>::get(hash), Some(RequestStatus::Requested { .. }))
}
fn request(hash: &T::Hash) {
Self::do_request_preimage(hash)
}
fn unrequest(hash: &T::Hash) {
let res = Self::do_unrequest_preimage(hash);
debug_assert!(res.is_ok(), "do_unrequest_preimage failed - counter underflow?");
}
}
impl<T: Config<Hash = PreimageHash>> StorePreimage for Pallet<T> {
const MAX_LENGTH: usize = MAX_SIZE as usize;
fn note(bytes: Cow<[u8]>) -> Result<T::Hash, DispatchError> {
// We don't really care if this fails, since that's only the case if someone else has
// already noted it.
let maybe_hash = Self::note_bytes(bytes, None).map(|(_, h)| h);
// Map to the correct trait error.
if maybe_hash == Err(DispatchError::from(Error::<T>::TooBig)) {
Err(DispatchError::Exhausted)
} else {
maybe_hash
}
}
fn unnote(hash: &T::Hash) {
// Should never fail if authorization check is skipped.
let res = Self::do_unnote_preimage(hash, None);
debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?");
+263
View File
@@ -0,0 +1,263 @@
// This file is part of Substrate.
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Storage migrations for the preimage pallet.
use super::*;
use frame_support::{
storage_alias,
traits::{ConstU32, OnRuntimeUpgrade},
};
use sp_std::collections::btree_map::BTreeMap;
/// The log target.
const TARGET: &'static str = "runtime::preimage::migration::v1";
/// The original data layout of the preimage pallet without a specific version number.
mod v0 {
use super::*;
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)]
pub enum RequestStatus<AccountId, Balance> {
Unrequested(Option<(AccountId, Balance)>),
Requested(u32),
}
#[storage_alias]
pub type PreimageFor<T: Config> = StorageMap<
Pallet<T>,
Identity,
<T as frame_system::Config>::Hash,
BoundedVec<u8, ConstU32<MAX_SIZE>>,
>;
#[storage_alias]
pub type StatusFor<T: Config> = StorageMap<
Pallet<T>,
Identity,
<T as frame_system::Config>::Hash,
RequestStatus<<T as frame_system::Config>::AccountId, BalanceOf<T>>,
>;
/// Returns the number of images or `None` if the storage is corrupted.
#[cfg(feature = "try-runtime")]
pub fn image_count<T: Config>() -> Option<u32> {
let images = v0::PreimageFor::<T>::iter_values().count() as u32;
let status = v0::StatusFor::<T>::iter_values().count() as u32;
if images == status {
Some(images)
} else {
None
}
}
}
pub mod v1 {
use super::*;
/// Migration for moving preimage from V0 to V1 storage.
///
/// Note: This needs to be run with the same hashing algorithm as before
/// since it is not re-hashing the preimages.
pub struct Migration<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for Migration<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
let images = v0::image_count::<T>().expect("v0 storage corrupted");
log::info!(target: TARGET, "Migrating {} images", &images);
Ok((images as u32).encode())
}
fn on_runtime_upgrade() -> Weight {
let mut weight = T::DbWeight::get().reads(1);
if StorageVersion::get::<Pallet<T>>() != 0 {
log::warn!(
target: TARGET,
"skipping MovePreimagesIntoBuckets: executed on wrong storage version.\
Expected version 0"
);
return weight
}
let status = v0::StatusFor::<T>::drain().collect::<Vec<_>>();
weight.saturating_accrue(T::DbWeight::get().reads(status.len() as u64));
let preimages = v0::PreimageFor::<T>::drain().collect::<BTreeMap<_, _>>();
weight.saturating_accrue(T::DbWeight::get().reads(preimages.len() as u64));
for (hash, status) in status.into_iter() {
let preimage = if let Some(preimage) = preimages.get(&hash) {
preimage
} else {
log::error!(target: TARGET, "preimage not found for hash {:?}", &hash);
continue
};
let len = preimage.len() as u32;
if len > MAX_SIZE {
log::error!(
target: TARGET,
"preimage too large for hash {:?}, len: {}",
&hash,
len
);
continue
}
let status = match status {
v0::RequestStatus::Unrequested(deposit) => match deposit {
Some(deposit) => RequestStatus::Unrequested { deposit, len },
// `None` depositor becomes system-requested.
None =>
RequestStatus::Requested { deposit: None, count: 1, len: Some(len) },
},
v0::RequestStatus::Requested(count) if count == 0 => {
log::error!(target: TARGET, "preimage has counter of zero: {:?}", hash);
continue
},
v0::RequestStatus::Requested(count) =>
RequestStatus::Requested { deposit: None, count, len: Some(len) },
};
log::trace!(target: TARGET, "Moving preimage {:?} with len {}", hash, len);
crate::StatusFor::<T>::insert(hash, status);
crate::PreimageFor::<T>::insert(&(hash, len), preimage);
weight.saturating_accrue(T::DbWeight::get().writes(2));
}
StorageVersion::new(1).put::<Pallet<T>>();
weight.saturating_add(T::DbWeight::get().writes(1))
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
let old_images: u32 =
Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
let new_images = image_count::<T>().expect("V1 storage corrupted");
if new_images != old_images {
log::error!(
target: TARGET,
"migrated {} images, expected {}",
new_images,
old_images
);
}
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
Ok(())
}
}
/// Returns the number of images or `None` if the storage is corrupted.
#[cfg(feature = "try-runtime")]
pub fn image_count<T: Config>() -> Option<u32> {
// Use iter_values() to ensure that the values are decodable.
let images = crate::PreimageFor::<T>::iter_values().count() as u32;
let status = crate::StatusFor::<T>::iter_values().count() as u32;
if images == status {
Some(images)
} else {
None
}
}
}
#[cfg(test)]
#[cfg(feature = "try-runtime")]
mod test {
use super::*;
use crate::mock::{Test as T, *};
use frame_support::bounded_vec;
#[test]
fn migration_works() {
new_test_ext().execute_with(|| {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 0);
// Insert some preimages into the v0 storage:
// Case 1: Unrequested without deposit
let (p, h) = preimage::<T>(128);
v0::PreimageFor::<T>::insert(h, p);
v0::StatusFor::<T>::insert(h, v0::RequestStatus::Unrequested(None));
// Case 2: Unrequested with deposit
let (p, h) = preimage::<T>(1024);
v0::PreimageFor::<T>::insert(h, p);
v0::StatusFor::<T>::insert(h, v0::RequestStatus::Unrequested(Some((1, 1))));
// Case 3: Requested by 0 (invalid)
let (p, h) = preimage::<T>(8192);
v0::PreimageFor::<T>::insert(h, p);
v0::StatusFor::<T>::insert(h, v0::RequestStatus::Requested(0));
// Case 4: Requested by 10
let (p, h) = preimage::<T>(65536);
v0::PreimageFor::<T>::insert(h, p);
v0::StatusFor::<T>::insert(h, v0::RequestStatus::Requested(10));
assert_eq!(v0::image_count::<T>(), Some(4));
assert_eq!(v1::image_count::<T>(), None, "V1 storage should be corrupted");
let state = v1::Migration::<T>::pre_upgrade().unwrap();
let _w = v1::Migration::<T>::on_runtime_upgrade();
v1::Migration::<T>::post_upgrade(state).unwrap();
// V0 and V1 share the same prefix, so `iter_values` still counts the same.
assert_eq!(v0::image_count::<T>(), Some(3));
assert_eq!(v1::image_count::<T>(), Some(3)); // One gets skipped therefore 3.
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1);
// Case 1: Unrequested without deposit becomes system-requested
let (p, h) = preimage::<T>(128);
assert_eq!(crate::PreimageFor::<T>::get(&(h, 128)), Some(p));
assert_eq!(
crate::StatusFor::<T>::get(h),
Some(RequestStatus::Requested { deposit: None, count: 1, len: Some(128) })
);
// Case 2: Unrequested with deposit becomes unrequested
let (p, h) = preimage::<T>(1024);
assert_eq!(crate::PreimageFor::<T>::get(&(h, 1024)), Some(p));
assert_eq!(
crate::StatusFor::<T>::get(h),
Some(RequestStatus::Unrequested { deposit: (1, 1), len: 1024 })
);
// Case 3: Requested by 0 should be skipped
let (_, h) = preimage::<T>(8192);
assert_eq!(crate::PreimageFor::<T>::get(&(h, 8192)), None);
assert_eq!(crate::StatusFor::<T>::get(h), None);
// Case 4: Requested by 10 becomes requested by 10
let (p, h) = preimage::<T>(65536);
assert_eq!(crate::PreimageFor::<T>::get(&(h, 65536)), Some(p));
assert_eq!(
crate::StatusFor::<T>::get(h),
Some(RequestStatus::Requested { deposit: None, count: 10, len: Some(65536) })
);
});
}
/// Returns a preimage with a given size and its hash.
fn preimage<T: Config>(
len: usize,
) -> (BoundedVec<u8, ConstU32<MAX_SIZE>>, <T as frame_system::Config>::Hash) {
let p = bounded_vec![1; len];
let h = <T as frame_system::Config>::Hashing::hash_of(&p);
(p, h)
}
}
-1
View File
@@ -105,7 +105,6 @@ impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type ManagerOrigin = EnsureSignedBy<One, u64>;
type MaxSize = ConstU32<1024>;
type BaseDeposit = ConstU64<2>;
type ByteDeposit = ConstU64<1>;
}
+268 -11
View File
@@ -17,11 +17,35 @@
//! # Scheduler tests.
#![cfg(test)]
use super::*;
use crate::mock::*;
use frame_support::{assert_noop, assert_ok};
use frame_support::{
assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_vec,
traits::{Bounded, BoundedInline, Hash as PreimageHash},
StorageNoopGuard,
};
use pallet_balances::Error as BalancesError;
use sp_core::{blake2_256, H256};
/// Returns one `Inline`, `Lookup` and `Legacy` item each with different data and hash.
pub fn make_bounded_values() -> (Bounded<Vec<u8>>, Bounded<Vec<u8>>, Bounded<Vec<u8>>) {
let data: BoundedInline = bounded_vec![1];
let inline = Bounded::<Vec<u8>>::Inline(data);
let data = vec![1, 2];
let hash: H256 = blake2_256(&data[..]).into();
let len = data.len() as u32;
let lookup = Bounded::<Vec<u8>>::unrequested(hash, len);
let data = vec![1, 2, 3];
let hash: H256 = blake2_256(&data[..]).into();
let legacy = Bounded::<Vec<u8>>::Legacy { hash, dummy: Default::default() };
(inline, lookup, legacy)
}
#[test]
fn user_note_preimage_works() {
@@ -56,10 +80,7 @@ fn manager_note_preimage_works() {
assert!(Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
assert_noop!(
Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]),
Error::<Test>::AlreadyNoted
);
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
});
}
@@ -130,14 +151,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])),
Error::<Test>::Requested
);
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])));
// it's still here.
let h = hashed([1]);
assert!(Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
// now it's gone
assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert!(!Preimage::have_preimage(&hashed([1])));
});
}
@@ -145,15 +168,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() {
fn request_note_order_makes_no_difference() {
let one_way = new_test_ext().execute_with(|| {
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
(
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
)
});
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
let other_way = (
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
@@ -189,6 +213,7 @@ fn request_user_note_order_makes_no_difference() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
let other_way = (
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
@@ -226,8 +251,240 @@ fn user_noted_then_requested_preimage_is_refunded_once_only() {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
// Still have reserve from `vec[1; 3]`.
assert_eq!(Balances::reserved_balance(2), 5);
assert_eq!(Balances::free_balance(2), 95);
});
}
#[test]
fn noted_preimage_use_correct_map() {
new_test_ext().execute_with(|| {
// Add one preimage per bucket...
for i in 0..7 {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; 128 << (i * 2)]));
}
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; MAX_SIZE as usize]));
assert_eq!(PreimageFor::<Test>::iter().count(), 8);
// All are present
assert_eq!(StatusFor::<Test>::iter().count(), 8);
// Now start removing them again...
for i in 0..7 {
assert_ok!(Preimage::unnote_preimage(
RuntimeOrigin::signed(1),
hashed(vec![0; 128 << (i * 2)])
));
}
assert_eq!(PreimageFor::<Test>::iter().count(), 1);
assert_ok!(Preimage::unnote_preimage(
RuntimeOrigin::signed(1),
hashed(vec![0; MAX_SIZE as usize])
));
assert_eq!(PreimageFor::<Test>::iter().count(), 0);
// All are gone
assert_eq!(StatusFor::<Test>::iter().count(), 0);
});
}
/// The `StorePreimage` and `QueryPreimage` traits work together.
#[test]
fn query_and_store_preimage_workflow() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let data: Vec<u8> = vec![1; 512];
let encoded = data.encode();
// Bound an unbound value.
let bound = Preimage::bound(data.clone()).unwrap();
let (len, hash) = (bound.len().unwrap(), bound.hash());
assert_eq!(hash, blake2_256(&encoded).into());
assert_eq!(bound.len(), Some(len));
assert!(bound.lookup_needed(), "Should not be Inlined");
assert_eq!(bound.lookup_len(), Some(len));
// The value is requested and available.
assert!(Preimage::is_requested(&hash));
assert!(<Preimage as QueryPreimage>::have(&bound));
assert_eq!(Preimage::len(&hash), Some(len));
// It can be fetched with length.
assert_eq!(Preimage::fetch(&hash, Some(len)).unwrap(), encoded);
// ... and without length.
assert_eq!(Preimage::fetch(&hash, None).unwrap(), encoded);
// ... but not with wrong length.
assert_err!(Preimage::fetch(&hash, Some(0)), DispatchError::Unavailable);
// It can be peeked and decoded correctly.
assert_eq!(Preimage::peek::<Vec<u8>>(&bound).unwrap(), (data.clone(), Some(len)));
// Request it two more times.
assert_eq!(Preimage::pick::<Vec<u8>>(hash, len), bound);
Preimage::request(&hash);
// It is requested thrice.
assert!(matches!(
StatusFor::<Test>::get(&hash).unwrap(),
RequestStatus::Requested { count: 3, .. }
));
// It can be realized and decoded correctly.
assert_eq!(Preimage::realize::<Vec<u8>>(&bound).unwrap(), (data.clone(), Some(len)));
assert!(matches!(
StatusFor::<Test>::get(&hash).unwrap(),
RequestStatus::Requested { count: 2, .. }
));
// Dropping should unrequest.
Preimage::drop(&bound);
assert!(matches!(
StatusFor::<Test>::get(&hash).unwrap(),
RequestStatus::Requested { count: 1, .. }
));
// Is still available.
assert!(<Preimage as QueryPreimage>::have(&bound));
// Manually unnote it.
Preimage::unnote(&hash);
// Is not available anymore.
assert!(!<Preimage as QueryPreimage>::have(&bound));
assert_err!(Preimage::fetch(&hash, Some(len)), DispatchError::Unavailable);
// And not requested since the traits assume permissioned origin.
assert!(!Preimage::is_requested(&hash));
// No storage changes remain. Checked by `StorageNoopGuard`.
});
}
/// The request function behaves as expected.
#[test]
fn query_preimage_request_works() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let data: Vec<u8> = vec![1; 10];
let hash: PreimageHash = blake2_256(&data[..]).into();
// Request the preimage.
<Preimage as QueryPreimage>::request(&hash);
// The preimage is requested with unknown length and cannot be fetched.
assert!(<Preimage as QueryPreimage>::is_requested(&hash));
assert!(<Preimage as QueryPreimage>::len(&hash).is_none());
assert_noop!(<Preimage as QueryPreimage>::fetch(&hash, None), DispatchError::Unavailable);
// Request again.
<Preimage as QueryPreimage>::request(&hash);
// The preimage is still requested.
assert!(<Preimage as QueryPreimage>::is_requested(&hash));
assert!(<Preimage as QueryPreimage>::len(&hash).is_none());
assert_noop!(<Preimage as QueryPreimage>::fetch(&hash, None), DispatchError::Unavailable);
// But there is only one entry in the map.
assert_eq!(StatusFor::<Test>::iter().count(), 1);
// Un-request the preimage.
<Preimage as QueryPreimage>::unrequest(&hash);
// It is still requested.
assert!(<Preimage as QueryPreimage>::is_requested(&hash));
// Un-request twice.
<Preimage as QueryPreimage>::unrequest(&hash);
// It is not requested anymore.
assert!(!<Preimage as QueryPreimage>::is_requested(&hash));
// And there is no entry in the map.
assert_eq!(StatusFor::<Test>::iter().count(), 0);
});
}
/// The `QueryPreimage` functions can be used together with `Bounded` values.
#[test]
fn query_preimage_hold_and_drop_work() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let (inline, lookup, legacy) = make_bounded_values();
// `hold` does nothing for `Inline` values.
assert_storage_noop!(<Preimage as QueryPreimage>::hold(&inline));
// `hold` requests `Lookup` values.
<Preimage as QueryPreimage>::hold(&lookup);
assert!(<Preimage as QueryPreimage>::is_requested(&lookup.hash()));
// `hold` requests `Legacy` values.
<Preimage as QueryPreimage>::hold(&legacy);
assert!(<Preimage as QueryPreimage>::is_requested(&legacy.hash()));
// There are two values requested in total.
assert_eq!(StatusFor::<Test>::iter().count(), 2);
// Cleanup by dropping both.
<Preimage as QueryPreimage>::drop(&lookup);
assert!(!<Preimage as QueryPreimage>::is_requested(&lookup.hash()));
<Preimage as QueryPreimage>::drop(&legacy);
assert!(!<Preimage as QueryPreimage>::is_requested(&legacy.hash()));
// There are no values requested anymore.
assert_eq!(StatusFor::<Test>::iter().count(), 0);
});
}
/// The `StorePreimage` trait works as expected.
#[test]
fn store_preimage_basic_works() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let data: Vec<u8> = vec![1; 512]; // Too large to inline.
let encoded = Cow::from(data.encode());
// Bound the data.
let bound = <Preimage as StorePreimage>::bound(data.clone()).unwrap();
// The preimage can be peeked.
assert_ok!(<Preimage as QueryPreimage>::peek(&bound));
// Un-note the preimage.
<Preimage as StorePreimage>::unnote(&bound.hash());
// The preimage cannot be peeked anymore.
assert_err!(<Preimage as QueryPreimage>::peek(&bound), DispatchError::Unavailable);
// Noting the wrong pre-image does not make it peek-able.
assert_ok!(<Preimage as StorePreimage>::note(Cow::Borrowed(&data)));
assert_err!(<Preimage as QueryPreimage>::peek(&bound), DispatchError::Unavailable);
// Manually note the preimage makes it peek-able again.
assert_ok!(<Preimage as StorePreimage>::note(encoded.clone()));
// Noting again works.
assert_ok!(<Preimage as StorePreimage>::note(encoded));
assert_ok!(<Preimage as QueryPreimage>::peek(&bound));
// Cleanup.
<Preimage as StorePreimage>::unnote(&bound.hash());
let data_hash = blake2_256(&data);
<Preimage as StorePreimage>::unnote(&data_hash.into());
// No storage changes remain. Checked by `StorageNoopGuard`.
});
}
#[test]
fn store_preimage_note_too_large_errors() {
new_test_ext().execute_with(|| {
// Works with `MAX_LENGTH`.
let len = <Preimage as StorePreimage>::MAX_LENGTH;
let data = vec![0u8; len];
assert_ok!(<Preimage as StorePreimage>::note(data.into()));
// Errors with `MAX_LENGTH+1`.
let data = vec![0u8; len + 1];
assert_err!(<Preimage as StorePreimage>::note(data.into()), DispatchError::Exhausted);
});
}
#[test]
fn store_preimage_bound_too_large_errors() {
new_test_ext().execute_with(|| {
// Using `MAX_LENGTH` number of bytes in a vector does not work
// since SCALE prepends the length.
let len = <Preimage as StorePreimage>::MAX_LENGTH;
let data: Vec<u8> = vec![0; len];
assert_err!(<Preimage as StorePreimage>::bound(data.clone()), DispatchError::Exhausted);
// Works with `MAX_LENGTH-4`.
let data: Vec<u8> = vec![0; len - 4];
assert_ok!(<Preimage as StorePreimage>::bound(data.clone()));
});
}
+65 -59
View File
@@ -18,22 +18,24 @@
//! Autogenerated weights for pallet_preimage
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/substrate
// /home/benchbot/cargo_target_dir/production/substrate
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet_preimage
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --template=./.maintain/frame-weight-template.hbs
// --heap-pages=4096
// --pallet=pallet_preimage
// --chain=dev
// --output=./frame/preimage/src/weights.rs
// --template=./.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
@@ -61,88 +63,90 @@ pub trait WeightInfo {
/// Weights for pallet_preimage using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
/// The range of component `s` is `[0, 4194304]`.
fn note_preimage(s: u32, ) -> Weight {
Weight::from_ref_time(0 as u64)
Weight::from_ref_time(32_591_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:0)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
/// The range of component `s` is `[0, 4194304]`.
fn note_requested_preimage(s: u32, ) -> Weight {
Weight::from_ref_time(0 as u64)
Weight::from_ref_time(23_350_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:0)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
/// The range of component `s` is `[0, 4194304]`.
fn note_no_deposit_preimage(s: u32, ) -> Weight {
Weight::from_ref_time(0 as u64)
Weight::from_ref_time(21_436_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unnote_preimage() -> Weight {
Weight::from_ref_time(44_380_000 as u64)
Weight::from_ref_time(44_567_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unnote_no_deposit_preimage() -> Weight {
Weight::from_ref_time(30_280_000 as u64)
Weight::from_ref_time(30_065_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_preimage() -> Weight {
Weight::from_ref_time(42_809_000 as u64)
Weight::from_ref_time(28_470_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_no_deposit_preimage() -> Weight {
Weight::from_ref_time(28_964_000 as u64)
Weight::from_ref_time(14_601_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_unnoted_preimage() -> Weight {
Weight::from_ref_time(17_555_000 as u64)
Weight::from_ref_time(20_121_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_requested_preimage() -> Weight {
Weight::from_ref_time(7_745_000 as u64)
Weight::from_ref_time(9_440_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unrequest_preimage() -> Weight {
Weight::from_ref_time(29_758_000 as u64)
Weight::from_ref_time(29_013_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unrequest_unnoted_preimage() -> Weight {
Weight::from_ref_time(18_360_000 as u64)
Weight::from_ref_time(9_223_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn unrequest_multi_referenced_preimage() -> Weight {
Weight::from_ref_time(7_439_000 as u64)
Weight::from_ref_time(9_252_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
@@ -150,88 +154,90 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// For backwards compatibility and tests
impl WeightInfo for () {
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
/// The range of component `s` is `[0, 4194304]`.
fn note_preimage(s: u32, ) -> Weight {
Weight::from_ref_time(0 as u64)
Weight::from_ref_time(32_591_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:0)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
/// The range of component `s` is `[0, 4194304]`.
fn note_requested_preimage(s: u32, ) -> Weight {
Weight::from_ref_time(0 as u64)
Weight::from_ref_time(23_350_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:0)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
/// The range of component `s` is `[0, 4194304]`.
fn note_no_deposit_preimage(s: u32, ) -> Weight {
Weight::from_ref_time(0 as u64)
Weight::from_ref_time(21_436_000 as u64)
// Standard Error: 0
.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unnote_preimage() -> Weight {
Weight::from_ref_time(44_380_000 as u64)
Weight::from_ref_time(44_567_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unnote_no_deposit_preimage() -> Weight {
Weight::from_ref_time(30_280_000 as u64)
Weight::from_ref_time(30_065_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_preimage() -> Weight {
Weight::from_ref_time(42_809_000 as u64)
Weight::from_ref_time(28_470_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_no_deposit_preimage() -> Weight {
Weight::from_ref_time(28_964_000 as u64)
Weight::from_ref_time(14_601_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_unnoted_preimage() -> Weight {
Weight::from_ref_time(17_555_000 as u64)
Weight::from_ref_time(20_121_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn request_requested_preimage() -> Weight {
Weight::from_ref_time(7_745_000 as u64)
Weight::from_ref_time(9_440_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unrequest_preimage() -> Weight {
Weight::from_ref_time(29_758_000 as u64)
Weight::from_ref_time(29_013_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Preimage PreimageFor (r:0 w:1)
fn unrequest_unnoted_preimage() -> Weight {
Weight::from_ref_time(18_360_000 as u64)
Weight::from_ref_time(9_223_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Preimage StatusFor (r:1 w:1)
fn unrequest_multi_referenced_preimage() -> Weight {
Weight::from_ref_time(7_439_000 as u64)
Weight::from_ref_time(9_252_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
+2 -2
View File
@@ -452,7 +452,7 @@ pub mod pallet {
ensure!(!friends.is_empty(), Error::<T>::NotEnoughFriends);
ensure!(threshold as usize <= friends.len(), Error::<T>::NotEnoughFriends);
let bounded_friends: FriendsOf<T> =
friends.try_into().map_err(|()| Error::<T>::MaxFriends)?;
friends.try_into().map_err(|_| Error::<T>::MaxFriends)?;
ensure!(Self::is_sorted_and_unique(&bounded_friends), Error::<T>::NotSorted);
// Total deposit is base fee + number of friends * factor fee
let friend_deposit = T::FriendDepositFactor::get()
@@ -554,7 +554,7 @@ pub mod pallet {
Err(pos) => active_recovery
.friends
.try_insert(pos, who.clone())
.map_err(|()| Error::<T>::MaxFriends)?,
.map_err(|_| Error::<T>::MaxFriends)?,
}
// Update storage with the latest details
<ActiveRecoveries<T>>::insert(&lost, &rescuer, active_recovery);
+11 -5
View File
@@ -24,10 +24,10 @@ use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}
use frame_support::{
assert_ok,
dispatch::UnfilteredDispatchable,
traits::{Currency, EnsureOrigin},
traits::{Bounded, Currency, EnsureOrigin},
};
use frame_system::RawOrigin;
use sp_runtime::traits::{Bounded, Hash};
use sp_runtime::traits::Bounded as ArithBounded;
const SEED: u32 = 0;
@@ -42,6 +42,12 @@ fn funded_account<T: Config<I>, I: 'static>(name: &'static str, index: u32) -> T
caller
}
fn dummy_call<T: Config<I>, I: 'static>() -> Bounded<<T as Config<I>>::RuntimeCall> {
let inner = frame_system::Call::remark { remark: vec![] };
let call = <T as Config<I>>::RuntimeCall::from(inner);
T::Preimages::bound(call).unwrap()
}
fn create_referendum<T: Config<I>, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) {
let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin();
if let Ok(caller) = frame_system::ensure_signed(origin.clone()) {
@@ -50,9 +56,9 @@ fn create_referendum<T: Config<I>, I: 'static>() -> (T::RuntimeOrigin, Referendu
}
let proposal_origin = Box::new(RawOrigin::Root.into());
let proposal_hash = T::Hashing::hash_of(&0);
let proposal = dummy_call::<T, I>();
let enactment_moment = DispatchTime::After(0u32.into());
let call = Call::<T, I>::submit { proposal_origin, proposal_hash, enactment_moment };
let call = crate::Call::<T, I>::submit { proposal_origin, proposal, enactment_moment };
assert_ok!(call.dispatch_bypass_filter(origin.clone()));
let index = ReferendumCount::<T, I>::get() - 1;
(origin, index)
@@ -196,7 +202,7 @@ benchmarks_instance_pallet! {
}: _<T::RuntimeOrigin>(
origin,
Box::new(RawOrigin::Root.into()),
T::Hashing::hash_of(&0),
dummy_call::<T, I>(),
DispatchTime::After(0u32.into())
) verify {
let index = ReferendumCount::<T, I>::get().checked_sub(1).unwrap();
+58 -46
View File
@@ -69,11 +69,11 @@ use frame_support::{
ensure,
traits::{
schedule::{
v2::{Anon as ScheduleAnon, Named as ScheduleNamed},
DispatchTime, MaybeHashed,
v3::{Anon as ScheduleAnon, Named as ScheduleNamed},
DispatchTime,
},
Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling,
ReservableCurrency, VoteTally,
Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage,
ReservableCurrency, StorePreimage, VoteTally,
},
BoundedVec,
};
@@ -92,10 +92,10 @@ use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch};
pub use self::{
pallet::*,
types::{
BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted,
NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf,
ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo,
TrackInfoOf, TracksInfo, VotesOf,
BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit,
InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo,
ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf,
TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf,
},
weights::WeightInfo,
};
@@ -149,23 +149,16 @@ pub mod pallet {
// System level stuff.
type RuntimeCall: Parameter
+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ From<Call<Self, I>>;
+ From<Call<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeCall>
+ From<frame_system::Call<Self>>;
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
/// The Scheduler.
type Scheduler: ScheduleAnon<
Self::BlockNumber,
CallOf<Self, I>,
PalletsOriginOf<Self>,
Hash = Self::Hash,
> + ScheduleNamed<
Self::BlockNumber,
CallOf<Self, I>,
PalletsOriginOf<Self>,
Hash = Self::Hash,
>;
type Scheduler: ScheduleAnon<Self::BlockNumber, CallOf<Self, I>, PalletsOriginOf<Self>>
+ ScheduleNamed<Self::BlockNumber, CallOf<Self, I>, PalletsOriginOf<Self>>;
/// Currency type for this pallet.
type Currency: ReservableCurrency<Self::AccountId>;
// Origins and unbalances.
@@ -221,6 +214,9 @@ pub mod pallet {
Self::BlockNumber,
RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin,
>;
/// The preimage provider.
type Preimages: QueryPreimage + StorePreimage;
}
/// The next free referendum index, aka the number of referenda started so far.
@@ -259,8 +255,8 @@ pub mod pallet {
index: ReferendumIndex,
/// The track (and by extension proposal dispatch origin) of this referendum.
track: TrackIdOf<T, I>,
/// The hash of the proposal up for referendum.
proposal_hash: T::Hash,
/// The proposal for the referendum.
proposal: BoundedCallOf<T, I>,
},
/// The decision deposit has been placed.
DecisionDepositPlaced {
@@ -293,8 +289,8 @@ pub mod pallet {
index: ReferendumIndex,
/// The track (and by extension proposal dispatch origin) of this referendum.
track: TrackIdOf<T, I>,
/// The hash of the proposal up for referendum.
proposal_hash: T::Hash,
/// The proposal for the referendum.
proposal: BoundedCallOf<T, I>,
/// The current tally of votes in this referendum.
tally: T::Tally,
},
@@ -381,7 +377,7 @@ pub mod pallet {
/// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds
/// available.
/// - `proposal_origin`: The origin from which the proposal should be executed.
/// - `proposal_hash`: The hash of the proposal preimage.
/// - `proposal`: The proposal.
/// - `enactment_moment`: The moment that the proposal should be enacted.
///
/// Emits `Submitted`.
@@ -389,7 +385,7 @@ pub mod pallet {
pub fn submit(
origin: OriginFor<T>,
proposal_origin: Box<PalletsOriginOf<T>>,
proposal_hash: T::Hash,
proposal: BoundedCallOf<T, I>,
enactment_moment: DispatchTime<T::BlockNumber>,
) -> DispatchResult {
let who = T::SubmitOrigin::ensure_origin(origin)?;
@@ -403,11 +399,12 @@ pub mod pallet {
r
});
let now = frame_system::Pallet::<T>::block_number();
let nudge_call = Call::nudge_referendum { index };
let nudge_call =
T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?;
let status = ReferendumStatus {
track,
origin: *proposal_origin,
proposal_hash,
proposal: proposal.clone(),
enactment: enactment_moment,
submitted: now,
submission_deposit,
@@ -419,7 +416,7 @@ pub mod pallet {
};
ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
Self::deposit_event(Event::<T, I>::Submitted { index, track, proposal_hash });
Self::deposit_event(Event::<T, I>::Submitted { index, track, proposal });
Ok(())
}
@@ -651,7 +648,8 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
let mut status = ReferendumStatusOf::<T, I> {
track: class,
origin: frame_support::dispatch::RawOrigin::Root.into(),
proposal_hash: <T::Hashing as sp_runtime::traits::Hash>::hash_of(&index),
proposal: T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))
.map_err(|_| ())?,
enactment: DispatchTime::After(Zero::zero()),
submitted: now,
submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() },
@@ -709,18 +707,18 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
track: &TrackInfoOf<T, I>,
desired: DispatchTime<T::BlockNumber>,
origin: PalletsOriginOf<T>,
call_hash: T::Hash,
call: BoundedCallOf<T, I>,
) {
let now = frame_system::Pallet::<T>::block_number();
let earliest_allowed = now.saturating_add(track.min_enactment_period);
let desired = desired.evaluate(now);
let ok = T::Scheduler::schedule_named(
(ASSEMBLY_ID, "enactment", index).encode(),
(ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256),
DispatchTime::At(desired.max(earliest_allowed)),
None,
63,
origin,
MaybeHashed::Hash(call_hash),
call,
)
.is_ok();
debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed");
@@ -728,7 +726,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Set an alarm to dispatch `call` at block number `when`.
fn set_alarm(
call: impl Into<CallOf<T, I>>,
call: BoundedCallOf<T, I>,
when: T::BlockNumber,
) -> Option<(T::BlockNumber, ScheduleAddressOf<T, I>)> {
let alarm_interval = T::AlarmInterval::get().max(One::one());
@@ -739,7 +737,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
None,
128u8,
frame_system::RawOrigin::Root.into(),
MaybeHashed::Value(call.into()),
call,
)
.ok()
.map(|x| (when, x));
@@ -776,7 +774,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Self::deposit_event(Event::<T, I>::DecisionStarted {
index,
tally: status.tally.clone(),
proposal_hash: status.proposal_hash,
proposal: status.proposal.clone(),
track: status.track,
});
let confirming = if is_passing {
@@ -843,12 +841,21 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
let alarm_interval = T::AlarmInterval::get().max(One::one());
let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval;
let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
track,
})) {
Ok(c) => c,
Err(_) => {
debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",);
return
},
};
let maybe_result = T::Scheduler::schedule(
DispatchTime::At(when),
None,
128u8,
frame_system::RawOrigin::Root.into(),
MaybeHashed::Value(Call::one_fewer_deciding { track }.into()),
call,
);
debug_assert!(
maybe_result.is_ok(),
@@ -871,7 +878,18 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) {
// Either no alarm or one that was different
Self::ensure_no_alarm(status);
status.alarm = Self::set_alarm(Call::nudge_referendum { index }, alarm);
let call =
match T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index })) {
Ok(c) => c,
Err(_) => {
debug_assert!(
false,
"Unable to create a bounded call from `nudge_referendum`??",
);
return false
},
};
status.alarm = Self::set_alarm(call, alarm);
true
} else {
false
@@ -987,14 +1005,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
// Passed!
Self::ensure_no_alarm(&mut status);
Self::note_one_fewer_deciding(status.track);
let (desired, call_hash) = (status.enactment, status.proposal_hash);
Self::schedule_enactment(
index,
track,
desired,
status.origin,
call_hash,
);
let (desired, call) = (status.enactment, status.proposal);
Self::schedule_enactment(index, track, desired, status.origin, call);
Self::deposit_event(Event::<T, I>::Confirmed {
index,
tally: status.tally,
+8 -10
View File
@@ -24,7 +24,7 @@ use frame_support::{
assert_ok, ord_parameter_types, parameter_types,
traits::{
ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling,
PreimageRecipient, SortedMembers,
SortedMembers,
},
weights::Weight,
};
@@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy};
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, Hash, IdentityLookup},
traits::{BlakeTwo256, IdentityLookup},
DispatchResult, Perbill,
};
@@ -97,7 +97,6 @@ impl pallet_preimage::Config for Test {
type WeightInfo = ();
type Currency = Balances;
type ManagerOrigin = EnsureRoot<u64>;
type MaxSize = ConstU32<4096>;
type BaseDeposit = ();
type ByteDeposit = ();
}
@@ -111,8 +110,7 @@ impl pallet_scheduler::Config for Test {
type MaxScheduledPerBlock = ConstU32<100>;
type WeightInfo = ();
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type PreimageProvider = Preimage;
type NoPreimagePostponement = ConstU64<10>;
type Preimages = Preimage;
}
impl pallet_balances::Config for Test {
type MaxReserves = ();
@@ -229,6 +227,7 @@ impl Config for Test {
type UndecidingTimeout = ConstU64<20>;
type AlarmInterval = AlarmInterval;
type Tracks = TestTracksInfo;
type Preimages = Preimage;
}
pub fn new_test_ext() -> sp_io::TestExternalities {
@@ -306,14 +305,13 @@ pub fn set_balance_proposal(value: u64) -> Vec<u8> {
.encode()
}
pub fn set_balance_proposal_hash(value: u64) -> H256 {
pub fn set_balance_proposal_bounded(value: u64) -> BoundedCallOf<Test, ()> {
let c = RuntimeCall::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)
<Preimage as StorePreimage>::bound(c).unwrap()
}
#[allow(dead_code)]
@@ -321,7 +319,7 @@ pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult {
Referenda::submit(
RuntimeOrigin::signed(who),
Box::new(frame_system::RawOrigin::Root.into()),
set_balance_proposal_hash(value),
set_balance_proposal_bounded(value),
DispatchTime::After(delay),
)
}
@@ -449,7 +447,7 @@ impl RefState {
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(frame_support::dispatch::RawOrigin::Root.into()),
set_balance_proposal_hash(1),
set_balance_proposal_bounded(1),
DispatchTime::At(10),
));
assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0));
+16 -16
View File
@@ -44,7 +44,7 @@ fn basic_happy_path_works() {
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
set_balance_proposal_hash(1),
set_balance_proposal_bounded(1),
DispatchTime::At(10),
));
assert_eq!(Balances::reserved_balance(&1), 2);
@@ -175,7 +175,7 @@ fn queueing_works() {
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(5),
Box::new(RawOrigin::Root.into()),
set_balance_proposal_hash(0),
set_balance_proposal_bounded(0),
DispatchTime::After(0),
));
assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(5), 0));
@@ -187,7 +187,7 @@ fn queueing_works() {
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(i),
Box::new(RawOrigin::Root.into()),
set_balance_proposal_hash(i),
set_balance_proposal_bounded(i),
DispatchTime::After(0),
));
assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(i), i as u32));
@@ -272,7 +272,7 @@ fn auto_timeout_should_happen_with_nothing_but_submit() {
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
set_balance_proposal_hash(1),
set_balance_proposal_bounded(1),
DispatchTime::At(20),
));
run_to(20);
@@ -292,13 +292,13 @@ fn tracks_are_distinguished() {
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
set_balance_proposal_hash(1),
set_balance_proposal_bounded(1),
DispatchTime::At(10),
));
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(2),
Box::new(RawOrigin::None.into()),
set_balance_proposal_hash(2),
set_balance_proposal_bounded(2),
DispatchTime::At(20),
));
@@ -315,7 +315,7 @@ fn tracks_are_distinguished() {
ReferendumInfo::Ongoing(ReferendumStatus {
track: 0,
origin: OriginCaller::system(RawOrigin::Root),
proposal_hash: set_balance_proposal_hash(1),
proposal: set_balance_proposal_bounded(1),
enactment: DispatchTime::At(10),
submitted: 1,
submission_deposit: Deposit { who: 1, amount: 2 },
@@ -331,7 +331,7 @@ fn tracks_are_distinguished() {
ReferendumInfo::Ongoing(ReferendumStatus {
track: 1,
origin: OriginCaller::system(RawOrigin::None),
proposal_hash: set_balance_proposal_hash(2),
proposal: set_balance_proposal_bounded(2),
enactment: DispatchTime::At(20),
submitted: 1,
submission_deposit: Deposit { who: 2, amount: 2 },
@@ -350,13 +350,13 @@ fn tracks_are_distinguished() {
#[test]
fn submit_errors_work() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
// No track for Signed origins.
assert_noop!(
Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Signed(2).into()),
h,
h.clone(),
DispatchTime::At(10),
),
Error::<Test>::NoTrack
@@ -381,7 +381,7 @@ fn decision_deposit_errors_work() {
let e = Error::<Test>::NotOngoing;
assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e);
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
@@ -403,7 +403,7 @@ fn refund_deposit_works() {
let e = Error::<Test>::BadReferendum;
assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(1), 0), e);
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
@@ -425,7 +425,7 @@ fn refund_deposit_works() {
#[test]
fn cancel_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
@@ -444,7 +444,7 @@ fn cancel_works() {
#[test]
fn cancel_errors_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
@@ -462,7 +462,7 @@ fn cancel_errors_works() {
#[test]
fn kill_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
@@ -482,7 +482,7 @@ fn kill_works() {
#[test]
fn kill_errors_works() {
new_test_ext().execute_with(|| {
let h = set_balance_proposal_hash(1);
let h = set_balance_proposal_bounded(1);
assert_ok!(Referenda::submit(
RuntimeOrigin::signed(1),
Box::new(RawOrigin::Root.into()),
+13 -9
View File
@@ -19,7 +19,10 @@
use super::*;
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use frame_support::{traits::schedule::Anon, Parameter};
use frame_support::{
traits::{schedule::v3::Anon, Bounded},
Parameter,
};
use scale_info::TypeInfo;
use sp_arithmetic::{Rounding::*, SignedRounding::*};
use sp_runtime::{FixedI64, PerThing, RuntimeDebug};
@@ -31,6 +34,7 @@ pub type NegativeImbalanceOf<T, I> = <<T as Config<I>>::Currency as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;
pub type CallOf<T, I> = <T as Config<I>>::RuntimeCall;
pub type BoundedCallOf<T, I> = Bounded<<T as Config<I>>::RuntimeCall>;
pub type VotesOf<T, I> = <T as Config<I>>::Votes;
pub type TallyOf<T, I> = <T as Config<I>>::Tally;
pub type PalletsOriginOf<T> =
@@ -39,7 +43,7 @@ pub type ReferendumInfoOf<T, I> = ReferendumInfo<
TrackIdOf<T, I>,
PalletsOriginOf<T>,
<T as frame_system::Config>::BlockNumber,
<T as frame_system::Config>::Hash,
BoundedCallOf<T, I>,
BalanceOf<T, I>,
TallyOf<T, I>,
<T as frame_system::Config>::AccountId,
@@ -49,7 +53,7 @@ pub type ReferendumStatusOf<T, I> = ReferendumStatus<
TrackIdOf<T, I>,
PalletsOriginOf<T>,
<T as frame_system::Config>::BlockNumber,
<T as frame_system::Config>::Hash,
BoundedCallOf<T, I>,
BalanceOf<T, I>,
TallyOf<T, I>,
<T as frame_system::Config>::AccountId,
@@ -160,7 +164,7 @@ pub struct ReferendumStatus<
TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
RuntimeOrigin: 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,
Call: 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,
@@ -171,7 +175,7 @@ pub struct ReferendumStatus<
/// The origin for this referendum.
pub(crate) origin: RuntimeOrigin,
/// The hash of the proposal up for referendum.
pub(crate) proposal_hash: Hash,
pub(crate) proposal: Call,
/// The time the proposal should be scheduled for enactment.
pub(crate) enactment: DispatchTime<Moment>,
/// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it
@@ -197,7 +201,7 @@ pub enum ReferendumInfo<
TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
Call: 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,
@@ -209,7 +213,7 @@ pub enum ReferendumInfo<
TrackId,
RuntimeOrigin,
Moment,
Hash,
Call,
Balance,
Tally,
AccountId,
@@ -232,12 +236,12 @@ impl<
TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
RuntimeOrigin: 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,
Call: 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, RuntimeOrigin, Moment, Hash, Balance, Tally, AccountId, ScheduleAddress>
> ReferendumInfo<TrackId, RuntimeOrigin, Moment, Call, 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.
+173 -158
View File
@@ -18,201 +18,219 @@
//! Scheduler pallet benchmarking.
use super::*;
use frame_benchmarking::benchmarks;
use frame_benchmarking::{account, benchmarks};
use frame_support::{
ensure,
traits::{OnInitialize, PreimageProvider, PreimageRecipient},
traits::{schedule::Priority, BoundedInline},
};
use sp_runtime::traits::Hash;
use frame_system::RawOrigin;
use sp_std::{prelude::*, vec};
use crate::Pallet as Scheduler;
use frame_system::Pallet as System;
use frame_system::Call as SystemCall;
const SEED: u32 = 0;
const BLOCK_NUMBER: u32 = 2;
type SystemOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;
/// Add `n` named items to the schedule.
/// Add `n` items to the schedule.
///
/// For `resolved`:
/// - `
/// - `None`: aborted (hash without preimage)
/// - `Some(true)`: hash resolves into call if possible, plain call otherwise
/// - `Some(false)`: plain call
fn fill_schedule<T: Config>(
when: T::BlockNumber,
n: u32,
periodic: bool,
named: bool,
resolved: Option<bool>,
) -> Result<(), &'static str> {
fn fill_schedule<T: Config>(when: T::BlockNumber, n: u32) -> Result<(), &'static str> {
let t = DispatchTime::At(when);
let origin: <T as Config>::PalletsOrigin = frame_system::RawOrigin::Root.into();
for i in 0..n {
// Named schedule is strictly heavier than anonymous
let (call, hash) = call_and_hash::<T>(i);
let call_or_hash = match resolved {
Some(true) => {
T::PreimageProvider::note_preimage(call.encode().try_into().unwrap());
if T::PreimageProvider::have_preimage(&hash) {
CallOrHashOf::<T>::Hash(hash)
} else {
call.into()
}
},
Some(false) => call.into(),
None => CallOrHashOf::<T>::Hash(hash),
};
let period = match periodic {
true => Some(((i + 100).into(), 100)),
false => None,
};
let t = DispatchTime::At(when);
let origin = frame_system::RawOrigin::Root.into();
if named {
Scheduler::<T>::do_schedule_named(i.encode(), t, period, 0, origin, call_or_hash)?;
} else {
Scheduler::<T>::do_schedule(t, period, 0, origin, call_or_hash)?;
}
let call = make_call::<T>(None);
let period = Some(((i + 100).into(), 100));
let name = u32_to_name(i);
Scheduler::<T>::do_schedule_named(name, t, period, 0, origin.clone(), call)?;
}
ensure!(Agenda::<T>::get(when).len() == n as usize, "didn't fill schedule");
Ok(())
}
fn call_and_hash<T: Config>(i: u32) -> (<T as Config>::RuntimeCall, T::Hash) {
// Essentially a no-op call.
let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: i.encode() }.into();
let hash = T::Hashing::hash_of(&call);
(call, hash)
fn u32_to_name(i: u32) -> TaskName {
i.using_encoded(blake2_256)
}
fn make_task<T: Config>(
periodic: bool,
named: bool,
signed: bool,
maybe_lookup_len: Option<u32>,
priority: Priority,
) -> ScheduledOf<T> {
let call = make_call::<T>(maybe_lookup_len);
let maybe_periodic = match periodic {
true => Some((100u32.into(), 100)),
false => None,
};
let maybe_id = match named {
true => Some(u32_to_name(0)),
false => None,
};
let origin = make_origin::<T>(signed);
Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData }
}
fn bounded<T: Config>(len: u32) -> Option<Bounded<<T as Config>::RuntimeCall>> {
let call =
<<T as Config>::RuntimeCall>::from(SystemCall::remark { remark: vec![0; len as usize] });
T::Preimages::bound(call).ok()
}
fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> Bounded<<T as Config>::RuntimeCall> {
let bound = BoundedInline::bound() as u32;
let mut len = match maybe_lookup_len {
Some(len) => len.min(T::Preimages::MAX_LENGTH as u32 - 2).max(bound) - 3,
None => bound.saturating_sub(4),
};
loop {
let c = match bounded::<T>(len) {
Some(x) => x,
None => {
len -= 1;
continue
},
};
if c.lookup_needed() == maybe_lookup_len.is_some() {
break c
}
if maybe_lookup_len.is_some() {
len += 1;
} else {
if len > 0 {
len -= 1;
} else {
break c
}
}
}
}
fn make_origin<T: Config>(signed: bool) -> <T as Config>::PalletsOrigin {
match signed {
true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(),
false => frame_system::RawOrigin::Root.into(),
}
}
fn dummy_counter() -> WeightCounter {
WeightCounter { used: Weight::zero(), limit: Weight::MAX }
}
benchmarks! {
on_initialize_periodic_named_resolved {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, true, true, Some(true))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), s * 2);
for i in 0..s {
assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
}
// `service_agendas` when no work is done.
service_agendas_base {
let now = T::BlockNumber::from(BLOCK_NUMBER);
IncompleteSince::<T>::put(now - One::one());
}: {
Scheduler::<T>::service_agendas(&mut dummy_counter(), now, 0);
} verify {
assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));
}
on_initialize_named_resolved {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, false, true, Some(true))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), s * 2);
assert!(Agenda::<T>::iter().count() == 0);
// `service_agenda` when no work is done.
service_agenda_base {
let now = BLOCK_NUMBER.into();
let s in 0 .. T::MaxScheduledPerBlock::get();
fill_schedule::<T>(now, s)?;
let mut executed = 0;
}: {
Scheduler::<T>::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0);
} verify {
assert_eq!(executed, 0);
}
on_initialize_periodic_resolved {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, true, false, Some(true))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), s * 2);
for i in 0..s {
assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
}
// `service_task` when the task is a non-periodic, non-named, non-fetched call which is not
// dispatched (e.g. due to being overweight).
service_task_base {
let now = BLOCK_NUMBER.into();
let task = make_task::<T>(false, false, false, None, 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
}: {
let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
} verify {
//assert_eq!(result, Ok(()));
}
on_initialize_resolved {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, false, false, Some(true))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), s * 2);
assert!(Agenda::<T>::iter().count() == 0);
// `service_task` when the task is a non-periodic, non-named, fetched call (with a known
// preimage length) and which is not dispatched (e.g. due to being overweight).
service_task_fetched {
let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32);
let now = BLOCK_NUMBER.into();
let task = make_task::<T>(false, false, false, Some(s), 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
}: {
let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
} verify {
}
on_initialize_named_aborted {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, false, true, None)?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), 0);
if let Some(delay) = T::NoPreimagePostponement::get() {
assert_eq!(Agenda::<T>::get(when + delay).len(), s as usize);
} else {
assert!(Agenda::<T>::iter().count() == 0);
}
// `service_task` when the task is a non-periodic, named, non-fetched call which is not
// dispatched (e.g. due to being overweight).
service_task_named {
let now = BLOCK_NUMBER.into();
let task = make_task::<T>(false, true, false, None, 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
}: {
let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
} verify {
}
on_initialize_aborted {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, false, false, None)?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), 0);
if let Some(delay) = T::NoPreimagePostponement::get() {
assert_eq!(Agenda::<T>::get(when + delay).len(), s as usize);
} else {
assert!(Agenda::<T>::iter().count() == 0);
}
// `service_task` when the task is a periodic, non-named, non-fetched call which is not
// dispatched (e.g. due to being overweight).
service_task_periodic {
let now = BLOCK_NUMBER.into();
let task = make_task::<T>(true, false, false, None, 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
}: {
let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
} verify {
}
on_initialize_periodic_named {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, true, true, Some(false))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
// `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight.
execute_dispatch_signed {
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };
let origin = make_origin::<T>(true);
let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;
}: {
assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());
}
verify {
assert_eq!(System::<T>::event_count(), s);
for i in 0..s {
assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
}
}
on_initialize_periodic {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, true, false, Some(false))?;
}: { Scheduler::<T>::on_initialize(when); }
verify {
assert_eq!(System::<T>::event_count(), s);
for i in 0..s {
assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
}
// `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight.
execute_dispatch_unsigned {
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };
let origin = make_origin::<T>(false);
let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;
}: {
assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());
}
on_initialize_named {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, false, true, Some(false))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), s);
assert!(Agenda::<T>::iter().count() == 0);
}
on_initialize {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, false, false, Some(false))?;
}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
verify {
assert_eq!(System::<T>::event_count(), s);
assert!(Agenda::<T>::iter().count() == 0);
}
schedule {
let s in 0 .. T::MaxScheduledPerBlock::get();
let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);
let when = BLOCK_NUMBER.into();
let periodic = Some((T::BlockNumber::one(), 100));
let priority = 0;
// Essentially a no-op call.
let inner_call = frame_system::Call::set_storage { items: vec![] }.into();
let call = Box::new(CallOrHashOf::<T>::Value(inner_call));
let call = Box::new(SystemCall::set_storage { items: vec![] }.into());
fill_schedule::<T>(when, s, true, true, Some(false))?;
let schedule_origin = T::ScheduleOrigin::successful_origin();
}: _<SystemOrigin<T>>(schedule_origin, when, periodic, priority, call)
fill_schedule::<T>(when, s)?;
}: _(RawOrigin::Root, when, periodic, priority, call)
verify {
ensure!(
Agenda::<T>::get(when).len() == (s + 1) as usize,
@@ -224,13 +242,13 @@ benchmarks! {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, true, true, Some(false))?;
fill_schedule::<T>(when, s)?;
assert_eq!(Agenda::<T>::get(when).len(), s as usize);
let schedule_origin = T::ScheduleOrigin::successful_origin();
}: _<SystemOrigin<T>>(schedule_origin, when, 0)
verify {
ensure!(
Lookup::<T>::get(0.encode()).is_none(),
Lookup::<T>::get(u32_to_name(0)).is_none(),
"didn't remove from lookup"
);
// Removed schedule is NONE
@@ -241,18 +259,16 @@ benchmarks! {
}
schedule_named {
let s in 0 .. T::MaxScheduledPerBlock::get();
let id = s.encode();
let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);
let id = u32_to_name(s);
let when = BLOCK_NUMBER.into();
let periodic = Some((T::BlockNumber::one(), 100));
let priority = 0;
// Essentially a no-op call.
let inner_call = frame_system::Call::set_storage { items: vec![] }.into();
let call = Box::new(CallOrHashOf::<T>::Value(inner_call));
let call = Box::new(SystemCall::set_storage { items: vec![] }.into());
fill_schedule::<T>(when, s, true, true, Some(false))?;
let schedule_origin = T::ScheduleOrigin::successful_origin();
}: _<SystemOrigin<T>>(schedule_origin, id, when, periodic, priority, call)
fill_schedule::<T>(when, s)?;
}: _(RawOrigin::Root, id, when, periodic, priority, call)
verify {
ensure!(
Agenda::<T>::get(when).len() == (s + 1) as usize,
@@ -264,12 +280,11 @@ benchmarks! {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
fill_schedule::<T>(when, s, true, true, Some(false))?;
let schedule_origin = T::ScheduleOrigin::successful_origin();
}: _<SystemOrigin<T>>(schedule_origin, 0.encode())
fill_schedule::<T>(when, s)?;
}: _(RawOrigin::Root, u32_to_name(0))
verify {
ensure!(
Lookup::<T>::get(0.encode()).is_none(),
Lookup::<T>::get(u32_to_name(0)).is_none(),
"didn't remove from lookup"
);
// Removed schedule is NONE
File diff suppressed because it is too large Load Diff
+402
View File
@@ -0,0 +1,402 @@
// 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.
//! Migrations for the scheduler pallet.
use super::*;
use frame_support::traits::OnRuntimeUpgrade;
/// The log target.
const TARGET: &'static str = "runtime::scheduler::migration";
pub mod v1 {
use super::*;
use frame_support::pallet_prelude::*;
#[frame_support::storage_alias]
pub(crate) type Agenda<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
<T as frame_system::Config>::BlockNumber,
Vec<
Option<
ScheduledV1<<T as Config>::RuntimeCall, <T as frame_system::Config>::BlockNumber>,
>,
>,
ValueQuery,
>;
#[frame_support::storage_alias]
pub(crate) type Lookup<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
Vec<u8>,
TaskAddress<<T as frame_system::Config>::BlockNumber>,
>;
}
pub mod v2 {
use super::*;
use frame_support::pallet_prelude::*;
#[frame_support::storage_alias]
pub(crate) type Agenda<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
<T as frame_system::Config>::BlockNumber,
Vec<Option<ScheduledV2Of<T>>>,
ValueQuery,
>;
#[frame_support::storage_alias]
pub(crate) type Lookup<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
Vec<u8>,
TaskAddress<<T as frame_system::Config>::BlockNumber>,
>;
}
pub mod v3 {
use super::*;
use frame_support::pallet_prelude::*;
#[frame_support::storage_alias]
pub(crate) type Agenda<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
<T as frame_system::Config>::BlockNumber,
Vec<Option<ScheduledV3Of<T>>>,
ValueQuery,
>;
#[frame_support::storage_alias]
pub(crate) type Lookup<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
Vec<u8>,
TaskAddress<<T as frame_system::Config>::BlockNumber>,
>;
/// Migrate the scheduler pallet from V3 to V4.
pub struct MigrateToV4<T>(sp_std::marker::PhantomData<T>);
impl<T: Config<Hash = PreimageHash>> OnRuntimeUpgrade for MigrateToV4<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 3, "Can only upgrade from version 3");
let agendas = Agenda::<T>::iter_keys().count() as u32;
let decodable_agendas = Agenda::<T>::iter_values().count() as u32;
if agendas != decodable_agendas {
// This is not necessarily an error, but can happen when there are Calls
// in an Agenda that are not valid anymore with the new runtime.
log::error!(
target: TARGET,
"Can only decode {} of {} agendas - others will be dropped",
decodable_agendas,
agendas
);
}
log::info!(target: TARGET, "Trying to migrate {} agendas...", decodable_agendas);
// Check that no agenda overflows `MaxScheduledPerBlock`.
let max_scheduled_per_block = T::MaxScheduledPerBlock::get() as usize;
for (block_number, agenda) in Agenda::<T>::iter() {
if agenda.iter().cloned().filter_map(|s| s).count() > max_scheduled_per_block {
log::error!(
target: TARGET,
"Would truncate agenda of block {:?} from {} items to {} items.",
block_number,
agenda.len(),
max_scheduled_per_block,
);
return Err("Agenda would overflow `MaxScheduledPerBlock`.")
}
}
// Check that bounding the calls will not overflow `MAX_LENGTH`.
let max_length = T::Preimages::MAX_LENGTH as usize;
for (block_number, agenda) in Agenda::<T>::iter() {
for schedule in agenda.iter().cloned().filter_map(|s| s) {
match schedule.call {
frame_support::traits::schedule::MaybeHashed::Value(call) => {
let l = call.using_encoded(|c| c.len());
if l > max_length {
log::error!(
target: TARGET,
"Call in agenda of block {:?} is too large: {} byte",
block_number,
l,
);
return Err("Call is too large.")
}
},
_ => (),
}
}
}
Ok((decodable_agendas as u32).encode())
}
fn on_runtime_upgrade() -> Weight {
let version = StorageVersion::get::<Pallet<T>>();
if version != 3 {
log::warn!(
target: TARGET,
"skipping v3 to v4 migration: executed on wrong storage version.\
Expected version 3, found {:?}",
version,
);
return T::DbWeight::get().reads(1)
}
crate::Pallet::<T>::migrate_v3_to_v4()
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
assert_eq!(StorageVersion::get::<Pallet<T>>(), 4, "Must upgrade");
// Check that everything decoded fine.
for k in crate::Agenda::<T>::iter_keys() {
assert!(crate::Agenda::<T>::try_get(k).is_ok(), "Cannot decode V4 Agenda");
}
let old_agendas: u32 =
Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
let new_agendas = crate::Agenda::<T>::iter_keys().count() as u32;
if old_agendas != new_agendas {
// This is not necessarily an error, but can happen when there are Calls
// in an Agenda that are not valid anymore in the new runtime.
log::error!(
target: TARGET,
"Did not migrate all Agendas. Previous {}, Now {}",
old_agendas,
new_agendas,
);
} else {
log::info!(target: TARGET, "Migrated {} agendas.", new_agendas);
}
Ok(())
}
}
}
#[cfg(test)]
#[cfg(feature = "try-runtime")]
mod test {
use super::*;
use crate::mock::*;
use frame_support::Hashable;
use sp_std::borrow::Cow;
use substrate_test_utils::assert_eq_uvec;
#[test]
#[allow(deprecated)]
fn migration_v3_to_v4_works() {
new_test_ext().execute_with(|| {
// Assume that we are at V3.
StorageVersion::new(3).put::<Scheduler>();
// Call that will be bounded to a `Lookup`.
let large_call =
RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1024] });
// Call that can be inlined.
let small_call =
RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 10] });
// Call that is already hashed and can will be converted to `Legacy`.
let hashed_call =
RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 2048] });
let bound_hashed_call = Preimage::bound(hashed_call.clone()).unwrap();
assert!(bound_hashed_call.lookup_needed());
// A Call by hash that will fail to decode becomes `None`.
let trash_data = vec![255u8; 1024];
let undecodable_hash = Preimage::note(Cow::Borrowed(&trash_data)).unwrap();
for i in 0..2u64 {
let k = i.twox_64_concat();
let old = vec![
Some(ScheduledV3Of::<Test> {
maybe_id: None,
priority: i as u8 + 10,
call: small_call.clone().into(),
maybe_periodic: None, // 1
origin: root(),
_phantom: PhantomData::<u64>::default(),
}),
None,
Some(ScheduledV3Of::<Test> {
maybe_id: Some(vec![i as u8; 32]),
priority: 123,
call: large_call.clone().into(),
maybe_periodic: Some((4u64, 20)),
origin: signed(i),
_phantom: PhantomData::<u64>::default(),
}),
Some(ScheduledV3Of::<Test> {
maybe_id: Some(vec![255 - i as u8; 320]),
priority: 123,
call: MaybeHashed::Hash(bound_hashed_call.hash()),
maybe_periodic: Some((8u64, 10)),
origin: signed(i),
_phantom: PhantomData::<u64>::default(),
}),
Some(ScheduledV3Of::<Test> {
maybe_id: Some(vec![i as u8; 320]),
priority: 123,
call: MaybeHashed::Hash(undecodable_hash.clone()),
maybe_periodic: Some((4u64, 20)),
origin: root(),
_phantom: PhantomData::<u64>::default(),
}),
];
frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);
}
let state = v3::MigrateToV4::<Test>::pre_upgrade().unwrap();
let _w = v3::MigrateToV4::<Test>::on_runtime_upgrade();
v3::MigrateToV4::<Test>::post_upgrade(state).unwrap();
let mut x = Agenda::<Test>::iter().map(|x| (x.0, x.1.into_inner())).collect::<Vec<_>>();
x.sort_by_key(|x| x.0);
let bound_large_call = Preimage::bound(large_call).unwrap();
assert!(bound_large_call.lookup_needed());
let bound_small_call = Preimage::bound(small_call).unwrap();
assert!(!bound_small_call.lookup_needed());
let expected = vec![
(
0,
vec![
Some(ScheduledOf::<Test> {
maybe_id: None,
priority: 10,
call: bound_small_call.clone(),
maybe_periodic: None,
origin: root(),
_phantom: PhantomData::<u64>::default(),
}),
None,
Some(ScheduledOf::<Test> {
maybe_id: Some(blake2_256(&[0u8; 32])),
priority: 123,
call: bound_large_call.clone(),
maybe_periodic: Some((4u64, 20)),
origin: signed(0),
_phantom: PhantomData::<u64>::default(),
}),
Some(ScheduledOf::<Test> {
maybe_id: Some(blake2_256(&[255u8; 320])),
priority: 123,
call: Bounded::from_legacy_hash(bound_hashed_call.hash()),
maybe_periodic: Some((8u64, 10)),
origin: signed(0),
_phantom: PhantomData::<u64>::default(),
}),
None,
],
),
(
1,
vec![
Some(ScheduledOf::<Test> {
maybe_id: None,
priority: 11,
call: bound_small_call.clone(),
maybe_periodic: None,
origin: root(),
_phantom: PhantomData::<u64>::default(),
}),
None,
Some(ScheduledOf::<Test> {
maybe_id: Some(blake2_256(&[1u8; 32])),
priority: 123,
call: bound_large_call.clone(),
maybe_periodic: Some((4u64, 20)),
origin: signed(1),
_phantom: PhantomData::<u64>::default(),
}),
Some(ScheduledOf::<Test> {
maybe_id: Some(blake2_256(&[254u8; 320])),
priority: 123,
call: Bounded::from_legacy_hash(bound_hashed_call.hash()),
maybe_periodic: Some((8u64, 10)),
origin: signed(1),
_phantom: PhantomData::<u64>::default(),
}),
None,
],
),
];
for (outer, (i, j)) in x.iter().zip(expected.iter()).enumerate() {
assert_eq!(i.0, j.0);
for (inner, (x, y)) in i.1.iter().zip(j.1.iter()).enumerate() {
assert_eq!(x, y, "at index: outer {} inner {}", outer, inner);
}
}
assert_eq_uvec!(x, expected);
assert_eq!(StorageVersion::get::<Scheduler>(), 4);
});
}
#[test]
#[allow(deprecated)]
fn migration_v3_to_v4_too_large_calls_are_ignored() {
new_test_ext().execute_with(|| {
// Assume that we are at V3.
StorageVersion::new(3).put::<Scheduler>();
let too_large_call = RuntimeCall::System(frame_system::Call::remark {
remark: vec![0; <Test as Config>::Preimages::MAX_LENGTH + 1],
});
let i = 0u64;
let k = i.twox_64_concat();
let old = vec![Some(ScheduledV3Of::<Test> {
maybe_id: None,
priority: 1,
call: too_large_call.clone().into(),
maybe_periodic: None,
origin: root(),
_phantom: PhantomData::<u64>::default(),
})];
frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);
// The pre_upgrade hook fails:
let err = v3::MigrateToV4::<Test>::pre_upgrade().unwrap_err();
assert!(err.contains("Call is too large"));
// But the migration itself works:
let _w = v3::MigrateToV4::<Test>::on_runtime_upgrade();
let mut x = Agenda::<Test>::iter().map(|x| (x.0, x.1.into_inner())).collect::<Vec<_>>();
x.sort_by_key(|x| x.0);
// The call becomes `None`.
let expected = vec![(0, vec![None])];
assert_eq_uvec!(x, expected);
assert_eq!(StorageVersion::get::<Scheduler>(), 4);
});
}
fn signed(i: u64) -> OriginCaller {
system::RawOrigin::Signed(i).into()
}
}
+47 -9
View File
@@ -124,7 +124,7 @@ parameter_types! {
}
impl system::Config for Test {
type BaseCallFilter = BaseFilter;
type BlockWeights = ();
type BlockWeights = BlockWeights;
type BlockLength = ();
type DbWeight = RocksDbWeight;
type RuntimeOrigin = RuntimeOrigin;
@@ -151,10 +151,6 @@ impl system::Config for Test {
impl logger::Config for Test {
type RuntimeEvent = RuntimeEvent;
}
parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;
pub const NoPreimagePostponement: Option<u64> = Some(2);
}
ord_parameter_types! {
pub const One: u64 = 1;
}
@@ -164,11 +160,54 @@ impl pallet_preimage::Config for Test {
type WeightInfo = ();
type Currency = ();
type ManagerOrigin = EnsureRoot<u64>;
type MaxSize = ConstU32<1024>;
type BaseDeposit = ();
type ByteDeposit = ();
}
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn service_agendas_base() -> Weight {
Weight::from_ref_time(0b0000_0001)
}
fn service_agenda_base(i: u32) -> Weight {
Weight::from_ref_time((i << 8) as u64 + 0b0000_0010)
}
fn service_task_base() -> Weight {
Weight::from_ref_time(0b0000_0100)
}
fn service_task_periodic() -> Weight {
Weight::from_ref_time(0b0000_1100)
}
fn service_task_named() -> Weight {
Weight::from_ref_time(0b0001_0100)
}
fn service_task_fetched(s: u32) -> Weight {
Weight::from_ref_time((s << 8) as u64 + 0b0010_0100)
}
fn execute_dispatch_signed() -> Weight {
Weight::from_ref_time(0b0100_0000)
}
fn execute_dispatch_unsigned() -> Weight {
Weight::from_ref_time(0b1000_0000)
}
fn schedule(_s: u32) -> Weight {
Weight::from_ref_time(50)
}
fn cancel(_s: u32) -> Weight {
Weight::from_ref_time(50)
}
fn schedule_named(_s: u32) -> Weight {
Weight::from_ref_time(50)
}
fn cancel_named(_s: u32) -> Weight {
Weight::from_ref_time(50)
}
}
parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
}
impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type RuntimeOrigin = RuntimeOrigin;
@@ -177,10 +216,9 @@ impl Config for Test {
type MaximumWeight = MaximumSchedulerWeight;
type ScheduleOrigin = EitherOfDiverse<EnsureRoot<u64>, EnsureSignedBy<One, u64>>;
type MaxScheduledPerBlock = ConstU32<10>;
type WeightInfo = ();
type WeightInfo = TestWeightInfo;
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type PreimageProvider = Preimage;
type NoPreimagePostponement = NoPreimagePostponement;
type Preimages = Preimage;
}
pub type LoggerCall = logger::Call<Test>;
File diff suppressed because it is too large Load Diff
+105 -235
View File
@@ -18,22 +18,24 @@
//! Autogenerated weights for pallet_scheduler
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/substrate
// /home/benchbot/cargo_target_dir/production/substrate
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet_scheduler
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --template=./.maintain/frame-weight-template.hbs
// --heap-pages=4096
// --pallet=pallet_scheduler
// --chain=dev
// --output=./frame/scheduler/src/weights.rs
// --template=./.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
@@ -44,16 +46,14 @@ use sp_std::marker::PhantomData;
/// Weight functions needed for pallet_scheduler.
pub trait WeightInfo {
fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight;
fn on_initialize_named_resolved(s: u32, ) -> Weight;
fn on_initialize_periodic_resolved(s: u32, ) -> Weight;
fn on_initialize_resolved(s: u32, ) -> Weight;
fn on_initialize_named_aborted(s: u32, ) -> Weight;
fn on_initialize_aborted(s: u32, ) -> Weight;
fn on_initialize_periodic_named(s: u32, ) -> Weight;
fn on_initialize_periodic(s: u32, ) -> Weight;
fn on_initialize_named(s: u32, ) -> Weight;
fn on_initialize(s: u32, ) -> Weight;
fn service_agendas_base() -> Weight;
fn service_agenda_base(s: u32, ) -> Weight;
fn service_task_base() -> Weight;
fn service_task_fetched(s: u32, ) -> Weight;
fn service_task_named() -> Weight;
fn service_task_periodic() -> Weight;
fn execute_dispatch_signed() -> Weight;
fn execute_dispatch_unsigned() -> Weight;
fn schedule(s: u32, ) -> Weight;
fn cancel(s: u32, ) -> Weight;
fn schedule_named(s: u32, ) -> Weight;
@@ -63,149 +63,84 @@ pub trait WeightInfo {
/// Weights for pallet_scheduler using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(9_994_000 as u64)
// Standard Error: 20_000
.saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64))
// Storage: Scheduler IncompleteSince (r:1 w:1)
fn service_agendas_base() -> Weight {
Weight::from_ref_time(4_992_000 as u64)
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[0, 512]`.
fn service_agenda_base(s: u32, ) -> Weight {
Weight::from_ref_time(4_320_000 as u64)
// Standard Error: 619
.saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
fn service_task_base() -> Weight {
Weight::from_ref_time(10_864_000 as u64)
}
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_named_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(10_318_000 as u64)
// Standard Error: 17_000
.saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
fn on_initialize_periodic_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(11_675_000 as u64)
// Standard Error: 17_000
.saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
fn on_initialize_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(11_934_000 as u64)
// Standard Error: 11_000
.saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:0)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_named_aborted(s: u32, ) -> Weight {
Weight::from_ref_time(7_279_000 as u64)
// Standard Error: 5_000
.saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64))
/// The range of component `s` is `[128, 4194304]`.
fn service_task_fetched(s: u32, ) -> Weight {
Weight::from_ref_time(24_586_000 as u64)
// Standard Error: 1
.saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(2 as u64))
.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:0)
fn on_initialize_aborted(s: u32, ) -> Weight {
Weight::from_ref_time(8_619_000 as u64)
// Standard Error: 4_000
.saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_periodic_named(s: u32, ) -> Weight {
Weight::from_ref_time(16_129_000 as u64)
// Standard Error: 7_000
.saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
fn service_task_named() -> Weight {
Weight::from_ref_time(13_127_000 as u64)
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
fn on_initialize_periodic(s: u32, ) -> Weight {
Weight::from_ref_time(15_785_000 as u64)
// Standard Error: 5_000
.saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_named(s: u32, ) -> Weight {
Weight::from_ref_time(15_778_000 as u64)
// Standard Error: 3_000
.saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
fn on_initialize(s: u32, ) -> Weight {
Weight::from_ref_time(15_912_000 as u64)
// Standard Error: 5_000
.saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
fn service_task_periodic() -> Weight {
Weight::from_ref_time(11_053_000 as u64)
}
fn execute_dispatch_signed() -> Weight {
Weight::from_ref_time(4_158_000 as u64)
}
fn execute_dispatch_unsigned() -> Weight {
Weight::from_ref_time(4_104_000 as u64)
}
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[0, 511]`.
fn schedule(s: u32, ) -> Weight {
Weight::from_ref_time(18_013_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(20_074_000 as u64)
// Standard Error: 765
.saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(1 as u64))
}
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
/// The range of component `s` is `[1, 512]`.
fn cancel(s: u32, ) -> Weight {
Weight::from_ref_time(18_131_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(21_509_000 as u64)
// Standard Error: 708
.saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(1 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[0, 511]`.
fn schedule_named(s: u32, ) -> Weight {
Weight::from_ref_time(21_230_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(22_427_000 as u64)
// Standard Error: 850
.saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[1, 512]`.
fn cancel_named(s: u32, ) -> Weight {
Weight::from_ref_time(20_139_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(22_875_000 as u64)
// Standard Error: 693
.saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64))
.saturating_add(T::DbWeight::get().reads(2 as u64))
.saturating_add(T::DbWeight::get().writes(2 as u64))
}
@@ -213,149 +148,84 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// For backwards compatibility and tests
impl WeightInfo for () {
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(9_994_000 as u64)
// Standard Error: 20_000
.saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64))
// Storage: Scheduler IncompleteSince (r:1 w:1)
fn service_agendas_base() -> Weight {
Weight::from_ref_time(4_992_000 as u64)
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[0, 512]`.
fn service_agenda_base(s: u32, ) -> Weight {
Weight::from_ref_time(4_320_000 as u64)
// Standard Error: 619
.saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
fn service_task_base() -> Weight {
Weight::from_ref_time(10_864_000 as u64)
}
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_named_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(10_318_000 as u64)
// Standard Error: 17_000
.saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
fn on_initialize_periodic_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(11_675_000 as u64)
// Standard Error: 17_000
.saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Preimage PreimageFor (r:1 w:1)
// Storage: Preimage StatusFor (r:1 w:1)
fn on_initialize_resolved(s: u32, ) -> Weight {
Weight::from_ref_time(11_934_000 as u64)
// Standard Error: 11_000
.saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:0)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_named_aborted(s: u32, ) -> Weight {
Weight::from_ref_time(7_279_000 as u64)
// Standard Error: 5_000
.saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64))
/// The range of component `s` is `[128, 4194304]`.
fn service_task_fetched(s: u32, ) -> Weight {
Weight::from_ref_time(24_586_000 as u64)
// Standard Error: 1
.saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Preimage PreimageFor (r:1 w:0)
fn on_initialize_aborted(s: u32, ) -> Weight {
Weight::from_ref_time(8_619_000 as u64)
// Standard Error: 4_000
.saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Scheduler Agenda (r:2 w:2)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_periodic_named(s: u32, ) -> Weight {
Weight::from_ref_time(16_129_000 as u64)
// Standard Error: 7_000
.saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
fn service_task_named() -> Weight {
Weight::from_ref_time(13_127_000 as u64)
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:2 w:2)
fn on_initialize_periodic(s: u32, ) -> Weight {
Weight::from_ref_time(15_785_000 as u64)
// Standard Error: 5_000
.saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
fn on_initialize_named(s: u32, ) -> Weight {
Weight::from_ref_time(15_778_000 as u64)
// Standard Error: 3_000
.saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
}
// Storage: Scheduler Agenda (r:1 w:1)
fn on_initialize(s: u32, ) -> Weight {
Weight::from_ref_time(15_912_000 as u64)
// Standard Error: 5_000
.saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
fn service_task_periodic() -> Weight {
Weight::from_ref_time(11_053_000 as u64)
}
fn execute_dispatch_signed() -> Weight {
Weight::from_ref_time(4_158_000 as u64)
}
fn execute_dispatch_unsigned() -> Weight {
Weight::from_ref_time(4_104_000 as u64)
}
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[0, 511]`.
fn schedule(s: u32, ) -> Weight {
Weight::from_ref_time(18_013_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(20_074_000 as u64)
// Standard Error: 765
.saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(1 as u64))
}
// Storage: Scheduler Agenda (r:1 w:1)
// Storage: Scheduler Lookup (r:0 w:1)
/// The range of component `s` is `[1, 512]`.
fn cancel(s: u32, ) -> Weight {
Weight::from_ref_time(18_131_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(21_509_000 as u64)
// Standard Error: 708
.saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(1 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[0, 511]`.
fn schedule_named(s: u32, ) -> Weight {
Weight::from_ref_time(21_230_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(22_427_000 as u64)
// Standard Error: 850
.saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
// Storage: Scheduler Lookup (r:1 w:1)
// Storage: Scheduler Agenda (r:1 w:1)
/// The range of component `s` is `[1, 512]`.
fn cancel_named(s: u32, ) -> Weight {
Weight::from_ref_time(20_139_000 as u64)
// Standard Error: 1_000
.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
Weight::from_ref_time(22_875_000 as u64)
// Standard Error: 693
.saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64))
.saturating_add(RocksDbWeight::get().reads(2 as u64))
.saturating_add(RocksDbWeight::get().writes(2 as u64))
}
@@ -169,6 +169,10 @@ pub fn expand_outer_origin(
&self.caller
}
fn into_caller(self) -> Self::PalletsOrigin {
self.caller
}
fn try_with_caller<R>(
mut self,
f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
@@ -190,13 +194,6 @@ pub fn expand_outer_origin(
fn signed(by: Self::AccountId) -> Self {
#system_path::RawOrigin::Signed(by).into()
}
fn as_signed(self) -> Option<Self::AccountId> {
match self.caller {
OriginCaller::system(#system_path::RawOrigin::Signed(by)) => Some(by),
_ => None,
}
}
}
#[derive(
@@ -215,7 +212,6 @@ pub fn expand_outer_origin(
// For backwards compatibility and ease of accessing these functions.
#[allow(dead_code)]
impl RuntimeOrigin {
#[doc = #doc_string_none_origin]
pub fn none() -> Self {
<RuntimeOrigin as #scrate::traits::OriginTrait>::none()
@@ -238,6 +234,21 @@ pub fn expand_outer_origin(
}
}
impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller {
fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> {
match self {
OriginCaller::system(x) => Some(x),
_ => None,
}
}
fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> {
match &self {
OriginCaller::system(o) => Some(o),
_ => None,
}
}
}
impl TryFrom<OriginCaller> for #system_path::Origin<#runtime> {
type Error = OriginCaller;
fn try_from(x: OriginCaller)
+19 -2
View File
@@ -3181,8 +3181,8 @@ mod tests {
dispatch::{DispatchClass, DispatchInfo, Pays},
metadata::*,
traits::{
CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize,
OnRuntimeUpgrade, PalletInfo,
CallerTrait, CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle,
OnInitialize, OnRuntimeUpgrade, PalletInfo,
},
};
use sp_weights::RuntimeDbWeight;
@@ -3300,6 +3300,16 @@ mod tests {
}
}
impl CallerTrait<<TraitImpl as system::Config>::AccountId> for OuterOrigin {
fn into_system(self) -> Option<RawOrigin<<TraitImpl as system::Config>::AccountId>> {
unimplemented!("Not required in tests!")
}
fn as_system_ref(&self) -> Option<&RawOrigin<<TraitImpl as system::Config>::AccountId>> {
unimplemented!("Not required in tests!")
}
}
impl crate::traits::OriginTrait for OuterOrigin {
type Call = <TraitImpl as system::Config>::RuntimeCall;
type PalletsOrigin = OuterOrigin;
@@ -3325,6 +3335,10 @@ mod tests {
unimplemented!("Not required in tests!")
}
fn into_caller(self) -> Self::PalletsOrigin {
unimplemented!("Not required in tests!")
}
fn try_with_caller<R>(
self,
_f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
@@ -3344,6 +3358,9 @@ mod tests {
fn as_signed(self) -> Option<Self::AccountId> {
unimplemented!("Not required in tests!")
}
fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
unimplemented!("Not required in tests!")
}
}
impl system::Config for TraitImpl {
+10 -5
View File
@@ -58,10 +58,11 @@ pub use misc::{
Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16,
ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly,
EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime,
IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider,
PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime,
WrapperKeepOpaque, WrapperOpaque,
IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp,
SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque,
};
#[allow(deprecated)]
pub use misc::{PreimageProvider, PreimageRecipient};
#[doc(hidden)]
pub use misc::{DEFENSIVE_OP_INTERNAL_ERROR, DEFENSIVE_OP_PUBLIC_ERROR};
@@ -96,8 +97,9 @@ mod dispatch;
#[allow(deprecated)]
pub use dispatch::EnsureOneOf;
pub use dispatch::{
AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg,
MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, UnfilteredDispatchable,
AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin,
EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess,
UnfilteredDispatchable,
};
mod voting;
@@ -106,6 +108,9 @@ pub use voting::{
U128CurrencyToVote, VoteTally,
};
mod preimages;
pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, StorePreimage};
#[cfg(feature = "try-runtime")]
mod try_runtime;
#[cfg(feature = "try-runtime")]
+31 -7
View File
@@ -236,17 +236,25 @@ pub trait UnfilteredDispatchable {
fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo;
}
/// The trait implemented by the overarching enumeration of the different pallets' origins.
/// Unlike `OriginTrait` impls, this does not include any kind of dispatch/call filter. Also, this
/// trait is more flexible in terms of how it can be used: it is a `Parameter` and `Member`, so it
/// can be used as dispatchable parameters as well as in storage items.
pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId>> {
/// Extract the signer from the message if it is a `Signed` origin.
fn into_system(self) -> Option<RawOrigin<AccountId>>;
/// Extract a reference to the system-level `RawOrigin` if it is that.
fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>;
}
/// Methods available on `frame_system::Config::RuntimeOrigin`.
pub trait OriginTrait: Sized {
/// Runtime call type, as in `frame_system::Config::Call`
type Call;
/// The caller origin, overarching type of all pallets origins.
type PalletsOrigin: Parameter
+ Member
+ Into<Self>
+ From<RawOrigin<Self::AccountId>>
+ MaxEncodedLen;
type PalletsOrigin: Into<Self> + CallerTrait<Self::AccountId> + MaxEncodedLen;
/// The AccountId used across the system.
type AccountId;
@@ -266,9 +274,12 @@ pub trait OriginTrait: Sized {
/// For root origin caller, the filters are bypassed and true is returned.
fn filter_call(&self, call: &Self::Call) -> bool;
/// Get the caller.
/// Get a reference to the caller (`CallerTrait` impl).
fn caller(&self) -> &Self::PalletsOrigin;
/// Consume `self` and return the caller.
fn into_caller(self) -> Self::PalletsOrigin;
/// Do something with the caller, consuming self but returning it if the caller was unused.
fn try_with_caller<R>(
self,
@@ -285,7 +296,20 @@ pub trait OriginTrait: Sized {
fn signed(by: Self::AccountId) -> Self;
/// Extract the signer from the message if it is a `Signed` origin.
fn as_signed(self) -> Option<Self::AccountId>;
fn as_signed(self) -> Option<Self::AccountId> {
self.into_caller().into_system().and_then(|s| {
if let RawOrigin::Signed(who) = s {
Some(who)
} else {
None
}
})
}
/// Extract a reference to the sytsem origin, if that's what the caller is.
fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
self.caller().as_system_ref()
}
}
#[cfg(test)]
+1 -1
View File
@@ -932,7 +932,7 @@ pub trait PreimageRecipient<Hash>: PreimageProvider<Hash> {
/// Maximum size of a preimage.
type MaxSize: Get<u32>;
/// Store the bytes of a preimage on chain.
/// Store the bytes of a preimage on chain infallible due to the bounded type.
fn note_preimage(bytes: crate::BoundedVec<u8, Self::MaxSize>);
/// Clear a previously noted preimage. This is infallible and should be treated more like a
@@ -0,0 +1,317 @@
// This file is part of Substrate.
// Copyright (C) 2019-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.
//! Stuff for dealing with 32-byte hashed preimages.
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use sp_core::{RuntimeDebug, H256};
use sp_io::hashing::blake2_256;
use sp_runtime::{traits::ConstU32, DispatchError};
use sp_std::borrow::Cow;
pub type Hash = H256;
pub type BoundedInline = crate::BoundedVec<u8, ConstU32<128>>;
#[derive(
Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug,
)]
#[codec(mel_bound())]
pub enum Bounded<T> {
/// A Blake2 256 hash with no preimage length. We
/// do not support creation of this except for transitioning from legacy state.
/// In the future we will make this a pure `Dummy` item storing only the final `dummy` field.
Legacy { hash: Hash, dummy: sp_std::marker::PhantomData<T> },
/// A an bounded `Call`. Its encoding must be at most 128 bytes.
Inline(BoundedInline),
/// A Blake2-256 hash of the call together with an upper limit for its size.
Lookup { hash: Hash, len: u32 },
}
impl<T> Bounded<T> {
/// Casts the wrapped type into something that encodes alike.
///
/// # Examples
/// ```
/// use frame_support::traits::Bounded;
///
/// // Transmute from `String` to `&str`.
/// let x: Bounded<String> = Bounded::Inline(Default::default());
/// let _: Bounded<&str> = x.transmute();
/// ```
pub fn transmute<S: Encode>(self) -> Bounded<S>
where
T: Encode + EncodeLike<S>,
{
use Bounded::*;
match self {
Legacy { hash, .. } => Legacy { hash, dummy: sp_std::marker::PhantomData },
Inline(x) => Inline(x),
Lookup { hash, len } => Lookup { hash, len },
}
}
/// Returns the hash of the preimage.
///
/// The hash is re-calculated every time if the preimage is inlined.
pub fn hash(&self) -> H256 {
use Bounded::*;
match self {
Legacy { hash, .. } => *hash,
Inline(x) => blake2_256(x.as_ref()).into(),
Lookup { hash, .. } => *hash,
}
}
}
// The maximum we expect a single legacy hash lookup to be.
const MAX_LEGACY_LEN: u32 = 1_000_000;
impl<T> Bounded<T> {
/// Returns the length of the preimage or `None` if the length is unknown.
pub fn len(&self) -> Option<u32> {
match self {
Self::Legacy { .. } => None,
Self::Inline(i) => Some(i.len() as u32),
Self::Lookup { len, .. } => Some(*len),
}
}
/// Returns whether the image will require a lookup to be peeked.
pub fn lookup_needed(&self) -> bool {
match self {
Self::Inline(..) => false,
Self::Legacy { .. } | Self::Lookup { .. } => true,
}
}
/// The maximum length of the lookup that is needed to peek `Self`.
pub fn lookup_len(&self) -> Option<u32> {
match self {
Self::Inline(..) => None,
Self::Legacy { .. } => Some(MAX_LEGACY_LEN),
Self::Lookup { len, .. } => Some(*len),
}
}
/// Constructs a `Lookup` bounded item.
pub fn unrequested(hash: Hash, len: u32) -> Self {
Self::Lookup { hash, len }
}
/// Constructs a `Legacy` bounded item.
#[deprecated = "This API is only for transitioning to Scheduler v3 API"]
pub fn from_legacy_hash(hash: impl Into<Hash>) -> Self {
Self::Legacy { hash: hash.into(), dummy: sp_std::marker::PhantomData }
}
}
pub type FetchResult = Result<Cow<'static, [u8]>, DispatchError>;
/// A interface for looking up preimages from their hash on chain.
pub trait QueryPreimage {
/// Returns whether a preimage exists for a given hash and if so its length.
fn len(hash: &Hash) -> Option<u32>;
/// Returns the preimage for a given hash. If given, `len` must be the size of the preimage.
fn fetch(hash: &Hash, len: Option<u32>) -> FetchResult;
/// Returns whether a preimage request exists for a given hash.
fn is_requested(hash: &Hash) -> bool;
/// Request that someone report a preimage. Providers use this to optimise the economics for
/// preimage reporting.
fn request(hash: &Hash);
/// Cancel a previous preimage request.
fn unrequest(hash: &Hash);
/// Request that the data required for decoding the given `bounded` value is made available.
fn hold<T>(bounded: &Bounded<T>) {
use Bounded::*;
match bounded {
Inline(..) => {},
Legacy { hash, .. } | Lookup { hash, .. } => Self::request(hash),
}
}
/// No longer request that the data required for decoding the given `bounded` value is made
/// available.
fn drop<T>(bounded: &Bounded<T>) {
use Bounded::*;
match bounded {
Inline(..) => {},
Legacy { hash, .. } | Lookup { hash, .. } => Self::unrequest(hash),
}
}
/// Check to see if all data required for the given `bounded` value is available for its
/// decoding.
fn have<T>(bounded: &Bounded<T>) -> bool {
use Bounded::*;
match bounded {
Inline(..) => true,
Legacy { hash, .. } | Lookup { hash, .. } => Self::len(hash).is_some(),
}
}
/// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. This may not
/// be `peek`-able or `realize`-able.
fn pick<T>(hash: Hash, len: u32) -> Bounded<T> {
Self::request(&hash);
Bounded::Lookup { hash, len }
}
/// Convert the given `bounded` instance back into its original instance, also returning the
/// exact size of its encoded form if it needed to be looked-up from a stored preimage).
///
/// NOTE: This does not remove any data needed for realization. If you will no longer use the
/// `bounded`, call `realize` instead or call `drop` afterwards.
fn peek<T: Decode>(bounded: &Bounded<T>) -> Result<(T, Option<u32>), DispatchError> {
use Bounded::*;
match bounded {
Inline(data) => T::decode(&mut &data[..]).ok().map(|x| (x, None)),
Lookup { hash, len } => {
let data = Self::fetch(hash, Some(*len))?;
T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32)))
},
Legacy { hash, .. } => {
let data = Self::fetch(hash, None)?;
T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32)))
},
}
.ok_or(DispatchError::Corruption)
}
/// Convert the given `bounded` value back into its original instance. If successful,
/// `drop` any data backing it. This will not break the realisability of independently
/// created instances of `Bounded` which happen to have identical data.
fn realize<T: Decode>(bounded: &Bounded<T>) -> Result<(T, Option<u32>), DispatchError> {
let r = Self::peek(bounded)?;
Self::drop(bounded);
Ok(r)
}
}
/// A interface for managing preimages to hashes on chain.
///
/// Note that this API does not assume any underlying user is calling, and thus
/// does not handle any preimage ownership or fees. Other system level logic that
/// uses this API should implement that on their own side.
pub trait StorePreimage: QueryPreimage {
/// The maximum length of preimage we can store.
///
/// This is the maximum length of the *encoded* value that can be passed to `bound`.
const MAX_LENGTH: usize;
/// Request and attempt to store the bytes of a preimage on chain.
///
/// May return `DispatchError::Exhausted` if the preimage is just too big.
fn note(bytes: Cow<[u8]>) -> Result<Hash, DispatchError>;
/// Attempt to clear a previously noted preimage. Exactly the same as `unrequest` but is
/// provided for symmetry.
fn unnote(hash: &Hash) {
Self::unrequest(hash)
}
/// Convert an otherwise unbounded or large value into a type ready for placing in storage. The
/// result is a type whose `MaxEncodedLen` is 131 bytes.
///
/// NOTE: Once this API is used, you should use either `drop` or `realize`.
fn bound<T: Encode>(t: T) -> Result<Bounded<T>, DispatchError> {
let data = t.encode();
let len = data.len() as u32;
Ok(match BoundedInline::try_from(data) {
Ok(bounded) => Bounded::Inline(bounded),
Err(unbounded) => Bounded::Lookup { hash: Self::note(unbounded.into())?, len },
})
}
}
impl QueryPreimage for () {
fn len(_: &Hash) -> Option<u32> {
None
}
fn fetch(_: &Hash, _: Option<u32>) -> FetchResult {
Err(DispatchError::Unavailable)
}
fn is_requested(_: &Hash) -> bool {
false
}
fn request(_: &Hash) {}
fn unrequest(_: &Hash) {}
}
impl StorePreimage for () {
const MAX_LENGTH: usize = 0;
fn note(_: Cow<[u8]>) -> Result<Hash, DispatchError> {
Err(DispatchError::Exhausted)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{bounded_vec, BoundedVec};
#[test]
fn bounded_size_is_correct() {
assert_eq!(<Bounded<Vec<u8>> as MaxEncodedLen>::max_encoded_len(), 131);
}
#[test]
fn bounded_basic_works() {
let data: BoundedVec<u8, _> = bounded_vec![b'a', b'b', b'c'];
let len = data.len() as u32;
let hash = blake2_256(&data).into();
// Inline works
{
let bound: Bounded<Vec<u8>> = Bounded::Inline(data.clone());
assert_eq!(bound.hash(), hash);
assert_eq!(bound.len(), Some(len));
assert!(!bound.lookup_needed());
assert_eq!(bound.lookup_len(), None);
}
// Legacy works
{
let bound: Bounded<Vec<u8>> = Bounded::Legacy { hash, dummy: Default::default() };
assert_eq!(bound.hash(), hash);
assert_eq!(bound.len(), None);
assert!(bound.lookup_needed());
assert_eq!(bound.lookup_len(), Some(1_000_000));
}
// Lookup works
{
let bound: Bounded<Vec<u8>> = Bounded::Lookup { hash, len: data.len() as u32 };
assert_eq!(bound.hash(), hash);
assert_eq!(bound.len(), Some(len));
assert!(bound.lookup_needed());
assert_eq!(bound.lookup_len(), Some(len));
}
}
#[test]
fn bounded_transmuting_works() {
let data: BoundedVec<u8, _> = bounded_vec![b'a', b'b', b'c'];
// Transmute a `String` into a `&str`.
let x: Bounded<String> = Bounded::Inline(data.clone());
let y: Bounded<&str> = x.transmute();
assert_eq!(y, Bounded::Inline(data));
}
}
+97 -2
View File
@@ -17,6 +17,8 @@
//! Traits and associated utilities for scheduling dispatchables in FRAME.
#[allow(deprecated)]
use super::PreimageProvider;
use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{traits::Saturating, DispatchError, RuntimeDebug};
@@ -128,6 +130,7 @@ impl<T: Decode, H> MaybeHashed<T, H> {
}
}
// TODO: deprecate
pub mod v1 {
use super::*;
@@ -283,6 +286,7 @@ pub mod v1 {
}
}
// TODO: deprecate
pub mod v2 {
use super::*;
@@ -375,6 +379,97 @@ pub mod v2 {
}
}
pub use v1::*;
pub mod v3 {
use super::*;
use crate::traits::Bounded;
use super::PreimageProvider;
/// A type that can be used as a scheduler.
pub trait Anon<BlockNumber, Call, Origin> {
/// An address which can be used for removing a scheduled task.
type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + Debug + TypeInfo;
/// Schedule a dispatch to happen at the beginning of some block in the future.
///
/// This is not named.
fn schedule(
when: DispatchTime<BlockNumber>,
maybe_periodic: Option<Period<BlockNumber>>,
priority: Priority,
origin: Origin,
call: Bounded<Call>,
) -> Result<Self::Address, DispatchError>;
/// Cancel a scheduled task. If periodic, then it will cancel all further instances of that,
/// also.
///
/// Will return an `Unavailable` error if the `address` is invalid.
///
/// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
/// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
///
/// NOTE2: This will not work to cancel periodic tasks after their initial execution. For
/// that, you must name the task explicitly using the `Named` trait.
fn cancel(address: Self::Address) -> Result<(), DispatchError>;
/// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
/// only if it is executed *before* the currently scheduled block. For periodic tasks,
/// this dispatch is guaranteed to succeed only before the *initial* execution; for
/// others, use `reschedule_named`.
///
/// Will return an `Unavailable` error if the `address` is invalid.
fn reschedule(
address: Self::Address,
when: DispatchTime<BlockNumber>,
) -> Result<Self::Address, DispatchError>;
/// Return the next dispatch time for a given task.
///
/// Will return an `Unavailable` error if the `address` is invalid.
fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, DispatchError>;
}
pub type TaskName = [u8; 32];
/// A type that can be used as a scheduler.
pub trait Named<BlockNumber, Call, Origin> {
/// An address which can be used for removing a scheduled task.
type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + sp_std::fmt::Debug;
/// Schedule a dispatch to happen at the beginning of some block in the future.
///
/// - `id`: The identity of the task. This must be unique and will return an error if not.
fn schedule_named(
id: TaskName,
when: DispatchTime<BlockNumber>,
maybe_periodic: Option<Period<BlockNumber>>,
priority: Priority,
origin: Origin,
call: Bounded<Call>,
) -> Result<Self::Address, DispatchError>;
/// Cancel a scheduled, named task. If periodic, then it will cancel all further instances
/// of that, also.
///
/// Will return an `Unavailable` error if the `id` is invalid.
///
/// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
/// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
fn cancel_named(id: TaskName) -> Result<(), DispatchError>;
/// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
/// only if it is executed *before* the currently scheduled block.
///
/// Will return an `Unavailable` error if the `id` is invalid.
fn reschedule_named(
id: TaskName,
when: DispatchTime<BlockNumber>,
) -> Result<Self::Address, DispatchError>;
/// Return the next dispatch time for a given task.
///
/// Will return an `Unavailable` error if the `id` is invalid.
fn next_dispatch_time(id: TaskName) -> Result<BlockNumber, DispatchError>;
}
}
pub use v1::*;
@@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
<&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
<&[(T,)] as EncodeLike<LinkedList<LikeT>>>
<&[T] as EncodeLike<Vec<U>>>
and 279 others
and 280 others
= note: required because of the requirements on the impl of `FullEncode` for `Bar`
= note: required because of the requirements on the impl of `FullCodec` for `Bar`
= note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
and 160 others
and 161 others
= note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar`
= note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
<&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
<&[(T,)] as EncodeLike<LinkedList<LikeT>>>
<&[T] as EncodeLike<Vec<U>>>
and 279 others
and 280 others
= note: required because of the requirements on the impl of `FullEncode` for `Bar`
= note: required because of the requirements on the impl of `FullCodec` for `Bar`
= note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
<&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
<&[(T,)] as EncodeLike<LinkedList<LikeT>>>
<&[T] as EncodeLike<Vec<U>>>
and 279 others
and 280 others
= note: required because of the requirements on the impl of `FullEncode` for `Bar`
= note: required because of the requirements on the impl of `FullCodec` for `Bar`
= note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
and 160 others
and 161 others
= note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar`
= note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
<&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
<&[(T,)] as EncodeLike<LinkedList<LikeT>>>
<&[T] as EncodeLike<Vec<U>>>
and 279 others
and 280 others
= note: required because of the requirements on the impl of `FullEncode` for `Bar`
= note: required because of the requirements on the impl of `FullCodec` for `Bar`
= note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and 77 others
and 78 others
= note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and 77 others
and 78 others
= note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key<frame_support::Twox64Concat, Bar>`
= note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo<T>, Key<frame_support::Twox64Concat, Bar>, u32>`
+4 -1
View File
@@ -222,7 +222,10 @@ pub mod pallet {
+ OriginTrait<Call = Self::RuntimeCall>;
/// The aggregated `RuntimeCall` type.
type RuntimeCall: Dispatchable + Debug;
type RuntimeCall: Parameter
+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ Debug
+ From<Call<Self>>;
/// Account index (aka nonce) type. This stores the number of previous transactions
/// associated with a sender account.
-1
View File
@@ -96,7 +96,6 @@ impl pallet_preimage::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type ManagerOrigin = EnsureRoot<Self::AccountId>;
type MaxSize = ConstU32<{ 4096 * 1024 }>; // PreimageMaxSize Taken from Polkadot as reference.
type BaseDeposit = ConstU64<1>;
type ByteDeposit = ConstU64<1>;
type WeightInfo = ();
@@ -276,6 +276,14 @@ impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> {
}
}
impl<'a, T, S: Get<u32>> BoundedSlice<'a, T, S> {
/// Create an instance from the first elements of the given slice (or all of it if it is smaller
/// than the length bound).
pub fn truncate_from(s: &'a [T]) -> Self {
Self(&s[0..(s.len().min(S::get() as usize))], PhantomData)
}
}
impl<T: Decode, S: Get<u32>> Decode for BoundedVec<T, S> {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
let inner = Vec::<T>::decode(input)?;
@@ -620,12 +628,12 @@ impl<T, S: Get<u32>> BoundedVec<T, S> {
/// # Panics
///
/// Panics if `index > len`.
pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> {
pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), T> {
if self.len() < Self::bound() {
self.0.insert(index, element);
Ok(())
} else {
Err(())
Err(element)
}
}
@@ -635,12 +643,12 @@ impl<T, S: Get<u32>> BoundedVec<T, S> {
/// # Panics
///
/// Panics if the new capacity exceeds isize::MAX bytes.
pub fn try_push(&mut self, element: T) -> Result<(), ()> {
pub fn try_push(&mut self, element: T) -> Result<(), T> {
if self.len() < Self::bound() {
self.0.push(element);
Ok(())
} else {
Err(())
Err(element)
}
}
}
@@ -673,13 +681,13 @@ where
}
impl<T, S: Get<u32>> TryFrom<Vec<T>> for BoundedVec<T, S> {
type Error = ();
type Error = Vec<T>;
fn try_from(t: Vec<T>) -> Result<Self, Self::Error> {
if t.len() <= Self::bound() {
// explicit check just above
Ok(Self::unchecked_from(t))
} else {
Err(())
Err(t)
}
}
}
@@ -886,6 +894,16 @@ pub mod test {
use super::*;
use crate::{bounded_vec, ConstU32};
#[test]
fn slice_truncate_from_works() {
let bounded = BoundedSlice::<u32, ConstU32<4>>::truncate_from(&[1, 2, 3, 4, 5]);
assert_eq!(bounded.deref(), &[1, 2, 3, 4]);
let bounded = BoundedSlice::<u32, ConstU32<4>>::truncate_from(&[1, 2, 3, 4]);
assert_eq!(bounded.deref(), &[1, 2, 3, 4]);
let bounded = BoundedSlice::<u32, ConstU32<4>>::truncate_from(&[1, 2, 3]);
assert_eq!(bounded.deref(), &[1, 2, 3]);
}
#[test]
fn slide_works() {
let mut b: BoundedVec<u32, ConstU32<6>> = bounded_vec![0, 1, 2, 3, 4, 5];
+34 -21
View File
@@ -547,6 +547,12 @@ pub enum DispatchError {
/// The number of transactional layers has been reached, or we are not in a transactional
/// layer.
Transactional(TransactionalError),
/// Resources exhausted, e.g. attempt to read/write data which is too large to manipulate.
Exhausted,
/// The state is corrupt; this is generally not going to fix itself.
Corruption,
/// Some resource (e.g. a preimage) is unavailable right now. This might fix itself later.
Unavailable,
}
/// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about
@@ -671,18 +677,21 @@ impl From<&'static str> for DispatchError {
impl From<DispatchError> for &'static str {
fn from(err: DispatchError) -> &'static str {
use DispatchError::*;
match err {
DispatchError::Other(msg) => msg,
DispatchError::CannotLookup => "Cannot lookup",
DispatchError::BadOrigin => "Bad origin",
DispatchError::Module(ModuleError { message, .. }) =>
message.unwrap_or("Unknown module error"),
DispatchError::ConsumerRemaining => "Consumer remaining",
DispatchError::NoProviders => "No providers",
DispatchError::TooManyConsumers => "Too many consumers",
DispatchError::Token(e) => e.into(),
DispatchError::Arithmetic(e) => e.into(),
DispatchError::Transactional(e) => e.into(),
Other(msg) => msg,
CannotLookup => "Cannot lookup",
BadOrigin => "Bad origin",
Module(ModuleError { message, .. }) => message.unwrap_or("Unknown module error"),
ConsumerRemaining => "Consumer remaining",
NoProviders => "No providers",
TooManyConsumers => "Too many consumers",
Token(e) => e.into(),
Arithmetic(e) => e.into(),
Transactional(e) => e.into(),
Exhausted => "Resources exhausted",
Corruption => "State corrupt",
Unavailable => "Resource unavailable",
}
}
}
@@ -698,33 +707,37 @@ where
impl traits::Printable for DispatchError {
fn print(&self) {
use DispatchError::*;
"DispatchError".print();
match self {
Self::Other(err) => err.print(),
Self::CannotLookup => "Cannot lookup".print(),
Self::BadOrigin => "Bad origin".print(),
Self::Module(ModuleError { index, error, message }) => {
Other(err) => err.print(),
CannotLookup => "Cannot lookup".print(),
BadOrigin => "Bad origin".print(),
Module(ModuleError { index, error, message }) => {
index.print();
error.print();
if let Some(msg) = message {
msg.print();
}
},
Self::ConsumerRemaining => "Consumer remaining".print(),
Self::NoProviders => "No providers".print(),
Self::TooManyConsumers => "Too many consumers".print(),
Self::Token(e) => {
ConsumerRemaining => "Consumer remaining".print(),
NoProviders => "No providers".print(),
TooManyConsumers => "Too many consumers".print(),
Token(e) => {
"Token error: ".print();
<&'static str>::from(*e).print();
},
Self::Arithmetic(e) => {
Arithmetic(e) => {
"Arithmetic error: ".print();
<&'static str>::from(*e).print();
},
Self::Transactional(e) => {
Transactional(e) => {
"Transactional error: ".print();
<&'static str>::from(*e).print();
},
Exhausted => "Resources exhausted".print(),
Corruption => "State corrupt".print(),
Unavailable => "Resource unavailable".print(),
}
}
}
+30 -5
View File
@@ -37,8 +37,9 @@ use trie_db::{Trie, TrieMut};
use cfg_if::cfg_if;
use frame_support::{
dispatch::RawOrigin,
parameter_types,
traits::{ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem},
traits::{CallerTrait, ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem},
weights::{RuntimeDbWeight, Weight},
};
use frame_system::limits::{BlockLength, BlockWeights};
@@ -119,7 +120,7 @@ pub fn native_version() -> NativeVersion {
}
/// Calls in transactions.
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct Transfer {
pub from: AccountId,
pub to: AccountId,
@@ -150,7 +151,7 @@ impl Transfer {
}
/// Extrinsic for test-runtime.
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum Extrinsic {
AuthoritiesChange(Vec<AuthorityId>),
Transfer {
@@ -446,11 +447,22 @@ impl GetRuntimeBlockType for Runtime {
#[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
pub struct RuntimeOrigin;
impl From<frame_system::Origin<Runtime>> for RuntimeOrigin {
fn from(_o: frame_system::Origin<Runtime>) -> Self {
impl From<RawOrigin<<Runtime as frame_system::Config>::AccountId>> for RuntimeOrigin {
fn from(_: RawOrigin<<Runtime as frame_system::Config>::AccountId>) -> Self {
unimplemented!("Not required in tests!")
}
}
impl CallerTrait<<Runtime as frame_system::Config>::AccountId> for RuntimeOrigin {
fn into_system(self) -> Option<RawOrigin<<Runtime as frame_system::Config>::AccountId>> {
unimplemented!("Not required in tests!")
}
fn as_system_ref(&self) -> Option<&RawOrigin<<Runtime as frame_system::Config>::AccountId>> {
unimplemented!("Not required in tests!")
}
}
impl From<RuntimeOrigin> for Result<frame_system::Origin<Runtime>, RuntimeOrigin> {
fn from(_origin: RuntimeOrigin) -> Result<frame_system::Origin<Runtime>, RuntimeOrigin> {
unimplemented!("Not required in tests!")
@@ -482,6 +494,10 @@ impl frame_support::traits::OriginTrait for RuntimeOrigin {
unimplemented!("Not required in tests!")
}
fn into_caller(self) -> Self::PalletsOrigin {
unimplemented!("Not required in tests!")
}
fn try_with_caller<R>(
self,
_f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
@@ -501,6 +517,9 @@ impl frame_support::traits::OriginTrait for RuntimeOrigin {
fn as_signed(self) -> Option<Self::AccountId> {
unimplemented!("Not required in tests!")
}
fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
unimplemented!("Not required in tests!")
}
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)]
@@ -583,6 +602,12 @@ parameter_types! {
BlockWeights::with_sensible_defaults(Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75));
}
impl From<frame_system::Call<Runtime>> for Extrinsic {
fn from(_: frame_system::Call<Runtime>) -> Self {
unimplemented!("Not required in tests!")
}
}
impl frame_system::Config for Runtime {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = RuntimeBlockWeights;