legacypool: use uint256 instead of big

This commit is contained in:
weiihann 2023-11-24 13:19:00 +08:00
parent cd0770ea68
commit af03289998
5 changed files with 39 additions and 26 deletions

View file

@ -34,3 +34,13 @@ var (
U2560 = uint256.NewInt(0) U2560 = uint256.NewInt(0)
) )
var (
Uint1 = uint256.NewInt(1)
Uint2 = uint256.NewInt(2)
Uint3 = uint256.NewInt(3)
Uint0 = uint256.NewInt(0)
Uint32 = uint256.NewInt(32)
Uint256 = uint256.NewInt(256)
Uint257 = uint256.NewInt(257)
)

View file

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
) )
const ( const (
@ -202,7 +203,7 @@ type LegacyPool struct {
config Config config Config
chainconfig *params.ChainConfig chainconfig *params.ChainConfig
chain BlockChain chain BlockChain
gasTip atomic.Pointer[big.Int] gasTip atomic.Pointer[uint256.Int]
txFeed event.Feed txFeed event.Feed
signer types.Signer signer types.Signer
mu sync.RWMutex mu sync.RWMutex
@ -292,7 +293,7 @@ func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserve txpool
pool.reserve = reserve pool.reserve = reserve
// Set the basic pool parameters // Set the basic pool parameters
pool.gasTip.Store(gasTip) pool.gasTip.Store(uint256.MustFromBig(gasTip))
// Initialize the state with head block, or fallback to empty one in // 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 // case the head state is not available(might occur when node is not
@ -434,10 +435,10 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) {
defer pool.mu.Unlock() defer pool.mu.Unlock()
old := pool.gasTip.Load() old := pool.gasTip.Load()
pool.gasTip.Store(new(big.Int).Set(tip)) pool.gasTip.Store(uint256.MustFromBig(tip))
// If the min miner fee increased, remove transactions below the new threshold // If the min miner fee increased, remove transactions below the new threshold
if tip.Cmp(old) > 0 { if uint256.MustFromBig(tip).Cmp(old) > 0 {
// pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead
drop := pool.all.RemotesBelowTip(tip) drop := pool.all.RemotesBelowTip(tip)
for _, tx := range drop { for _, tx := range drop {
@ -532,7 +533,7 @@ func (pool *LegacyPool) Pending(enforceTips bool) map[common.Address][]*txpool.L
// If the miner requests tip enforcement, cap the lists now // If the miner requests tip enforcement, cap the lists now
if enforceTips && !pool.locals.contains(addr) { if enforceTips && !pool.locals.contains(addr) {
for i, tx := range txs { for i, tx := range txs {
if tx.EffectiveGasTipIntCmp(pool.gasTip.Load(), pool.priced.urgent.baseFee) < 0 { if tx.EffectiveGasTipIntCmp(pool.gasTip.Load().ToBig(), pool.priced.urgent.baseFee) < 0 {
txs = txs[:i] txs = txs[:i]
break break
} }
@ -594,7 +595,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
1<<types.AccessListTxType | 1<<types.AccessListTxType |
1<<types.DynamicFeeTxType, 1<<types.DynamicFeeTxType,
MaxSize: txMaxSize, MaxSize: txMaxSize,
MinTip: pool.gasTip.Load(), MinTip: pool.gasTip.Load().ToBig(),
} }
if local { if local {
opts.MinTip = new(big.Int) opts.MinTip = new(big.Int)
@ -624,7 +625,7 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
}, },
ExistingExpenditure: func(addr common.Address) *big.Int { ExistingExpenditure: func(addr common.Address) *big.Int {
if list := pool.pending[addr]; list != nil { if list := pool.pending[addr]; list != nil {
return list.totalcost return list.totalcost.ToBig()
} }
return new(big.Int) return new(big.Int)
}, },
@ -1441,7 +1442,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
} }
log.Trace("Removed old queued transactions", "count", len(forwards)) log.Trace("Removed old queued transactions", "count", len(forwards))
// Drop all transactions that are too costly (low balance or out of gas) // Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(pool.currentState.GetBalance(addr).ToBig(), gasLimit) drops, _ := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
for _, tx := range drops { for _, tx := range drops {
hash := tx.Hash() hash := tx.Hash()
pool.all.Remove(hash) pool.all.Remove(hash)
@ -1642,7 +1643,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
log.Trace("Removed old pending transaction", "hash", hash) log.Trace("Removed old pending transaction", "hash", hash)
} }
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.currentState.GetBalance(addr).ToBig(), gasLimit) drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
for _, tx := range drops { for _, tx := range drops {
hash := tx.Hash() hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash) log.Trace("Removed unpayable pending transaction", "hash", hash)

View file

@ -199,9 +199,6 @@ func validatePoolInternals(pool *LegacyPool) error {
if nonce := pool.pendingNonces.get(addr); nonce != last+1 { if nonce := pool.pendingNonces.get(addr); nonce != last+1 {
return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1) return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1)
} }
if txs.totalcost.Cmp(common.Big0) < 0 {
return fmt.Errorf("totalcost went negative: %v", txs.totalcost)
}
} }
return nil return nil
} }
@ -349,7 +346,7 @@ func TestInvalidTransactions(t *testing.T) {
} }
tx = transaction(1, 100000, key) tx = transaction(1, 100000, key)
pool.gasTip.Store(big.NewInt(1000)) pool.gasTip.Store(uint256.NewInt(1000))
if err, want := pool.addRemote(tx), txpool.ErrUnderpriced; !errors.Is(err, want) { if err, want := pool.addRemote(tx), txpool.ErrUnderpriced; !errors.Is(err, want) {
t.Errorf("want %v have %v", want, err) t.Errorf("want %v have %v", want, err)
} }

View file

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256"
) )
// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
@ -271,9 +272,9 @@ type list struct {
strict bool // Whether nonces are strictly continuous or not strict bool // Whether nonces are strictly continuous or not
txs *sortedMap // Heap indexed sorted hash map of the transactions txs *sortedMap // Heap indexed sorted hash map of the transactions
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) costcap *uint256.Int // Price of the highest costing transaction (reset only if exceeds balance)
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
totalcost *big.Int // Total cost of all transactions in the list totalcost *uint256.Int // Total cost of all transactions in the list
} }
// newList create a new transaction list for maintaining nonce-indexable fast, // newList create a new transaction list for maintaining nonce-indexable fast,
@ -282,8 +283,8 @@ func newList(strict bool) *list {
return &list{ return &list{
strict: strict, strict: strict,
txs: newSortedMap(), txs: newSortedMap(),
costcap: new(big.Int), costcap: new(uint256.Int),
totalcost: new(big.Int), totalcost: new(uint256.Int),
} }
} }
@ -325,10 +326,11 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
l.subTotalCost([]*types.Transaction{old}) l.subTotalCost([]*types.Transaction{old})
} }
// Add new tx cost to totalcost // Add new tx cost to totalcost
l.totalcost.Add(l.totalcost, tx.Cost()) l.totalcost.Add(l.totalcost, uint256.MustFromBig(tx.Cost()))
// Otherwise overwrite the old transaction with the current one // Otherwise overwrite the old transaction with the current one
l.txs.Put(tx) l.txs.Put(tx)
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { if cost := uint256.MustFromBig(tx.Cost()); l.costcap.Cmp(cost) < 0 {
l.costcap = cost l.costcap = cost
} }
if gas := tx.Gas(); l.gascap < gas { if gas := tx.Gas(); l.gascap < gas {
@ -355,17 +357,17 @@ func (l *list) Forward(threshold uint64) types.Transactions {
// a point in calculating all the costs or if the balance covers all. If the threshold // a point in calculating all the costs or if the balance covers all. If the threshold
// is lower than the costgas cap, the caps will be reset to a new high after removing // is lower than the costgas cap, the caps will be reset to a new high after removing
// the newly invalidated transactions. // the newly invalidated transactions.
func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) { func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactions, types.Transactions) {
// If all transactions are below the threshold, short circuit // If all transactions are below the threshold, short circuit
if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
return nil, nil return nil, nil
} }
l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds l.costcap = new(uint256.Int).Set(costLimit) // Lower the caps to the thresholds
l.gascap = gasLimit l.gascap = gasLimit
// Filter out all the transactions above the account's funds // Filter out all the transactions above the account's funds
removed := l.txs.Filter(func(tx *types.Transaction) bool { removed := l.txs.Filter(func(tx *types.Transaction) bool {
return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit) > 0 return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit.ToBig()) > 0
}) })
if len(removed) == 0 { if len(removed) == 0 {
@ -456,7 +458,10 @@ func (l *list) LastElement() *types.Transaction {
// total cost of all transactions. // total cost of all transactions.
func (l *list) subTotalCost(txs []*types.Transaction) { func (l *list) subTotalCost(txs []*types.Transaction) {
for _, tx := range txs { 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")
}
} }
} }

View file

@ -17,12 +17,12 @@
package legacypool package legacypool
import ( import (
"math/big"
"math/rand" "math/rand"
"testing" "testing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/holiman/uint256"
) )
// Tests that transactions can be added to strict lists and list contents and // Tests that transactions can be added to strict lists and list contents and
@ -60,7 +60,7 @@ func BenchmarkListAdd(b *testing.B) {
txs[i] = transaction(uint64(i), 0, key) txs[i] = transaction(uint64(i), 0, key)
} }
// Insert the transactions in a random order // Insert the transactions in a random order
priceLimit := big.NewInt(int64(DefaultConfig.PriceLimit)) priceLimit := uint256.NewInt(DefaultConfig.PriceLimit)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
list := newList(true) list := newList(true)