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.
This commit is contained in:
Daniel Liu 2025-12-22 15:21:48 +08:00 committed by GitHub
parent 63783a6b4c
commit d78d79add0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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
}
}