@@ -44,7 +44,7 @@ use frame_support::{
44
44
dispatch:: DispatchResult ,
45
45
} ;
46
46
use sp_runtime:: {
47
- Fixed128 , FixedPointNumber ,
47
+ Fixed128 , FixedPointNumber , FixedPointOperand ,
48
48
transaction_validity:: {
49
49
TransactionPriority , ValidTransaction , InvalidTransaction , TransactionValidityError ,
50
50
TransactionValidity ,
@@ -104,7 +104,9 @@ decl_module! {
104
104
}
105
105
}
106
106
107
- impl < T : Trait > Module < T > {
107
+ impl < T : Trait > Module < T > where
108
+ BalanceOf < T > : FixedPointOperand
109
+ {
108
110
/// Query the data that we know about the fee of a given `call`.
109
111
///
110
112
/// This module is not and cannot be aware of the internals of a signed extension, for example
@@ -163,35 +165,63 @@ impl<T: Trait> Module<T> {
163
165
) -> BalanceOf < T > where
164
166
T :: Call : Dispatchable < Info =DispatchInfo > ,
165
167
{
166
- if info. pays_fee == Pays :: Yes {
168
+ Self :: compute_fee_raw ( len, info. weight , tip, info. pays_fee )
169
+ }
170
+
171
+ /// Compute the actual post dispatch fee for a particular transaction.
172
+ ///
173
+ /// Identical to `compute_fee` with the only difference that the post dispatch corrected
174
+ /// weight is used for the weight fee calculation.
175
+ pub fn compute_actual_fee (
176
+ len : u32 ,
177
+ info : & DispatchInfoOf < T :: Call > ,
178
+ post_info : & PostDispatchInfoOf < T :: Call > ,
179
+ tip : BalanceOf < T > ,
180
+ ) -> BalanceOf < T > where
181
+ T :: Call : Dispatchable < Info =DispatchInfo , PostInfo =PostDispatchInfo > ,
182
+ {
183
+ Self :: compute_fee_raw ( len, post_info. calc_actual_weight ( info) , tip, info. pays_fee )
184
+ }
185
+
186
+ fn compute_fee_raw (
187
+ len : u32 ,
188
+ weight : Weight ,
189
+ tip : BalanceOf < T > ,
190
+ pays_fee : Pays ,
191
+ ) -> BalanceOf < T > {
192
+ if pays_fee == Pays :: Yes {
167
193
let len = <BalanceOf < T > >:: from ( len) ;
168
194
let per_byte = T :: TransactionByteFee :: get ( ) ;
169
195
let len_fee = per_byte. saturating_mul ( len) ;
170
- let unadjusted_weight_fee = Self :: weight_to_fee ( info . weight ) ;
196
+ let unadjusted_weight_fee = Self :: weight_to_fee ( weight) ;
171
197
172
198
// the adjustable part of the fee
173
199
let adjustable_fee = len_fee. saturating_add ( unadjusted_weight_fee) ;
174
200
let targeted_fee_adjustment = NextFeeMultiplier :: get ( ) ;
175
- let adjusted_fee = targeted_fee_adjustment. saturating_mul_acc_int ( adjustable_fee. saturated_into ( ) ) ;
201
+ let adjusted_fee = targeted_fee_adjustment. saturating_mul_acc_int ( adjustable_fee) ;
176
202
177
203
let base_fee = Self :: weight_to_fee ( T :: ExtrinsicBaseWeight :: get ( ) ) ;
178
- base_fee. saturating_add ( adjusted_fee. saturated_into ( ) ) . saturating_add ( tip)
204
+ base_fee. saturating_add ( adjusted_fee) . saturating_add ( tip)
179
205
} else {
180
206
tip
181
207
}
182
208
}
209
+ }
183
210
211
+ impl < T : Trait > Module < T > {
184
212
/// Compute the fee for the specified weight.
185
213
///
186
214
/// This fee is already adjusted by the per block fee adjustment factor and is therefore
187
215
/// the share that the weight contributes to the overall fee of a transaction.
216
+ ///
217
+ /// This function is generic in order to supply the contracts module with a way
218
+ /// to calculate the gas price. The contracts module is not able to put the necessary
219
+ /// `BalanceOf<T>` contraints on its trait. This function is not to be used by this module.
188
220
pub fn weight_to_fee_with_adjustment < Balance > ( weight : Weight ) -> Balance where
189
221
Balance : UniqueSaturatedFrom < u128 >
190
222
{
191
- let fee = UniqueSaturatedInto :: < u128 > :: unique_saturated_into ( Self :: weight_to_fee ( weight) ) ;
192
- UniqueSaturatedFrom :: unique_saturated_from (
193
- NextFeeMultiplier :: get ( ) . saturating_mul_acc_int ( fee)
194
- )
223
+ let fee: u128 = Self :: weight_to_fee ( weight) . unique_saturated_into ( ) ;
224
+ Balance :: unique_saturated_from ( NextFeeMultiplier :: get ( ) . saturating_mul_acc_int ( fee) )
195
225
}
196
226
197
227
fn weight_to_fee ( weight : Weight ) -> BalanceOf < T > {
@@ -209,7 +239,7 @@ pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(#[codec(compact)] Ba
209
239
210
240
impl < T : Trait + Send + Sync > ChargeTransactionPayment < T > where
211
241
T :: Call : Dispatchable < Info =DispatchInfo , PostInfo =PostDispatchInfo > ,
212
- BalanceOf < T > : Send + Sync ,
242
+ BalanceOf < T > : Send + Sync + FixedPointOperand ,
213
243
{
214
244
/// utility constructor. Used only in client/factory code.
215
245
pub fn from ( fee : BalanceOf < T > ) -> Self {
@@ -258,14 +288,14 @@ impl<T: Trait + Send + Sync> sp_std::fmt::Debug for ChargeTransactionPayment<T>
258
288
}
259
289
260
290
impl < T : Trait + Send + Sync > SignedExtension for ChargeTransactionPayment < T > where
261
- BalanceOf < T > : Send + Sync + From < u64 > ,
291
+ BalanceOf < T > : Send + Sync + From < u64 > + FixedPointOperand ,
262
292
T :: Call : Dispatchable < Info =DispatchInfo , PostInfo =PostDispatchInfo > ,
263
293
{
264
294
const IDENTIFIER : & ' static str = "ChargeTransactionPayment" ;
265
295
type AccountId = T :: AccountId ;
266
296
type Call = T :: Call ;
267
297
type AdditionalSigned = ( ) ;
268
- type Pre = ( BalanceOf < T > , Self :: AccountId , Option < NegativeImbalanceOf < T > > ) ;
298
+ type Pre = ( BalanceOf < T > , Self :: AccountId , Option < NegativeImbalanceOf < T > > , BalanceOf < T > ) ;
269
299
fn additional_signed ( & self ) -> sp_std:: result:: Result < ( ) , TransactionValidityError > { Ok ( ( ) ) }
270
300
271
301
fn validate (
@@ -291,20 +321,26 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> whe
291
321
info : & DispatchInfoOf < Self :: Call > ,
292
322
len : usize
293
323
) -> Result < Self :: Pre , TransactionValidityError > {
294
- let ( _ , imbalance) = self . withdraw_fee ( who, info, len) ?;
295
- Ok ( ( self . 0 , who. clone ( ) , imbalance) )
324
+ let ( fee , imbalance) = self . withdraw_fee ( who, info, len) ?;
325
+ Ok ( ( self . 0 , who. clone ( ) , imbalance, fee ) )
296
326
}
297
327
298
328
fn post_dispatch (
299
329
pre : Self :: Pre ,
300
330
info : & DispatchInfoOf < Self :: Call > ,
301
331
post_info : & PostDispatchInfoOf < Self :: Call > ,
302
- _len : usize ,
332
+ len : usize ,
303
333
_result : & DispatchResult ,
304
334
) -> Result < ( ) , TransactionValidityError > {
305
- let ( tip, who, imbalance) = pre;
335
+ let ( tip, who, imbalance, fee ) = pre;
306
336
if let Some ( payed) = imbalance {
307
- let refund = Module :: < T > :: weight_to_fee_with_adjustment ( post_info. calc_unspent ( info) ) ;
337
+ let actual_fee = Module :: < T > :: compute_actual_fee (
338
+ len as u32 ,
339
+ info,
340
+ post_info,
341
+ tip,
342
+ ) ;
343
+ let refund = fee. saturating_sub ( actual_fee) ;
308
344
let actual_payment = match T :: Currency :: deposit_into_existing ( & who, refund) {
309
345
Ok ( refund_imbalance) => {
310
346
// The refund cannot be larger than the up front payed max weight.
@@ -789,6 +825,39 @@ mod tests {
789
825
} ) ;
790
826
}
791
827
828
+ #[ test]
829
+ fn compute_fee_works_with_negative_multiplier ( ) {
830
+ ExtBuilder :: default ( )
831
+ . base_weight ( 100 )
832
+ . byte_fee ( 10 )
833
+ . balance_factor ( 0 )
834
+ . build ( )
835
+ . execute_with ( ||
836
+ {
837
+ // Add a next fee multiplier
838
+ NextFeeMultiplier :: put ( Fixed128 :: saturating_from_rational ( -1 , 2 ) ) ; // = -1/2 = -.5
839
+ // Base fee is unaffected by multiplier
840
+ let dispatch_info = DispatchInfo {
841
+ weight : 0 ,
842
+ class : DispatchClass :: Operational ,
843
+ pays_fee : Pays :: Yes ,
844
+ } ;
845
+ assert_eq ! ( Module :: <Runtime >:: compute_fee( 0 , & dispatch_info, 0 ) , 100 ) ;
846
+
847
+ // Everything works together :)
848
+ let dispatch_info = DispatchInfo {
849
+ weight : 123 ,
850
+ class : DispatchClass :: Operational ,
851
+ pays_fee : Pays :: Yes ,
852
+ } ;
853
+ // 123 weight, 456 length, 100 base
854
+ // adjustable fee = (123 * 1) + (456 * 10) = 4683
855
+ // adjusted fee = 4683 - (4683 * -.5) = 4683 - 2341.5 = 4683 - 2341 = 2342
856
+ // final fee = 100 + 2342 + 789 tip = 3231
857
+ assert_eq ! ( Module :: <Runtime >:: compute_fee( 456 , & dispatch_info, 789 ) , 3231 ) ;
858
+ } ) ;
859
+ }
860
+
792
861
#[ test]
793
862
fn compute_fee_does_not_overflow ( ) {
794
863
ExtBuilder :: default ( )
@@ -906,4 +975,41 @@ mod tests {
906
975
assert_eq ! ( System :: events( ) . len( ) , 0 ) ;
907
976
} ) ;
908
977
}
978
+
979
+ #[ test]
980
+ fn refund_consistent_with_actual_weight ( ) {
981
+ ExtBuilder :: default ( )
982
+ . balance_factor ( 10 )
983
+ . base_weight ( 7 )
984
+ . build ( )
985
+ . execute_with ( ||
986
+ {
987
+ let info = info_from_weight ( 100 ) ;
988
+ let post_info = post_info_from_weight ( 33 ) ;
989
+ let prev_balance = Balances :: free_balance ( 2 ) ;
990
+ let len = 10 ;
991
+ let tip = 5 ;
992
+
993
+ NextFeeMultiplier :: put ( Fixed128 :: saturating_from_rational ( 1 , 4 ) ) ;
994
+
995
+ let pre = ChargeTransactionPayment :: < Runtime > :: from ( tip)
996
+ . pre_dispatch ( & 2 , CALL , & info, len)
997
+ . unwrap ( ) ;
998
+
999
+ ChargeTransactionPayment :: < Runtime >
1000
+ :: post_dispatch ( pre, & info, & post_info, len, & Ok ( ( ) ) )
1001
+ . unwrap ( ) ;
1002
+
1003
+ let refund_based_fee = prev_balance - Balances :: free_balance ( 2 ) ;
1004
+ let actual_fee = Module :: < Runtime >
1005
+ :: compute_actual_fee ( len as u32 , & info, & post_info, tip) ;
1006
+
1007
+ // 33 weight, 10 length, 7 base
1008
+ // adjustable fee = (33 * 1) + (10 * 1) = 43
1009
+ // adjusted fee = 43 + (43 * .25) = 43 + 10.75 = 43 + 10 = 53
1010
+ // final fee = 7 + 53 + 5 tip = 65
1011
+ assert_eq ! ( actual_fee, 65 ) ;
1012
+ assert_eq ! ( refund_based_fee, actual_fee) ;
1013
+ } ) ;
1014
+ }
909
1015
}
0 commit comments