From 5bc363275c79645e0383c26466e8c0f8994bacda Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Wed, 11 Mar 2026 10:14:44 +0800 Subject: [PATCH] feat(core/txpool): respect nolocals-setting #28435 (#2128) --- core/txpool/legacypool/legacypool.go | 3 ++ core/txpool/legacypool/legacypool_test.go | 49 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 81e409a0da..493caa7201 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1145,6 +1145,9 @@ func (pool *LegacyPool) addRemoteSync(tx *types.Transaction) error { // If sync is set, the method will block until all internal maintenance related // to the add is finished. Only use this during tests for determinism! func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error { + // Do not treat as local if local transactions have been disabled + local = local && !pool.config.NoLocals + // Filter out known ones without obtaining the pool lock or recovering signatures var ( errs = make([]error, len(txs)) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 3d4a9002aa..f25edfd346 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -1604,6 +1604,55 @@ func TestRepricing(t *testing.T) { } } +func TestMinGasPriceEnforced(t *testing.T) { + t.Parallel() + + // Create the pool to test the pricing enforcement with + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase())) + blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed)) + + txPoolConfig := DefaultConfig + txPoolConfig.NoLocals = true + pool := New(txPoolConfig, blockchain) + pool.Init(txPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) + defer pool.Close() + + key, _ := crypto.GenerateKey() + testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1_000_000_000_000_000_000)) + + minGasPrice := common.GetMinGasPrice(blockchain.CurrentBlock().Number) + legacyPrice := new(big.Int).Add(minGasPrice, big.NewInt(1)) + dynamicTip := new(big.Int).Add(minGasPrice, big.NewInt(1)) + dynamicFeeCap := new(big.Int).Add(minGasPrice, big.NewInt(2)) + + tx := pricedTransaction(0, 100000, legacyPrice, key) + pool.SetGasTip(new(big.Int).Add(legacyPrice, big.NewInt(1))) + + if err := pool.addLocal(tx); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("Min tip not enforced") + } + + if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("Min tip not enforced") + } + + tx = dynamicFeeTx(0, 100000, dynamicFeeCap, dynamicTip, key) + pool.SetGasTip(new(big.Int).Add(dynamicTip, big.NewInt(1))) + + if err := pool.addLocal(tx); !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("Min tip not enforced") + } + + if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; !errors.Is(err, txpool.ErrUnderpriced) { + t.Fatalf("Min tip not enforced") + } + // Make sure the tx is accepted if locals are enabled + pool.config.NoLocals = false + if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; err != nil { + t.Fatalf("Min tip enforced with locals enabled, error: %v", err) + } +} + // Tests that setting the transaction pool gas price to a higher value correctly // discards everything cheaper (legacy & dynamic fee) than that and moves any // gapped transactions back from the pending pool to the queue.