通过调用名称和参数匹配,用于来自其他托盘的调用

Match by call name and parameters, for a call from other pallets

我有一个模块方法可以将固定费用与来自不同托盘的呼叫相关联。 因此,我试图通过托盘、调用名称和调用参数来匹配传递给我的方法的调用作为参数。

与此类似的内容:

impl<T: Config> Module<T>
{
    fn compute_call_fee_(call: &<T as Config>::Call) -> Result<u64, &'static str> {
        let fee = match *call {
            Call::PalletA(palletA::Call::name_of_palletA_call(x,y)) => 50u64, // here this is not real syntax, this is what I need to figure out
            _ => 100u64
        };

        Ok(fee)
    }
}

对于上述情况,配置特征将从匹配的不同托盘实现配置特征:

pub trait Config: system::Config + palletA::Config + palletB::Config {
    type Call: Parameter + Dispatchable<Origin = Self::Origin> + GetDispatchInfo;
}

如何通过源托盘、函数名称和函数参数在 call 上进行匹配?

我试过:

在您粘贴完整代码(特别是 type Call = xxx 部分)之前很难说,但我可以猜到您错过的是:type Call: IsSubType<pallet_balances::Call<Self>>;。你提到了另一个推荐相同的问题,但我猜你没有正确使用它。

请注意,总体而言,外部 Call(您通过 type Call 传递到托盘中的那个)实现了两件事:

  • From<pallet_call> 用于每个单独的托盘调用。这将允许您始终将内部 Call 转换为外部 Call.
  • IsSubType<pallet_call> 用于每个单独的托盘调用。这将允许您有条件地将外部调用转换为内部调用(如果存在)。

也许这里的命名可以更好一些。我会考虑至少将外部 Call 重命名为.. OuterCall.

最后,绝对推荐运行节点模板上的cargo expand,寻找enum Call

TLDR;如果你将它应用在节点模板之上,这个差异将起作用,也应该回答你的问题。

diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml
index 12b810de1..6f91e8c9a 100644
--- a/bin/node-template/pallets/template/Cargo.toml
+++ b/bin/node-template/pallets/template/Cargo.toml
@@ -25,6 +25,11 @@ default-features = false
 version = "2.0.0"
 path = "../../../../frame/system"
 
+[dependencies.pallet-balances]
+default-features = false
+version = "2.0.0"
+path = "../../../../frame/balances"
+
 [dev-dependencies.sp-core]
 default-features = false
 version = "2.0.0"
@@ -46,5 +51,6 @@ default = ['std']
 std = [
    'codec/std',
    'frame-support/std',
-   'frame-system/std'
+   'frame-system/std',
+   'pallet-balances/std'
 ]
diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs
index 24de4f2f5..562675a0b 100644
--- a/bin/node-template/pallets/template/src/lib.rs
+++ b/bin/node-template/pallets/template/src/lib.rs
@@ -14,9 +14,11 @@ mod mock;
 mod tests;
 
 /// Configure the pallet by specifying the parameters and types on which it depends.
-pub trait Config: frame_system::Config {
+use frame_support::traits::IsSubType;
+pub trait Config: frame_system::Config + pallet_balances::Config {
    /// Because this pallet emits events, it depends on the runtime's definition of an event.
    type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
+   type Call: IsSubType<pallet_balances::Call<Self>>;
 }
 
 // The pallet's runtime storage items.
diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs
index 51df3dd5a..4ca2ab613 100644
--- a/bin/node-template/runtime/src/lib.rs
+++ b/bin/node-template/runtime/src/lib.rs
@@ -258,6 +258,7 @@ impl pallet_sudo::Config for Runtime {
 /// Configure the pallet template in pallets/template.
 impl template::Config for Runtime {
    type Event = Event;
+   type Call = Call;
 }
 
 // Create the runtime by composing the FRAME pallets that were previously configured.

最终,使用IsSubType确实是解决方案。

我需要将它添加到与 Config 特征关联的 type Call 中,如@kiaenigma 所示:

pub trait Config pub trait Config: system::Config + palletA::Config + palletB::Config {
    type Call: Parameter + Dispatchable<Origin = Self::Origin> + GetDispatchInfo + IsSubType<palletA::Call<Self>> + IsSubType<palletB::Call<Self>>;
}

然后在模块的方法中,将我的代码稍微更改为:

impl<T: Config> Module<T>
{
    fn compute_call_fee_(call: &<T as Config>::Call) -> Result<u64, DispatchError> {
        match call.is_sub_type() {
            Some(palletA::Call::palletA_method1(_arg1,_arg2)) => return Ok(60_u64),
            Some(palletA::Call::palletA_method2(_arg1,_arg2,_arg3)) => return Ok(60_u64),
            _ => {}
        };
        match call.is_sub_type() {
            Some(palletB::Call::palletB_method1(_arg1)) => return Ok(40_u64),
            _ => {}
        };

        return 80_u64;
    }
}