diff --git a/CHANGELOG.md b/CHANGELOG.md index 35ff3cb91a1..8576a014553 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/x/txfees/keeper/mempool-1559/code.go b/x/txfees/keeper/mempool-1559/code.go index 0d1d8ba4043..d41291ca1a3 100644 --- a/x/txfees/keeper/mempool-1559/code.go +++ b/x/txfees/keeper/mempool-1559/code.go @@ -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" @@ -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{} diff --git a/x/txfees/module.go b/x/txfees/module.go index bbc4914de7a..14b0e9d7fbe 100644 --- a/x/txfees/module.go +++ b/x/txfees/module.go @@ -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.