@@ -36,7 +36,8 @@ use codec::{Encode, Decode};
3636use frame_support:: {
3737 decl_storage, decl_module,
3838 traits:: { Currency , Get , OnUnbalanced , ExistenceRequirement , WithdrawReason , Imbalance } ,
39- weights:: { Weight , DispatchInfo , GetDispatchInfo } ,
39+ weights:: { Weight , DispatchInfo , PostDispatchInfo , GetDispatchInfo } ,
40+ dispatch:: DispatchResult ,
4041} ;
4142use sp_runtime:: {
4243 Fixed64 ,
@@ -46,7 +47,7 @@ use sp_runtime::{
4647 } ,
4748 traits:: {
4849 Zero , Saturating , SignedExtension , SaturatedConversion , Convert , Dispatchable ,
49- DispatchInfoOf ,
50+ DispatchInfoOf , PostDispatchInfoOf ,
5051 } ,
5152} ;
5253use pallet_transaction_payment_rpc_runtime_api:: RuntimeDispatchInfo ;
@@ -102,7 +103,7 @@ decl_module! {
102103}
103104
104105impl < T : Trait > Module < T > where
105- T :: Call : Dispatchable < Info =DispatchInfo > ,
106+ T :: Call : Dispatchable < Info =DispatchInfo , PostInfo = PostDispatchInfo > ,
106107{
107108 /// Query the data that we know about the fee of a given `call`.
108109 ///
@@ -140,7 +141,8 @@ impl<T: Trait> Module<T> where
140141pub struct ChargeTransactionPayment < T : Trait + Send + Sync > ( #[ codec( compact) ] BalanceOf < T > ) ;
141142
142143impl < T : Trait + Send + Sync > ChargeTransactionPayment < T > where
143- T :: Call : Dispatchable < Info =DispatchInfo > ,
144+ T :: Call : Dispatchable < Info =DispatchInfo , PostInfo =PostDispatchInfo > ,
145+ BalanceOf < T > : Send + Sync ,
144146{
145147 /// utility constructor. Used only in client/factory code.
146148 pub fn from ( fee : BalanceOf < T > ) -> Self {
@@ -165,22 +167,12 @@ impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> where
165167 len : u32 ,
166168 info : & DispatchInfoOf < T :: Call > ,
167169 tip : BalanceOf < T > ,
168- ) -> BalanceOf < T >
169- where
170- BalanceOf < T > : Sync + Send ,
171- {
170+ ) -> BalanceOf < T > {
172171 if info. pays_fee {
173172 let len = <BalanceOf < T > >:: from ( len) ;
174173 let per_byte = T :: TransactionByteFee :: get ( ) ;
175174 let len_fee = per_byte. saturating_mul ( len) ;
176-
177- let weight_fee = {
178- // cap the weight to the maximum defined in runtime, otherwise it will be the
179- // `Bounded` maximum of its data type, which is not desired.
180- let capped_weight = info. weight
181- . min ( <T as frame_system:: Trait >:: MaximumBlockWeight :: get ( ) ) ;
182- T :: WeightToFee :: convert ( capped_weight)
183- } ;
175+ let weight_fee = Self :: compute_weight_fee ( info. weight ) ;
184176
185177 // the adjustable part of the fee
186178 let adjustable_fee = len_fee. saturating_add ( weight_fee) ;
@@ -194,6 +186,42 @@ impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> where
194186 tip
195187 }
196188 }
189+
190+ fn compute_weight_fee ( weight : Weight ) -> BalanceOf < T > {
191+ // cap the weight to the maximum defined in runtime, otherwise it will be the
192+ // `Bounded` maximum of its data type, which is not desired.
193+ let capped_weight = weight. min ( <T as frame_system:: Trait >:: MaximumBlockWeight :: get ( ) ) ;
194+ T :: WeightToFee :: convert ( capped_weight)
195+ }
196+
197+ fn withdraw_fee (
198+ & self ,
199+ who : & T :: AccountId ,
200+ info : & DispatchInfoOf < T :: Call > ,
201+ len : usize ,
202+ ) -> Result < ( BalanceOf < T > , Option < NegativeImbalanceOf < T > > ) , TransactionValidityError > {
203+ let tip = self . 0 ;
204+ let fee = Self :: compute_fee ( len as u32 , info, tip) ;
205+
206+ // Only mess with balances if fee is not zero.
207+ if fee. is_zero ( ) {
208+ return Ok ( ( fee, None ) ) ;
209+ }
210+
211+ match T :: Currency :: withdraw (
212+ who,
213+ fee,
214+ if tip. is_zero ( ) {
215+ WithdrawReason :: TransactionPayment . into ( )
216+ } else {
217+ WithdrawReason :: TransactionPayment | WithdrawReason :: Tip
218+ } ,
219+ ExistenceRequirement :: KeepAlive ,
220+ ) {
221+ Ok ( imbalance) => Ok ( ( fee, Some ( imbalance) ) ) ,
222+ Err ( _) => Err ( InvalidTransaction :: Payment . into ( ) ) ,
223+ }
224+ }
197225}
198226
199227impl < T : Trait + Send + Sync > sp_std:: fmt:: Debug for ChargeTransactionPayment < T > {
@@ -209,13 +237,13 @@ impl<T: Trait + Send + Sync> sp_std::fmt::Debug for ChargeTransactionPayment<T>
209237
210238impl < T : Trait + Send + Sync > SignedExtension for ChargeTransactionPayment < T > where
211239 BalanceOf < T > : Send + Sync ,
212- T :: Call : Dispatchable < Info =DispatchInfo > ,
240+ T :: Call : Dispatchable < Info =DispatchInfo , PostInfo = PostDispatchInfo > ,
213241{
214242 const IDENTIFIER : & ' static str = "ChargeTransactionPayment" ;
215243 type AccountId = T :: AccountId ;
216244 type Call = T :: Call ;
217245 type AdditionalSigned = ( ) ;
218- type Pre = ( ) ;
246+ type Pre = ( BalanceOf < T > , Self :: AccountId , Option < NegativeImbalanceOf < T > > ) ;
219247 fn additional_signed ( & self ) -> sp_std:: result:: Result < ( ) , TransactionValidityError > { Ok ( ( ) ) }
220248
221249 fn validate (
@@ -225,35 +253,55 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> whe
225253 info : & DispatchInfoOf < Self :: Call > ,
226254 len : usize ,
227255 ) -> TransactionValidity {
228- // pay any fees.
229- let tip = self . 0 ;
230- let fee = Self :: compute_fee ( len as u32 , info, tip) ;
231- // Only mess with balances if fee is not zero.
232- if !fee. is_zero ( ) {
233- let imbalance = match T :: Currency :: withdraw (
234- who,
235- fee,
236- if tip. is_zero ( ) {
237- WithdrawReason :: TransactionPayment . into ( )
238- } else {
239- WithdrawReason :: TransactionPayment | WithdrawReason :: Tip
240- } ,
241- ExistenceRequirement :: KeepAlive ,
242- ) {
243- Ok ( imbalance) => imbalance,
244- Err ( _) => return InvalidTransaction :: Payment . into ( ) ,
245- } ;
246- let imbalances = imbalance. split ( tip) ;
247- T :: OnTransactionPayment :: on_unbalanceds ( Some ( imbalances. 0 ) . into_iter ( )
248- . chain ( Some ( imbalances. 1 ) ) ) ;
249- }
256+ let ( fee, _) = self . withdraw_fee ( who, info, len) ?;
250257
251258 let mut r = ValidTransaction :: default ( ) ;
252259 // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which
253260 // will be a bit more than setting the priority to tip. For now, this is enough.
254261 r. priority = fee. saturated_into :: < TransactionPriority > ( ) ;
255262 Ok ( r)
256263 }
264+
265+ fn pre_dispatch (
266+ self ,
267+ who : & Self :: AccountId ,
268+ _call : & Self :: Call ,
269+ info : & DispatchInfoOf < Self :: Call > ,
270+ len : usize
271+ ) -> Result < Self :: Pre , TransactionValidityError > {
272+ let ( _, imbalance) = self . withdraw_fee ( who, info, len) ?;
273+ Ok ( ( self . 0 , who. clone ( ) , imbalance) )
274+ }
275+
276+ fn post_dispatch (
277+ pre : Self :: Pre ,
278+ info : & DispatchInfoOf < Self :: Call > ,
279+ post_info : & PostDispatchInfoOf < Self :: Call > ,
280+ _len : usize ,
281+ _result : & DispatchResult ,
282+ ) -> Result < ( ) , TransactionValidityError > {
283+ let ( tip, who, imbalance) = pre;
284+ if let Some ( payed) = imbalance {
285+ let refund = Self :: compute_weight_fee ( post_info. calc_unspent ( info) ) ;
286+ let actual_payment = match T :: Currency :: deposit_into_existing ( & who, refund) {
287+ Ok ( refund_imbalance) => {
288+ // The refund cannot be larger than the up front payed max weight.
289+ // `PostDispatchInfo::calc_unspent` guards against such a case.
290+ match payed. offset ( refund_imbalance) {
291+ Ok ( actual_payment) => actual_payment,
292+ Err ( _) => return Err ( InvalidTransaction :: Payment . into ( ) ) ,
293+ }
294+ }
295+ // We do not recreate the account using the refund. The up front payment
296+ // is gone in that case.
297+ Err ( _) => payed,
298+ } ;
299+ let imbalances = actual_payment. split ( tip) ;
300+ T :: OnTransactionPayment :: on_unbalanceds ( Some ( imbalances. 0 ) . into_iter ( )
301+ . chain ( Some ( imbalances. 1 ) ) ) ;
302+ }
303+ Ok ( ( ) )
304+ }
257305}
258306
259307#[ cfg( test) ]
0 commit comments