0

Given the following extrinsic

#[pallet::weight(<T as Config>::WeightInfo::foo(*hint))]
fn foo(hint: u32) {
   let real = get_real();

   if real > hint {
      return <Error<T>>::HintTooLow;
   }

   // do something
   Ok(real.into())
}

Is it possible to report the actual weight (real) but charge a different fee (hint) from within the extrinsic? PostDispatch seems to affect the weight & subsequently the fee via WeightToFee. Probably what is desired here is a different weight to correct block weight and to charge fee, separately.

Rationale: Prevent a user from spamming the network by maliciously overestimating the hint thereby tricking block authors, tx priority, etc.

4
  • I'd have a look at this and please let us know if there is still something unclear: substrate.stackexchange.com/questions/6103/… Commented Dec 19, 2022 at 16:40
  • I looked into it and the concepts are quite clear to me, however, it doesn't address the question - can one report the actual weight used but charge fee on a different weight to disincentivize spamming extrinsics with a higher weight hint to maliciously trick the tx pool?
    – nbaztec
    Commented Dec 20, 2022 at 11:22
  • 1
    I don't fully understand your reasoning, but yes you can. You could write your own pallet where you implement the post-dispatch logic differently. Commented Dec 20, 2022 at 14:27
  • Yeah seems I'd either need to modify transaction-payment or write my own payment pallet to take into account the DispatchInfo & PostDispatchInfo weights for charging fees.
    – nbaztec
    Commented Dec 21, 2022 at 11:02

1 Answer 1

0

I coincidentally bumped into this question. Assuming though that you meant the following:

#[pallet::weight(<T as Config>::WeightInfo::foo(*hint))]
fn foo(hint: u32) -> DispatchResultWithPostInfo {
   let real = get_real();

   if real > hint {
      return <Error<T>>::HintTooLow.with_weight(T::WeightInfo::foo(real);
   }

   // do something
   Ok(Some(T::WeightInfo::foo(real)).into())
}

I would like to explain what will happen and what are the dangers:

When a block author is building a block it goes to its tx pool and finds this tx on top (most priority) and will run its respective weight function => foo(hint) in your case (to be found in the pallet's weights.rs). If there is enough weight left in the block, meaning the resulting weight of foo(hint) (the DispatchInfo) is less than the available weight left in the block, the block author will include it in the block and validate and apply the extrinsic.

Now the extrinsic's logic will be executed and because your return value is the DispatchResultWithPostInfo you can give PostDispatchInfo. This will be the actual weight that will be accounted for in the block and what the user will pay for in terms of fees. In the other case where an extrinsic has the return value DispatchResult. The user will pay for the weight determined when authoring the block => DispatchInfo.

In your case I assume you would like to return the real weight in any scenario (failing or successfully executing the extrinsic) since otherwise your chain could be spammed. Why?

If for example we would change real -> hint:

if real > hint {
    return Error<T>::HintTooLow.with_weight(T::WeightInfo::foo(hint));
}

Someone could spam your chain with hint == 0 and not having to pay a dime for the execution and therefore spamming your chain for free.

I still do not understand what you are trying to accomplish or why, but I hope this can be useful for others in the future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.