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