use super::*;
use crate::Pallet as Collective;
use core::mem::size_of;
use sp_runtime::traits::Bounded;
use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller};
use frame_system::{
pallet_prelude::BlockNumberFor, Call as SystemCall, Pallet as System, RawOrigin as SystemOrigin,
};
const SEED: u32 = 0;
const MAX_BYTES: u32 = 1_024;
fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) {
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
}
fn id_to_remark_data(id: u32, length: usize) -> Vec<u8> {
id.to_le_bytes().into_iter().cycle().take(length).collect()
}
benchmarks_instance_pallet! {
set_members {
let m in 0 .. T::MaxMembers::get();
let n in 0 .. T::MaxMembers::get();
let p in 0 .. T::MaxProposals::get();
let mut old_members = vec![];
for i in 0 .. m {
let old_member = account::<T::AccountId>("old member", i, SEED);
old_members.push(old_member);
}
let old_members_count = old_members.len() as u32;
Collective::<T, I>::set_members(
SystemOrigin::Root.into(),
old_members.clone(),
old_members.last().cloned(),
T::MaxMembers::get(),
)?;
if m > 0 {
let threshold = m.max(2);
let length = 100;
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, length) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(old_members.last().unwrap().clone()).into(),
threshold,
Box::new(proposal.clone()),
MAX_BYTES,
)?;
let hash = T::Hashing::hash_of(&proposal);
for j in 2 .. m - 1 {
let voter = &old_members[j as usize];
let approve = true;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
hash,
i,
approve,
)?;
}
}
}
let mut new_members = vec![];
for i in 0 .. n {
let member = account::<T::AccountId>("member", i, SEED);
new_members.push(member);
}
}: _(SystemOrigin::Root, new_members.clone(), new_members.last().cloned(), T::MaxMembers::get())
verify {
new_members.sort();
assert_eq!(Members::<T, I>::get(), new_members);
}
execute {
let b in 2 .. MAX_BYTES;
let m in 1 .. T::MaxMembers::get();
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone());
Collective::<T, I>::set_members(SystemOrigin::Root.into(), members, None, T::MaxMembers::get())?;
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(1, b as usize) }.into();
}: _(SystemOrigin::Signed(caller), Box::new(proposal.clone()), bytes_in_storage)
verify {
let proposal_hash = T::Hashing::hash_of(&proposal);
assert_last_event::<T, I>(
Event::MemberExecuted { proposal_hash, result: Ok(()) }.into()
);
}
propose_execute {
let b in 2 .. MAX_BYTES;
let m in 1 .. T::MaxMembers::get();
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone());
Collective::<T, I>::set_members(SystemOrigin::Root.into(), members, None, T::MaxMembers::get())?;
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(1, b as usize) }.into();
let threshold = 1;
}: propose(SystemOrigin::Signed(caller), threshold, Box::new(proposal.clone()), bytes_in_storage)
verify {
let proposal_hash = T::Hashing::hash_of(&proposal);
assert_last_event::<T, I>(
Event::Executed { proposal_hash, result: Ok(()) }.into()
);
}
propose_proposed {
let b in 2 .. MAX_BYTES;
let m in 2 .. T::MaxMembers::get();
let p in 1 .. T::MaxProposals::get();
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone());
Collective::<T, I>::set_members(SystemOrigin::Root.into(), members, None, T::MaxMembers::get())?;
let threshold = m;
for i in 0 .. p - 1 {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, b as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(caller.clone()).into(),
threshold,
Box::new(proposal),
bytes_in_storage,
)?;
}
assert_eq!(Proposals::<T, I>::get().len(), (p - 1) as usize);
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(p, b as usize) }.into();
}: propose(SystemOrigin::Signed(caller.clone()), threshold, Box::new(proposal.clone()), bytes_in_storage)
verify {
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
let proposal_hash = T::Hashing::hash_of(&proposal);
assert_last_event::<T, I>(Event::Proposed { account: caller, proposal_index: p - 1, proposal_hash, threshold }.into());
}
vote {
let m in 5 .. T::MaxMembers::get();
let p = T::MaxProposals::get();
let b = MAX_BYTES;
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
let proposer: T::AccountId = account::<T::AccountId>("proposer", 0, SEED);
members.push(proposer.clone());
for i in 1 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let voter: T::AccountId = account::<T::AccountId>("voter", 0, SEED);
members.push(voter.clone());
Collective::<T, I>::set_members(SystemOrigin::Root.into(), members.clone(), None, T::MaxMembers::get())?;
let threshold = m - 1;
let mut last_hash = T::Hash::default();
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, b as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(proposer.clone()).into(),
threshold,
Box::new(proposal.clone()),
bytes_in_storage,
)?;
last_hash = T::Hashing::hash_of(&proposal);
}
let index = p - 1;
for j in 0 .. m - 3 {
let voter = &members[j as usize];
let approve = true;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
index,
approve,
)?;
}
let approve = true;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
index,
approve,
)?;
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
let approve = false;
let voter_key = frame_system::Account::<T>::hashed_key_for(&voter);
frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into());
}: _(SystemOrigin::Signed(voter), last_hash, index, approve)
verify {
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
let voting = Voting::<T, I>::get(&last_hash).ok_or("Proposal Missing")?;
assert_eq!(voting.ayes.len(), (m - 3) as usize);
assert_eq!(voting.nays.len(), 1);
}
close_early_disapproved {
let m in 4 .. T::MaxMembers::get();
let p in 1 .. T::MaxProposals::get();
let bytes = 100;
let bytes_in_storage = bytes + size_of::<u32>() as u32;
let mut members = vec![];
let proposer = account::<T::AccountId>("proposer", 0, SEED);
members.push(proposer.clone());
for i in 1 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let voter = account::<T::AccountId>("voter", 0, SEED);
members.push(voter.clone());
Collective::<T, I>::set_members(SystemOrigin::Root.into(), members.clone(), None, T::MaxMembers::get())?;
let threshold = m;
let mut last_hash = T::Hash::default();
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, bytes as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(proposer.clone()).into(),
threshold,
Box::new(proposal.clone()),
bytes_in_storage,
)?;
last_hash = T::Hashing::hash_of(&proposal);
}
let index = p - 1;
for j in 0 .. m - 2 {
let voter = &members[j as usize];
let approve = true;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
index,
approve,
)?;
}
let approve = true;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
index,
approve,
)?;
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
let approve = false;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
index,
approve,
)?;
let voter_key = frame_system::Account::<T>::hashed_key_for(&voter);
frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into());
}: close(SystemOrigin::Signed(voter), last_hash, index, Weight::MAX, bytes_in_storage)
verify {
assert_eq!(Proposals::<T, I>::get().len(), (p - 1) as usize);
assert_last_event::<T, I>(Event::Disapproved { proposal_hash: last_hash }.into());
}
close_early_approved {
let b in 2 .. MAX_BYTES;
let m in 4 .. T::MaxMembers::get();
let p in 1 .. T::MaxProposals::get();
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone());
Collective::<T, I>::set_members(SystemOrigin::Root.into(), members.clone(), None, T::MaxMembers::get())?;
let threshold = 2;
let mut last_hash = T::Hash::default();
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, b as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(caller.clone()).into(),
threshold,
Box::new(proposal.clone()),
bytes_in_storage,
)?;
last_hash = T::Hashing::hash_of(&proposal);
}
Collective::<T, I>::vote(
SystemOrigin::Signed(caller.clone()).into(),
last_hash,
p - 1,
false,
)?;
for j in 2 .. m - 1 {
let voter = &members[j as usize];
let approve = false;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
p - 1,
approve,
)?;
}
Collective::<T, I>::vote(
SystemOrigin::Signed(members[0].clone()).into(),
last_hash,
p - 1,
true,
)?;
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
let index = p - 1;
let approve = true;
Collective::<T, I>::vote(
SystemOrigin::Signed(caller.clone()).into(),
last_hash,
index, approve,
)?;
}: close(SystemOrigin::Signed(caller), last_hash, index, Weight::MAX, bytes_in_storage)
verify {
assert_eq!(Proposals::<T, I>::get().len(), (p - 1) as usize);
assert_last_event::<T, I>(Event::Executed { proposal_hash: last_hash, result: Ok(()) }.into());
}
close_disapproved {
let m in 4 .. T::MaxMembers::get();
let p in 1 .. T::MaxProposals::get();
let bytes = 100;
let bytes_in_storage = bytes + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone());
Collective::<T, I>::set_members(
SystemOrigin::Root.into(),
members.clone(),
Some(caller.clone()),
T::MaxMembers::get(),
)?;
let threshold = m - 1;
let mut last_hash = T::Hash::default();
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, bytes as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(caller.clone()).into(),
threshold,
Box::new(proposal.clone()),
bytes_in_storage,
)?;
last_hash = T::Hashing::hash_of(&proposal);
}
let index = p - 1;
let mut yes_votes: MemberCount = 0;
for j in 2 .. m - 1 {
let voter = &members[j as usize];
let approve = true;
yes_votes += 1;
if <<T as Config<I>>::DefaultVote as DefaultVote>::default_vote(
Some(false),
yes_votes,
0,
m,) {
break;
}
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
index,
approve,
)?;
}
Collective::<T, I>::vote(
SystemOrigin::Signed(caller.clone()).into(),
last_hash,
index,
false,
)?;
System::<T>::set_block_number(BlockNumberFor::<T>::max_value());
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
}: close(SystemOrigin::Signed(caller), last_hash, index, Weight::MAX, bytes_in_storage)
verify {
assert_eq!(Proposals::<T, I>::get().len(), (p - 1) as usize);
assert_last_event::<T, I>(Event::Disapproved { proposal_hash: last_hash }.into());
}
close_approved {
let b in 2 .. MAX_BYTES;
let m in 4 .. T::MaxMembers::get();
let p in 1 .. T::MaxProposals::get();
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone());
Collective::<T, I>::set_members(
SystemOrigin::Root.into(),
members.clone(),
Some(caller.clone()),
T::MaxMembers::get(),
)?;
let threshold = 2;
let mut last_hash = T::Hash::default();
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, b as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(caller.clone()).into(),
threshold,
Box::new(proposal.clone()),
bytes_in_storage,
)?;
last_hash = T::Hashing::hash_of(&proposal);
}
Collective::<T, _>::vote(
SystemOrigin::Signed(caller.clone()).into(),
last_hash,
p - 1,
true )?;
for j in 2 .. m - 1 {
let voter = &members[j as usize];
let approve = false;
Collective::<T, I>::vote(
SystemOrigin::Signed(voter.clone()).into(),
last_hash,
p - 1,
approve
)?;
}
System::<T>::set_block_number(BlockNumberFor::<T>::max_value());
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
}: close(SystemOrigin::Signed(caller), last_hash, p - 1, Weight::MAX, bytes_in_storage)
verify {
assert_eq!(Proposals::<T, I>::get().len(), (p - 1) as usize);
assert_last_event::<T, I>(Event::Executed { proposal_hash: last_hash, result: Ok(()) }.into());
}
disapprove_proposal {
let p in 1 .. T::MaxProposals::get();
let m = 3;
let b = MAX_BYTES;
let bytes_in_storage = b + size_of::<u32>() as u32;
let mut members = vec![];
for i in 0 .. m - 1 {
let member = account::<T::AccountId>("member", i, SEED);
members.push(member);
}
let caller = account::<T::AccountId>("caller", 0, SEED);
members.push(caller.clone());
Collective::<T, I>::set_members(
SystemOrigin::Root.into(),
members.clone(),
Some(caller.clone()),
T::MaxMembers::get(),
)?;
let threshold = m - 1;
let mut last_hash = T::Hash::default();
for i in 0 .. p {
let proposal: T::Proposal = SystemCall::<T>::remark { remark: id_to_remark_data(i, b as usize) }.into();
Collective::<T, I>::propose(
SystemOrigin::Signed(caller.clone()).into(),
threshold,
Box::new(proposal.clone()),
bytes_in_storage,
)?;
last_hash = T::Hashing::hash_of(&proposal);
}
System::<T>::set_block_number(BlockNumberFor::<T>::max_value());
assert_eq!(Proposals::<T, I>::get().len(), p as usize);
}: _(SystemOrigin::Root, last_hash)
verify {
assert_eq!(Proposals::<T, I>::get().len(), (p - 1) as usize);
assert_last_event::<T, I>(Event::Disapproved { proposal_hash: last_hash }.into());
}
impl_benchmark_test_suite!(Collective, crate::tests::ExtBuilder::default().build(), crate::tests::Test);
}