add instantiable support for treasury pallet (#7058)

* add instantiable support for treasury pallet

* update treasury pallet benchmarking code to support multi-instance

* use benchmark_intance! macro; fix hard coded treasury identity string; fix over characters line width limitation error

* fix line return style
This commit is contained in:
Kerwin Zhu
2020-09-14 16:59:01 +08:00
committed by GitHub
parent 2348f03f0f
commit f9441b3ea5
3 changed files with 141 additions and 121 deletions
+42 -40
View File
@@ -22,7 +22,7 @@
use super::*;
use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, account, whitelisted_caller};
use frame_benchmarking::{benchmarks_instance, account, whitelisted_caller};
use frame_support::traits::OnInitialize;
use crate::Module as Treasury;
@@ -30,13 +30,13 @@ use crate::Module as Treasury;
const SEED: u32 = 0;
// Create the pre-requisite information needed to create a treasury `propose_spend`.
fn setup_proposal<T: Trait>(u: u32) -> (
fn setup_proposal<T: Trait<I>, I: Instance>(u: u32) -> (
T::AccountId,
BalanceOf<T>,
BalanceOf<T, I>,
<T::Lookup as StaticLookup>::Source,
) {
let caller = account("caller", u, SEED);
let value: BalanceOf<T> = T::ProposalBondMinimum::get().saturating_mul(100.into());
let value: BalanceOf<T, I> = T::ProposalBondMinimum::get().saturating_mul(100.into());
let _ = T::Currency::make_free_balance_be(&caller, value);
let beneficiary = account("beneficiary", u, SEED);
let beneficiary_lookup = T::Lookup::unlookup(beneficiary);
@@ -44,7 +44,7 @@ fn setup_proposal<T: Trait>(u: u32) -> (
}
// Create the pre-requisite information needed to create a `report_awesome`.
fn setup_awesome<T: Trait>(length: u32) -> (T::AccountId, Vec<u8>, T::AccountId) {
fn setup_awesome<T: Trait<I>, I: Instance>(length: u32) -> (T::AccountId, Vec<u8>, T::AccountId) {
let caller = whitelisted_caller();
let value = T::TipReportDepositBase::get()
+ T::TipReportDepositPerByte::get() * length.into()
@@ -56,8 +56,8 @@ fn setup_awesome<T: Trait>(length: u32) -> (T::AccountId, Vec<u8>, T::AccountId)
}
// Create the pre-requisite information needed to call `tip_new`.
fn setup_tip<T: Trait>(r: u32, t: u32) ->
Result<(T::AccountId, Vec<u8>, T::AccountId, BalanceOf<T>), &'static str>
fn setup_tip<T: Trait<I>, I: Instance>(r: u32, t: u32) ->
Result<(T::AccountId, Vec<u8>, T::AccountId, BalanceOf<T, I>), &'static str>
{
let tippers_count = T::Tippers::count();
@@ -77,13 +77,15 @@ fn setup_tip<T: Trait>(r: u32, t: u32) ->
// Create `t` new tips for the tip proposal with `hash`.
// This function automatically makes the tip able to close.
fn create_tips<T: Trait>(t: u32, hash: T::Hash, value: BalanceOf<T>) -> Result<(), &'static str> {
fn create_tips<T: Trait<I>, I: Instance>(t: u32, hash: T::Hash, value: BalanceOf<T, I>) ->
Result<(), &'static str>
{
for i in 0 .. t {
let caller = account("member", i, SEED);
ensure!(T::Tippers::contains(&caller), "caller is not a tipper");
Treasury::<T>::tip(RawOrigin::Signed(caller).into(), hash, value)?;
Treasury::<T, I>::tip(RawOrigin::Signed(caller).into(), hash, value)?;
}
Tips::<T>::mutate(hash, |maybe_tip| {
Tips::<T, I>::mutate(hash, |maybe_tip| {
if let Some(open_tip) = maybe_tip {
open_tip.closes = Some(T::BlockNumber::zero());
}
@@ -92,30 +94,30 @@ fn create_tips<T: Trait>(t: u32, hash: T::Hash, value: BalanceOf<T>) -> Result<(
}
// Create proposals that are approved for use in `on_initialize`.
fn create_approved_proposals<T: Trait>(n: u32) -> Result<(), &'static str> {
fn create_approved_proposals<T: Trait<I>, I: Instance>(n: u32) -> Result<(), &'static str> {
for i in 0 .. n {
let (caller, value, lookup) = setup_proposal::<T>(i);
Treasury::<T>::propose_spend(
let (caller, value, lookup) = setup_proposal::<T, I>(i);
Treasury::<T, I>::propose_spend(
RawOrigin::Signed(caller).into(),
value,
lookup
)?;
let proposal_id = ProposalCount::get() - 1;
Treasury::<T>::approve_proposal(RawOrigin::Root.into(), proposal_id)?;
let proposal_id = <ProposalCount<I>>::get() - 1;
Treasury::<T, I>::approve_proposal(RawOrigin::Root.into(), proposal_id)?;
}
ensure!(Approvals::get().len() == n as usize, "Not all approved");
ensure!(<Approvals<I>>::get().len() == n as usize, "Not all approved");
Ok(())
}
const MAX_BYTES: u32 = 16384;
const MAX_TIPPERS: u32 = 100;
benchmarks! {
benchmarks_instance! {
_ { }
propose_spend {
let u in 0 .. 1000;
let (caller, value, beneficiary_lookup) = setup_proposal::<T>(u);
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(u);
// 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());
@@ -123,29 +125,29 @@ benchmarks! {
reject_proposal {
let u in 0 .. 1000;
let (caller, value, beneficiary_lookup) = setup_proposal::<T>(u);
Treasury::<T>::propose_spend(
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(u);
Treasury::<T, _>::propose_spend(
RawOrigin::Signed(caller).into(),
value,
beneficiary_lookup
)?;
let proposal_id = ProposalCount::get() - 1;
let proposal_id = Treasury::<T, _>::proposal_count() - 1;
}: _(RawOrigin::Root, proposal_id)
approve_proposal {
let u in 0 .. 1000;
let (caller, value, beneficiary_lookup) = setup_proposal::<T>(u);
Treasury::<T>::propose_spend(
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(u);
Treasury::<T, _>::propose_spend(
RawOrigin::Signed(caller).into(),
value,
beneficiary_lookup
)?;
let proposal_id = ProposalCount::get() - 1;
let proposal_id = Treasury::<T, _>::proposal_count() - 1;
}: _(RawOrigin::Root, proposal_id)
report_awesome {
let r in 0 .. MAX_BYTES;
let (caller, reason, awesome_person) = setup_awesome::<T>(r);
let (caller, reason, awesome_person) = setup_awesome::<T, _>(r);
// 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());
@@ -153,8 +155,8 @@ benchmarks! {
retract_tip {
let r in 0 .. MAX_BYTES;
let (caller, reason, awesome_person) = setup_awesome::<T>(r);
Treasury::<T>::report_awesome(
let (caller, reason, awesome_person) = setup_awesome::<T, _>(r);
Treasury::<T, _>::report_awesome(
RawOrigin::Signed(caller.clone()).into(),
reason.clone(),
awesome_person.clone()
@@ -170,7 +172,7 @@ benchmarks! {
let r in 0 .. MAX_BYTES;
let t in 1 .. MAX_TIPPERS;
let (caller, reason, beneficiary, value) = setup_tip::<T>(r, t)?;
let (caller, reason, beneficiary, value) = setup_tip::<T, _>(r, t)?;
// 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());
@@ -178,9 +180,9 @@ benchmarks! {
tip {
let t in 1 .. MAX_TIPPERS;
let (member, reason, beneficiary, value) = setup_tip::<T>(0, t)?;
let (member, reason, beneficiary, value) = setup_tip::<T, _>(0, t)?;
let value = T::Currency::minimum_balance().saturating_mul(100.into());
Treasury::<T>::tip_new(
Treasury::<T, _>::tip_new(
RawOrigin::Signed(member).into(),
reason.clone(),
beneficiary.clone(),
@@ -188,8 +190,8 @@ benchmarks! {
)?;
let reason_hash = T::Hashing::hash(&reason[..]);
let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary));
ensure!(Tips::<T>::contains_key(hash), "tip does not exist");
create_tips::<T>(t - 1, hash.clone(), value)?;
ensure!(Tips::<T, _>::contains_key(hash), "tip does not exist");
create_tips::<T, _>(t - 1, hash.clone(), value)?;
let caller = account("member", t - 1, SEED);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
@@ -200,14 +202,14 @@ benchmarks! {
let t in 1 .. MAX_TIPPERS;
// Make sure pot is funded
let pot_account = Treasury::<T>::account_id();
let pot_account = Treasury::<T, _>::account_id();
let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000.into());
let _ = T::Currency::make_free_balance_be(&pot_account, value);
// Set up a new tip proposal
let (member, reason, beneficiary, value) = setup_tip::<T>(0, t)?;
let (member, reason, beneficiary, value) = setup_tip::<T, _>(0, t)?;
let value = T::Currency::minimum_balance().saturating_mul(100.into());
Treasury::<T>::tip_new(
Treasury::<T, _>::tip_new(
RawOrigin::Signed(member).into(),
reason.clone(),
beneficiary.clone(),
@@ -217,8 +219,8 @@ benchmarks! {
// Create a bunch of tips
let reason_hash = T::Hashing::hash(&reason[..]);
let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary));
ensure!(Tips::<T>::contains_key(hash), "tip does not exist");
create_tips::<T>(t, hash.clone(), value)?;
ensure!(Tips::<T, _>::contains_key(hash), "tip does not exist");
create_tips::<T, _>(t, hash.clone(), value)?;
let caller = account("caller", t, SEED);
// Whitelist caller account from further DB operations.
@@ -228,12 +230,12 @@ benchmarks! {
on_initialize {
let p in 0 .. 100;
let pot_account = Treasury::<T>::account_id();
let pot_account = Treasury::<T, _>::account_id();
let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000.into());
let _ = T::Currency::make_free_balance_be(&pot_account, value);
create_approved_proposals::<T>(p)?;
create_approved_proposals::<T, _>(p)?;
}: {
Treasury::<T>::on_initialize(T::BlockNumber::zero());
Treasury::<T, _>::on_initialize(T::BlockNumber::zero());
}
}
+72 -66
View File
@@ -107,9 +107,12 @@ use frame_system::{self as system, ensure_signed};
mod tests;
mod benchmarking;
type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
type PositiveImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::PositiveImbalance;
type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::NegativeImbalance;
type BalanceOf<T, I> =
<<T as Trait<I>>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
type PositiveImbalanceOf<T, I> =
<<T as Trait<I>>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::PositiveImbalance;
type NegativeImbalanceOf<T, I> =
<<T as Trait<I>>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::NegativeImbalance;
pub trait WeightInfo {
fn propose_spend(u: u32, ) -> Weight;
@@ -135,7 +138,7 @@ impl WeightInfo for () {
fn on_initialize(_p: u32, ) -> Weight { 1_000_000_000 }
}
pub trait Trait: frame_system::Trait {
pub trait Trait<I=DefaultInstance>: frame_system::Trait {
/// The treasury's module id, used for deriving its sovereign account ID.
type ModuleId: Get<ModuleId>;
@@ -160,23 +163,23 @@ pub trait Trait: frame_system::Trait {
type TipFindersFee: Get<Percent>;
/// The amount held on deposit for placing a tip report.
type TipReportDepositBase: Get<BalanceOf<Self>>;
type TipReportDepositBase: Get<BalanceOf<Self, I>>;
/// The amount held on deposit per byte within the tip report reason.
type TipReportDepositPerByte: Get<BalanceOf<Self>>;
type TipReportDepositPerByte: Get<BalanceOf<Self, I>>;
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
type Event: From<Event<Self, I>> + Into<<Self as frame_system::Trait>::Event>;
/// Handler for the unbalanced decrease when slashing for a rejected proposal.
type ProposalRejection: OnUnbalanced<NegativeImbalanceOf<Self>>;
type ProposalRejection: OnUnbalanced<NegativeImbalanceOf<Self, I>>;
/// Fraction of a proposal's value that should be bonded in order to place the proposal.
/// An accepted proposal gets these back. A rejected proposal does not.
type ProposalBond: Get<Permill>;
/// Minimum amount of funds that should be placed in a deposit for making a proposal.
type ProposalBondMinimum: Get<BalanceOf<Self>>;
type ProposalBondMinimum: Get<BalanceOf<Self, I>>;
/// Period between successive spends.
type SpendPeriod: Get<Self::BlockNumber>;
@@ -185,7 +188,7 @@ pub trait Trait: frame_system::Trait {
type Burn: Get<Permill>;
/// Handler for the unbalanced decrease when treasury funds are burned.
type BurnDestination: OnUnbalanced<NegativeImbalanceOf<Self>>;
type BurnDestination: OnUnbalanced<NegativeImbalanceOf<Self, I>>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
@@ -236,14 +239,14 @@ pub struct OpenTip<
}
decl_storage! {
trait Store for Module<T: Trait> as Treasury {
trait Store for Module<T: Trait<I>, I: Instance=DefaultInstance> as Treasury {
/// Number of proposals that have been made.
ProposalCount get(fn proposal_count): ProposalIndex;
/// Proposals that have been made.
Proposals get(fn proposals):
map hasher(twox_64_concat) ProposalIndex
=> Option<Proposal<T::AccountId, BalanceOf<T>>>;
=> Option<Proposal<T::AccountId, BalanceOf<T, I>>>;
/// Proposal indices that have been approved but not yet awarded.
Approvals get(fn approvals): Vec<ProposalIndex>;
@@ -253,7 +256,7 @@ decl_storage! {
/// guaranteed to be a secure hash.
pub Tips get(fn tips):
map hasher(twox_64_concat) T::Hash
=> Option<OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>>;
=> Option<OpenTip<T::AccountId, BalanceOf<T, I>, T::BlockNumber, T::Hash>>;
/// Simple preimage lookup from the reason's hash to the original data. Again, has an
/// insecure enumerable hash since the key is guaranteed to be the result of a secure hash.
@@ -263,7 +266,7 @@ decl_storage! {
build(|_config| {
// Create Treasury account
let _ = T::Currency::make_free_balance_be(
&<Module<T>>::account_id(),
&<Module<T, I>>::account_id(),
T::Currency::minimum_balance(),
);
});
@@ -271,9 +274,9 @@ decl_storage! {
}
decl_event!(
pub enum Event<T>
pub enum Event<T, I=DefaultInstance>
where
Balance = BalanceOf<T>,
Balance = BalanceOf<T, I>,
<T as frame_system::Trait>::AccountId,
<T as frame_system::Trait>::Hash,
{
@@ -305,7 +308,7 @@ decl_event!(
decl_error! {
/// Error for the treasury module.
pub enum Error for Module<T: Trait> {
pub enum Error for Module<T: Trait<I>, I: Instance> {
/// Proposer's balance is too low.
InsufficientProposersBalance,
/// No proposal at that index.
@@ -326,13 +329,16 @@ decl_error! {
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
pub struct Module<T: Trait<I>, I: Instance=DefaultInstance>
for enum Call
where origin: T::Origin
{
/// Fraction of a proposal's value that should be bonded in order to place the proposal.
/// An accepted proposal gets these back. A rejected proposal does not.
const ProposalBond: Permill = T::ProposalBond::get();
/// Minimum amount of funds that should be placed in a deposit for making a proposal.
const ProposalBondMinimum: BalanceOf<T> = T::ProposalBondMinimum::get();
const ProposalBondMinimum: BalanceOf<T, I> = T::ProposalBondMinimum::get();
/// Period between successive spends.
const SpendPeriod: T::BlockNumber = T::SpendPeriod::get();
@@ -347,15 +353,15 @@ decl_module! {
const TipFindersFee: Percent = T::TipFindersFee::get();
/// The amount held on deposit for placing a tip report.
const TipReportDepositBase: BalanceOf<T> = T::TipReportDepositBase::get();
const TipReportDepositBase: BalanceOf<T, I> = T::TipReportDepositBase::get();
/// The amount held on deposit per byte within the tip report reason.
const TipReportDepositPerByte: BalanceOf<T> = T::TipReportDepositPerByte::get();
const TipReportDepositPerByte: BalanceOf<T, I> = T::TipReportDepositPerByte::get();
/// The treasury's module id, used for deriving its sovereign account ID.
const ModuleId: ModuleId = T::ModuleId::get();
type Error = Error<T>;
type Error = Error<T, I>;
fn deposit_event() = default;
@@ -371,7 +377,7 @@ decl_module! {
#[weight = 120_000_000 + T::DbWeight::get().reads_writes(1, 2)]
fn propose_spend(
origin,
#[compact] value: BalanceOf<T>,
#[compact] value: BalanceOf<T, I>,
beneficiary: <T::Lookup as StaticLookup>::Source
) {
let proposer = ensure_signed(origin)?;
@@ -379,11 +385,11 @@ decl_module! {
let bond = Self::calculate_bond(value);
T::Currency::reserve(&proposer, bond)
.map_err(|_| Error::<T>::InsufficientProposersBalance)?;
.map_err(|_| Error::<T, I>::InsufficientProposersBalance)?;
let c = Self::proposal_count();
ProposalCount::put(c + 1);
<Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond });
<ProposalCount<I>>::put(c + 1);
<Proposals<T, I>>::insert(c, Proposal { proposer, value, beneficiary, bond });
Self::deposit_event(RawEvent::Proposed(c));
}
@@ -401,12 +407,12 @@ decl_module! {
fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) {
T::RejectOrigin::ensure_origin(origin)?;
let proposal = <Proposals<T>>::take(&proposal_id).ok_or(Error::<T>::InvalidProposalIndex)?;
let proposal = <Proposals<T, I>>::take(&proposal_id).ok_or(Error::<T, I>::InvalidProposalIndex)?;
let value = proposal.bond;
let imbalance = T::Currency::slash_reserved(&proposal.proposer, value).0;
T::ProposalRejection::on_unbalanced(imbalance);
Self::deposit_event(Event::<T>::Rejected(proposal_id, value));
Self::deposit_event(Event::<T, I>::Rejected(proposal_id, value));
}
/// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary
@@ -423,8 +429,8 @@ decl_module! {
fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) {
T::ApproveOrigin::ensure_origin(origin)?;
ensure!(<Proposals<T>>::contains_key(proposal_id), Error::<T>::InvalidProposalIndex);
Approvals::mutate(|v| v.push(proposal_id));
ensure!(<Proposals<T, I>>::contains_key(proposal_id), Error::<T, I>::InvalidProposalIndex);
<Approvals<I>>::mutate(|v| v.push(proposal_id));
}
/// Report something `reason` that deserves a tip and claim any eventual the finder's fee.
@@ -451,18 +457,18 @@ decl_module! {
let finder = ensure_signed(origin)?;
const MAX_SENSIBLE_REASON_LENGTH: usize = 16384;
ensure!(reason.len() <= MAX_SENSIBLE_REASON_LENGTH, Error::<T>::ReasonTooBig);
ensure!(reason.len() <= MAX_SENSIBLE_REASON_LENGTH, Error::<T, I>::ReasonTooBig);
let reason_hash = T::Hashing::hash(&reason[..]);
ensure!(!Reasons::<T>::contains_key(&reason_hash), Error::<T>::AlreadyKnown);
ensure!(!Reasons::<T, I>::contains_key(&reason_hash), Error::<T, I>::AlreadyKnown);
let hash = T::Hashing::hash_of(&(&reason_hash, &who));
ensure!(!Tips::<T>::contains_key(&hash), Error::<T>::AlreadyKnown);
ensure!(!Tips::<T, I>::contains_key(&hash), Error::<T, I>::AlreadyKnown);
let deposit = T::TipReportDepositBase::get()
+ T::TipReportDepositPerByte::get() * (reason.len() as u32).into();
T::Currency::reserve(&finder, deposit)?;
Reasons::<T>::insert(&reason_hash, &reason);
Reasons::<T, I>::insert(&reason_hash, &reason);
let tip = OpenTip {
reason: reason_hash,
who,
@@ -472,7 +478,7 @@ decl_module! {
tips: vec![],
finders_fee: true
};
Tips::<T>::insert(&hash, tip);
Tips::<T, I>::insert(&hash, tip);
Self::deposit_event(RawEvent::NewTip(hash));
}
@@ -498,11 +504,11 @@ decl_module! {
#[weight = 120_000_000 + T::DbWeight::get().reads_writes(1, 2)]
fn retract_tip(origin, hash: T::Hash) {
let who = ensure_signed(origin)?;
let tip = Tips::<T>::get(&hash).ok_or(Error::<T>::UnknownTip)?;
ensure!(tip.finder == who, Error::<T>::NotFinder);
let tip = Tips::<T, I>::get(&hash).ok_or(Error::<T, I>::UnknownTip)?;
ensure!(tip.finder == who, Error::<T, I>::NotFinder);
Reasons::<T>::remove(&tip.reason);
Tips::<T>::remove(&hash);
Reasons::<T, I>::remove(&tip.reason);
Tips::<T, I>::remove(&hash);
if !tip.deposit.is_zero() {
let _ = T::Currency::unreserve(&who, tip.deposit);
}
@@ -535,14 +541,14 @@ decl_module! {
+ 4_000 * reason.len() as Weight
+ 480_000 * T::Tippers::max_len() as Weight
+ T::DbWeight::get().reads_writes(2, 2)]
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, tip_value: BalanceOf<T>) {
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, tip_value: BalanceOf<T, I>) {
let tipper = ensure_signed(origin)?;
ensure!(T::Tippers::contains(&tipper), BadOrigin);
let reason_hash = T::Hashing::hash(&reason[..]);
ensure!(!Reasons::<T>::contains_key(&reason_hash), Error::<T>::AlreadyKnown);
ensure!(!Reasons::<T, I>::contains_key(&reason_hash), Error::<T, I>::AlreadyKnown);
let hash = T::Hashing::hash_of(&(&reason_hash, &who));
Reasons::<T>::insert(&reason_hash, &reason);
Reasons::<T, I>::insert(&reason_hash, &reason);
Self::deposit_event(RawEvent::NewTip(hash.clone()));
let tips = vec![(tipper.clone(), tip_value)];
let tip = OpenTip {
@@ -554,7 +560,7 @@ decl_module! {
tips,
finders_fee: false,
};
Tips::<T>::insert(&hash, tip);
Tips::<T, I>::insert(&hash, tip);
}
/// Declare a tip value for an already-open tip.
@@ -584,15 +590,15 @@ decl_module! {
/// # </weight>
#[weight = 68_000_000 + 2_000_000 * T::Tippers::max_len() as Weight
+ T::DbWeight::get().reads_writes(2, 1)]
fn tip(origin, hash: T::Hash, tip_value: BalanceOf<T>) {
fn tip(origin, hash: T::Hash, tip_value: BalanceOf<T, I>) {
let tipper = ensure_signed(origin)?;
ensure!(T::Tippers::contains(&tipper), BadOrigin);
let mut tip = Tips::<T>::get(hash).ok_or(Error::<T>::UnknownTip)?;
let mut tip = Tips::<T, I>::get(hash).ok_or(Error::<T, I>::UnknownTip)?;
if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) {
Self::deposit_event(RawEvent::TipClosing(hash.clone()));
}
Tips::<T>::insert(&hash, tip);
Tips::<T, I>::insert(&hash, tip);
}
/// Close and payout a tip.
@@ -617,12 +623,12 @@ decl_module! {
fn close_tip(origin, hash: T::Hash) {
ensure_signed(origin)?;
let tip = Tips::<T>::get(hash).ok_or(Error::<T>::UnknownTip)?;
let n = tip.closes.as_ref().ok_or(Error::<T>::StillOpen)?;
ensure!(system::Module::<T>::block_number() >= *n, Error::<T>::Premature);
let tip = Tips::<T, I>::get(hash).ok_or(Error::<T, I>::UnknownTip)?;
let n = tip.closes.as_ref().ok_or(Error::<T, I>::StillOpen)?;
ensure!(system::Module::<T>::block_number() >= *n, Error::<T, I>::Premature);
// closed.
Reasons::<T>::remove(&tip.reason);
Tips::<T>::remove(hash);
Reasons::<T, I>::remove(&tip.reason);
Tips::<T, I>::remove(hash);
Self::payout_tip(hash, tip);
}
@@ -647,7 +653,7 @@ decl_module! {
}
}
impl<T: Trait> Module<T> {
impl<T: Trait<I>, I: Instance> Module<T, I> {
// Add public immutables and private mutables.
/// The account ID of the treasury pot.
@@ -659,7 +665,7 @@ impl<T: Trait> Module<T> {
}
/// The needed bond for a proposal whose spend is `value`.
fn calculate_bond(value: BalanceOf<T>) -> BalanceOf<T> {
fn calculate_bond(value: BalanceOf<T, I>) -> BalanceOf<T, I> {
T::ProposalBondMinimum::get().max(T::ProposalBond::get() * value)
}
@@ -668,9 +674,9 @@ impl<T: Trait> Module<T> {
///
/// `O(T)` and one storage access.
fn insert_tip_and_check_closing(
tip: &mut OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
tip: &mut OpenTip<T::AccountId, BalanceOf<T, I>, T::BlockNumber, T::Hash>,
tipper: T::AccountId,
tip_value: BalanceOf<T>,
tip_value: BalanceOf<T, I>,
) -> bool {
match tip.tips.binary_search_by_key(&&tipper, |x| &x.0) {
Ok(pos) => tip.tips[pos] = (tipper, tip_value),
@@ -687,7 +693,7 @@ impl<T: Trait> Module<T> {
}
/// Remove any non-members of `Tippers` from a `tips` vector. `O(T)`.
fn retain_active_tips(tips: &mut Vec<(T::AccountId, BalanceOf<T>)>) {
fn retain_active_tips(tips: &mut Vec<(T::AccountId, BalanceOf<T, I>)>) {
let members = T::Tippers::sorted_members();
let mut members_iter = members.iter();
let mut member = members_iter.next();
@@ -711,7 +717,7 @@ impl<T: Trait> Module<T> {
///
/// Up to three balance operations.
/// Plus `O(T)` (`T` is Tippers length).
fn payout_tip(hash: T::Hash, tip: OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>) {
fn payout_tip(hash: T::Hash, tip: OpenTip<T::AccountId, BalanceOf<T, I>, T::BlockNumber, T::Hash>) {
let mut tips = tip.tips;
Self::retain_active_tips(&mut tips);
tips.sort_by_key(|i| i.1);
@@ -742,15 +748,15 @@ impl<T: Trait> Module<T> {
Self::deposit_event(RawEvent::Spending(budget_remaining));
let mut missed_any = false;
let mut imbalance = <PositiveImbalanceOf<T>>::zero();
let prior_approvals_len = Approvals::mutate(|v| {
let mut imbalance = <PositiveImbalanceOf<T, I>>::zero();
let prior_approvals_len = <Approvals<I>>::mutate(|v| {
let prior_approvals_len = v.len() as u64;
v.retain(|&index| {
// Should always be true, but shouldn't panic if false or we're screwed.
if let Some(p) = Self::proposals(index) {
if p.value <= budget_remaining {
budget_remaining -= p.value;
<Proposals<T>>::remove(index);
<Proposals<T, I>>::remove(index);
// return their deposit.
let _ = T::Currency::unreserve(&p.proposer, p.bond);
@@ -804,7 +810,7 @@ impl<T: Trait> Module<T> {
/// Return the amount of money in the pot.
// The existential deposit is not part of the pot so treasury account never gets deleted.
fn pot() -> BalanceOf<T> {
fn pot() -> BalanceOf<T, I> {
T::Currency::free_balance(&Self::account_id())
// Must never be less than 0 but better be safe.
.saturating_sub(T::Currency::minimum_balance())
@@ -838,9 +844,9 @@ impl<T: Trait> Module<T> {
for (hash, old_tip) in StorageKeyIterator::<
T::Hash,
OldOpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
OldOpenTip<T::AccountId, BalanceOf<T, I>, T::BlockNumber, T::Hash>,
Twox64Concat,
>::new(b"Treasury", b"Tips").drain()
>::new(I::PREFIX.as_bytes(), b"Tips").drain()
{
let (finder, deposit, finders_fee) = match old_tip.finder {
Some((finder, deposit)) => (finder, deposit, true),
@@ -855,13 +861,13 @@ impl<T: Trait> Module<T> {
tips: old_tip.tips,
finders_fee
};
Tips::<T>::insert(hash, new_tip)
Tips::<T, I>::insert(hash, new_tip)
}
}
}
impl<T: Trait> OnUnbalanced<NegativeImbalanceOf<T>> for Module<T> {
fn on_nonzero_unbalanced(amount: NegativeImbalanceOf<T>) {
impl<T: Trait<I>, I: Instance> OnUnbalanced<NegativeImbalanceOf<T, I>> for Module<T, I> {
fn on_nonzero_unbalanced(amount: NegativeImbalanceOf<T, I>) {
let numeric_amount = amount.peek();
// Must resolve into existing but better to be safe.
+27 -15
View File
@@ -162,7 +162,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
// Total issuance will be 200 with treasury account initialized at ED.
balances: vec![(0, 100), (1, 98), (2, 1)],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::default().assimilate_storage::<Test>(&mut t).unwrap();
GenesisConfig::default().assimilate_storage::<Test, _>(&mut t).unwrap();
t.into()
}
@@ -185,7 +185,7 @@ fn tip_new_cannot_be_used_twice() {
assert_ok!(Treasury::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
assert_noop!(
Treasury::tip_new(Origin::signed(11), b"awesome.dot".to_vec(), 3, 10),
Error::<Test>::AlreadyKnown
Error::<Test, _>::AlreadyKnown
);
});
}
@@ -201,7 +201,7 @@ fn report_awesome_and_tip_works() {
// other reports don't count.
assert_noop!(
Treasury::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3),
Error::<Test>::AlreadyKnown
Error::<Test, _>::AlreadyKnown
);
let h = tip_hash();
@@ -259,7 +259,7 @@ fn close_tip_works() {
assert_ok!(Treasury::tip(Origin::signed(11), h.clone(), 10));
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test>::StillOpen);
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test, _>::StillOpen);
assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 10));
@@ -273,7 +273,7 @@ fn close_tip_works() {
RawEvent::TipClosing(h),
);
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test>::Premature);
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test, _>::Premature);
System::set_block_number(2);
assert_noop!(Treasury::close_tip(Origin::none(), h.into()), BadOrigin);
@@ -290,7 +290,7 @@ fn close_tip_works() {
RawEvent::TipClosed(h, 3, 10),
);
assert_noop!(Treasury::close_tip(Origin::signed(100), h.into()), Error::<Test>::UnknownTip);
assert_noop!(Treasury::close_tip(Origin::signed(100), h.into()), Error::<Test, _>::UnknownTip);
});
}
@@ -304,10 +304,10 @@ fn retract_tip_works() {
assert_ok!(Treasury::tip(Origin::signed(10), h.clone(), 10));
assert_ok!(Treasury::tip(Origin::signed(11), h.clone(), 10));
assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 10));
assert_noop!(Treasury::retract_tip(Origin::signed(10), h.clone()), Error::<Test>::NotFinder);
assert_noop!(Treasury::retract_tip(Origin::signed(10), h.clone()), Error::<Test, _>::NotFinder);
assert_ok!(Treasury::retract_tip(Origin::signed(0), h.clone()));
System::set_block_number(2);
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test>::UnknownTip);
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test, _>::UnknownTip);
// with tip new
Balances::make_free_balance_be(&Treasury::account_id(), 101);
@@ -315,10 +315,10 @@ fn retract_tip_works() {
let h = tip_hash();
assert_ok!(Treasury::tip(Origin::signed(11), h.clone(), 10));
assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 10));
assert_noop!(Treasury::retract_tip(Origin::signed(0), h.clone()), Error::<Test>::NotFinder);
assert_noop!(Treasury::retract_tip(Origin::signed(0), h.clone()), Error::<Test, _>::NotFinder);
assert_ok!(Treasury::retract_tip(Origin::signed(10), h.clone()));
System::set_block_number(2);
assert_noop!(Treasury::close_tip(Origin::signed(10), h.into()), Error::<Test>::UnknownTip);
assert_noop!(Treasury::close_tip(Origin::signed(10), h.into()), Error::<Test, _>::UnknownTip);
});
}
@@ -387,7 +387,7 @@ fn spend_proposal_fails_when_proposer_poor() {
new_test_ext().execute_with(|| {
assert_noop!(
Treasury::propose_spend(Origin::signed(2), 100, 3),
Error::<Test>::InsufficientProposersBalance,
Error::<Test, _>::InsufficientProposersBalance,
);
});
}
@@ -440,21 +440,30 @@ fn reject_already_rejected_spend_proposal_fails() {
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::root(), 0));
assert_noop!(Treasury::reject_proposal(Origin::root(), 0), Error::<Test>::InvalidProposalIndex);
assert_noop!(
Treasury::reject_proposal(Origin::root(), 0),
Error::<Test, _>::InvalidProposalIndex,
);
});
}
#[test]
fn reject_non_existent_spend_proposal_fails() {
new_test_ext().execute_with(|| {
assert_noop!(Treasury::reject_proposal(Origin::root(), 0), Error::<Test>::InvalidProposalIndex);
assert_noop!(
Treasury::reject_proposal(Origin::root(), 0),
Error::<Test, _>::InvalidProposalIndex,
);
});
}
#[test]
fn accept_non_existent_spend_proposal_fails() {
new_test_ext().execute_with(|| {
assert_noop!(Treasury::approve_proposal(Origin::root(), 0), Error::<Test>::InvalidProposalIndex);
assert_noop!(
Treasury::approve_proposal(Origin::root(), 0),
Error::<Test, _>::InvalidProposalIndex,
);
});
}
@@ -465,7 +474,10 @@ fn accept_already_rejected_spend_proposal_fails() {
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::root(), 0));
assert_noop!(Treasury::approve_proposal(Origin::root(), 0), Error::<Test>::InvalidProposalIndex);
assert_noop!(
Treasury::approve_proposal(Origin::root(), 0),
Error::<Test, _>::InvalidProposalIndex,
);
});
}