github.com/gochain-io/gochain@v2.2.26+incompatible/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/big" 22 "sort" 23 24 "github.com/gochain-io/gochain/core/types" 25 ) 26 27 // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for 28 // retrieving sorted transactions from the possibly gapped future queue. 29 type nonceHeap []uint64 30 31 func (h nonceHeap) Len() int { return len(h) } 32 func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] } 33 func (h nonceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 34 35 func (h *nonceHeap) Push(x interface{}) { 36 *h = append(*h, x.(uint64)) 37 } 38 39 func (h *nonceHeap) Pop() interface{} { 40 old := *h 41 n := len(old) 42 x := old[n-1] 43 *h = old[0 : n-1] 44 return x 45 } 46 47 // txSortedMap is a nonce->transaction hash map with a heap based index to allow 48 // iterating over the contents in a nonce-incrementing way. 49 type txSortedMap struct { 50 items map[uint64]*types.Transaction // Hash map storing the transaction data 51 index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) 52 cache types.Transactions // Cache of the transactions already sorted 53 } 54 55 // newTxSortedMap creates a new nonce-sorted transaction map. 56 func newTxSortedMap() *txSortedMap { 57 return &txSortedMap{ 58 items: make(map[uint64]*types.Transaction), 59 index: &nonceHeap{}, 60 } 61 } 62 63 // Get retrieves the current transactions associated with the given nonce. 64 func (m *txSortedMap) Get(nonce uint64) *types.Transaction { 65 return m.items[nonce] 66 } 67 68 // Put inserts a new transaction into the map, also updating the map's nonce 69 // index. If a transaction already exists with the same nonce, it's overwritten. 70 func (m *txSortedMap) Put(tx *types.Transaction) { 71 nonce := tx.Nonce() 72 if m.items[nonce] == nil { 73 heap.Push(m.index, nonce) 74 } 75 m.items[nonce], m.cache = tx, nil 76 } 77 78 // Forward removes all transactions from the map with a nonce lower than the 79 // provided threshold. Every removed transaction is passed to fn for any post-removal 80 // maintenance. 81 func (m *txSortedMap) Forward(threshold uint64, fn func(*types.Transaction)) { 82 var removed int 83 // Pop off heap items until the threshold is reached 84 for m.index.Len() > 0 && (*m.index)[0] < threshold { 85 nonce := heap.Pop(m.index).(uint64) 86 item := m.items[nonce] 87 delete(m.items, nonce) 88 fn(item) 89 removed++ 90 } 91 // If we had a cached order, shift the front 92 if m.cache != nil { 93 m.cache = m.cache[removed:] 94 } 95 } 96 97 // Filter iterates over the list of transactions calling filter, removing and calling removed for each match. If strict 98 // is true, then all txs with nonces higher than the first match are removed and passed to invalid. 99 func (m *txSortedMap) Filter(filter func(*types.Transaction) bool, strict bool, removed, invalid func(*types.Transaction)) { 100 if strict { 101 // Iterate in order so we can slice off the higher nonces. 102 m.ensureCache() 103 for i, tx := range m.cache { 104 if !filter(tx) { 105 continue 106 } 107 delete(m.items, tx.Nonce()) 108 removed(tx) 109 110 if len(m.cache) > i+1 { 111 for _, tx := range m.cache[i+1:] { 112 delete(m.items, tx.Nonce()) 113 invalid(tx) 114 } 115 } 116 117 m.cache = m.cache[:i] 118 119 // Rebuild heap. 120 *m.index = make([]uint64, 0, len(m.items)) 121 for nonce := range m.items { 122 *m.index = append(*m.index, nonce) 123 } 124 heap.Init(m.index) 125 126 return 127 } 128 return 129 } 130 131 var matched bool 132 for nonce, tx := range m.items { 133 if !filter(tx) { 134 continue 135 } 136 matched = true 137 delete(m.items, nonce) 138 removed(tx) 139 } 140 141 // If transactions were removed, the heap and cache are ruined 142 if matched { 143 *m.index = make([]uint64, 0, len(m.items)) 144 for nonce := range m.items { 145 *m.index = append(*m.index, nonce) 146 } 147 heap.Init(m.index) 148 149 m.cache = nil 150 } 151 } 152 153 // Cap places a hard limit on the number of items, removing and calling removed with each transaction 154 // exceeding that limit. 155 func (m *txSortedMap) Cap(threshold int, removed func(*types.Transaction)) { 156 // Short circuit if the number of items is under the limit. 157 if len(m.items) <= threshold { 158 return 159 } 160 161 // Resort the heap to drop the highest nonce'd transactions. 162 var drops int 163 sort.Sort(*m.index) 164 for size := len(m.items); size > threshold; size-- { 165 item := m.items[(*m.index)[size-1]] 166 delete(m.items, (*m.index)[size-1]) 167 removed(item) 168 drops++ 169 } 170 *m.index = (*m.index)[:threshold] 171 // Restore the heap. 172 heap.Init(m.index) 173 174 // If we had a cache, shift the back 175 if m.cache != nil { 176 m.cache = m.cache[:len(m.cache)-drops] 177 } 178 } 179 180 // Remove deletes a transaction from the maintained map, returning whether the transaction was found. If strict is true 181 // then it will also remove invalidated txs (higher than nonce) and call invalid for each one. 182 func (m *txSortedMap) Remove(nonce uint64, strict bool, invalid func(*types.Transaction)) bool { 183 // Short circuit if no transaction is present 184 _, ok := m.items[nonce] 185 if !ok { 186 return false 187 } 188 m.ensureCache() 189 delete(m.items, nonce) 190 i := sort.Search(len(m.cache), func(i int) bool { 191 return m.cache[i].Nonce() >= nonce 192 }) 193 194 if !strict { 195 // Repair the cache and heap. 196 copy(m.cache[i:], m.cache[i+1:]) 197 m.cache = m.cache[:len(m.cache)-1] 198 for i := 0; i < m.index.Len(); i++ { 199 if (*m.index)[i] == nonce { 200 heap.Remove(m.index, i) 201 break 202 } 203 } 204 return true 205 } 206 207 // Remove invalidated. 208 for _, tx := range m.cache[i+1:] { 209 delete(m.items, tx.Nonce()) 210 invalid(tx) 211 } 212 213 // Repair the cache and heap. 214 m.cache = m.cache[:i] 215 *m.index = make([]uint64, 0, len(m.items)) 216 for nonce := range m.items { 217 *m.index = append(*m.index, nonce) 218 } 219 heap.Init(m.index) 220 221 return true 222 } 223 224 // Ready iterates over a sequentially increasing list of transactions that are ready for processing, removing 225 // and calling fn for each one. 226 // 227 // Note, all transactions with nonces lower than start will also be included to 228 // prevent getting into and invalid state. This is not something that should ever 229 // happen but better to be self correcting than failing! 230 func (m *txSortedMap) Ready(start uint64, fn func(*types.Transaction)) { 231 // Short circuit if no transactions are available 232 if m.index.Len() == 0 || (*m.index)[0] > start { 233 return 234 } 235 if m.cache == nil { 236 for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ { 237 heap.Pop(m.index) 238 item := m.items[next] 239 delete(m.items, next) 240 fn(item) 241 } 242 return 243 } 244 next := m.cache[0].Nonce() 245 for i, item := range m.cache { 246 nonce := item.Nonce() 247 if nonce != next { 248 // Update cache. 249 m.cache = m.cache[i:] 250 break 251 } 252 delete(m.items, nonce) 253 fn(item) 254 next++ 255 } 256 // Rebuild heap. 257 *m.index = make([]uint64, 0, len(m.items)) 258 for nonce := range m.items { 259 *m.index = append(*m.index, nonce) 260 } 261 heap.Init(m.index) 262 } 263 264 // Len returns the length of the transaction map. 265 func (m *txSortedMap) Len() int { 266 return len(m.items) 267 } 268 269 // Flatten creates a nonce-sorted slice of transactions based on the loosely 270 // sorted internal representation. The result of the sorting is cached in case 271 // it's requested again before any modifications are made to the contents. 272 func (m *txSortedMap) Flatten() types.Transactions { 273 m.ensureCache() 274 // Copy the cache to prevent accidental modifications 275 txs := make(types.Transactions, len(m.cache)) 276 copy(txs, m.cache) 277 return txs 278 } 279 280 // ForLast calls fn with each of the last n txs in nonce order. The result of the sorting is cached in case 281 // it's requested again before any modifications are made to the contents. 282 func (m *txSortedMap) ForLast(n int, fn func(*types.Transaction)) { 283 m.ensureCache() 284 i := len(m.cache) - n 285 if i < 0 { 286 i = 0 287 } 288 for _, tx := range m.cache[i:] { 289 delete(m.items, tx.Nonce()) 290 fn(tx) 291 } 292 m.cache = m.cache[:i] 293 294 // Rebuild heap. 295 *m.index = make([]uint64, 0, len(m.items)) 296 for nonce := range m.items { 297 *m.index = append(*m.index, nonce) 298 } 299 heap.Init(m.index) 300 } 301 302 // Last returns the highest nonce tx. The result of the sorting is cached in case 303 // it's requested again before any modifications are made to the contents. 304 func (m *txSortedMap) Last() *types.Transaction { 305 m.ensureCache() 306 return m.cache[len(m.cache)-1] 307 } 308 309 func (m *txSortedMap) ensureCache() { 310 // If the sorting was not cached yet, create and cache it 311 if m.cache == nil { 312 m.cache = make(types.Transactions, 0, len(m.items)) 313 for _, tx := range m.items { 314 m.cache = append(m.cache, tx) 315 } 316 sort.Sort(types.TxByNonce(m.cache)) 317 } 318 } 319 320 // txList is a "list" of transactions belonging to an account, sorted by account 321 // nonce. The same type can be used both for storing contiguous transactions for 322 // the executable/pending queue; and for storing gapped transactions for the non- 323 // executable/future queue, with minor behavioral changes. 324 type txList struct { 325 strict bool // Whether nonces are strictly continuous or not 326 txs *txSortedMap // Heap indexed sorted hash map of the transactions 327 328 costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) 329 gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) 330 } 331 332 // newTxList create a new transaction list for maintaining nonce-indexable fast, 333 // gapped, sortable transaction lists. 334 func newTxList(strict bool) *txList { 335 return &txList{ 336 strict: strict, 337 txs: newTxSortedMap(), 338 costcap: new(big.Int), 339 } 340 } 341 342 // Overlaps returns whether the transaction specified has the same nonce as one 343 // already contained within the list. 344 func (l *txList) Overlaps(tx *types.Transaction) bool { 345 return l.txs.Get(tx.Nonce()) != nil 346 } 347 348 // Add tries to insert a new transaction into the list, returning whether the 349 // transaction was accepted, and if yes, any previous transaction it replaced. 350 // 351 // If the new transaction is accepted into the list, the lists' cost and gas 352 // thresholds are also potentially updated. 353 func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) { 354 // If there's an older better transaction, abort 355 old := l.txs.Get(tx.Nonce()) 356 if old != nil { 357 threshold := new(big.Int).Div(new(big.Int).Mul(old.GasPrice(), big.NewInt(100+int64(priceBump))), big.NewInt(100)) 358 // Have to ensure that the new gas price is higher than the old gas 359 // price as well as checking the percentage threshold to ensure that 360 // this is accurate for low (Wei-level) gas price replacements 361 if old.CmpGasPriceTx(tx) >= 0 || tx.CmpGasPrice(threshold) < 0 { 362 return false, nil 363 } 364 } 365 // Otherwise overwrite the old transaction with the current one 366 l.add(tx) 367 return true, old 368 } 369 370 func (l *txList) add(tx *types.Transaction) { 371 l.txs.Put(tx) 372 if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { 373 l.costcap = cost 374 } 375 if gas := tx.Gas(); l.gascap < gas { 376 l.gascap = gas 377 } 378 } 379 380 // Forward removes all transactions from the list with a nonce lower than the 381 // provided threshold. Every removed transaction is passed to fn for any post-removal 382 // maintenance. 383 func (l *txList) Forward(threshold uint64, fn func(*types.Transaction)) { 384 l.txs.Forward(threshold, fn) 385 } 386 387 // Filter removes all transactions from the list with a cost or gas limit higher 388 // than the provided thresholds. Every removed transaction is returned for any 389 // post-removal maintenance. Strict-mode invalidated transactions are also 390 // returned. 391 // 392 // This method uses the cached costcap and gascap to quickly decide if there's even 393 // a point in calculating all the costs or if the balance covers all. If the threshold 394 // is lower than the costgas cap, the caps will be reset to a new high after removing 395 // the newly invalidated transactions. 396 func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, removed, invalid func(*types.Transaction)) { 397 // If all transactions are below the threshold, short circuit 398 if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { 399 return 400 } 401 l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds 402 l.gascap = gasLimit 403 404 filter := func(tx *types.Transaction) bool { 405 return tx.Cost().Cmp(costLimit) > 0 || tx.Gas() > gasLimit 406 } 407 l.txs.Filter(filter, l.strict, removed, invalid) 408 } 409 410 // Cap places a hard limit on the number of items, removing and calling removed with each transaction 411 // exceeding that limit. 412 func (l *txList) Cap(threshold int, removed func(*types.Transaction)) { 413 l.txs.Cap(threshold, removed) 414 } 415 416 // Remove deletes a transaction from the maintained list, returning whether the 417 // transaction was found, and also calling invalid with each transaction invalidated due to 418 // the deletion (strict mode only). 419 func (l *txList) Remove(tx *types.Transaction, invalid func(*types.Transaction)) bool { 420 return l.txs.Remove(tx.Nonce(), l.strict, invalid) 421 } 422 423 // Ready iterates over a sequentially increasing list of transactions that are ready for processing, removing 424 // and calling fn for each one. 425 // 426 // Note, all transactions with nonces lower than start will also be included to 427 // prevent getting into an invalid state. This is not something that should ever 428 // happen but better to be self correcting than failing! 429 func (l *txList) Ready(start uint64, fn func(*types.Transaction)) { 430 l.txs.Ready(start, fn) 431 } 432 433 // Len returns the length of the transaction list. 434 func (l *txList) Len() int { 435 return l.txs.Len() 436 } 437 438 // Empty returns whether the list of transactions is empty or not. 439 func (l *txList) Empty() bool { 440 return l.Len() == 0 441 } 442 443 // Flatten creates a nonce-sorted slice of transactions based on the loosely 444 // sorted internal representation. The result of the sorting is cached in case 445 // it's requested again before any modifications are made to the contents. 446 func (l *txList) Flatten() types.Transactions { 447 return l.txs.Flatten() 448 } 449 450 // ForLast calls fn with each of the last n txs in nonce order. The result of the sorting is cached in case 451 // it's requested again before any modifications are made to the contents. 452 func (l *txList) ForLast(n int, fn func(*types.Transaction)) { 453 l.txs.ForLast(n, fn) 454 } 455 456 // Last returns the highest nonce tx. The result of the sorting is cached in case 457 // it's requested again before any modifications are made to the contents. 458 func (l *txList) Last() *types.Transaction { 459 return l.txs.Last() 460 }