moonbeam
moonbeam copied to clipboard
Use `transaction-payment`'s congestion modifier for Ethereum base-fee
What does it do?
This PR explores using a common congestion-based modifier for both Ethereum- and Substrate-based fees. Specifically, it attempts to transform the transaction-payment
NextFeeMultiplier
to achieve something suitable for an EIP-1559 base-fee
.
I break down issues I've encountered below into "design" issues and "technical" issues.
Design issues
transaction-payment
only applies its congestion modifier to the weight portion of its fee.
Like Ethereum, it contains several components in its fee calculation:
- weight-fee: this accounts for resources used during execution
- length-fee: this pays for the size of the signed txn
- extrinsic-base-fee: this handles signature verification and any other work common to all transactions
- tip: a flat amount (expressed in currency) that is not scaled
Unlike Ethereum, the congestion modifier only applies to the weight portion of the fee.
Ethereum lumps all categories of fees into a total gas used and then applies the congestion modifier to the entire sum.
This means that converting the modifier in the way I have done here is going to work better for some transactions (those whose fee is based mostly on computation resources) than others.
Technical issue: Default modifier value in transaciton-payment
One of the first hurdles I encountered in exploring this is that transaction-payment
does not provide any mechanism for specifying the initial modifier at genesis.
It defaults to 1
(the type is a FixedU128
, which contains 18 decimal places). Our runtimes currently specify a minimum of 0.0000001
, and in practice tend to be close to this value. This huge discrepancy means that our tests will operate on a very different modifier than in real-world.
Solutions
- PR Substrate and introduce a proper
GenesisConfig
- Tune other parts of our fee mechanism to work properly with a modifier value closer to 1 (side-note: Polkadot chains use a minimum of
0.1
)
Convert<Multiplier, Multiplier>
Note that transaction-payment
allows its config to specify a Convert<Multiplier, Multiplier>
impl which can entirely replace the congestion modifier calculation. We could potentially use this to make this pallet work closer to EIP-1559.
Testing / Tuning
One way to help us tune (and also test) this could be to have a suite of tests which create pairs of substrate + ethereum transactions which are similar (using precompiles might be an easy way to make similar txns). Then we can use the tests to show that each pair of tests has similar txn cost even as the modifier grows across a range of values.
Analysis
The fees converge as the network becomes more congested (logarithmic scale). If the network remains empty, then the fees are also held at a constant value.
The following table exhibits the effect of the multiplier starting from 0.000003
(currently in moonriver) to increasing magnitudes. We see that the substrate and evm fees converge on higher multiplier values but substrate fees will always be higher than evm fees by a factor of base + length
fees.
Multiplier Fees
------------------------------------
0.000003 12,746,162,435,424 | substrate
147,518,810 | evm
12,746,014,916,614 | diff
199.9% | diff%
147,548,488 | substrate-weight-fee-part
12,500,000,000,000 | substrate-base-fee-part
------------------------------------ |
0.001 12,783,532,386,936 | substrate
37,517,500,000 | evm
12,746,014,886,936 | diff
198.8% | diff%
37,517,500,000 | substrate-weight-fee-part
12,500,000,000,000 | substrate-base-fee-part
------------------------------------ |
0.1 16,497,764,886,936 | substrate
3,751,750,000,000 | evm
12,746,014,886,936 | diff
125.8% | diff%
3,751,750,000,000 | substrate-weight-fee-part
12,500,000,000,000 | substrate-base-fee-part
------------------------------------ |
1 50,226,016,145,686 | substrate
37,480,001,258,750 | evm
12,746,014,886,936 | diff
29% | diff%
37,480,001,258,750 | substrate-weight-fee-part
12,500,000,000,000 | substrate-base-fee-part
------------------------------------ |
10 387,546,027,474,436 | substrate
374,800,012,587,500 | evm
12,746,014,886,936 | diff
3.3% | diff%
374,800,012,587,500 | substrate-weight-fee-part
12,500,000,000,000 | substrate-base-fee-part
------------------------------------ |
100 3,760,746,140,761,936 | substrate
3,748,000,125,875,000 | evm
12,746,014,886,936 | diff
0.3% | diff%
3,748,000,125,875,000 | substrate-weight-fee-part
12,500,000,000,000 | substrate-base-fee-part
From the above table the range of 1.0 - 200.0
seems good so far.
TODO
- [ ] Find solution for no
GenesisConfig
intransaction-payment
- [ ] Fix existing test cases
- [ ] Tune values to work for various transaction types
- [ ] New tests
- [ ] Document breaking changes
The NextFeeMultiplier
is much similar to the base-fee pallet but on the substrate side. Why not use base-fee
pallet here?
The
NextFeeMultiplier
is much similar to the base-fee pallet but on the substrate side. Why not usebase-fee
pallet here?
@AsceticBear The initial reason being having to maintain/re-implement less code/functionality which is quite easy to get wrong (e.g. fees will never recover or continuously drift in a single direction). The original motivation we have here is to adapt the EVM fees to the changing network traffic and substrate already provides us with a well-tested mechanism in place - this also means the network fee would be more in tandem between Substrate and EVM.
The
NextFeeMultiplier
is much similar to the base-fee pallet but on the substrate side. Why not usebase-fee
pallet here?
A bit more detail:
I explored using this and came to the conclusion that EIP1559's design isn't well suited for a network that doesn't experience consistent congestion.
Basically, I think the original design creates a feedback mechanism that keeps the congestion modifier within a reasonable range, something like this:
congestion up -> fees up -> fewer txns eligible -> blocks less full -> congestion down
and
congestion down -> fees down -> more txns eligible -> blocks more full -> congestion up
Without this, it becomes critical to tune pallet base-fee
's Threshold
parameters because incorrect tuning will create a permanent upward or downward trend. The pallet has no bounds on the fee itself (nor does EIP1559) which can eventually result in fees being either near-zero or impossibly expensive.
While pallet transaction-payment
has a similar mechanism, it has far more knobs to tune (including a minimum fee) to alleviate this.