mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 00:31:07 +00:00
Do a refund based on the actual weight (#5584)
This refunds weight and the weight bases fee back to the sender of an extrinsic after the dispatch.
This commit is contained in:
committed by
GitHub
parent
8e0d01570f
commit
bd91e58a9a
@@ -36,7 +36,8 @@ use codec::{Encode, Decode};
|
||||
use frame_support::{
|
||||
decl_storage, decl_module,
|
||||
traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason, Imbalance},
|
||||
weights::{Weight, DispatchInfo, GetDispatchInfo},
|
||||
weights::{Weight, DispatchInfo, PostDispatchInfo, GetDispatchInfo},
|
||||
dispatch::DispatchResult,
|
||||
};
|
||||
use sp_runtime::{
|
||||
Fixed64,
|
||||
@@ -46,7 +47,7 @@ use sp_runtime::{
|
||||
},
|
||||
traits::{
|
||||
Zero, Saturating, SignedExtension, SaturatedConversion, Convert, Dispatchable,
|
||||
DispatchInfoOf,
|
||||
DispatchInfoOf, PostDispatchInfoOf,
|
||||
},
|
||||
};
|
||||
use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
|
||||
@@ -102,7 +103,7 @@ decl_module! {
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> where
|
||||
T::Call: Dispatchable<Info=DispatchInfo>,
|
||||
T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo>,
|
||||
{
|
||||
/// Query the data that we know about the fee of a given `call`.
|
||||
///
|
||||
@@ -140,7 +141,8 @@ impl<T: Trait> Module<T> where
|
||||
pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(#[codec(compact)] BalanceOf<T>);
|
||||
|
||||
impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> where
|
||||
T::Call: Dispatchable<Info=DispatchInfo>,
|
||||
T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo>,
|
||||
BalanceOf<T>: Send + Sync,
|
||||
{
|
||||
/// utility constructor. Used only in client/factory code.
|
||||
pub fn from(fee: BalanceOf<T>) -> Self {
|
||||
@@ -165,22 +167,12 @@ impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> where
|
||||
len: u32,
|
||||
info: &DispatchInfoOf<T::Call>,
|
||||
tip: BalanceOf<T>,
|
||||
) -> BalanceOf<T>
|
||||
where
|
||||
BalanceOf<T>: Sync + Send,
|
||||
{
|
||||
) -> BalanceOf<T> {
|
||||
if info.pays_fee {
|
||||
let len = <BalanceOf<T>>::from(len);
|
||||
let per_byte = T::TransactionByteFee::get();
|
||||
let len_fee = per_byte.saturating_mul(len);
|
||||
|
||||
let weight_fee = {
|
||||
// cap the weight to the maximum defined in runtime, otherwise it will be the
|
||||
// `Bounded` maximum of its data type, which is not desired.
|
||||
let capped_weight = info.weight
|
||||
.min(<T as frame_system::Trait>::MaximumBlockWeight::get());
|
||||
T::WeightToFee::convert(capped_weight)
|
||||
};
|
||||
let weight_fee = Self::compute_weight_fee(info.weight);
|
||||
|
||||
// the adjustable part of the fee
|
||||
let adjustable_fee = len_fee.saturating_add(weight_fee);
|
||||
@@ -194,6 +186,42 @@ impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> where
|
||||
tip
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_weight_fee(weight: Weight) -> BalanceOf<T> {
|
||||
// cap the weight to the maximum defined in runtime, otherwise it will be the
|
||||
// `Bounded` maximum of its data type, which is not desired.
|
||||
let capped_weight = weight.min(<T as frame_system::Trait>::MaximumBlockWeight::get());
|
||||
T::WeightToFee::convert(capped_weight)
|
||||
}
|
||||
|
||||
fn withdraw_fee(
|
||||
&self,
|
||||
who: &T::AccountId,
|
||||
info: &DispatchInfoOf<T::Call>,
|
||||
len: usize,
|
||||
) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {
|
||||
let tip = self.0;
|
||||
let fee = Self::compute_fee(len as u32, info, tip);
|
||||
|
||||
// Only mess with balances if fee is not zero.
|
||||
if fee.is_zero() {
|
||||
return Ok((fee, None));
|
||||
}
|
||||
|
||||
match T::Currency::withdraw(
|
||||
who,
|
||||
fee,
|
||||
if tip.is_zero() {
|
||||
WithdrawReason::TransactionPayment.into()
|
||||
} else {
|
||||
WithdrawReason::TransactionPayment | WithdrawReason::Tip
|
||||
},
|
||||
ExistenceRequirement::KeepAlive,
|
||||
) {
|
||||
Ok(imbalance) => Ok((fee, Some(imbalance))),
|
||||
Err(_) => Err(InvalidTransaction::Payment.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<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>
|
||||
|
||||
impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> where
|
||||
BalanceOf<T>: Send + Sync,
|
||||
T::Call: Dispatchable<Info=DispatchInfo>,
|
||||
T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo>,
|
||||
{
|
||||
const IDENTIFIER: &'static str = "ChargeTransactionPayment";
|
||||
type AccountId = T::AccountId;
|
||||
type Call = T::Call;
|
||||
type AdditionalSigned = ();
|
||||
type Pre = ();
|
||||
type Pre = (BalanceOf<T>, Self::AccountId, Option<NegativeImbalanceOf<T>>);
|
||||
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) }
|
||||
|
||||
fn validate(
|
||||
@@ -225,28 +253,7 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> whe
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
len: usize,
|
||||
) -> TransactionValidity {
|
||||
// pay any fees.
|
||||
let tip = self.0;
|
||||
let fee = Self::compute_fee(len as u32, info, tip);
|
||||
// Only mess with balances if fee is not zero.
|
||||
if !fee.is_zero() {
|
||||
let imbalance = match T::Currency::withdraw(
|
||||
who,
|
||||
fee,
|
||||
if tip.is_zero() {
|
||||
WithdrawReason::TransactionPayment.into()
|
||||
} else {
|
||||
WithdrawReason::TransactionPayment | WithdrawReason::Tip
|
||||
},
|
||||
ExistenceRequirement::KeepAlive,
|
||||
) {
|
||||
Ok(imbalance) => imbalance,
|
||||
Err(_) => return InvalidTransaction::Payment.into(),
|
||||
};
|
||||
let imbalances = imbalance.split(tip);
|
||||
T::OnTransactionPayment::on_unbalanceds(Some(imbalances.0).into_iter()
|
||||
.chain(Some(imbalances.1)));
|
||||
}
|
||||
let (fee, _) = self.withdraw_fee(who, info, len)?;
|
||||
|
||||
let mut r = ValidTransaction::default();
|
||||
// NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which
|
||||
@@ -254,6 +261,47 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> whe
|
||||
r.priority = fee.saturated_into::<TransactionPriority>();
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn pre_dispatch(
|
||||
self,
|
||||
who: &Self::AccountId,
|
||||
_call: &Self::Call,
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
len: usize
|
||||
) -> Result<Self::Pre, TransactionValidityError> {
|
||||
let (_, imbalance) = self.withdraw_fee(who, info, len)?;
|
||||
Ok((self.0, who.clone(), imbalance))
|
||||
}
|
||||
|
||||
fn post_dispatch(
|
||||
pre: Self::Pre,
|
||||
info: &DispatchInfoOf<Self::Call>,
|
||||
post_info: &PostDispatchInfoOf<Self::Call>,
|
||||
_len: usize,
|
||||
_result: &DispatchResult,
|
||||
) -> Result<(), TransactionValidityError> {
|
||||
let (tip, who, imbalance) = pre;
|
||||
if let Some(payed) = imbalance {
|
||||
let refund = Self::compute_weight_fee(post_info.calc_unspent(info));
|
||||
let actual_payment = match T::Currency::deposit_into_existing(&who, refund) {
|
||||
Ok(refund_imbalance) => {
|
||||
// The refund cannot be larger than the up front payed max weight.
|
||||
// `PostDispatchInfo::calc_unspent` guards against such a case.
|
||||
match payed.offset(refund_imbalance) {
|
||||
Ok(actual_payment) => actual_payment,
|
||||
Err(_) => return Err(InvalidTransaction::Payment.into()),
|
||||
}
|
||||
}
|
||||
// We do not recreate the account using the refund. The up front payment
|
||||
// is gone in that case.
|
||||
Err(_) => payed,
|
||||
};
|
||||
let imbalances = actual_payment.split(tip);
|
||||
T::OnTransactionPayment::on_unbalanceds(Some(imbalances.0).into_iter()
|
||||
.chain(Some(imbalances.1)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user