From 9d6e8fc83f797985a9c0306303554cdd0cb79116 Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Tue, 10 Mar 2026 21:20:40 +0800 Subject: [PATCH] refactor(core/txpool/legacypool): use uint256.Int instead of big.Int #28606 (#2134) --- core/txpool/legacypool/legacypool.go | 31 ++++++++------- core/txpool/legacypool/legacypool2_test.go | 8 ++-- core/txpool/legacypool/legacypool_test.go | 46 +++++++++++----------- core/txpool/legacypool/list.go | 33 ++++++++++------ core/txpool/legacypool/list_test.go | 19 ++++++++- core/txpool/subpool.go | 2 +- core/txpool/txpool.go | 2 +- eth/backend.go | 2 +- 8 files changed, 86 insertions(+), 57 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 224f6159a9..81e409a0da 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -40,6 +40,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/metrics" "github.com/XinFinOrg/XDPoSChain/params" + "github.com/holiman/uint256" ) const ( @@ -245,7 +246,7 @@ type LegacyPool struct { config Config chainconfig *params.ChainConfig chain BlockChain - gasTip atomic.Pointer[big.Int] + gasTip atomic.Pointer[uint256.Int] txFeed event.Feed signer types.Signer mu sync.RWMutex @@ -334,12 +335,12 @@ func (pool *LegacyPool) Filter(tx *types.Transaction) bool { // head to allow balance / nonce checks. The transaction journal will be loaded // from disk and filtered based on the provided starting settings. The internal // goroutines will be spun up and the pool deemed operational afterwards. -func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserver *txpool.Reserver) error { +func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserver *txpool.Reserver) error { // Set the address reserver to request exclusive access to pooled accounts pool.reserver = reserver // Set the basic pool parameters - pool.gasTip.Store(gasTip) + pool.gasTip.Store(uint256.NewInt(gasTip)) // Initialize the state with head block, or fallback to empty one in // case the head state is not available(might occur when node is not @@ -491,11 +492,13 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) error { return fmt.Errorf("reject too high gas tip: %v, maximum: %v", tip, defaultMaxTip) } - old := pool.gasTip.Load() - pool.gasTip.Store(new(big.Int).Set(tip)) - + var ( + newTip = uint256.MustFromBig(tip) + old = pool.gasTip.Load() + ) + pool.gasTip.Store(newTip) // If the min miner fee increased, remove transactions below the new threshold - if tip.Cmp(old) > 0 { + if newTip.Cmp(old) > 0 { // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead drop := pool.all.RemotesBelowTip(tip) for _, tx := range drop { @@ -503,7 +506,7 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) error { } pool.priced.Removed(len(drop)) } - log.Info("Legacy pool tip threshold updated", "tip", tip) + log.Info("Legacy pool tip threshold updated", "tip", newTip) return nil } @@ -591,7 +594,7 @@ func (pool *LegacyPool) Pending(enforceTips bool) map[common.Address][]*txpool.L // If the miner requests tip enforcement, cap the lists now if enforceTips && !pool.locals.contains(addr) { for i, tx := range txs { - if !tx.IsSpecialTransaction() && tx.EffectiveGasTipIntCmp(pool.gasTip.Load(), pool.priced.urgent.baseFee) < 0 { + if !tx.IsSpecialTransaction() && tx.EffectiveGasTipIntCmp(pool.gasTip.Load().ToBig(), pool.priced.urgent.baseFee) < 0 { txs = txs[:i] break } @@ -653,7 +656,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro 1< gasLimit || new(big.Int).Add(costLimit, feeCapacity).Cmp(tx.TxCost(number)) < 0 + return tx.Gas() > gasLimit || new(big.Int).Add(costLimit.ToBig(), feeCapacity).Cmp(tx.TxCost(number)) < 0 } } - return tx.Gas() > gasLimit || tx.Cost().Cmp(maximum) > 0 + return tx.Gas() > gasLimit || tx.Cost().Cmp(maximum.ToBig()) > 0 }) if len(removed) == 0 { @@ -467,7 +473,10 @@ func (l *list) LastElement() *types.Transaction { // total cost of all transactions. func (l *list) subTotalCost(txs []*types.Transaction) { for _, tx := range txs { - l.totalcost.Sub(l.totalcost, tx.Cost()) + _, underflow := l.totalcost.SubOverflow(l.totalcost, uint256.MustFromBig(tx.Cost())) + if underflow { + panic("totalcost underflow") + } } } diff --git a/core/txpool/legacypool/list_test.go b/core/txpool/legacypool/list_test.go index 79f067011e..5a6b9af466 100644 --- a/core/txpool/legacypool/list_test.go +++ b/core/txpool/legacypool/list_test.go @@ -21,8 +21,10 @@ import ( "math/rand" "testing" + "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" + "github.com/holiman/uint256" ) // Tests that transactions can be added to strict lists and list contents and @@ -51,6 +53,21 @@ func TestStrictListAdd(t *testing.T) { } } +// TestListAddVeryExpensive tests adding txs which exceed 256 bits in cost. It is +// expected that the list does not panic. +func TestListAddVeryExpensive(t *testing.T) { + key, _ := crypto.GenerateKey() + list := newList(true) + for i := 0; i < 3; i++ { + value := big.NewInt(100) + gasprice, _ := new(big.Int).SetString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0) + gaslimit := uint64(i) + tx, _ := types.SignTx(types.NewTransaction(uint64(i), common.Address{}, value, gaslimit, gasprice, nil), types.HomesteadSigner{}, key) + t.Logf("cost: %x bitlen: %d\n", tx.Cost(), tx.Cost().BitLen()) + list.Add(tx, DefaultConfig.PriceBump) + } +} + func BenchmarkListAdd(t *testing.B) { // Generate a list of transactions to insert key, _ := crypto.GenerateKey() @@ -61,7 +78,7 @@ func BenchmarkListAdd(t *testing.B) { } // Insert the transactions in a random order list := newList(true) - priceLimit := big.NewInt(int64(DefaultConfig.PriceLimit)) + priceLimit := uint256.NewInt(DefaultConfig.PriceLimit) t.ResetTimer() for _, v := range rand.Perm(len(txs)) { list.Add(txs[v], DefaultConfig.PriceBump) diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index e27e1b4754..cfc038362d 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -75,7 +75,7 @@ type SubPool interface { // These should not be passed as a constructor argument - nor should the pools // start by themselves - in order to keep multiple subpools in lockstep with // one another. - Init(gasTip *big.Int, head *types.Header, reserver *Reserver) error + Init(gasTip uint64, head *types.Header, reserver *Reserver) error // Close terminates any background processing threads and releases any held // resources. diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 9cdb6a39fa..f2c4ad3c00 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -61,7 +61,7 @@ type TxPool struct { // New creates a new transaction pool to gather, sort and filter inbound // transactions from the network. -func New(gasTip *big.Int, chain BlockChain, subpools []SubPool) (*TxPool, error) { +func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { // Retrieve the current head so that all subpools and this main coordinator // pool will have the same starting state, even if the chain moves forward // during initialization. diff --git a/eth/backend.go b/eth/backend.go index eaed1b7250..cfad928deb 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -262,7 +262,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin } legacyPool := legacypool.New(config.TxPool, eth.blockchain) - eth.txPool, err = txpool.New(new(big.Int).SetUint64(config.TxPool.PriceLimit), eth.blockchain, []txpool.SubPool{legacyPool}) + eth.txPool, err = txpool.New(config.TxPool.PriceLimit, eth.blockchain, []txpool.SubPool{legacyPool}) if err != nil { return nil, err }