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