make sure the index can be reheaped when call filter method again

This commit is contained in:
maskpp 2025-07-27 12:21:17 +08:00
parent b369a855fb
commit 640d0079d5

View file

@ -18,6 +18,7 @@ package legacypool
import ( import (
"container/heap" "container/heap"
"maps"
"math" "math"
"math/big" "math/big"
"slices" "slices"
@ -113,23 +114,12 @@ func (m *SortedMap) Forward(threshold uint64) types.Transactions {
// If you want to do several consecutive filterings, it's therefore better to first // If you want to do several consecutive filterings, it's therefore better to first
// do a .filter(func1) followed by .Filter(func2) or reheap() // do a .filter(func1) followed by .Filter(func2) or reheap()
func (m *SortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { func (m *SortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions {
removed := m.filter(filter) return m.filter(filter)
// If transactions were removed, the heap and cache are ruined
if len(removed) > 0 {
m.reheap()
}
return removed
} }
func (m *SortedMap) reheap() { func (m *SortedMap) reheap() {
*m.index = make([]uint64, 0, len(m.items)) *m.index = slices.Collect(maps.Keys(m.items))
for nonce := range m.items {
*m.index = append(*m.index, nonce)
}
heap.Init(m.index) heap.Init(m.index)
m.cacheMu.Lock()
m.cache = nil
m.cacheMu.Unlock()
} }
// filter is identical to Filter, but **does not** regenerate the heap. This method // filter is identical to Filter, but **does not** regenerate the heap. This method
@ -148,6 +138,8 @@ func (m *SortedMap) filter(filter func(*types.Transaction) bool) types.Transacti
m.cacheMu.Lock() m.cacheMu.Lock()
m.cache = nil m.cache = nil
m.cacheMu.Unlock() m.cacheMu.Unlock()
// If transactions were removed, the heap and cache are ruined
m.reheap()
} }
return removed return removed
} }
@ -238,10 +230,7 @@ func (m *SortedMap) flatten() types.Transactions {
defer m.cacheMu.Unlock() defer m.cacheMu.Unlock()
// If the sorting was not cached yet, create and cache it // If the sorting was not cached yet, create and cache it
if m.cache == nil { if m.cache == nil {
m.cache = make(types.Transactions, 0, len(m.items)) m.cache = slices.Collect(maps.Values(m.items))
for _, tx := range m.items {
m.cache = append(m.cache, tx)
}
sort.Sort(types.TxByNonce(m.cache)) sort.Sort(types.TxByNonce(m.cache))
} }
return m.cache return m.cache
@ -251,11 +240,8 @@ func (m *SortedMap) flatten() types.Transactions {
// sorted internal representation. The result of the sorting is cached in case // sorted internal representation. The result of the sorting is cached in case
// it's requested again before any modifications are made to the contents. // it's requested again before any modifications are made to the contents.
func (m *SortedMap) Flatten() types.Transactions { func (m *SortedMap) Flatten() types.Transactions {
cache := m.flatten()
// Copy the cache to prevent accidental modification // Copy the cache to prevent accidental modification
txs := make(types.Transactions, len(cache)) return slices.Clone(m.flatten())
copy(txs, cache)
return txs
} }
// LastElement returns the last element of a flattened list, thus, the // LastElement returns the last element of a flattened list, thus, the
@ -367,11 +353,11 @@ func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactio
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(uint256.Int).Set(costLimit) // Lower the caps to the thresholds l.costcap.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.ToBig()) > 0 return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit.ToBig()) > 0
}) })
@ -392,7 +378,6 @@ func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactio
// Reset total cost // Reset total cost
l.subTotalCost(removed) l.subTotalCost(removed)
l.subTotalCost(invalids) l.subTotalCost(invalids)
l.txs.reheap()
return removed, invalids return removed, invalids
} }