mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 05:51:02 +00:00
Several tweaks needed for Governance 2.0 (#11124)
* Add stepped curve for referenda * Treasury SpendOrigin * Add tests * Better Origin Or-gating * Reciprocal curve * Tests for reciprical and rounding in PerThings * Tweaks and new quad curve * Const derivation of reciprocal curve parameters * Remove some unneeded code * Actually useful linear curve * Fixes * Provisional curves * Rejig 'turnout' as 'support' * Use TypedGet * Fixes * Enable curve's ceil to be configured * Formatting * Fixes * Fixes * Fixes * Remove EnsureOneOf * Fixes * Fixes * Fixes * Formatting * Fixes * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Grumbles * Formatting * Fixes * APIs of VoteTally should include class * Fixes * Fix overlay prefix removal result * Second part of the overlay prefix removal fix. * Formatting * Fixes * Add some tests and make clear rounding algo * Fixes * Formatting * Revert questionable fix * Introduce test for kill_prefix * Fixes * Formatting * Fixes * Fix possible overflow * Docs * Add benchmark test * Formatting * Update frame/referenda/src/types.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Docs * Fixes * Use latest API in tests * Formatting * Whitespace * Use latest API in tests Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
@@ -22,7 +22,11 @@
|
||||
use super::{Pallet as Treasury, *};
|
||||
|
||||
use frame_benchmarking::{account, benchmarks_instance_pallet};
|
||||
use frame_support::{ensure, traits::OnInitialize};
|
||||
use frame_support::{
|
||||
dispatch::UnfilteredDispatchable,
|
||||
ensure,
|
||||
traits::{EnsureOrigin, OnInitialize},
|
||||
};
|
||||
use frame_system::RawOrigin;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
@@ -57,7 +61,21 @@ fn setup_pot_account<T: Config<I>, I: 'static>() {
|
||||
let _ = T::Currency::make_free_balance_be(&pot_account, value);
|
||||
}
|
||||
|
||||
fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::Event) {
|
||||
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
|
||||
}
|
||||
|
||||
benchmarks_instance_pallet! {
|
||||
spend {
|
||||
let (_, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
let origin = T::SpendOrigin::successful_origin();
|
||||
let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap();
|
||||
let call = Call::<T, I>::spend { amount: value, beneficiary: beneficiary_lookup };
|
||||
}: { call.dispatch_bypass_filter(origin)? }
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into())
|
||||
}
|
||||
|
||||
propose_spend {
|
||||
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
// Whitelist caller account from further DB operations.
|
||||
|
||||
@@ -198,6 +198,11 @@ pub mod pallet {
|
||||
/// NOTE: This parameter is also used within the Bounties Pallet extension if enabled.
|
||||
#[pallet::constant]
|
||||
type MaxApprovals: Get<u32>;
|
||||
|
||||
/// The origin required for approving spends from the treasury outside of the proposal
|
||||
/// process. The `Success` value is the maximum amount that this origin is allowed to
|
||||
/// spend at a time.
|
||||
type SpendOrigin: EnsureOrigin<Self::Origin, Success = BalanceOf<Self, I>>;
|
||||
}
|
||||
|
||||
/// Number of proposals that have been made.
|
||||
@@ -275,6 +280,12 @@ pub mod pallet {
|
||||
Rollover { rollover_balance: BalanceOf<T, I> },
|
||||
/// Some funds have been deposited.
|
||||
Deposit { value: BalanceOf<T, I> },
|
||||
/// A new spend proposal has been approved.
|
||||
SpendApproved {
|
||||
proposal_index: ProposalIndex,
|
||||
amount: BalanceOf<T, I>,
|
||||
beneficiary: T::AccountId,
|
||||
},
|
||||
}
|
||||
|
||||
/// Error for the treasury pallet.
|
||||
@@ -286,6 +297,9 @@ pub mod pallet {
|
||||
InvalidIndex,
|
||||
/// Too many approvals in the queue.
|
||||
TooManyApprovals,
|
||||
/// The spend origin is valid but the amount it is allowed to spend is lower than the
|
||||
/// amount to be spent.
|
||||
InsufficientPermission,
|
||||
/// Proposal has not been approved.
|
||||
ProposalNotApproved,
|
||||
}
|
||||
@@ -393,6 +407,40 @@ pub mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Propose and approve a spend of treasury funds.
|
||||
///
|
||||
/// - `origin`: Must be `SpendOrigin` with the `Success` value being at least `amount`.
|
||||
/// - `amount`: The amount to be transferred from the treasury to the `beneficiary`.
|
||||
/// - `beneficiary`: The destination account for the transfer.
|
||||
///
|
||||
/// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the
|
||||
/// beneficiary.
|
||||
#[pallet::weight(T::WeightInfo::spend())]
|
||||
pub fn spend(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] amount: BalanceOf<T, I>,
|
||||
beneficiary: <T::Lookup as StaticLookup>::Source,
|
||||
) -> DispatchResult {
|
||||
let max_amount = T::SpendOrigin::ensure_origin(origin)?;
|
||||
let beneficiary = T::Lookup::lookup(beneficiary)?;
|
||||
|
||||
ensure!(amount <= max_amount, Error::<T, I>::InsufficientPermission);
|
||||
let proposal_index = Self::proposal_count();
|
||||
Approvals::<T, I>::try_append(proposal_index)
|
||||
.map_err(|_| Error::<T, I>::TooManyApprovals)?;
|
||||
let proposal = Proposal {
|
||||
proposer: beneficiary.clone(),
|
||||
value: amount,
|
||||
beneficiary: beneficiary.clone(),
|
||||
bond: Default::default(),
|
||||
};
|
||||
Proposals::<T, I>::insert(proposal_index, proposal);
|
||||
ProposalCount::<T, I>::put(proposal_index + 1);
|
||||
|
||||
Self::deposit_event(Event::SpendApproved { proposal_index, amount, beneficiary });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Force a previously approved proposal to be removed from the approval queue.
|
||||
/// The original deposit will no longer be returned.
|
||||
///
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::cell::RefCell;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
traits::{BadOrigin, BlakeTwo256, IdentityLookup},
|
||||
};
|
||||
|
||||
use frame_support::{
|
||||
@@ -101,8 +101,26 @@ parameter_types! {
|
||||
pub const ProposalBond: Permill = Permill::from_percent(5);
|
||||
pub const Burn: Permill = Permill::from_percent(50);
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub const MaxApprovals: u32 = 100;
|
||||
}
|
||||
pub struct TestSpendOrigin;
|
||||
impl frame_support::traits::EnsureOrigin<Origin> for TestSpendOrigin {
|
||||
type Success = u64;
|
||||
fn try_origin(o: Origin) -> Result<Self::Success, Origin> {
|
||||
Result::<frame_system::RawOrigin<_>, Origin>::from(o).and_then(|o| match o {
|
||||
frame_system::RawOrigin::Root => Ok(u64::max_value()),
|
||||
frame_system::RawOrigin::Signed(10) => Ok(5),
|
||||
frame_system::RawOrigin::Signed(11) => Ok(10),
|
||||
frame_system::RawOrigin::Signed(12) => Ok(20),
|
||||
frame_system::RawOrigin::Signed(13) => Ok(50),
|
||||
r => Err(Origin::from(r)),
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn successful_origin() -> Origin {
|
||||
Origin::root()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type PalletId = TreasuryPalletId;
|
||||
type Currency = pallet_balances::Pallet<Test>;
|
||||
@@ -119,6 +137,7 @@ impl Config for Test {
|
||||
type WeightInfo = ();
|
||||
type SpendFunds = ();
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = TestSpendOrigin;
|
||||
}
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
@@ -141,6 +160,51 @@ fn genesis_config_works() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_origin_permissioning_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(Treasury::spend(Origin::signed(1), 1, 1), BadOrigin);
|
||||
assert_noop!(
|
||||
Treasury::spend(Origin::signed(10), 6, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
assert_noop!(
|
||||
Treasury::spend(Origin::signed(11), 11, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
assert_noop!(
|
||||
Treasury::spend(Origin::signed(12), 21, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
assert_noop!(
|
||||
Treasury::spend(Origin::signed(13), 51, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_origin_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Check that accumulate works when we have Some value in Dummy already.
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(Treasury::spend(Origin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(Origin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(Origin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(Origin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(Origin::signed(11), 10, 6));
|
||||
assert_ok!(Treasury::spend(Origin::signed(12), 20, 6));
|
||||
assert_ok!(Treasury::spend(Origin::signed(13), 50, 6));
|
||||
|
||||
<Treasury as OnInitialize<u64>>::on_initialize(1);
|
||||
assert_eq!(Balances::free_balance(6), 0);
|
||||
|
||||
<Treasury as OnInitialize<u64>>::on_initialize(2);
|
||||
assert_eq!(Balances::free_balance(6), 100);
|
||||
assert_eq!(Treasury::pot(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minting_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
@@ -372,7 +436,7 @@ fn max_approvals_limited() {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), u64::MAX);
|
||||
Balances::make_free_balance_be(&0, u64::MAX);
|
||||
|
||||
for _ in 0..MaxApprovals::get() {
|
||||
for _ in 0..<Test as Config>::MaxApprovals::get() {
|
||||
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
|
||||
assert_ok!(Treasury::approve_proposal(Origin::root(), 0));
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_treasury.
|
||||
pub trait WeightInfo {
|
||||
fn spend() -> Weight;
|
||||
fn propose_spend() -> Weight;
|
||||
fn reject_proposal() -> Weight;
|
||||
fn approve_proposal(p: u32, ) -> Weight;
|
||||
@@ -54,6 +55,13 @@ pub trait WeightInfo {
|
||||
/// Weights for pallet_treasury using the Substrate node and recommended hardware.
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
// Storage: Treasury Proposals (r:0 w:1)
|
||||
fn spend() -> Weight {
|
||||
(22_063_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
// Storage: Treasury Proposals (r:0 w:1)
|
||||
fn propose_spend() -> Weight {
|
||||
@@ -100,6 +108,13 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
// Storage: Treasury Proposals (r:0 w:1)
|
||||
fn spend() -> Weight {
|
||||
(22_063_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
// Storage: Treasury Proposals (r:0 w:1)
|
||||
fn propose_spend() -> Weight {
|
||||
|
||||
Reference in New Issue
Block a user