From d78d79add00851ec88de6f056fb0a1296c2bc6b2 Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Mon, 22 Dec 2025 15:21:48 +0800 Subject: [PATCH] core/txpool: allow zero tip transactions with minimum gas price enforcement (#1879) This commit simplifies the transaction pool's gas price validation logic while maintaining network security through the existing minimum gas price requirement. Changes: - Set default PriceLimit to 0 (was 1), allowing transactions with zero tip - Remove PriceLimit >= 1 validation in config sanitization - Simplify Pending() method by using EffectiveGasTipIntCmp consistently - Unify validateTxBasics() logic to use GasTipCapIntCmp for all transactions Key Points: 1. Economic Protection: All transactions still require gasPrice >= 12.5 Gwei (enforced by GetMinGasPrice check in validateTx), providing sufficient protection against DoS attacks even with zero tip. 2. Miner Incentives: Since XDPoSChain includes baseFee in miner rewards (unlike standard EIP-1559), miners still earn the full gasPrice even when tip is 0. This maintains miner revenue while allowing greater flexibility. 3. Special Transactions: BlockSigner and Randomize contract transactions remain exempt from gas price checks, as they are critical for consensus. 4. Code Quality: Reduces complexity by 11 lines and unifies validation logic, making the codebase more maintainable. Security Analysis: - No nil pointer risks: EffectiveGasTipIntCmp has built-in nil handling - No DoS vulnerability: 12.5 Gwei minimum ensures economic cost per transaction - EIP-1559 compatible: Existing minGasPrice check covers all validation needs - Backward compatible: Only relaxes restrictions, doesn't break existing behavior This change benefits system transactions and special use cases while maintaining all existing security guarantees through the network's minimum gas price floor. --- core/txpool/txpool.go | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 4e9b1caf05..bf5fe9673d 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -204,7 +204,7 @@ var DefaultConfig = Config{ Journal: "transactions.rlp", Rejournal: time.Hour, - PriceLimit: 1, + PriceLimit: 0, PriceBump: 10, AccountSlots: 16, @@ -223,10 +223,6 @@ func (config *Config) sanitize() Config { log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) conf.Rejournal = time.Second } - if conf.PriceLimit < 1 { - log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultConfig.PriceLimit) - conf.PriceLimit = DefaultConfig.PriceLimit - } if conf.PriceBump < 1 { log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultConfig.PriceBump) conf.PriceBump = DefaultConfig.PriceBump @@ -572,9 +568,9 @@ func (pool *TxPool) Pending(enforceTips bool) map[common.Address]types.Transacti txs := list.Flatten() // If the miner requests tip enforcement, cap the lists now - if enforceTips && pool.priced.urgent.baseFee != nil && !pool.locals.contains(addr) { + if enforceTips && !pool.locals.contains(addr) { for i, tx := range txs { - if !tx.IsSpecialTransaction() && tx.GasPrice().Cmp(pool.priced.urgent.baseFee) < 0 { + if !tx.IsSpecialTransaction() && tx.EffectiveGasTipIntCmp(pool.gasPrice, pool.priced.urgent.baseFee) < 0 { txs = txs[:i] break } @@ -670,15 +666,8 @@ func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error { return core.ErrNonceMax } // Drop non-local transactions under our own minimal accepted gas price or tip - if !local { - isUnderpriced := false - if pool.priced.urgent.baseFee != nil { - // check tx.GasPrice() when GasTipCap() == 0 - isUnderpriced = tx.GasPrice().Cmp(pool.priced.urgent.baseFee) < 0 - } else { - isUnderpriced = tx.GasTipCapIntCmp(pool.gasPrice) < 0 - } - if isUnderpriced && (!tx.IsSpecialTransaction() || (pool.IsSigner != nil && !pool.IsSigner(from))) { + if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 { + if !tx.IsSpecialTransaction() || (pool.IsSigner != nil && !pool.IsSigner(from)) { return ErrUnderpriced } }