@@ -20,6 +20,7 @@ import (
2020 "container/heap"
2121 "math"
2222 "math/big"
23+ "slices"
2324 "sort"
2425 "sync"
2526 "sync/atomic"
@@ -49,16 +50,18 @@ func (h *nonceHeap) Pop() interface{} {
4950 old := * h
5051 n := len (old )
5152 x := old [n - 1 ]
53+ old [n - 1 ] = 0
5254 * h = old [0 : n - 1 ]
5355 return x
5456}
5557
5658// txSortedMap is a nonce->transaction hash map with a heap based index to allow
5759// iterating over the contents in a nonce-incrementing way.
5860type txSortedMap struct {
59- items map [uint64 ]* types.Transaction // Hash map storing the transaction data
60- index * nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
61- cache types.Transactions // Cache of the transactions already sorted
61+ items map [uint64 ]* types.Transaction // Hash map storing the transaction data
62+ index * nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
63+ cache types.Transactions // Cache of the transactions already sorted
64+ cacheMu sync.Mutex // Mutex covering the cache
6265}
6366
6467// newTxSortedMap creates a new nonce-sorted transaction map.
@@ -81,7 +84,9 @@ func (m *txSortedMap) Put(tx *types.Transaction) {
8184 if m .items [nonce ] == nil {
8285 heap .Push (m .index , nonce )
8386 }
87+ m .cacheMu .Lock ()
8488 m .items [nonce ], m .cache = tx , nil
89+ m .cacheMu .Unlock ()
8590}
8691
8792// Forward removes all transactions from the map with a nonce lower than the
@@ -97,9 +102,11 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
97102 delete (m .items , nonce )
98103 }
99104 // If we had a cached order, shift the front
105+ m .cacheMu .Lock ()
100106 if m .cache != nil {
101107 m .cache = m .cache [len (removed ):]
102108 }
109+ m .cacheMu .Unlock ()
103110 return removed
104111}
105112
@@ -123,7 +130,9 @@ func (m *txSortedMap) reheap() {
123130 * m .index = append (* m .index , nonce )
124131 }
125132 heap .Init (m .index )
133+ m .cacheMu .Lock ()
126134 m .cache = nil
135+ m .cacheMu .Unlock ()
127136}
128137
129138// filter is identical to Filter, but **does not** regenerate the heap. This method
@@ -139,7 +148,9 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac
139148 }
140149 }
141150 if len (removed ) > 0 {
151+ m .cacheMu .Lock ()
142152 m .cache = nil
153+ m .cacheMu .Unlock ()
143154 }
144155 return removed
145156}
@@ -153,19 +164,21 @@ func (m *txSortedMap) Cap(threshold int) types.Transactions {
153164 }
154165 // Otherwise gather and drop the highest nonce'd transactions
155166 var drops types.Transactions
156-
157- sort .Sort (* m .index )
167+ slices .Sort (* m .index )
158168 for size := len (m .items ); size > threshold ; size -- {
159169 drops = append (drops , m .items [(* m .index )[size - 1 ]])
160170 delete (m .items , (* m .index )[size - 1 ])
161171 }
162172 * m .index = (* m .index )[:threshold ]
163- heap .Init (m .index )
173+ // The sorted m.index slice is still a valid heap, so there is no need to
174+ // reheap after deleting tail items.
164175
165176 // If we had a cache, shift the back
177+ m .cacheMu .Lock ()
166178 if m .cache != nil {
167179 m .cache = m .cache [:len (m .cache )- len (drops )]
168180 }
181+ m .cacheMu .Unlock ()
169182 return drops
170183}
171184
@@ -185,7 +198,9 @@ func (m *txSortedMap) Remove(nonce uint64) bool {
185198 }
186199 }
187200 delete (m .items , nonce )
201+ m .cacheMu .Lock ()
188202 m .cache = nil
203+ m .cacheMu .Unlock ()
189204
190205 return true
191206}
@@ -195,7 +210,7 @@ func (m *txSortedMap) Remove(nonce uint64) bool {
195210// removed from the list.
196211//
197212// Note, all transactions with nonces lower than start will also be returned to
198- // prevent getting into and invalid state. This is not something that should ever
213+ // prevent getting into an invalid state. This is not something that should ever
199214// happen but better to be self correcting than failing!
200215func (m * txSortedMap ) Ready (start uint64 ) types.Transactions {
201216 // Short circuit if no transactions are available
@@ -209,7 +224,9 @@ func (m *txSortedMap) Ready(start uint64) types.Transactions {
209224 delete (m .items , next )
210225 heap .Pop (m .index )
211226 }
227+ m .cacheMu .Lock ()
212228 m .cache = nil
229+ m .cacheMu .Unlock ()
213230
214231 return ready
215232}
@@ -220,6 +237,8 @@ func (m *txSortedMap) Len() int {
220237}
221238
222239func (m * txSortedMap ) flatten () types.Transactions {
240+ m .cacheMu .Lock ()
241+ defer m .cacheMu .Unlock ()
223242 // If the sorting was not cached yet, create and cache it
224243 if m .cache == nil {
225244 m .cache = make (types.Transactions , 0 , len (m .items ))
@@ -604,6 +623,7 @@ func (l *txPricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool
604623
605624// Discard finds a number of most underpriced transactions, removes them from the
606625// priced list and returns them for further removal from the entire pool.
626+ // If noPending is set to true, we will only consider the floating list
607627//
608628// Note local transaction won't be considered for eviction.
609629func (l * txPricedList ) Discard (slots int , force bool ) (types.Transactions , bool ) {
0 commit comments