首页 > 解决方案 > 我们可以从作为参数传递给基板中函数的调用(类型)中获取托盘和函数数据吗?

问题描述

fn pre_dispatch(
        self,
        who: &Self::AccountId,
        call: &Self::Call,
        info: &DispatchInfoOf<Self::Call>,
        len: usize
    ) -> Result<Self::Pre, TransactionValidityError> {
        let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;
        Ok((self.0, who.clone(), imbalance))
    }

(上面的代码是从 txn-payment-pallet 复制的)
这里我们可以从调用中获取函数名和参数(参数之一),并且根据用户传递的函数名,pallet,参数,我想计算费用。
例如,如果它是从pallet-staking::bond(x : amount_of_tokens_to_be_bonded)调用的,我想根据x 为txn 设置费用。那可能吗??同样,我想根据用户输入的函数调用参数设置费用。

标签: blockchainsubstratepolkadot

解决方案


你可以,但它需要一些类型的杂耍才能做到这一点。

首先,您需要type Call = T::Call;ChargeTransactionPayment. 往里看trait Config,那里看pallet_transaction_payment不到type Call。相反,这种类型来自frame_system::Config(这是所有托盘的超级特征)。

对顶层运行时聚合器文件的简要介绍可以发现,这种Call类型本质上是运行时的外部调用,一个封装了所有托盘调用的枚举。

话虽这么说,这里的重点是,从内部pallet_transaction_payment,我们无法知道这个外部调用是否包含这个来自质押的特定调用。为此,您需要通过一个新的 trait bound 来强制执行这个假设,即IsSubType. 此特征专门用于从包装类型(如外部调用)转换为其内部变体。请参阅为's类型实现的这种类型的示例node_runtimeCall

将以下差异应用于基板主控应该完全符合您的要求。

diff --git a/Cargo.lock b/Cargo.lock
index ea54adf99e..df66185163 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6074,6 +6074,7 @@ dependencies = [
  "frame-support",
  "frame-system",
  "pallet-balances",
+ "pallet-staking",
  "parity-scale-codec",
  "scale-info",
  "serde",
diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml
index 1d3066e39f..0e705514bb 100644
--- a/frame/transaction-payment/Cargo.toml
+++ b/frame/transaction-payment/Cargo.toml
@@ -27,6 +27,7 @@ sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primit
 
 frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
 frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
+pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../staking" }
 
 [dev-dependencies]
 serde_json = "1.0.68"
@@ -44,5 +45,6 @@ std = [
    "sp-std/std",
    "frame-support/std",
    "frame-system/std",
+   "pallet-staking/std",
 ]
 try-runtime = ["frame-support/try-runtime"]
diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs
index 59d94a8237..3b0803663d 100644
--- a/frame/transaction-payment/src/lib.rs
+++ b/frame/transaction-payment/src/lib.rs
@@ -251,7 +251,7 @@ pub mod pallet {
    pub struct Pallet<T>(_);
 
    #[pallet::config]
-   pub trait Config: frame_system::Config {
+   pub trait Config: frame_system::Config + pallet_staking::Config {
        /// Handler for withdrawing, refunding and depositing the transaction fee.
        /// Transaction fees are withdrawn before the transaction is executed.
        /// After the transaction was executed the transaction weight can be
@@ -696,7 +696,8 @@ impl<T: Config> sp_std::fmt::Debug for ChargeTransactionPayment<T> {
 impl<T: Config> SignedExtension for ChargeTransactionPayment<T>
 where
    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,
-   T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
+   T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>
+       + frame_support::traits::IsSubType<pallet_staking::Call<T>>,
 {
    const IDENTIFIER: &'static str = "ChargeTransactionPayment";
    type AccountId = T::AccountId;
@@ -736,8 +737,15 @@ where
        info: &DispatchInfoOf<Self::Call>,
        len: usize,
    ) -> Result<Self::Pre, TransactionValidityError> {
-       let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;
-       Ok((self.0, who.clone(), imbalance))
+       use frame_support::traits::IsSubType;
+       if let Some(pallet_staking::Call::bond_extra { .. }) = call.is_sub_type() {
+           // skip
+           todo!()
+       } else {
+           // default impl
+           let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;
+           Ok((self.0, who.clone(), imbalance))
+       }
    }
 
    fn post_dispatch(

请注意,这种方法意味着pallet_staking::Config存在于运行时中,这与 Frame 的模块化不相符,并且没有实现 ergo。如果你想拥有这个功能,到目前为止,唯一的方法是pallet_transaction_payment为你的运行时分叉和定制它。


推荐阅读