github.com/klaytn/klaytn@v1.12.1/blockchain/tx_list.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/tx_list.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package blockchain 22 23 import ( 24 "container/heap" 25 "math" 26 "math/big" 27 "sort" 28 29 "github.com/klaytn/klaytn/blockchain/types" 30 "github.com/klaytn/klaytn/common" 31 ) 32 33 // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for 34 // retrieving sorted transactions from the possibly gapped future queue. 35 type nonceHeap []uint64 36 37 func (h nonceHeap) Len() int { return len(h) } 38 func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] } 39 func (h nonceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 40 41 func (h *nonceHeap) Push(x interface{}) { 42 *h = append(*h, x.(uint64)) 43 } 44 45 func (h *nonceHeap) Pop() interface{} { 46 old := *h 47 n := len(old) 48 x := old[n-1] 49 *h = old[0 : n-1] 50 return x 51 } 52 53 // txSortedMap 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 txSortedMap 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 // newTxSortedMap creates a new nonce-sorted transaction map. 62 func newTxSortedMap() *txSortedMap { 63 return &txSortedMap{ 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 *txSortedMap) 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 *txSortedMap) 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 *txSortedMap) 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 func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { 106 var removed types.Transactions 107 108 // Collect all the transactions to filter out 109 for nonce, tx := range m.items { 110 if filter(tx) { 111 removed = append(removed, tx) 112 delete(m.items, nonce) 113 } 114 } 115 // If transactions were removed, the heap and cache are ruined 116 if len(removed) > 0 { 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 123 m.cache = nil 124 } 125 return removed 126 } 127 128 // Cap places a hard limit on the number of items, returning all transactions 129 // exceeding that limit. 130 func (m *txSortedMap) Cap(threshold int) types.Transactions { 131 // Short circuit if the number of items is under the limit 132 if len(m.items) <= threshold { 133 return nil 134 } 135 // Otherwise gather and drop the highest nonce'd transactions 136 var drops types.Transactions 137 138 sort.Sort(*m.index) 139 for size := len(m.items); size > threshold; size-- { 140 drops = append(drops, m.items[(*m.index)[size-1]]) 141 delete(m.items, (*m.index)[size-1]) 142 } 143 *m.index = (*m.index)[:threshold] 144 heap.Init(m.index) 145 146 // If we had a cache, shift the back 147 if m.cache != nil { 148 m.cache = m.cache[:len(m.cache)-len(drops)] 149 } 150 return drops 151 } 152 153 // Remove deletes a transaction from the maintained map, returning whether the 154 // transaction was found. 155 func (m *txSortedMap) Remove(nonce uint64) bool { 156 // Short circuit if no transaction is present 157 _, ok := m.items[nonce] 158 if !ok { 159 return false 160 } 161 // Otherwise delete the transaction and fix the heap index 162 for i := 0; i < m.index.Len(); i++ { 163 if (*m.index)[i] == nonce { 164 heap.Remove(m.index, i) 165 break 166 } 167 } 168 delete(m.items, nonce) 169 m.cache = nil 170 171 return true 172 } 173 174 // Ready retrieves a sequentially increasing list of transactions starting at the 175 // provided nonce that is ready for processing. The returned transactions will be 176 // removed from the list. 177 // 178 // Note, all transactions with nonces lower than start will also be returned to 179 // prevent getting into and invalid state. This is not something that should ever 180 // happen but better to be self correcting than failing! 181 func (m *txSortedMap) Ready(start uint64) types.Transactions { 182 // Short circuit if no transactions are available 183 if m.index.Len() == 0 || (*m.index)[0] > start { 184 return nil 185 } 186 // Otherwise start accumulating incremental transactions 187 var ready types.Transactions 188 for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ { 189 ready = append(ready, m.items[next]) 190 delete(m.items, next) 191 heap.Pop(m.index) 192 } 193 m.cache = nil 194 195 return ready 196 } 197 198 // ReadyWithGasPrice retrieves a sequentially increasing list of transactions that greater than or 199 // equal to the given baseFee starting at the provided nonce that is ready for processing. 200 // If there is a transaction lower than the baseFee during the search, only previously collected transactions 201 // are returned. The returned transactions will be removed from the list. 202 // 203 // Note, all transactions with nonces lower than start will also be returned to 204 // prevent getting into and invalid state. This is not something that should ever 205 // happen but better to be self correcting than failing! 206 func (m *txSortedMap) ReadyWithGasPrice(start uint64, baseFee *big.Int) types.Transactions { 207 // Short circuit if no transactions are available 208 if m.index.Len() == 0 || (*m.index)[0] > start { 209 return nil 210 } 211 // Otherwise start accumulating incremental transactions 212 ready := make(types.Transactions, 0, m.index.Len()) 213 for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ { 214 if m.items[next].GasPrice().Cmp(baseFee) < 0 { 215 break 216 } 217 ready = append(ready, m.items[next]) 218 delete(m.items, next) 219 heap.Pop(m.index) 220 } 221 // If we had a cached order, shift the front 222 if m.cache != nil { 223 m.cache = m.cache[len(ready):] 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 // Flatten creates a nonce-sorted slice of transactions based on the loosely 235 // sorted internal representation. The result of the sorting is cached in case 236 // it's requested again before any modifications are made to the contents. 237 func (m *txSortedMap) Flatten() types.Transactions { 238 return m.FlattenByCount(0) 239 } 240 241 func (m *txSortedMap) FlattenByCount(count int64) types.Transactions { 242 // If the sorting was not cached yet, create and cache it 243 if m.cache == nil { 244 m.cache = make(types.Transactions, 0, len(m.items)) 245 for _, tx := range m.items { 246 m.cache = append(m.cache, tx) 247 } 248 sort.Sort(types.TxByNonce(m.cache)) 249 } 250 txLen := int64(len(m.cache)) 251 if count != 0 && txLen > count { 252 txLen = count 253 } 254 // Copy the cache to prevent accidental modifications 255 txs := make(types.Transactions, txLen) 256 copy(txs, m.cache) 257 return txs 258 } 259 260 // CachedTxsFlattenByCount returns a nonce-sorted slice including at most 261 // a requested number of cached in case it's requested again before any 262 // modifications are made to the contents. 263 func (m *txSortedMap) CachedTxsFlattenByCount(count int) types.Transactions { 264 if count <= 0 { 265 return nil 266 } 267 // If the sorting was not cached yet, create and cache it 268 if m.cache == nil { 269 m.cache = make(types.Transactions, 0, len(m.items)) 270 for _, tx := range m.items { 271 m.cache = append(m.cache, tx) 272 } 273 sort.Sort(types.TxByNonce(m.cache)) 274 } 275 txLen := len(m.cache) 276 if count != 0 && txLen > count { 277 txLen = count 278 } 279 return m.cache[:txLen] 280 } 281 282 // txList is a "list" of transactions belonging to an account, sorted by account 283 // nonce. The same type can be used both for storing contiguous transactions for 284 // the executable/pending queue; and for storing gapped transactions for the non- 285 // executable/future queue, with minor behavioral changes. 286 type txList struct { 287 strict bool // Whether nonces are strictly continuous or not 288 txs *txSortedMap // Heap indexed sorted hash map of the transactions 289 } 290 291 // newTxList create a new transaction list for maintaining nonce-indexable fast, 292 // gapped, sortable transaction lists. 293 func newTxList(strict bool) *txList { 294 return &txList{ 295 strict: strict, 296 txs: newTxSortedMap(), 297 } 298 } 299 300 // Overlaps returns whether the transaction specified has the same nonce as one 301 // already contained within the list. 302 func (l *txList) Overlaps(tx *types.Transaction) bool { 303 return l.txs.Get(tx.Nonce()) != nil 304 } 305 306 // Add tries to insert a new transaction into the list, returning whether the 307 // transaction was accepted, and if yes, any previous transaction it replaced. 308 // 309 // If the new transaction is accepted into the list, the lists' cost and gas 310 // thresholds are also potentially updated. 311 func (l *txList) Add(tx *types.Transaction, priceBump uint64, magmaHardforked bool) (bool, *types.Transaction) { 312 // If there's an older better transaction, abort 313 old := l.txs.Get(tx.Nonce()) 314 if old != nil { 315 // If tx is CancelTransaction, replace it even thought tx has lower gasPrice than previous tx. 316 if tx.Type().IsCancelTransaction() { 317 logger.Trace("New tx is a cancel transaction. replace it!", "old", old.String(), "new", tx.String()) 318 } else if magmaHardforked { 319 if old.GasPrice().Cmp(tx.GasPrice()) >= 0 { 320 // If gas price of older is bigger than newer, abort. 321 logger.Trace("already nonce exist and the gasprice is lower then older", "nonce", tx.Nonce(), "with gasprice", old.GasPrice(), "priceBump", priceBump, "new tx.gasprice", tx.GasPrice()) 322 return false, nil 323 } 324 // Otherwise overwrite the old transaction with the current one. 325 logger.Trace("The transaction was substituted by competitive gas price", "old", old.String(), "new", tx.String()) 326 } else { 327 logger.Trace("already nonce exist", "nonce", tx.Nonce(), "with gasprice", old.GasPrice(), "priceBump", priceBump, "new tx.gasprice", tx.GasPrice()) 328 return false, nil 329 } 330 } 331 332 l.txs.Put(tx) 333 return true, old 334 } 335 336 // Forward removes all transactions from the list with a nonce lower than the 337 // provided threshold. Every removed transaction is returned for any post-removal 338 // maintenance. 339 func (l *txList) Forward(threshold uint64) types.Transactions { 340 return l.txs.Forward(threshold) 341 } 342 343 // Filter removes all transactions from the list with a cost higher 344 // than the provided thresholds. Every removed transaction is returned for any 345 // post-removal maintenance. Strict-mode invalidated transactions are also 346 // returned. 347 // 348 // This method uses the cached costcap to quickly decide if there's even 349 // a point in calculating all the costs or if the balance covers all. If the threshold 350 // is lower than the costcap, the caps will be reset to a new high after removing 351 // the newly invalidated transactions. 352 func (l *txList) Filter(sender common.Address, pool *TxPool) (types.Transactions, types.Transactions) { 353 // Filter out all the transactions above the account's funds 354 removed := l.txs.Filter(func(tx *types.Transaction) bool { 355 senderBalance := pool.getBalance(sender) 356 // Drop a tx if it is marked as un-executable on block generation process. 357 if tx.IsMarkedUnexecutable() { 358 return true 359 } 360 // Since there are mutable values such as accountKey in the state, a tx can be invalidated with the state change. 361 if tx.ValidateMutableValue(pool.currentState, pool.signer, pool.currentBlockNumber) != nil { 362 return true 363 } 364 // In case of fee-delegated transactions, the comparison value should consider tx fee and fee ratio. 365 if tx.IsFeeDelegatedTransaction() { 366 feePayer, _ := tx.FeePayer() 367 feePayerBalance := pool.getBalance(feePayer) 368 feeRatio, isRatioTx := tx.FeeRatio() 369 370 // Handling the special case when the sender and fee payer are the same. 371 if sender == feePayer { 372 return senderBalance.Cmp(tx.Cost()) < 0 373 } 374 if isRatioTx { 375 feeByFeePayer, feeBySender := types.CalcFeeWithRatio(feeRatio, tx.Fee()) 376 return senderBalance.Cmp(new(big.Int).Add(tx.Value(), feeBySender)) < 0 || feePayerBalance.Cmp(feeByFeePayer) < 0 377 } else { 378 return senderBalance.Cmp(tx.Value()) < 0 || feePayerBalance.Cmp(tx.Fee()) < 0 379 } 380 } 381 // For other transactions, all tx cost should be payable by the sender. 382 return senderBalance.Cmp(tx.Cost()) < 0 383 }) 384 385 // If the list was strict, filter anything above the lowest nonce 386 var invalids types.Transactions 387 388 if l.strict && len(removed) > 0 { 389 lowest := uint64(math.MaxUint64) 390 for _, tx := range removed { 391 if nonce := tx.Nonce(); lowest > nonce { 392 lowest = nonce 393 } 394 } 395 invalids = l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest }) 396 } 397 return removed, invalids 398 } 399 400 // FilterUnexecutable removes all transactions marked as unexecutable. 401 func (l *txList) FilterUnexecutable() (types.Transactions, types.Transactions) { 402 removed := l.txs.Filter(func(tx *types.Transaction) bool { 403 // Drop a tx if it is marked as un-executable on block generation process. 404 if tx.IsMarkedUnexecutable() { 405 return true 406 } 407 return false 408 }) 409 410 // If the list was strict, filter anything above the lowest nonce 411 var invalids types.Transactions 412 413 if l.strict && len(removed) > 0 { 414 lowest := uint64(math.MaxUint64) 415 for _, tx := range removed { 416 if nonce := tx.Nonce(); lowest > nonce { 417 lowest = nonce 418 } 419 } 420 invalids = l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest }) 421 } 422 return removed, invalids 423 } 424 425 // Cap places a hard limit on the number of items, returning all transactions 426 // exceeding that limit. 427 func (l *txList) Cap(threshold int) types.Transactions { 428 return l.txs.Cap(threshold) 429 } 430 431 // Remove deletes a transaction from the maintained list, returning whether the 432 // transaction was found, and also returning any transaction invalidated due to 433 // the deletion (strict mode only). 434 func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) { 435 // Remove the transaction from the set 436 nonce := tx.Nonce() 437 if removed := l.txs.Remove(nonce); !removed { 438 return false, nil 439 } 440 // In strict mode, filter out non-executable transactions 441 if l.strict { 442 return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) 443 } 444 return true, nil 445 } 446 447 // Ready retrieves a sequentially increasing list of transactions starting at the 448 // provided nonce that is ready for processing. The returned transactions will be 449 // removed from the list. 450 // 451 // Note, all transactions with nonces lower than start will also be returned to 452 // prevent getting into and invalid state. This is not something that should ever 453 // happen but better to be self correcting than failing! 454 func (l *txList) Ready(start uint64) types.Transactions { 455 return l.txs.Ready(start) 456 } 457 458 // ReadyWithGasPrice retrieves a sequentially increasing list of transactions that greater than or 459 // equal to the given baseFee starting at the provided nonce that is ready for processing. 460 // If there is a transaction lower than the baseFee during the search, only previously collected transactions 461 // are returned. The returned transactions will be removed from the list. 462 // 463 // Note, all transactions with nonces lower than start will also be returned to 464 // prevent getting into and invalid state. This is not something that should ever 465 // happen but better to be self correcting than failing! 466 func (l *txList) ReadyWithGasPrice(start uint64, baseFee *big.Int) types.Transactions { 467 return l.txs.ReadyWithGasPrice(start, baseFee) 468 } 469 470 // Len returns the length of the transaction list. 471 func (l *txList) Len() int { 472 return l.txs.Len() 473 } 474 475 // Empty returns whether the list of transactions is empty or not. 476 func (l *txList) Empty() bool { 477 return l.Len() == 0 478 } 479 480 // Flatten creates a nonce-sorted slice of transactions based on the loosely 481 // sorted internal representation. The result of the sorting is cached in case 482 // it's requested again before any modifications are made to the contents. 483 func (l *txList) Flatten() types.Transactions { 484 return l.txs.Flatten() 485 } 486 487 func (l *txList) FlattenByCount(count int64) types.Transactions { 488 return l.txs.FlattenByCount(count) 489 } 490 491 func (l *txList) CachedTxsFlattenByCount(count int) types.Transactions { 492 return l.txs.CachedTxsFlattenByCount(count) 493 } 494 495 // priceHeap is a heap.Interface implementation over transactions for retrieving 496 // price-sorted transactions to discard when the pool fills up. 497 type priceHeap []*types.Transaction 498 499 func (h priceHeap) Len() int { return len(h) } 500 func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 501 502 func (h priceHeap) Less(i, j int) bool { 503 // Sort primarily by price, returning the cheaper one 504 switch h[i].GasPrice().Cmp(h[j].GasPrice()) { 505 case -1: 506 return true 507 case 1: 508 return false 509 } 510 // If the prices match, stabilize via nonces (high nonce is worse) 511 return h[i].Nonce() > h[j].Nonce() 512 } 513 514 func (h *priceHeap) Push(x interface{}) { 515 *h = append(*h, x.(*types.Transaction)) 516 } 517 518 func (h *priceHeap) Pop() interface{} { 519 old := *h 520 n := len(old) 521 x := old[n-1] 522 *h = old[0 : n-1] 523 return x 524 } 525 526 // txPricedList is a price-sorted heap to allow operating on transactions pool 527 // contents in a price-incrementing way. 528 type txPricedList struct { 529 all *txLookup // Pointer to the map of all transactions 530 items *priceHeap // Heap of prices of all the stored transactions 531 stales int // Number of stale price points to (re-heap trigger) 532 } 533 534 // newTxPricedList creates a new price-sorted transaction heap. 535 func newTxPricedList(all *txLookup) *txPricedList { 536 return &txPricedList{ 537 all: all, 538 items: new(priceHeap), 539 } 540 } 541 542 // Put inserts a new transaction into the heap. 543 func (l *txPricedList) Put(tx *types.Transaction) { 544 heap.Push(l.items, tx) 545 } 546 547 // Removed notifies the prices transaction list that an old transaction dropped 548 // from the pool. The list will just keep a counter of stale objects and update 549 // the heap if a large enough ratio of transactions go stale. 550 func (l *txPricedList) Removed() { 551 // Bump the stale counter, but exit if still too low (< 25%) 552 l.stales++ 553 if l.stales <= len(*l.items)/4 { 554 return 555 } 556 // Seems we've reached a critical number of stale transactions, reheap 557 reheap := make(priceHeap, 0, l.all.Count()) 558 559 l.stales, l.items = 0, &reheap 560 l.all.Range(func(hash common.Hash, tx *types.Transaction) bool { 561 *l.items = append(*l.items, tx) 562 return true 563 }) 564 heap.Init(l.items) 565 } 566 567 // Cap finds all the transactions below the given price threshold, drops them 568 // from the priced list and returs them for further removal from the entire pool. 569 func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transactions { 570 drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop 571 save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep 572 573 for len(*l.items) > 0 { 574 // Discard stale transactions if found during cleanup 575 tx := heap.Pop(l.items).(*types.Transaction) 576 if l.all.Get(tx.Hash()) == nil { 577 l.stales-- 578 continue 579 } 580 // Stop the discards if we've reached the threshold 581 if tx.GasPrice().Cmp(threshold) >= 0 { 582 save = append(save, tx) 583 break 584 } 585 // Non stale transaction found, discard unless local 586 if local.containsTx(tx) { 587 save = append(save, tx) 588 } else { 589 drop = append(drop, tx) 590 } 591 } 592 for _, tx := range save { 593 heap.Push(l.items, tx) 594 } 595 return drop 596 } 597 598 // Underpriced checks whether a transaction is cheaper than (or as cheap as) the 599 // lowest priced transaction currently being tracked. 600 func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) bool { 601 // Local transactions cannot be underpriced 602 if local.containsTx(tx) { 603 return false 604 } 605 // Discard stale price points if found at the heap start 606 for len(*l.items) > 0 { 607 head := []*types.Transaction(*l.items)[0] 608 if l.all.Get(head.Hash()) == nil { 609 l.stales-- 610 heap.Pop(l.items) 611 continue 612 } 613 break 614 } 615 // Check if the transaction is underpriced or not 616 if len(*l.items) == 0 { 617 logger.Error("Pricing query for empty pool") // This cannot happen, print to catch programming errors 618 return false 619 } 620 cheapest := []*types.Transaction(*l.items)[0] 621 return cheapest.GasPrice().Cmp(tx.GasPrice()) >= 0 622 } 623 624 // Discard finds a number of most underpriced transactions, removes them from the 625 // priced list and returns them for further removal from the entire pool. 626 func (l *txPricedList) Discard(slots int, local *accountSet) types.Transactions { 627 drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop 628 save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep 629 630 for len(*l.items) > 0 && slots > 0 { 631 // Discard stale transactions if found during cleanup 632 tx := heap.Pop(l.items).(*types.Transaction) 633 if l.all.Get(tx.Hash()) == nil { 634 l.stales-- 635 continue 636 } 637 // Non stale transaction found, discard unless local 638 if local.containsTx(tx) { 639 save = append(save, tx) 640 } else { 641 drop = append(drop, tx) 642 slots -= numSlots(tx) 643 } 644 } 645 for _, tx := range save { 646 heap.Push(l.items, tx) 647 } 648 return drop 649 }