Skip to content

Commit

Permalink
legacypool: use uint256 instead of big
Browse files Browse the repository at this point in the history
  • Loading branch information
weiihann committed Jan 25, 2024
1 parent cd0770e commit af03289
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 26 deletions.
10 changes: 10 additions & 0 deletions common/big.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ var (

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)
)
19 changes: 10 additions & 9 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)

const (
Expand Down Expand Up @@ -202,7 +203,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
Expand Down Expand Up @@ -292,7 +293,7 @@ func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserve txpool
pool.reserve = reserve

// 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
// case the head state is not available(might occur when node is not
Expand Down Expand Up @@ -434,10 +435,10 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) {
defer pool.mu.Unlock()

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 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
drop := pool.all.RemotesBelowTip(tip)
for _, tx := range drop {
Expand Down Expand Up @@ -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 enforceTips && !pool.locals.contains(addr) {
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]
break
}
Expand Down Expand Up @@ -594,7 +595,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
1<<types.AccessListTxType |
1<<types.DynamicFeeTxType,
MaxSize: txMaxSize,
MinTip: pool.gasTip.Load(),
MinTip: pool.gasTip.Load().ToBig(),
}
if local {
opts.MinTip = new(big.Int)
Expand Down Expand Up @@ -624,7 +625,7 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
},
ExistingExpenditure: func(addr common.Address) *big.Int {
if list := pool.pending[addr]; list != nil {
return list.totalcost
return list.totalcost.ToBig()
}
return new(big.Int)
},
Expand Down Expand Up @@ -1441,7 +1442,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
}
log.Trace("Removed old queued transactions", "count", len(forwards))
// 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 {
hash := tx.Hash()
pool.all.Remove(hash)
Expand Down Expand Up @@ -1642,7 +1643,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
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
drops, invalids := list.Filter(pool.currentState.GetBalance(addr).ToBig(), gasLimit)
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
for _, tx := range drops {
hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash)
Expand Down
5 changes: 1 addition & 4 deletions core/txpool/legacypool/legacypool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,6 @@ func validatePoolInternals(pool *LegacyPool) error {
if nonce := pool.pendingNonces.get(addr); 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
}
Expand Down Expand Up @@ -349,7 +346,7 @@ func TestInvalidTransactions(t *testing.T) {
}

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) {
t.Errorf("want %v have %v", want, err)
}
Expand Down
27 changes: 16 additions & 11 deletions core/txpool/legacypool/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256"
)

// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
Expand Down Expand Up @@ -271,9 +272,9 @@ type list struct {
strict bool // Whether nonces are strictly continuous or not
txs *sortedMap // Heap indexed sorted hash map of the transactions

costcap *big.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)
totalcost *big.Int // Total cost of all transactions in the list
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)
totalcost *uint256.Int // Total cost of all transactions in the list
}

// newList create a new transaction list for maintaining nonce-indexable fast,
Expand All @@ -282,8 +283,8 @@ func newList(strict bool) *list {
return &list{
strict: strict,
txs: newSortedMap(),
costcap: new(big.Int),
totalcost: new(big.Int),
costcap: new(uint256.Int),
totalcost: new(uint256.Int),
}
}

Expand Down Expand Up @@ -325,10 +326,11 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
l.subTotalCost([]*types.Transaction{old})
}
// 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
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
}
if gas := tx.Gas(); l.gascap < gas {
Expand All @@ -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
// is lower than the costgas cap, the caps will be reset to a new high after removing
// 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 l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
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

// Filter out all the transactions above the account's funds
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 {
Expand Down Expand Up @@ -456,7 +458,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")
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/txpool/legacypool/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
package legacypool

import (
"math/big"
"math/rand"
"testing"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/holiman/uint256"
)

// Tests that transactions can be added to strict lists and list contents and
Expand Down Expand Up @@ -60,7 +60,7 @@ func BenchmarkListAdd(b *testing.B) {
txs[i] = transaction(uint64(i), 0, key)
}
// Insert the transactions in a random order
priceLimit := big.NewInt(int64(DefaultConfig.PriceLimit))
priceLimit := uint256.NewInt(DefaultConfig.PriceLimit)
b.ResetTimer()
for i := 0; i < b.N; i++ {
list := newList(true)
Expand Down

0 comments on commit af03289

Please sign in to comment.