Skip to content

Commit

Permalink
Proposal to update the mempool 1559 parameters for v22 (#7285)
Browse files Browse the repository at this point in the history
We have observed the mempool 1559 parameters spiking way higher than they need to, due to a series of issue.
- Block's have too low of a gas capacity
- Different nodes have very divergent mempools, and don't have Ethereum's incentives for maximizing tx fee
- The recheck factor forces the base fee to get at minimum 3x higher than the spam rate.
- Wallets use a large multiplier (3x) due to the above issues
  - Leading to users paying 9x over the spam that needs to get evicted at peaks.

The need for the recheck factor was to offer a grace period for txs that become candidates for eviction due to momentary surges, or differences between mempool sizes between validator operators. Its because we are in a FIFO mempool, with no way right now to "preserve" user txs at too low of a fee, that may be valid later. Theres no system for keeping them in the network, and no system for flagging the issue to users. An alternative is to keep a higher recheck factor for just RPC nodes, but not validators, if we see user txs not making it in. (That way they are still "remembered" and kept in the network. Though they may never get re-gossipped)

With all nodes ideally getting aligned on one fee market / mempool version in the next release, we can revisit this recheck factor. It was already lowered from its previous `4` to `3` in a prior release that got to a subset of nodes. This PR suggests a further 25% reduction to `2.25`. Maybe it should be a bit higher to remain more conservative though? The issue now is really moreso about supporting user txs from occasional fee spikes, instead of handling inconsitencies between 1559 nodes and non-1559 nodes.

This further lowers the reset interval as this has gotten to more nodes.
  • Loading branch information
ValarDragon authored Jan 12, 2024
1 parent d3621eb commit bdcd251
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## v22.0.0

### Fee Market Parameter Updates
* [#7285](https://github.com/osmosis-labs/osmosis/pull/7285) The following updates are applied:
* Dynamic recheck factor based on current base fee value. Under 0.01, the recheck factor is 3.
In face of continuous spam, will take ~19 blocks from base fee > spam cost, to mempool eviction.
Above 0.01, the recheck factor is 2.3. In face of continuous spam, will take ~15 blocks from base fee > spam cost, to mempool eviction.
* Reset interval set to 6000 which is approximately 8.5 hours.
* Default base fee is reduced by 2 to 0.005.
* Set target gas to .625 * block_gas_limt = 187.5 million

### State Breaking

### API
Expand Down
65 changes: 51 additions & 14 deletions x/txfees/keeper/mempool-1559/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,72 @@ import (
This logic does two things:
- Maintaining data parsed from chain transaction execution and updating eipState accordingly.
- Resetting eipState to default every ResetInterval (3000) block height intervals to maintain consistency.
- Resetting eipState to default every ResetInterval (6000) block height intervals to maintain consistency.
Additionally:
- Periodically evaluating CheckTx and RecheckTx for compliance with these parameters.
Note: The reset interval is set to 3000 blocks, which is approximately 6 hours. Consider adjusting for a smaller time interval (e.g., 500 blocks = 1 hour) if necessary.
Note: The reset interval is set to 6000 blocks, which is approximately 8.5 hours.
Challenges:
- Transactions falling under their gas bounds are currently discarded by nodes. This behavior can be modified for CheckTx, rather than RecheckTx.
Global variables stored in memory:
- DefaultBaseFee: Default base fee, initialized to 0.01.
- DefaultBaseFee: Default base fee, initialized to 0.005.
- MinBaseFee: Minimum base fee, initialized to 0.0025.
- MaxBaseFee: Maximum base fee, initialized to 5.
- MaxBlockChangeRate: The maximum block change rate, initialized to 1/10.
Global constants:
- TargetGas: Gas wanted per block, initialized to 75,000,000.
- ResetInterval: The interval at which eipState is reset, initialized to 3000 blocks.
- TargetGas: Gas wanted per block, initialized to .625 * block_gas_limt = 187.5 million.
- ResetInterval: The interval at which eipState is reset, initialized to 6000 blocks.
- BackupFile: File for backup, set to "eip1559state.json".
- RecheckFeeConstant: A constant value for rechecking fees, initialized to 3.3.
- RecheckFeeConstant: A constant value for rechecking fees, initialized to 2.25.
*/

var (
DefaultBaseFee = sdk.MustNewDecFromStr("0.01")
// We expect wallet multiplier * DefaultBaseFee < MinBaseFee * RecheckFeeConstant
// conservatively assume a wallet multiplier of at least 7%.
DefaultBaseFee = sdk.MustNewDecFromStr("0.0060")
MinBaseFee = sdk.MustNewDecFromStr("0.0025")
MaxBaseFee = sdk.MustNewDecFromStr("5")
ResetInterval = int64(6000)

// Max increase per block is a factor of 1.06, max decrease is 9/10
// If recovering at ~30M gas per block, decrease is .94
// If recovering at ~30M gas per block, decrease is .916
MaxBlockChangeRate = sdk.NewDec(1).Quo(sdk.NewDec(10))
TargetGas = int64(187_500_000)
TargetBlockSpacePercent = sdk.MustNewDecFromStr("0.625")

// N.B. on the reason for having two base fee constants for high and low fees:
//
// At higher base fees, we apply a smaller re-check factor.
// The reason for this is that the recheck factor forces the base fee to get at minimum
// "recheck factor" times higher than the spam rate. This leads to slow recovery
// and a bad UX for user transactions. We aim for spam to start getting evicted from the mempool
// sooner as to avoid more severe UX degradation for user transactions. Therefore,
// we apply a smaller recheck factor at higher base fees.
//
// For low base fees:
// In face of continuous spam, will take ~19 blocks from base fee > spam cost, to mempool eviction
// ceil(log_{1.06}(RecheckFeeConstant))
// So potentially 1.8 minutes of impaired UX from 1559 nodes on top of time to get to base fee > spam.
RecheckFeeConstant = "3.0"
ResetInterval = int64(3000)
// ceil(log_{1.06}(RecheckFeeConstantLowBaseFee)) (assuming base fee not going over threshold)
// So potentially 1.2 minutes of impaired UX from 1559 nodes on top of time to get to base fee > spam.
RecheckFeeConstantLowBaseFee = "3"
//
// For high base fees:
// In face of continuous spam, will take ~15 blocks from base fee > spam cost, to mempool eviction
// ceil(log_{1.06}(RecheckFeeConstantHighBaseFee)) (assuming base fee surpasses threshold)
RecheckFeeConstantHighBaseFee = "2.3"
// Note, the choice of 0.01 was made by observing base fee metrics on mainnet and selecting
// this value from Grafana dashboards. The observation is that below this threshold, we do not
// observe user UX degradation. Therefore, we keep the original recheck factor.
RecheckFeeBaseFeeThreshold = sdk.MustNewDecFromStr("0.01")
)

var RecheckFeeDec = sdk.MustNewDecFromStr(RecheckFeeConstant)
var (
RecheckFeeLowBaseFeeDec = sdk.MustNewDecFromStr(RecheckFeeConstantLowBaseFee)
RecheckFeeHighBaseFeeDec = sdk.MustNewDecFromStr(RecheckFeeConstantHighBaseFee)
)

const (
BackupFilename = "eip1559state.json"
Expand Down Expand Up @@ -155,7 +180,19 @@ func (e *EipState) GetCurBaseFee() osmomath.Dec {
// GetCurRecheckBaseFee returns a clone of the CurBaseFee / RecheckFeeConstant to account for
// rechecked transactions in the feedecorator ante handler
func (e *EipState) GetCurRecheckBaseFee() osmomath.Dec {
return e.CurBaseFee.Clone().Quo(RecheckFeeDec)
baseFee := e.CurBaseFee.Clone()

// At higher base fees, we apply a smaller re-check factor.
// The reason for this is that the recheck factor forces the base fee to get at minimum
// "recheck factor" times higher than the spam rate. This leads to slow recovery
// and a bad UX for user transactions. We aim for spam to start getting evicted from the mempool
// sooner as to avoid more severe UX degradation for user transactions. Therefore,
// we apply a smaller recheck factor at higher base fees.
if baseFee.GT(RecheckFeeBaseFeeThreshold) {
return baseFee.QuoMut(RecheckFeeHighBaseFeeDec)
}

return baseFee.QuoMut(RecheckFeeLowBaseFeeDec)
}

var rwMtx = sync.Mutex{}
Expand Down
1 change: 1 addition & 0 deletions x/txfees/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ func (AppModule) ConsensusVersion() uint64 { return 1 }
// Then, on every block, we check if the current consensus param bytes have changed in comparison to the cached value.
// If they have, we unmarshal the current consensus params, update the target gas, and cache the value.
// This is done to improve performance by not having to fetch and unmarshal the consensus params on every block.
// TODO: Move this to EIP-1559 code
func (am AppModule) CheckAndSetTargetGas(ctx sdk.Context) {
// Check if the block gas limit has changed.
// If it has, update the target gas for eip1559.
Expand Down

0 comments on commit bdcd251

Please sign in to comment.