@@ -99,7 +99,30 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
99
99
100
100
// Filter iterates over the list of transactions and removes all of them for which
101
101
// the specified function evaluates to true.
102
+ // Filter, as opposed to 'filter', re-initialises the heap after the operation is done.
103
+ // If you want to do several consecutive filterings, it's therefore better to first
104
+ // do a .filter(func1) followed by .Filter(func2) or reheap()
102
105
func (m * txSortedMap ) Filter (filter func (* types.Transaction ) bool ) types.Transactions {
106
+ removed := m .filter (filter )
107
+ // If transactions were removed, the heap and cache are ruined
108
+ if len (removed ) > 0 {
109
+ m .reheap ()
110
+ }
111
+ return removed
112
+ }
113
+
114
+ func (m * txSortedMap ) reheap () {
115
+ * m .index = make ([]uint64 , 0 , len (m .items ))
116
+ for nonce := range m .items {
117
+ * m .index = append (* m .index , nonce )
118
+ }
119
+ heap .Init (m .index )
120
+ m .cache = nil
121
+ }
122
+
123
+ // filter is identical to Filter, but **does not** regenerate the heap. This method
124
+ // should only be used if followed immediately by a call to Filter or reheap()
125
+ func (m * txSortedMap ) filter (filter func (* types.Transaction ) bool ) types.Transactions {
103
126
var removed types.Transactions
104
127
105
128
// Collect all the transactions to filter out
@@ -109,14 +132,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac
109
132
delete (m .items , nonce )
110
133
}
111
134
}
112
- // If transactions were removed, the heap and cache are ruined
113
135
if len (removed ) > 0 {
114
- * m .index = make ([]uint64 , 0 , len (m .items ))
115
- for nonce := range m .items {
116
- * m .index = append (* m .index , nonce )
117
- }
118
- heap .Init (m .index )
119
-
120
136
m .cache = nil
121
137
}
122
138
return removed
@@ -197,10 +213,7 @@ func (m *txSortedMap) Len() int {
197
213
return len (m .items )
198
214
}
199
215
200
- // Flatten creates a nonce-sorted slice of transactions based on the loosely
201
- // sorted internal representation. The result of the sorting is cached in case
202
- // it's requested again before any modifications are made to the contents.
203
- func (m * txSortedMap ) Flatten () types.Transactions {
216
+ func (m * txSortedMap ) flatten () types.Transactions {
204
217
// If the sorting was not cached yet, create and cache it
205
218
if m .cache == nil {
206
219
m .cache = make (types.Transactions , 0 , len (m .items ))
@@ -209,12 +222,27 @@ func (m *txSortedMap) Flatten() types.Transactions {
209
222
}
210
223
sort .Sort (types .TxByNonce (m .cache ))
211
224
}
225
+ return m .cache
226
+ }
227
+
228
+ // Flatten creates a nonce-sorted slice of transactions based on the loosely
229
+ // sorted internal representation. The result of the sorting is cached in case
230
+ // it's requested again before any modifications are made to the contents.
231
+ func (m * txSortedMap ) Flatten () types.Transactions {
212
232
// Copy the cache to prevent accidental modifications
213
- txs := make (types.Transactions , len (m .cache ))
214
- copy (txs , m .cache )
233
+ cache := m .flatten ()
234
+ txs := make (types.Transactions , len (cache ))
235
+ copy (txs , cache )
215
236
return txs
216
237
}
217
238
239
+ // LastElement returns the last element of a flattened list, thus, the
240
+ // transaction with the highest nonce
241
+ func (m * txSortedMap ) LastElement () * types.Transaction {
242
+ cache := m .flatten ()
243
+ return cache [len (cache )- 1 ]
244
+ }
245
+
218
246
// txList is a "list" of transactions belonging to an account, sorted by account
219
247
// nonce. The same type can be used both for storing contiguous transactions for
220
248
// the executable/pending queue; and for storing gapped transactions for the non-
@@ -252,7 +280,11 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
252
280
// If there's an older better transaction, abort
253
281
old := l .txs .Get (tx .Nonce ())
254
282
if old != nil {
255
- threshold := new (big.Int ).Div (new (big.Int ).Mul (old .GasPrice (), big .NewInt (100 + int64 (priceBump ))), big .NewInt (100 ))
283
+ // threshold = oldGP * (100 + priceBump) / 100
284
+ a := big .NewInt (100 + int64 (priceBump ))
285
+ a = a .Mul (a , old .GasPrice ())
286
+ b := big .NewInt (100 )
287
+ threshold := a .Div (a , b )
256
288
// Have to ensure that the new gas price is higher than the old gas
257
289
// price as well as checking the percentage threshold to ensure that
258
290
// this is accurate for low (Wei-level) gas price replacements
@@ -296,20 +328,25 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions
296
328
l .gascap = gasLimit
297
329
298
330
// Filter out all the transactions above the account's funds
299
- removed := l .txs .Filter (func (tx * types.Transaction ) bool { return tx .Cost ().Cmp (costLimit ) > 0 || tx .Gas () > gasLimit })
331
+ removed := l .txs .Filter (func (tx * types.Transaction ) bool {
332
+ return tx .Gas () > gasLimit || tx .Cost ().Cmp (costLimit ) > 0
333
+ })
300
334
301
- // If the list was strict, filter anything above the lowest nonce
335
+ if len (removed ) == 0 {
336
+ return nil , nil
337
+ }
302
338
var invalids types.Transactions
303
-
304
- if l .strict && len ( removed ) > 0 {
339
+ // If the list was strict, filter anything above the lowest nonce
340
+ if l .strict {
305
341
lowest := uint64 (math .MaxUint64 )
306
342
for _ , tx := range removed {
307
343
if nonce := tx .Nonce (); lowest > nonce {
308
344
lowest = nonce
309
345
}
310
346
}
311
- invalids = l .txs .Filter (func (tx * types.Transaction ) bool { return tx .Nonce () > lowest })
347
+ invalids = l .txs .filter (func (tx * types.Transaction ) bool { return tx .Nonce () > lowest })
312
348
}
349
+ l .txs .reheap ()
313
350
return removed , invalids
314
351
}
315
352
@@ -363,6 +400,12 @@ func (l *txList) Flatten() types.Transactions {
363
400
return l .txs .Flatten ()
364
401
}
365
402
403
+ // LastElement returns the last element of a flattened list, thus, the
404
+ // transaction with the highest nonce
405
+ func (l * txList ) LastElement () * types.Transaction {
406
+ return l .txs .LastElement ()
407
+ }
408
+
366
409
// priceHeap is a heap.Interface implementation over transactions for retrieving
367
410
// price-sorted transactions to discard when the pool fills up.
368
411
type priceHeap []* types.Transaction
@@ -495,8 +538,29 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo
495
538
// Discard finds a number of most underpriced transactions, removes them from the
496
539
// priced list and returns them for further removal from the entire pool.
497
540
func (l * txPricedList ) Discard (slots int , local * accountSet ) types.Transactions {
498
- drop := make (types.Transactions , 0 , slots ) // Remote underpriced transactions to drop
499
- save := make (types.Transactions , 0 , 64 ) // Local underpriced transactions to keep
541
+ // If we have some local accountset, those will not be discarded
542
+ if ! local .empty () {
543
+ // In case the list is filled to the brim with 'local' txs, we do this
544
+ // little check to avoid unpacking / repacking the heap later on, which
545
+ // is very expensive
546
+ discardable := 0
547
+ for _ , tx := range * l .items {
548
+ if ! local .containsTx (tx ) {
549
+ discardable ++
550
+ }
551
+ if discardable >= slots {
552
+ break
553
+ }
554
+ }
555
+ if slots > discardable {
556
+ slots = discardable
557
+ }
558
+ }
559
+ if slots == 0 {
560
+ return nil
561
+ }
562
+ drop := make (types.Transactions , 0 , slots ) // Remote underpriced transactions to drop
563
+ save := make (types.Transactions , 0 , len (* l .items )- slots ) // Local underpriced transactions to keep
500
564
501
565
for len (* l .items ) > 0 && slots > 0 {
502
566
// Discard stale transactions if found during cleanup
0 commit comments