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