0

Substrate allows you to "re-dispatch" an extrinsic, for example when calling the sudo function in the sudo module we have:

            let res = match proposal.dispatch(system::RawOrigin::Root.into()) {
                Ok(_) => true,
                Err(e) => {
                    let e: DispatchError = e.into();
                    sr_primitives::print(e);
                    false
                }
            };

In this model, the underlying extrinsic being executed (proposal) does not go through the SignedExtension flow, so will not collect any fees (fees are collected based on the sudo function, not the underlying proposal.

In this example that may be reasonable (since the sudo account is special and can be considered to be trusted), but in other cases (e.g. with a multisig which re-dispatches a proposed transaction) this doesn't seem to be the case.

Is there any way to pass a proposal back through the SignedExtension flow so that things like TakeFee can be assessed on the underlying transaction?

Adam Dossa
  • 228
  • 1
  • 8

2 Answers2

1

Indeed you can see pallet_sudo take a Dispatchable, this dispatchable doesn't contains the weight information available in DispatchInfo, nor any logic to compute fees.

If you want to compute fees maybe you want not a dispatchable but the actual extrinsic to execute. The frame-executive crate is generic over the extrinsic, you should be able to make use of similar trait bounds.

Then in the runtime definition (bin/node/runtime/src/lib.rs) you should be able to make something like:

impl pallet_mine::Trait for Runtime {
    extrinsic: UncheckedExtrinsic
}
thiolliere
  • 516
  • 2
  • 3
1

What @thiolliere recommended sounds reasonable to me. Elaborating a bit more:

  • the generic Extrinsic type of the runtime is required in the executive to have the trait Applyable. In the implementation of Applyable, you see that the inner call is Dispatchable.
  • The signed extension pipeline is triggered inside the fn apply() of the same trait. So you'd probably want to do: type Extrinsic: Applyable<_, _> in your trait and as mentioned pass the extrinsic type of the runtime to it.

At the end of the day, it boils down to abstracting over the high level, opaque Extrinsic or the more course grained inner Dispatchable Call enum variant.

Note that depending on what you want to achieve, you could also stay only abstracted over the inner call and manually deduct some more fees. You could make the proposal type (if similar to democracy, it is simply a Call) be bounded to GetDispatchInfo (i.e. type Proposal: Dispatchable + ... + GetDispatchInfo). This allows you to read the weight value via poposal.get_dispatch_info(). Combined with the encoded length, you can practically either reproduce, or do something similar to to what TakeFees is doing.

kianenigma
  • 1,365
  • 12
  • 20