github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/core/txpool/legacypool/list.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package legacypool 18 19 import ( 20 "container/heap" 21 "math" 22 "math/big" 23 "slices" 24 "sort" 25 "sync" 26 "sync/atomic" 27 "time" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/holiman/uint256" 32 ) 33 34 // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for 35 // retrieving sorted transactions from the possibly gapped future queue. 36 type nonceHeap []uint64 37 38 func (h nonceHeap) Len() int { return len(h) } 39 func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] } 40 func (h nonceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 41 42 func (h *nonceHeap) Push(x interface{}) { 43 *h = append(*h, x.(uint64)) 44 } 45 46 func (h *nonceHeap) Pop() interface{} { 47 old := *h 48 n := len(old) 49 x := old[n-1] 50 old[n-1] = 0 51 *h = old[0 : n-1] 52 return x 53 } 54 55 // sortedMap is a nonce->transaction hash map with a heap based index to allow 56 // iterating over the contents in a nonce-incrementing way. 57 type sortedMap struct { 58 items map[uint64]*types.Transaction // Hash map storing the transaction data 59 index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) 60 cache types.Transactions // Cache of the transactions already sorted 61 cacheMu sync.Mutex // Mutex covering the cache 62 } 63 64 // newSortedMap creates a new nonce-sorted transaction map. 65 func newSortedMap() *sortedMap { 66 return &sortedMap{ 67 items: make(map[uint64]*types.Transaction), 68 index: new(nonceHeap), 69 } 70 } 71 72 // Get retrieves the current transactions associated with the given nonce. 73 func (m *sortedMap) Get(nonce uint64) *types.Transaction { 74 return m.items[nonce] 75 } 76 77 // Put inserts a new transaction into the map, also updating the map's nonce 78 // index. If a transaction already exists with the same nonce, it's overwritten. 79 func (m *sortedMap) Put(tx *types.Transaction) { 80 nonce := tx.Nonce() 81 if m.items[nonce] == nil { 82 heap.Push(m.index, nonce) 83 } 84 m.cacheMu.Lock() 85 m.items[nonce], m.cache = tx, nil 86 m.cacheMu.Unlock() 87 } 88 89 // Forward removes all transactions from the map with a nonce lower than the 90 // provided threshold. Every removed transaction is returned for any post-removal 91 // maintenance. 92 func (m *sortedMap) Forward(threshold uint64) types.Transactions { 93 var removed types.Transactions 94 95 // Pop off heap items until the threshold is reached 96 for m.index.Len() > 0 && (*m.index)[0] < threshold { 97 nonce := heap.Pop(m.index).(uint64) 98 removed = append(removed, m.items[nonce]) 99 delete(m.items, nonce) 100 } 101 // If we had a cached order, shift the front 102 m.cacheMu.Lock() 103 if m.cache != nil { 104 m.cache = m.cache[len(removed):] 105 } 106 m.cacheMu.Unlock() 107 return removed 108 } 109 110 // Filter iterates over the list of transactions and removes all of them for which 111 // the specified function evaluates to true. 112 // Filter, as opposed to 'filter', re-initialises the heap after the operation is done. 113 // If you want to do several consecutive filterings, it's therefore better to first 114 // do a .filter(func1) followed by .Filter(func2) or reheap() 115 func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { 116 removed := m.filter(filter) 117 // If transactions were removed, the heap and cache are ruined 118 if len(removed) > 0 { 119 m.reheap() 120 } 121 return removed 122 } 123 124 func (m *sortedMap) reheap() { 125 *m.index = make([]uint64, 0, len(m.items)) 126 for nonce := range m.items { 127 *m.index = append(*m.index, nonce) 128 } 129 heap.Init(m.index) 130 m.cacheMu.Lock() 131 m.cache = nil 132 m.cacheMu.Unlock() 133 } 134 135 // filter is identical to Filter, but **does not** regenerate the heap. This method 136 // should only be used if followed immediately by a call to Filter or reheap() 137 func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { 138 var removed types.Transactions 139 140 // Collect all the transactions to filter out 141 for nonce, tx := range m.items { 142 if filter(tx) { 143 removed = append(removed, tx) 144 delete(m.items, nonce) 145 } 146 } 147 if len(removed) > 0 { 148 m.cacheMu.Lock() 149 m.cache = nil 150 m.cacheMu.Unlock() 151 } 152 return removed 153 } 154 155 // Cap places a hard limit on the number of items, returning all transactions 156 // exceeding that limit. 157 func (m *sortedMap) Cap(threshold int) types.Transactions { 158 // Short circuit if the number of items is under the limit 159 if len(m.items) <= threshold { 160 return nil 161 } 162 // Otherwise gather and drop the highest nonce'd transactions 163 var drops types.Transactions 164 slices.Sort(*m.index) 165 for size := len(m.items); size > threshold; size-- { 166 drops = append(drops, m.items[(*m.index)[size-1]]) 167 delete(m.items, (*m.index)[size-1]) 168 } 169 *m.index = (*m.index)[:threshold] 170 // The sorted m.index slice is still a valid heap, so there is no need to 171 // reheap after deleting tail items. 172 173 // If we had a cache, shift the back 174 m.cacheMu.Lock() 175 if m.cache != nil { 176 m.cache = m.cache[:len(m.cache)-len(drops)] 177 } 178 m.cacheMu.Unlock() 179 return drops 180 } 181 182 // Remove deletes a transaction from the maintained map, returning whether the 183 // transaction was found. 184 func (m *sortedMap) Remove(nonce uint64) bool { 185 // Short circuit if no transaction is present 186 _, ok := m.items[nonce] 187 if !ok { 188 return false 189 } 190 // Otherwise delete the transaction and fix the heap index 191 for i := 0; i < m.index.Len(); i++ { 192 if (*m.index)[i] == nonce { 193 heap.Remove(m.index, i) 194 break 195 } 196 } 197 delete(m.items, nonce) 198 m.cacheMu.Lock() 199 m.cache = nil 200 m.cacheMu.Unlock() 201 202 return true 203 } 204 205 // Ready retrieves a sequentially increasing list of transactions starting at the 206 // provided nonce that is ready for processing. The returned transactions will be 207 // removed from the list. 208 // 209 // Note, all transactions with nonces lower than start will also be returned to 210 // prevent getting into an invalid state. This is not something that should ever 211 // happen but better to be self correcting than failing! 212 func (m *sortedMap) Ready(start uint64) types.Transactions { 213 // Short circuit if no transactions are available 214 if m.index.Len() == 0 || (*m.index)[0] > start { 215 return nil 216 } 217 // Otherwise start accumulating incremental transactions 218 var ready types.Transactions 219 for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ { 220 ready = append(ready, m.items[next]) 221 delete(m.items, next) 222 heap.Pop(m.index) 223 } 224 m.cacheMu.Lock() 225 m.cache = nil 226 m.cacheMu.Unlock() 227 228 return ready 229 } 230 231 // Len returns the length of the transaction map. 232 func (m *sortedMap) Len() int { 233 return len(m.items) 234 } 235 236 func (m *sortedMap) flatten() types.Transactions { 237 m.cacheMu.Lock() 238 defer m.cacheMu.Unlock() 239 // If the sorting was not cached yet, create and cache it 240 if m.cache == nil { 241 m.cache = make(types.Transactions, 0, len(m.items)) 242 for _, tx := range m.items { 243 m.cache = append(m.cache, tx) 244 } 245 sort.Sort(types.TxByNonce(m.cache)) 246 } 247 return m.cache 248 } 249 250 // Flatten creates a nonce-sorted slice of transactions based on the loosely 251 // sorted internal representation. The result of the sorting is cached in case 252 // it's requested again before any modifications are made to the contents. 253 func (m *sortedMap) Flatten() types.Transactions { 254 cache := m.flatten() 255 // Copy the cache to prevent accidental modification 256 txs := make(types.Transactions, len(cache)) 257 copy(txs, cache) 258 return txs 259 } 260 261 // LastElement returns the last element of a flattened list, thus, the 262 // transaction with the highest nonce 263 func (m *sortedMap) LastElement() *types.Transaction { 264 cache := m.flatten() 265 return cache[len(cache)-1] 266 } 267 268 // list is a "list" of transactions belonging to an account, sorted by account 269 // nonce. The same type can be used both for storing contiguous transactions for 270 // the executable/pending queue; and for storing gapped transactions for the non- 271 // executable/future queue, with minor behavioral changes. 272 type list struct { 273 strict bool // Whether nonces are strictly continuous or not 274 txs *sortedMap // Heap indexed sorted hash map of the transactions 275 276 costcap *uint256.Int // Price of the highest costing transaction (reset only if exceeds balance) 277 gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) 278 totalcost *uint256.Int // Total cost of all transactions in the list 279 } 280 281 // newList creates a new transaction list for maintaining nonce-indexable fast, 282 // gapped, sortable transaction lists. 283 func newList(strict bool) *list { 284 return &list{ 285 strict: strict, 286 txs: newSortedMap(), 287 costcap: new(uint256.Int), 288 totalcost: new(uint256.Int), 289 } 290 } 291 292 // Contains returns whether the list contains a transaction 293 // with the provided nonce. 294 func (l *list) Contains(nonce uint64) bool { 295 return l.txs.Get(nonce) != nil 296 } 297 298 // Add tries to insert a new transaction into the list, returning whether the 299 // transaction was accepted, and if yes, any previous transaction it replaced. 300 // 301 // If the new transaction is accepted into the list, the lists' cost and gas 302 // thresholds are also potentially updated. 303 func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) { 304 // If there's an older better transaction, abort 305 old := l.txs.Get(tx.Nonce()) 306 if old != nil { 307 if old.GasFeeCapCmp(tx) >= 0 || old.GasTipCapCmp(tx) >= 0 { 308 return false, nil 309 } 310 // thresholdFeeCap = oldFC * (100 + priceBump) / 100 311 a := big.NewInt(100 + int64(priceBump)) 312 aFeeCap := new(big.Int).Mul(a, old.GasFeeCap()) 313 aTip := a.Mul(a, old.GasTipCap()) 314 315 // thresholdTip = oldTip * (100 + priceBump) / 100 316 b := big.NewInt(100) 317 thresholdFeeCap := aFeeCap.Div(aFeeCap, b) 318 thresholdTip := aTip.Div(aTip, b) 319 320 // We have to ensure that both the new fee cap and tip are higher than the 321 // old ones as well as checking the percentage threshold to ensure that 322 // this is accurate for low (Wei-level) gas price replacements. 323 if tx.GasFeeCapIntCmp(thresholdFeeCap) < 0 || tx.GasTipCapIntCmp(thresholdTip) < 0 { 324 return false, nil 325 } 326 // Old is being replaced, subtract old cost 327 l.subTotalCost([]*types.Transaction{old}) 328 } 329 // Add new tx cost to totalcost 330 cost, overflow := uint256.FromBig(tx.Cost()) 331 if overflow { 332 return false, nil 333 } 334 l.totalcost.Add(l.totalcost, cost) 335 336 // Otherwise overwrite the old transaction with the current one 337 l.txs.Put(tx) 338 if l.costcap.Cmp(cost) < 0 { 339 l.costcap = cost 340 } 341 if gas := tx.Gas(); l.gascap < gas { 342 l.gascap = gas 343 } 344 return true, old 345 } 346 347 // Forward removes all transactions from the list with a nonce lower than the 348 // provided threshold. Every removed transaction is returned for any post-removal 349 // maintenance. 350 func (l *list) Forward(threshold uint64) types.Transactions { 351 txs := l.txs.Forward(threshold) 352 l.subTotalCost(txs) 353 return txs 354 } 355 356 // Filter removes all transactions from the list with a cost or gas limit higher 357 // than the provided thresholds. Every removed transaction is returned for any 358 // post-removal maintenance. Strict-mode invalidated transactions are also 359 // returned. 360 // 361 // This method uses the cached costcap and gascap to quickly decide if there's even 362 // a point in calculating all the costs or if the balance covers all. If the threshold 363 // is lower than the costgas cap, the caps will be reset to a new high after removing 364 // the newly invalidated transactions. 365 func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactions, types.Transactions) { 366 // If all transactions are below the threshold, short circuit 367 if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { 368 return nil, nil 369 } 370 l.costcap = new(uint256.Int).Set(costLimit) // Lower the caps to the thresholds 371 l.gascap = gasLimit 372 373 // Filter out all the transactions above the account's funds 374 removed := l.txs.Filter(func(tx *types.Transaction) bool { 375 return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit.ToBig()) > 0 376 }) 377 378 if len(removed) == 0 { 379 return nil, nil 380 } 381 var invalids types.Transactions 382 // If the list was strict, filter anything above the lowest nonce 383 if l.strict { 384 lowest := uint64(math.MaxUint64) 385 for _, tx := range removed { 386 if nonce := tx.Nonce(); lowest > nonce { 387 lowest = nonce 388 } 389 } 390 invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest }) 391 } 392 // Reset total cost 393 l.subTotalCost(removed) 394 l.subTotalCost(invalids) 395 l.txs.reheap() 396 return removed, invalids 397 } 398 399 // Cap places a hard limit on the number of items, returning all transactions 400 // exceeding that limit. 401 func (l *list) Cap(threshold int) types.Transactions { 402 txs := l.txs.Cap(threshold) 403 l.subTotalCost(txs) 404 return txs 405 } 406 407 // Remove deletes a transaction from the maintained list, returning whether the 408 // transaction was found, and also returning any transaction invalidated due to 409 // the deletion (strict mode only). 410 func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) { 411 // Remove the transaction from the set 412 nonce := tx.Nonce() 413 if removed := l.txs.Remove(nonce); !removed { 414 return false, nil 415 } 416 l.subTotalCost([]*types.Transaction{tx}) 417 // In strict mode, filter out non-executable transactions 418 if l.strict { 419 txs := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) 420 l.subTotalCost(txs) 421 return true, txs 422 } 423 return true, nil 424 } 425 426 // Ready retrieves a sequentially increasing list of transactions starting at the 427 // provided nonce that is ready for processing. The returned transactions will be 428 // removed from the list. 429 // 430 // Note, all transactions with nonces lower than start will also be returned to 431 // prevent getting into an invalid state. This is not something that should ever 432 // happen but better to be self correcting than failing! 433 func (l *list) Ready(start uint64) types.Transactions { 434 txs := l.txs.Ready(start) 435 l.subTotalCost(txs) 436 return txs 437 } 438 439 // Len returns the length of the transaction list. 440 func (l *list) Len() int { 441 return l.txs.Len() 442 } 443 444 // Empty returns whether the list of transactions is empty or not. 445 func (l *list) Empty() bool { 446 return l.Len() == 0 447 } 448 449 // Flatten creates a nonce-sorted slice of transactions based on the loosely 450 // sorted internal representation. The result of the sorting is cached in case 451 // it's requested again before any modifications are made to the contents. 452 func (l *list) Flatten() types.Transactions { 453 return l.txs.Flatten() 454 } 455 456 // LastElement returns the last element of a flattened list, thus, the 457 // transaction with the highest nonce 458 func (l *list) LastElement() *types.Transaction { 459 return l.txs.LastElement() 460 } 461 462 // subTotalCost subtracts the cost of the given transactions from the 463 // total cost of all transactions. 464 func (l *list) subTotalCost(txs []*types.Transaction) { 465 for _, tx := range txs { 466 _, underflow := l.totalcost.SubOverflow(l.totalcost, uint256.MustFromBig(tx.Cost())) 467 if underflow { 468 panic("totalcost underflow") 469 } 470 } 471 } 472 473 // priceHeap is a heap.Interface implementation over transactions for retrieving 474 // price-sorted transactions to discard when the pool fills up. If baseFee is set 475 // then the heap is sorted based on the effective tip based on the given base fee. 476 // If baseFee is nil then the sorting is based on gasFeeCap. 477 type priceHeap struct { 478 baseFee *big.Int // heap should always be re-sorted after baseFee is changed 479 list []*types.Transaction 480 } 481 482 func (h *priceHeap) Len() int { return len(h.list) } 483 func (h *priceHeap) Swap(i, j int) { h.list[i], h.list[j] = h.list[j], h.list[i] } 484 485 func (h *priceHeap) Less(i, j int) bool { 486 switch h.cmp(h.list[i], h.list[j]) { 487 case -1: 488 return true 489 case 1: 490 return false 491 default: 492 return h.list[i].Nonce() > h.list[j].Nonce() 493 } 494 } 495 496 func (h *priceHeap) cmp(a, b *types.Transaction) int { 497 if h.baseFee != nil { 498 // Compare effective tips if baseFee is specified 499 if c := a.EffectiveGasTipCmp(b, h.baseFee); c != 0 { 500 return c 501 } 502 } 503 // Compare fee caps if baseFee is not specified or effective tips are equal 504 if c := a.GasFeeCapCmp(b); c != 0 { 505 return c 506 } 507 // Compare tips if effective tips and fee caps are equal 508 return a.GasTipCapCmp(b) 509 } 510 511 func (h *priceHeap) Push(x interface{}) { 512 tx := x.(*types.Transaction) 513 h.list = append(h.list, tx) 514 } 515 516 func (h *priceHeap) Pop() interface{} { 517 old := h.list 518 n := len(old) 519 x := old[n-1] 520 old[n-1] = nil 521 h.list = old[0 : n-1] 522 return x 523 } 524 525 // pricedList is a price-sorted heap to allow operating on transactions pool 526 // contents in a price-incrementing way. It's built upon the all transactions 527 // in txpool but only interested in the remote part. It means only remote transactions 528 // will be considered for tracking, sorting, eviction, etc. 529 // 530 // Two heaps are used for sorting: the urgent heap (based on effective tip in the next 531 // block) and the floating heap (based on gasFeeCap). Always the bigger heap is chosen for 532 // eviction. Transactions evicted from the urgent heap are first demoted into the floating heap. 533 // In some cases (during a congestion, when blocks are full) the urgent heap can provide 534 // better candidates for inclusion while in other cases (at the top of the baseFee peak) 535 // the floating heap is better. When baseFee is decreasing they behave similarly. 536 type pricedList struct { 537 // Number of stale price points to (re-heap trigger). 538 stales atomic.Int64 539 540 all *lookup // Pointer to the map of all transactions 541 urgent, floating priceHeap // Heaps of prices of all the stored **remote** transactions 542 reheapMu sync.Mutex // Mutex asserts that only one routine is reheaping the list 543 } 544 545 const ( 546 // urgentRatio : floatingRatio is the capacity ratio of the two queues 547 urgentRatio = 4 548 floatingRatio = 1 549 ) 550 551 // newPricedList creates a new price-sorted transaction heap. 552 func newPricedList(all *lookup) *pricedList { 553 return &pricedList{ 554 all: all, 555 } 556 } 557 558 // Put inserts a new transaction into the heap. 559 func (l *pricedList) Put(tx *types.Transaction, local bool) { 560 if local { 561 return 562 } 563 // Insert every new transaction to the urgent heap first; Discard will balance the heaps 564 heap.Push(&l.urgent, tx) 565 } 566 567 // Removed notifies the prices transaction list that an old transaction dropped 568 // from the pool. The list will just keep a counter of stale objects and update 569 // the heap if a large enough ratio of transactions go stale. 570 func (l *pricedList) Removed(count int) { 571 // Bump the stale counter, but exit if still too low (< 25%) 572 stales := l.stales.Add(int64(count)) 573 if int(stales) <= (len(l.urgent.list)+len(l.floating.list))/4 { 574 return 575 } 576 // Seems we've reached a critical number of stale transactions, reheap 577 l.Reheap() 578 } 579 580 // Underpriced checks whether a transaction is cheaper than (or as cheap as) the 581 // lowest priced (remote) transaction currently being tracked. 582 func (l *pricedList) Underpriced(tx *types.Transaction) bool { 583 // Note: with two queues, being underpriced is defined as being worse than the worst item 584 // in all non-empty queues if there is any. If both queues are empty then nothing is underpriced. 585 return (l.underpricedFor(&l.urgent, tx) || len(l.urgent.list) == 0) && 586 (l.underpricedFor(&l.floating, tx) || len(l.floating.list) == 0) && 587 (len(l.urgent.list) != 0 || len(l.floating.list) != 0) 588 } 589 590 // underpricedFor checks whether a transaction is cheaper than (or as cheap as) the 591 // lowest priced (remote) transaction in the given heap. 592 func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { 593 // Discard stale price points if found at the heap start 594 for len(h.list) > 0 { 595 head := h.list[0] 596 if l.all.GetRemote(head.Hash()) == nil { // Removed or migrated 597 l.stales.Add(-1) 598 heap.Pop(h) 599 continue 600 } 601 break 602 } 603 // Check if the transaction is underpriced or not 604 if len(h.list) == 0 { 605 return false // There is no remote transaction at all. 606 } 607 // If the remote transaction is even cheaper than the 608 // cheapest one tracked locally, reject it. 609 return h.cmp(h.list[0], tx) >= 0 610 } 611 612 // Discard finds a number of most underpriced transactions, removes them from the 613 // priced list and returns them for further removal from the entire pool. 614 // If noPending is set to true, we will only consider the floating list 615 // 616 // Note local transaction won't be considered for eviction. 617 func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { 618 drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop 619 for slots > 0 { 620 if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio { 621 // Discard stale transactions if found during cleanup 622 tx := heap.Pop(&l.urgent).(*types.Transaction) 623 if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated 624 l.stales.Add(-1) 625 continue 626 } 627 // Non stale transaction found, move to floating heap 628 heap.Push(&l.floating, tx) 629 } else { 630 if len(l.floating.list) == 0 { 631 // Stop if both heaps are empty 632 break 633 } 634 // Discard stale transactions if found during cleanup 635 tx := heap.Pop(&l.floating).(*types.Transaction) 636 if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated 637 l.stales.Add(-1) 638 continue 639 } 640 // Non stale transaction found, discard it 641 drop = append(drop, tx) 642 slots -= numSlots(tx) 643 } 644 } 645 // If we still can't make enough room for the new transaction 646 if slots > 0 && !force { 647 for _, tx := range drop { 648 heap.Push(&l.urgent, tx) 649 } 650 return nil, false 651 } 652 return drop, true 653 } 654 655 // Reheap forcibly rebuilds the heap based on the current remote transaction set. 656 func (l *pricedList) Reheap() { 657 l.reheapMu.Lock() 658 defer l.reheapMu.Unlock() 659 start := time.Now() 660 l.stales.Store(0) 661 l.urgent.list = make([]*types.Transaction, 0, l.all.RemoteCount()) 662 l.all.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { 663 l.urgent.list = append(l.urgent.list, tx) 664 return true 665 }, false, true) // Only iterate remotes 666 heap.Init(&l.urgent) 667 668 // balance out the two heaps by moving the worse half of transactions into the 669 // floating heap 670 // Note: Discard would also do this before the first eviction but Reheap can do 671 // is more efficiently. Also, Underpriced would work suboptimally the first time 672 // if the floating queue was empty. 673 floatingCount := len(l.urgent.list) * floatingRatio / (urgentRatio + floatingRatio) 674 l.floating.list = make([]*types.Transaction, floatingCount) 675 for i := 0; i < floatingCount; i++ { 676 l.floating.list[i] = heap.Pop(&l.urgent).(*types.Transaction) 677 } 678 heap.Init(&l.floating) 679 reheapTimer.Update(time.Since(start)) 680 } 681 682 // SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not 683 // necessary to call right before SetBaseFee when processing a new block. 684 func (l *pricedList) SetBaseFee(baseFee *big.Int) { 685 l.urgent.baseFee = baseFee 686 l.Reheap() 687 }