Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 9441e44

Browse files
authored
Update treasury weights. (#5723)
* treasury weight formula * use max tippers count * doc * Fix upper bound * rounding a bit * remove unused + doc * as u64 -> as Weight * 2 significative digits rounded up * rename ContainsCountUpperBound -> ContainsLengthBound * add doc * sender account -> origin account * fix
1 parent e2dcddd commit 9441e44

File tree

4 files changed

+101
-46
lines changed

4 files changed

+101
-46
lines changed

frame/elections-phragmen/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ use frame_support::{
9393
traits::{
9494
Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons,
9595
ChangeMembers, OnUnbalanced, WithdrawReason, Contains, BalanceStatus, InitializeMembers,
96+
ContainsLengthBound,
9697
}
9798
};
9899
use sp_phragmen::{build_support_map, ExtendedBalance, VoteWeight, PhragmenResult};
@@ -880,6 +881,15 @@ impl<T: Trait> Contains<T::AccountId> for Module<T> {
880881
}
881882
}
882883

884+
impl<T: Trait> ContainsLengthBound for Module<T> {
885+
fn min_len() -> usize { 0 }
886+
887+
/// Implementation uses a parameter type so calling is cost-free.
888+
fn max_len() -> usize {
889+
Self::desired_members() as usize
890+
}
891+
}
892+
883893
#[cfg(test)]
884894
mod tests {
885895
use super::*;

frame/support/src/traits.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,7 @@ impl<T: Default> Get<T> for () {
190190
fn get() -> T { T::default() }
191191
}
192192

193-
/// A trait for querying whether a type can be said to statically "contain" a value. Similar
194-
/// in nature to `Get`, except it is designed to be lazy rather than active (you can't ask it to
195-
/// enumerate all values that it contains) and work for multiple values rather than just one.
193+
/// A trait for querying whether a type can be said to "contain" a value.
196194
pub trait Contains<T: Ord> {
197195
/// Return `true` if this "contains" the given value `t`.
198196
fn contains(t: &T) -> bool { Self::sorted_members().binary_search(t).is_ok() }
@@ -211,6 +209,14 @@ pub trait Contains<T: Ord> {
211209
fn add(_t: &T) { unimplemented!() }
212210
}
213211

212+
/// A trait for querying bound for the length of an implementation of `Contains`
213+
pub trait ContainsLengthBound {
214+
/// Minimum number of elements contained
215+
fn min_len() -> usize;
216+
/// Maximum number of elements contained
217+
fn max_len() -> usize;
218+
}
219+
214220
/// Determiner to say whether a given account is unused.
215221
pub trait IsDeadAccount<AccountId> {
216222
/// Is the given account dead?

frame/treasury/src/lib.rs

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ use sp_runtime::{Permill, ModuleId, Percent, RuntimeDebug, traits::{
9999
Zero, StaticLookup, AccountIdConversion, Saturating, Hash, BadOrigin
100100
}};
101101
use frame_support::weights::{Weight, DispatchClass};
102-
use frame_support::traits::{Contains, EnsureOrigin};
102+
use frame_support::traits::{Contains, ContainsLengthBound, EnsureOrigin};
103103
use codec::{Encode, Decode};
104104
use frame_system::{self as system, ensure_signed, ensure_root};
105105

@@ -124,7 +124,9 @@ pub trait Trait: frame_system::Trait {
124124
type RejectOrigin: EnsureOrigin<Self::Origin>;
125125

126126
/// Origin from which tippers must come.
127-
type Tippers: Contains<Self::AccountId>;
127+
///
128+
/// `ContainsLengthBound::max_len` must be cost free (i.e. no storage read or heavy operation).
129+
type Tippers: Contains<Self::AccountId> + ContainsLengthBound;
128130

129131
/// The period for which a tip remains open after is has achieved threshold tippers.
130132
type TipCountdown: Get<Self::BlockNumber>;
@@ -326,11 +328,11 @@ decl_module! {
326328
/// proposal is awarded.
327329
///
328330
/// # <weight>
329-
/// - O(1).
330-
/// - Limited storage reads.
331-
/// - One DB change, one extra DB entry.
331+
/// - Complexity: O(1)
332+
/// - DbReads: `ProposalCount`, `origin account`
333+
/// - DbWrites: `ProposalCount`, `Proposals`, `origin account`
332334
/// # </weight>
333-
#[weight = 500_000_000]
335+
#[weight = 120_000_000 + T::DbWeight::get().reads_writes(1, 2)]
334336
fn propose_spend(
335337
origin,
336338
#[compact] value: BalanceOf<T>,
@@ -353,11 +355,11 @@ decl_module! {
353355
/// Reject a proposed spend. The original deposit will be slashed.
354356
///
355357
/// # <weight>
356-
/// - O(1).
357-
/// - Limited storage reads.
358-
/// - One DB clear.
358+
/// - Complexity: O(1)
359+
/// - DbReads: `Proposals`, `rejected proposer account`
360+
/// - DbWrites: `Proposals`, `rejected proposer account`
359361
/// # </weight>
360-
#[weight = (100_000_000, DispatchClass::Operational)]
362+
#[weight = (130_000_000 + T::DbWeight::get().reads_writes(2, 2), DispatchClass::Operational)]
361363
fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) {
362364
T::RejectOrigin::try_origin(origin)
363365
.map(|_| ())
@@ -375,11 +377,11 @@ decl_module! {
375377
/// and the original deposit will be returned.
376378
///
377379
/// # <weight>
378-
/// - O(1).
379-
/// - Limited storage reads.
380-
/// - One DB change.
380+
/// - Complexity: O(1).
381+
/// - DbReads: `Proposals`, `Approvals`
382+
/// - DbWrite: `Approvals`
381383
/// # </weight>
382-
#[weight = (100_000_000, DispatchClass::Operational)]
384+
#[weight = (34_000_000 + T::DbWeight::get().reads_writes(2, 1), DispatchClass::Operational)]
383385
fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) {
384386
T::ApproveOrigin::try_origin(origin)
385387
.map(|_| ())
@@ -403,12 +405,12 @@ decl_module! {
403405
/// Emits `NewTip` if successful.
404406
///
405407
/// # <weight>
406-
/// - `O(R)` where `R` length of `reason`.
407-
/// - One balance operation.
408-
/// - One storage mutation (codec `O(R)`).
409-
/// - One event.
408+
/// - Complexity: `O(R)` where `R` length of `reason`.
409+
/// - encoding and hashing of 'reason'
410+
/// - DbReads: `Reasons`, `Tips`, `who account data`
411+
/// - DbWrites: `Tips`, `who account data`
410412
/// # </weight>
411-
#[weight = 100_000_000]
413+
#[weight = 140_000_000 + 4_000 * reason.len() as Weight + T::DbWeight::get().reads_writes(3, 2)]
412414
fn report_awesome(origin, reason: Vec<u8>, who: T::AccountId) {
413415
let finder = ensure_signed(origin)?;
414416

@@ -445,12 +447,12 @@ decl_module! {
445447
/// Emits `TipRetracted` if successful.
446448
///
447449
/// # <weight>
448-
/// - `O(T)`
449-
/// - One balance operation.
450-
/// - Two storage removals (one read, codec `O(T)`).
451-
/// - One event.
450+
/// - Complexity: `O(1)`
451+
/// - Depends on the length of `T::Hash` which is fixed.
452+
/// - DbReads: `Tips`, `origin account`
453+
/// - DbWrites: `Reasons`, `Tips`, `origin account`
452454
/// # </weight>
453-
#[weight = 50_000_000]
455+
#[weight = 120_000_000 + T::DbWeight::get().reads_writes(1, 2)]
454456
fn retract_tip(origin, hash: T::Hash) {
455457
let who = ensure_signed(origin)?;
456458
let tip = Tips::<T>::get(&hash).ok_or(Error::<T>::UnknownTip)?;
@@ -477,12 +479,18 @@ decl_module! {
477479
/// Emits `NewTip` if successful.
478480
///
479481
/// # <weight>
480-
/// - `O(R + T)` where `R` length of `reason`, `T` is the number of tippers. `T` is
481-
/// naturally capped as a membership set, `R` is limited through transaction-size.
482-
/// - Two storage insertions (codecs `O(R)`, `O(T)`), one read `O(1)`.
483-
/// - One event.
482+
/// - Complexity: `O(R + T)` where `R` length of `reason`, `T` is the number of tippers.
483+
/// - `O(T)`: decoding `Tipper` vec of length `T`
484+
/// `T` is charged as upper bound given by `ContainsLengthBound`.
485+
/// The actual cost depends on the implementation of `T::Tippers`.
486+
/// - `O(R)`: hashing and encoding of reason of length `R`
487+
/// - DbReads: `Tippers`, `Reasons`
488+
/// - DbWrites: `Reasons`, `Tips`
484489
/// # </weight>
485-
#[weight = 150_000_000]
490+
#[weight = 110_000_000
491+
+ 4_000 * reason.len() as Weight
492+
+ 480_000 * T::Tippers::max_len() as Weight
493+
+ T::DbWeight::get().reads_writes(2, 2)]
486494
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, tip_value: BalanceOf<T>) {
487495
let tipper = ensure_signed(origin)?;
488496
ensure!(T::Tippers::contains(&tipper), BadOrigin);
@@ -512,11 +520,18 @@ decl_module! {
512520
/// has started.
513521
///
514522
/// # <weight>
515-
/// - `O(T)`
516-
/// - One storage mutation (codec `O(T)`), one storage read `O(1)`.
517-
/// - Up to one event.
523+
/// - Complexity: `O(T)` where `T` is the number of tippers.
524+
/// decoding `Tipper` vec of length `T`, insert tip and check closing,
525+
/// `T` is charged as upper bound given by `ContainsLengthBound`.
526+
/// The actual cost depends on the implementation of `T::Tippers`.
527+
///
528+
/// Actually weight could be lower as it depends on how many tips are in `OpenTip` but it
529+
/// is weighted as if almost full i.e of length `T-1`.
530+
/// - DbReads: `Tippers`, `Tips`
531+
/// - DbWrites: `Tips`
518532
/// # </weight>
519-
#[weight = 50_000_000]
533+
#[weight = 68_000_000 + 2_000_000 * T::Tippers::max_len() as Weight
534+
+ T::DbWeight::get().reads_writes(2, 1)]
520535
fn tip(origin, hash: T::Hash, tip_value: BalanceOf<T>) {
521536
let tipper = ensure_signed(origin)?;
522537
ensure!(T::Tippers::contains(&tipper), BadOrigin);
@@ -538,11 +553,15 @@ decl_module! {
538553
/// as the hash of the tuple of the original tip `reason` and the beneficiary account ID.
539554
///
540555
/// # <weight>
541-
/// - `O(T)`
542-
/// - One storage retrieval (codec `O(T)`) and two removals.
543-
/// - Up to three balance operations.
556+
/// - Complexity: `O(T)` where `T` is the number of tippers.
557+
/// decoding `Tipper` vec of length `T`.
558+
/// `T` is charged as upper bound given by `ContainsLengthBound`.
559+
/// The actual cost depends on the implementation of `T::Tippers`.
560+
/// - DbReads: `Tips`, `Tippers`, `tip finder`
561+
/// - DbWrites: `Reasons`, `Tips`, `Tippers`, `tip finder`
544562
/// # </weight>
545-
#[weight = 50_000_000]
563+
#[weight = 220_000_000 + 1_100_000 * T::Tippers::max_len() as Weight
564+
+ T::DbWeight::get().reads_writes(3, 3)]
546565
fn close_tip(origin, hash: T::Hash) {
547566
ensure_signed(origin)?;
548567

@@ -555,13 +574,23 @@ decl_module! {
555574
Self::payout_tip(hash, tip);
556575
}
557576

577+
/// # <weight>
578+
/// - Complexity: `O(A)` where `A` is the number of approvals
579+
/// - Db reads and writes: `Approvals`, `pot account data`
580+
/// - Db reads and writes per approval:
581+
/// `Proposals`, `proposer account data`, `beneficiary account data`
582+
/// - The weight is overestimated if some approvals got missed.
583+
/// # </weight>
558584
fn on_initialize(n: T::BlockNumber) -> Weight {
559585
// Check to see if we should spend some funds!
560586
if (n % T::SpendPeriod::get()).is_zero() {
561-
Self::spend_funds();
562-
}
587+
let approvals_len = Self::spend_funds();
563588

564-
0
589+
270_000_000 * approvals_len
590+
+ T::DbWeight::get().reads_writes(2 + approvals_len * 3, 2 + approvals_len * 3)
591+
} else {
592+
0
593+
}
565594
}
566595
}
567596
}
@@ -653,14 +682,15 @@ impl<T: Trait> Module<T> {
653682
Self::deposit_event(RawEvent::TipClosed(hash, tip.who, payout));
654683
}
655684

656-
// Spend some money!
657-
fn spend_funds() {
685+
/// Spend some money! returns number of approvals before spend.
686+
fn spend_funds() -> u64 {
658687
let mut budget_remaining = Self::pot();
659688
Self::deposit_event(RawEvent::Spending(budget_remaining));
660689

661690
let mut missed_any = false;
662691
let mut imbalance = <PositiveImbalanceOf<T>>::zero();
663-
Approvals::mutate(|v| {
692+
let prior_approvals_len = Approvals::mutate(|v| {
693+
let prior_approvals_len = v.len() as u64;
664694
v.retain(|&index| {
665695
// Should always be true, but shouldn't panic if false or we're screwed.
666696
if let Some(p) = Self::proposals(index) {
@@ -684,6 +714,7 @@ impl<T: Trait> Module<T> {
684714
false
685715
}
686716
});
717+
prior_approvals_len
687718
});
688719

689720
if !missed_any {
@@ -710,6 +741,8 @@ impl<T: Trait> Module<T> {
710741
}
711742

712743
Self::deposit_event(RawEvent::Rollover(budget_remaining));
744+
745+
prior_approvals_len
713746
}
714747

715748
/// Return the amount of money in the pot.

frame/treasury/src/tests.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ impl Contains<u64> for TenToFourteen {
111111
})
112112
}
113113
}
114+
impl ContainsLengthBound for TenToFourteen {
115+
fn max_len() -> usize {
116+
TEN_TO_FOURTEEN.with(|v| v.borrow().len())
117+
}
118+
fn min_len() -> usize { 0 }
119+
}
114120
parameter_types! {
115121
pub const ProposalBond: Permill = Permill::from_percent(5);
116122
pub const ProposalBondMinimum: u64 = 1;

0 commit comments

Comments
 (0)