Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Align GasWeightMapping with Substrate do_pre_dispatch logic #865

Merged

Conversation

tgmichel
Copy link
Contributor

This is a followup PR for what was mentioned by @notlesh in #851 (comment)

This PR proposes:

  • Removing the original implementation in pallet-evm that treated Gas and Weight as the same unit.
  • Introduces WeightPerGas associated type to pallet-evm.
  • Implements GasWeightMapping for an arbitrary struct in pallet-evm in which's gas_to_weight implementation the base base extrinsic weight is substracted to the result.

The goal is align with how CheckWeight::do_pre_dispatch works. In there, (pre-dispatch) DispatchInfoOf + base_extrinsic is put in frame_system::BlockWeights storage. After (post-dispatch), PostInfo (the actual gas/weight used by the evm) is used to correct the accounted Weight, but the base_extrinsic still over-accounted. By subtracting the base_extrinsic in the gas_to_weight we fix that.

Note

This proposal assumes:

  • Base extrinsic weight is a constant set at runtime.
  • The constant base extrinsic weight is set to a value LTE to 21_000 * WeigthPerGas.

@tgmichel tgmichel marked this pull request as ready for review September 26, 2022 16:12
@notlesh
Copy link
Contributor

notlesh commented Sep 26, 2022

This is a good fix given how involved it would be to fix through substrate, but there is one quite minor issue left: the txpool will avoid including txns which would just barely fit. In other words, when a txn would fit by a margin smaller than extrinsic_base_weight, it might be skipped over.

...quite minor... :)

@tgmichel
Copy link
Contributor Author

tgmichel commented Sep 27, 2022

when a txn would fit by a margin smaller than extrinsic_base_weight, it might be skipped over

That also applies to any extrinsic no? If a weight annotation hints 99 weight, the weight left in the block is 100, and the base extrinsic weight is 2, then that extrinsic overall weight is 101 and it would exhaust resources.

@notlesh
Copy link
Contributor

notlesh commented Sep 27, 2022

That also applies to any extrinsic no?

You mean a normal Substrate txn? Yes, it would apply to those as well, but they would end up charging for that weight (instead of refunding it later like we're trying to do here).

Edit: elaborate:

Take the following example, let's say we have two similar txns, one Substrate-based and one Ethereum-based.

Substrate:
* 1000 extrinsic_base_weight (will not be refunded)
* 4000 <all other fees>

Ethereum:
* 1000 extrinsic_base_weight (will be refunded)
* 5000 weight (from used gas, assume used_gas == gas_limit for simplicity)

Notice that both have a total weight after post-dispatch of 5000.

The normal Substrate txn will work something like this as far as txpool is concerned:

  • All fees known ahead-of-of time, so 1000 + 4000 = 5000 will be accounted for in pre-dispatch.
  • Post-dispatch will not change the weight accounting, so the total of 5000 weight will be charged.
  • There's no problem with the accounting in this case

The Ethereum txn will work a bit differently:

  • Worst-case fee assumed in pre-dispatch, so we account for 1000 + 5000 = 6000. We are overestimating the weight at this point.
  • Pre-dispatch: 5000 weight was used, now we refund 1000, leaving us with the correct 5000.
  • This is fine in all cases except where the txpool would have included 5000 but rejected 6000. In this case, we will skip the txn even though we could have included it.

@tgmichel
Copy link
Contributor Author

This is fine in all cases except where the txpool would have included 5000 but rejected 6000. In this case, we will skip the txn even though we could have included it.

Sorry but I'm not sure I totally understand, or more specifically how is that related to this change. Including (or not) the transaction in a block based on the weight annotation overestimation - gas limit VS. gas used - is what ethereum does. If the user is hinting he might spend up to 6000, and the txpool has 5000 space left, the transaction must not be included, independently on what the real usage was after exiting the evm.

@notlesh
Copy link
Contributor

notlesh commented Sep 28, 2022

This is fine in all cases except where the txpool would have included 5000 but rejected 6000. In this case, we will skip the txn even though we could have included it.

If the user is hinting he might spend up to 6000, and the txpool has 5000 space left, the transaction must not be included, independently on what the real usage was after exiting the evm.

The user is hinting at 5000 weight (from gas_limit.), not 6000. The extra 1000 is the weight we have to remove later (the extrinsic_base_weight that we can't easily get rid of). As long as we still have to add it first, it will make its apparent size larger to pre-dispatch, and this could have subtle effects like I described in the txpool.

In my example, the user hints at 5000 weight, and by the time we are done executing (with the changes in this PR), it will correctly account for 5000. But in pre-dispatch it will still be 6000.

@notlesh
Copy link
Contributor

notlesh commented Sep 29, 2022

You can ignore the above concerns of mine, I was confused about this approach. I see that it will result in the desired behavior. (cc @sorpaas)

However, I do think we should have a separate fn in GasWeightMapping for this because there are cases where we want extrinsic_base_weight removed (the ones in this PR) and other cases where we don't (the Dispatch precompile, cases outside of Frontier...).

@tgmichel
Copy link
Contributor Author

tgmichel commented Oct 4, 2022

However, I do think we should have a separate fn in GasWeightMapping for this because there are cases where we want extrinsic_base_weight removed (the ones in this PR) and other cases where we don't (the Dispatch precompile, cases outside of Frontier...).

Instead a separate function I added the without_base_weight param, it should be equivalent.

@sorpaas sorpaas merged commit 2d802a1 into polkadot-evm:master Oct 4, 2022
@librelois librelois deleted the tgm-fix-gas-to-weight branch October 20, 2022 11:49
tgmichel added a commit to moonbeam-foundation/frontier that referenced this pull request Oct 20, 2022
…adot-evm#865)

* Align `GasWeightMapping` with Substrate `do_pre_dispatch` logic

* Add `without_base_extrinsic` param

* fmt

(cherry picked from commit 2d802a1)
abhijeetbhagat pushed a commit to web3labs/frontier that referenced this pull request Jan 11, 2023
…adot-evm#865)

* Align `GasWeightMapping` with Substrate `do_pre_dispatch` logic

* Add `without_base_extrinsic` param

* fmt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants