github.com/phillinzzz/newBsc@v1.1.6/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 26 "github.com/phillinzzz/newBsc/common" 27 "github.com/phillinzzz/newBsc/core/types" 28 ) 29 30 var txSortedMapPool = sync.Pool{ 31 New: func() interface{} { 32 return make(types.Transactions, 0, 10) 33 }, 34 } 35 36 // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for 37 // retrieving sorted transactions from the possibly gapped future queue. 38 type nonceHeap []uint64 39 40 func (h nonceHeap) Len() int { return len(h) } 41 func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] } 42 func (h nonceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 43 44 func (h *nonceHeap) Push(x interface{}) { 45 *h = append(*h, x.(uint64)) 46 } 47 48 func (h *nonceHeap) Pop() interface{} { 49 old := *h 50 n := len(old) 51 x := old[n-1] 52 *h = old[0 : n-1] 53 return x 54 } 55 56 // txSortedMap is a nonce->transaction hash map with a heap based index to allow 57 // iterating over the contents in a nonce-incrementing way. 58 type 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 62 } 63 64 // newTxSortedMap creates a new nonce-sorted transaction map. 65 func newTxSortedMap() *txSortedMap { 66 return &txSortedMap{ 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 *txSortedMap) 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 *txSortedMap) Put(tx *types.Transaction) { 80 nonce := tx.Nonce() 81 if m.items[nonce] == nil { 82 heap.Push(m.index, nonce) 83 } 84 if m.cache != nil { 85 txSortedMapPool.Put(m.cache) 86 } 87 m.items[nonce], m.cache = tx, nil 88 } 89 90 // Forward removes all transactions from the map with a nonce lower than the 91 // provided threshold. Every removed transaction is returned for any post-removal 92 // maintenance. 93 func (m *txSortedMap) Forward(threshold uint64) types.Transactions { 94 var removed types.Transactions 95 96 // Pop off heap items until the threshold is reached 97 for m.index.Len() > 0 && (*m.index)[0] < threshold { 98 nonce := heap.Pop(m.index).(uint64) 99 removed = append(removed, m.items[nonce]) 100 delete(m.items, nonce) 101 } 102 // If we had a cached order, shift the front 103 if m.cache != nil { 104 m.cache = m.cache[len(removed):] 105 } 106 return removed 107 } 108 109 // Filter iterates over the list of transactions and removes all of them for which 110 // the specified function evaluates to true. 111 // Filter, as opposed to 'filter', re-initialises the heap after the operation is done. 112 // If you want to do several consecutive filterings, it's therefore better to first 113 // do a .filter(func1) followed by .Filter(func2) or reheap() 114 func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { 115 removed := m.filter(filter) 116 // If transactions were removed, the heap and cache are ruined 117 if len(removed) > 0 { 118 m.reheap() 119 } 120 return removed 121 } 122 123 func (m *txSortedMap) reheap() { 124 *m.index = make([]uint64, 0, len(m.items)) 125 for nonce := range m.items { 126 *m.index = append(*m.index, nonce) 127 } 128 heap.Init(m.index) 129 m.cache = nil 130 } 131 132 // filter is identical to Filter, but **does not** regenerate the heap. This method 133 // should only be used if followed immediately by a call to Filter or reheap() 134 func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { 135 var removed types.Transactions 136 137 // Collect all the transactions to filter out 138 for nonce, tx := range m.items { 139 if filter(tx) { 140 removed = append(removed, tx) 141 delete(m.items, nonce) 142 } 143 } 144 if len(removed) > 0 { 145 if m.cache != nil { 146 txSortedMapPool.Put(m.cache) 147 m.cache = nil 148 } 149 } 150 return removed 151 } 152 153 // Cap places a hard limit on the number of items, returning all transactions 154 // exceeding that limit. 155 func (m *txSortedMap) Cap(threshold int) types.Transactions { 156 // Short circuit if the number of items is under the limit 157 if len(m.items) <= threshold { 158 return nil 159 } 160 // Otherwise gather and drop the highest nonce'd transactions 161 var drops types.Transactions 162 163 sort.Sort(*m.index) 164 for size := len(m.items); size > threshold; size-- { 165 drops = append(drops, m.items[(*m.index)[size-1]]) 166 delete(m.items, (*m.index)[size-1]) 167 } 168 *m.index = (*m.index)[:threshold] 169 heap.Init(m.index) 170 171 // If we had a cache, shift the back 172 if m.cache != nil { 173 m.cache = m.cache[:len(m.cache)-len(drops)] 174 } 175 return drops 176 } 177 178 // Remove deletes a transaction from the maintained map, returning whether the 179 // transaction was found. 180 func (m *txSortedMap) Remove(nonce uint64) bool { 181 // Short circuit if no transaction is present 182 _, ok := m.items[nonce] 183 if !ok { 184 return false 185 } 186 // Otherwise delete the transaction and fix the heap index 187 for i := 0; i < m.index.Len(); i++ { 188 if (*m.index)[i] == nonce { 189 heap.Remove(m.index, i) 190 break 191 } 192 } 193 delete(m.items, nonce) 194 if m.cache != nil { 195 txSortedMapPool.Put(m.cache) 196 m.cache = nil 197 } 198 199 return true 200 } 201 202 // Ready retrieves a sequentially increasing list of transactions starting at the 203 // provided nonce that is ready for processing. The returned transactions will be 204 // removed from the list. 205 // 206 // Note, all transactions with nonces lower than start will also be returned to 207 // prevent getting into and invalid state. This is not something that should ever 208 // happen but better to be self correcting than failing! 209 func (m *txSortedMap) Ready(start uint64) types.Transactions { 210 // Short circuit if no transactions are available 211 if m.index.Len() == 0 || (*m.index)[0] > start { 212 return nil 213 } 214 // Otherwise start accumulating incremental transactions 215 var ready types.Transactions 216 for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ { 217 ready = append(ready, m.items[next]) 218 delete(m.items, next) 219 heap.Pop(m.index) 220 } 221 if m.cache != nil { 222 txSortedMapPool.Put(m.cache) 223 m.cache = nil 224 } 225 226 return ready 227 } 228 229 // Len returns the length of the transaction map. 230 func (m *txSortedMap) Len() int { 231 return len(m.items) 232 } 233 234 func (m *txSortedMap) flatten() types.Transactions { 235 // If the sorting was not cached yet, create and cache it 236 if m.cache == nil { 237 cache := txSortedMapPool.Get() 238 if cache != nil { 239 m.cache = cache.(types.Transactions) 240 m.cache = m.cache[:0] 241 } else { 242 m.cache = make(types.Transactions, 0, len(m.items)) 243 } 244 for _, tx := range m.items { 245 m.cache = append(m.cache, tx) 246 } 247 sort.Sort(types.TxByNonce(m.cache)) 248 } 249 return m.cache 250 } 251 252 // Flatten creates a nonce-sorted slice of transactions based on the loosely 253 // sorted internal representation. The result of the sorting is cached in case 254 // it's requested again before any modifications are made to the contents. 255 func (m *txSortedMap) Flatten() types.Transactions { 256 // Copy the cache to prevent accidental modifications 257 cache := m.flatten() 258 txs := make(types.Transactions, len(cache)) 259 copy(txs, cache) 260 return txs 261 } 262 263 // LastElement returns the last element of a flattened list, thus, the 264 // transaction with the highest nonce 265 func (m *txSortedMap) LastElement() *types.Transaction { 266 cache := m.flatten() 267 return cache[len(cache)-1] 268 } 269 270 // txList is a "list" of transactions belonging to an account, sorted by account 271 // nonce. The same type can be used both for storing contiguous transactions for 272 // the executable/pending queue; and for storing gapped transactions for the non- 273 // executable/future queue, with minor behavioral changes. 274 type txList struct { 275 strict bool // Whether nonces are strictly continuous or not 276 txs *txSortedMap // Heap indexed sorted hash map of the transactions 277 278 costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) 279 gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) 280 } 281 282 // newTxList create a new transaction list for maintaining nonce-indexable fast, 283 // gapped, sortable transaction lists. 284 func newTxList(strict bool) *txList { 285 return &txList{ 286 strict: strict, 287 txs: newTxSortedMap(), 288 costcap: new(big.Int), 289 } 290 } 291 292 // Overlaps returns whether the transaction specified has the same nonce as one 293 // already contained within the list. 294 func (l *txList) Overlaps(tx *types.Transaction) bool { 295 return l.txs.Get(tx.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 *txList) 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 // threshold = oldGP * (100 + priceBump) / 100 308 a := big.NewInt(100 + int64(priceBump)) 309 a = a.Mul(a, old.GasPrice()) 310 b := big.NewInt(100) 311 threshold := a.Div(a, b) 312 // Have to ensure that the new gas price is higher than the old gas 313 // price as well as checking the percentage threshold to ensure that 314 // this is accurate for low (Wei-level) gas price replacements 315 if old.GasPriceCmp(tx) >= 0 || tx.GasPriceIntCmp(threshold) < 0 { 316 return false, nil 317 } 318 } 319 // Otherwise overwrite the old transaction with the current one 320 l.txs.Put(tx) 321 if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { 322 l.costcap = cost 323 } 324 if gas := tx.Gas(); l.gascap < gas { 325 l.gascap = gas 326 } 327 return true, old 328 } 329 330 // Forward removes all transactions from the list with a nonce lower than the 331 // provided threshold. Every removed transaction is returned for any post-removal 332 // maintenance. 333 func (l *txList) Forward(threshold uint64) types.Transactions { 334 return l.txs.Forward(threshold) 335 } 336 337 // Filter removes all transactions from the list with a cost or gas limit higher 338 // than the provided thresholds. Every removed transaction is returned for any 339 // post-removal maintenance. Strict-mode invalidated transactions are also 340 // returned. 341 // 342 // This method uses the cached costcap and gascap to quickly decide if there's even 343 // a point in calculating all the costs or if the balance covers all. If the threshold 344 // is lower than the costgas cap, the caps will be reset to a new high after removing 345 // the newly invalidated transactions. 346 func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) { 347 // If all transactions are below the threshold, short circuit 348 if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { 349 return nil, nil 350 } 351 l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds 352 l.gascap = gasLimit 353 354 // Filter out all the transactions above the account's funds 355 removed := l.txs.Filter(func(tx *types.Transaction) bool { 356 return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit) > 0 357 }) 358 359 if len(removed) == 0 { 360 return nil, nil 361 } 362 var invalids types.Transactions 363 // If the list was strict, filter anything above the lowest nonce 364 if l.strict { 365 lowest := uint64(math.MaxUint64) 366 for _, tx := range removed { 367 if nonce := tx.Nonce(); lowest > nonce { 368 lowest = nonce 369 } 370 } 371 invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest }) 372 } 373 l.txs.reheap() 374 return removed, invalids 375 } 376 377 // Cap places a hard limit on the number of items, returning all transactions 378 // exceeding that limit. 379 func (l *txList) Cap(threshold int) types.Transactions { 380 return l.txs.Cap(threshold) 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 *txList) 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 // In strict mode, filter out non-executable transactions 393 if l.strict { 394 return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) 395 } 396 return true, nil 397 } 398 399 // Ready retrieves a sequentially increasing list of transactions starting at the 400 // provided nonce that is ready for processing. The returned transactions will be 401 // removed from the list. 402 // 403 // Note, all transactions with nonces lower than start will also be returned to 404 // prevent getting into and invalid state. This is not something that should ever 405 // happen but better to be self correcting than failing! 406 func (l *txList) Ready(start uint64) types.Transactions { 407 return l.txs.Ready(start) 408 } 409 410 // Len returns the length of the transaction list. 411 func (l *txList) Len() int { 412 return len(l.txs.items) 413 } 414 415 // Empty returns whether the list of transactions is empty or not. 416 func (l *txList) Empty() bool { 417 return l.Len() == 0 418 } 419 420 // Flatten creates a nonce-sorted slice of transactions based on the loosely 421 // sorted internal representation. The result of the sorting is cached in case 422 // it's requested again before any modifications are made to the contents. 423 func (l *txList) Flatten() types.Transactions { 424 return l.txs.Flatten() 425 } 426 427 // LastElement returns the last element of a flattened list, thus, the 428 // transaction with the highest nonce 429 func (l *txList) LastElement() *types.Transaction { 430 return l.txs.LastElement() 431 } 432 433 // priceHeap is a heap.Interface implementation over transactions for retrieving 434 // price-sorted transactions to discard when the pool fills up. 435 type priceHeap []*types.Transaction 436 437 func (h priceHeap) Len() int { return len(h) } 438 func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 439 440 func (h priceHeap) Less(i, j int) bool { 441 // Sort primarily by price, returning the cheaper one 442 switch h[i].GasPriceCmp(h[j]) { 443 case -1: 444 return true 445 case 1: 446 return false 447 } 448 // If the prices match, stabilize via nonces (high nonce is worse) 449 return h[i].Nonce() > h[j].Nonce() 450 } 451 452 func (h *priceHeap) Push(x interface{}) { 453 *h = append(*h, x.(*types.Transaction)) 454 } 455 456 func (h *priceHeap) Pop() interface{} { 457 old := *h 458 n := len(old) 459 x := old[n-1] 460 old[n-1] = nil 461 *h = old[0 : n-1] 462 return x 463 } 464 465 // txPricedList is a price-sorted heap to allow operating on transactions pool 466 // contents in a price-incrementing way. It's built opon the all transactions 467 // in txpool but only interested in the remote part. It means only remote transactions 468 // will be considered for tracking, sorting, eviction, etc. 469 type txPricedList struct { 470 all *txLookup // Pointer to the map of all transactions 471 remotes *priceHeap // Heap of prices of all the stored **remote** transactions 472 stales int // Number of stale price points to (re-heap trigger) 473 } 474 475 // newTxPricedList creates a new price-sorted transaction heap. 476 func newTxPricedList(all *txLookup) *txPricedList { 477 return &txPricedList{ 478 all: all, 479 remotes: new(priceHeap), 480 } 481 } 482 483 // Put inserts a new transaction into the heap. 484 func (l *txPricedList) Put(tx *types.Transaction, local bool) { 485 if local { 486 return 487 } 488 heap.Push(l.remotes, tx) 489 } 490 491 // Removed notifies the prices transaction list that an old transaction dropped 492 // from the pool. The list will just keep a counter of stale objects and update 493 // the heap if a large enough ratio of transactions go stale. 494 func (l *txPricedList) Removed(count int) { 495 // Bump the stale counter, but exit if still too low (< 25%) 496 l.stales += count 497 if l.stales <= len(*l.remotes)/4 { 498 return 499 } 500 // Seems we've reached a critical number of stale transactions, reheap 501 l.Reheap() 502 } 503 504 // Cap finds all the transactions below the given price threshold, drops them 505 // from the priced list and returns them for further removal from the entire pool. 506 // 507 // Note: only remote transactions will be considered for eviction. 508 func (l *txPricedList) Cap(threshold *big.Int) types.Transactions { 509 drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop 510 for len(*l.remotes) > 0 { 511 // Discard stale transactions if found during cleanup 512 cheapest := (*l.remotes)[0] 513 if l.all.GetRemote(cheapest.Hash()) == nil { // Removed or migrated 514 heap.Pop(l.remotes) 515 l.stales-- 516 continue 517 } 518 // Stop the discards if we've reached the threshold 519 if cheapest.GasPriceIntCmp(threshold) >= 0 { 520 break 521 } 522 heap.Pop(l.remotes) 523 drop = append(drop, cheapest) 524 } 525 return drop 526 } 527 528 // Underpriced checks whether a transaction is cheaper than (or as cheap as) the 529 // lowest priced (remote) transaction currently being tracked. 530 func (l *txPricedList) Underpriced(tx *types.Transaction) bool { 531 // Discard stale price points if found at the heap start 532 for len(*l.remotes) > 0 { 533 head := []*types.Transaction(*l.remotes)[0] 534 if l.all.GetRemote(head.Hash()) == nil { // Removed or migrated 535 l.stales-- 536 heap.Pop(l.remotes) 537 continue 538 } 539 break 540 } 541 // Check if the transaction is underpriced or not 542 if len(*l.remotes) == 0 { 543 return false // There is no remote transaction at all. 544 } 545 // If the remote transaction is even cheaper than the 546 // cheapest one tracked locally, reject it. 547 cheapest := []*types.Transaction(*l.remotes)[0] 548 return cheapest.GasPriceCmp(tx) >= 0 549 } 550 551 // Discard finds a number of most underpriced transactions, removes them from the 552 // priced list and returns them for further removal from the entire pool. 553 // 554 // Note local transaction won't be considered for eviction. 555 func (l *txPricedList) Discard(slots int, force bool) (types.Transactions, bool) { 556 drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop 557 for len(*l.remotes) > 0 && slots > 0 { 558 // Discard stale transactions if found during cleanup 559 tx := heap.Pop(l.remotes).(*types.Transaction) 560 if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated 561 l.stales-- 562 continue 563 } 564 // Non stale transaction found, discard it 565 drop = append(drop, tx) 566 slots -= numSlots(tx) 567 } 568 // If we still can't make enough room for the new transaction 569 if slots > 0 && !force { 570 for _, tx := range drop { 571 heap.Push(l.remotes, tx) 572 } 573 return nil, false 574 } 575 return drop, true 576 } 577 578 // Reheap forcibly rebuilds the heap based on the current remote transaction set. 579 func (l *txPricedList) Reheap() { 580 reheap := make(priceHeap, 0, l.all.RemoteCount()) 581 582 l.stales, l.remotes = 0, &reheap 583 l.all.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { 584 *l.remotes = append(*l.remotes, tx) 585 return true 586 }, false, true) // Only iterate remotes 587 heap.Init(l.remotes) 588 }