@@ -99,7 +99,7 @@ use sp_runtime::{Permill, ModuleId, Percent, RuntimeDebug, traits::{
9999 Zero , StaticLookup , AccountIdConversion , Saturating , Hash , BadOrigin
100100} } ;
101101use frame_support:: weights:: { Weight , DispatchClass } ;
102- use frame_support:: traits:: { Contains , EnsureOrigin } ;
102+ use frame_support:: traits:: { Contains , ContainsLengthBound , EnsureOrigin } ;
103103use codec:: { Encode , Decode } ;
104104use 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.
0 commit comments