github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/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/ethereum/go-ethereum/core/types" 26 ) 27 28 // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for 29 // retrieving sorted transactions from the possibly gapped future queue. 30 type nonceHeap []uint64 31 32 func (h nonceHeap) Len() int { return len(h) } 33 func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] } 34 func (h nonceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 35 36 func (h *nonceHeap) Push(x interface{}) { 37 *h = append(*h, x.(uint64)) 38 } 39 40 func (h *nonceHeap) Pop() interface{} { 41 old := *h 42 n := len(old) 43 x := old[n-1] 44 *h = old[0 : n-1] 45 return x 46 } 47 48 // txSortedMap is a nonce->transaction hash map with a heap based index to allow 49 // iterating over the contents in a nonce-incrementing way. 50 type txSortedMap struct { 51 items map[uint64]*types.Transaction // Hash map storing the transaction data 52 index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) 53 cache types.Transactions // Cache of the transactions already sorted 54 } 55 56 // newTxSortedMap creates a new sorted transaction map. 57 func newTxSortedMap() *txSortedMap { 58 return &txSortedMap{ 59 items: make(map[uint64]*types.Transaction), 60 index: &nonceHeap{}, 61 } 62 } 63 64 // Get retrieves the current transactions associated with the given nonce. 65 func (m *txSortedMap) Get(nonce uint64) *types.Transaction { 66 return m.items[nonce] 67 } 68 69 // Put inserts a new transaction into the map, also updating the map's nonce 70 // index. If a transaction already exists with the same nonce, it's overwritten. 71 func (m *txSortedMap) Put(tx *types.Transaction) { 72 nonce := tx.Nonce() 73 if m.items[nonce] == nil { 74 heap.Push(m.index, nonce) 75 } 76 m.items[nonce], m.cache = tx, nil 77 } 78 79 // Forward removes all transactions from the map with a nonce lower than the 80 // provided threshold. Every removed transaction is returned for any post-removal 81 // maintenance. 82 func (m *txSortedMap) Forward(threshold uint64) types.Transactions { 83 var removed types.Transactions 84 85 // Pop off heap items until the threshold is reached 86 for m.index.Len() > 0 && (*m.index)[0] < threshold { 87 nonce := heap.Pop(m.index).(uint64) 88 removed = append(removed, m.items[nonce]) 89 delete(m.items, nonce) 90 } 91 // If we had a cached order, shift the front 92 if m.cache != nil { 93 m.cache = m.cache[len(removed):] 94 } 95 return removed 96 } 97 98 // Filter iterates over the list of transactions and removes all of them for which 99 // the specified function evaluates to true. 100 func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { 101 var removed types.Transactions 102 103 // Collect all the transactions to filter out 104 for nonce, tx := range m.items { 105 if filter(tx) { 106 removed = append(removed, tx) 107 delete(m.items, nonce) 108 } 109 } 110 // If transactions were removed, the heap and cache are ruined 111 if len(removed) > 0 { 112 *m.index = make([]uint64, 0, len(m.items)) 113 for nonce := range m.items { 114 *m.index = append(*m.index, nonce) 115 } 116 heap.Init(m.index) 117 118 m.cache = nil 119 } 120 return removed 121 } 122 123 // Cap places a hard limit on the number of items, returning all transactions 124 // exceeding that limit. 125 func (m *txSortedMap) Cap(threshold int) types.Transactions { 126 // Short circuit if the number of items is under the limit 127 if len(m.items) <= threshold { 128 return nil 129 } 130 // Otherwise gather and drop the highest nonce'd transactions 131 var drops types.Transactions 132 133 sort.Sort(*m.index) 134 for size := len(m.items); size > threshold; size-- { 135 drops = append(drops, m.items[(*m.index)[size-1]]) 136 delete(m.items, (*m.index)[size-1]) 137 } 138 *m.index = (*m.index)[:threshold] 139 heap.Init(m.index) 140 141 // If we had a cache, shift the back 142 if m.cache != nil { 143 m.cache = m.cache[:len(m.cache)-len(drops)] 144 } 145 return drops 146 } 147 148 // Remove deletes a transaction from the maintained map, returning whether the 149 // transaction was found. 150 func (m *txSortedMap) Remove(nonce uint64) bool { 151 // Short circuit if no transaction is present 152 _, ok := m.items[nonce] 153 if !ok { 154 return false 155 } 156 // Otherwise delete the transaction and fix the heap index 157 for i := 0; i < m.index.Len(); i++ { 158 if (*m.index)[i] == nonce { 159 heap.Remove(m.index, i) 160 break 161 } 162 } 163 delete(m.items, nonce) 164 m.cache = nil 165 166 return true 167 } 168 169 // Ready retrieves a sequentially increasing list of transactions starting at the 170 // provided nonce that is ready for processing. The returned transactions will be 171 // removed from the list. 172 // 173 // Note, all transactions with nonces lower than start will also be returned to 174 // prevent getting into and invalid state. This is not something that should ever 175 // happen but better to be self correcting than failing! 176 func (m *txSortedMap) Ready(start uint64) types.Transactions { 177 // Short circuit if no transactions are available 178 if m.index.Len() == 0 || (*m.index)[0] > start { 179 return nil 180 } 181 // Otherwise start accumulating incremental transactions 182 var ready types.Transactions 183 for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ { 184 ready = append(ready, m.items[next]) 185 delete(m.items, next) 186 heap.Pop(m.index) 187 } 188 m.cache = nil 189 190 return ready 191 } 192 193 // Len returns the length of the transaction map. 194 func (m *txSortedMap) Len() int { 195 return len(m.items) 196 } 197 198 // Flatten creates a nonce-sorted slice of transactions based on the loosely 199 // sorted internal representation. The result of the sorting is cached in case 200 // it's requested again before any modifications are made to the contents. 201 func (m *txSortedMap) Flatten() types.Transactions { 202 // If the sorting was not cached yet, create and cache it 203 if m.cache == nil { 204 m.cache = make(types.Transactions, 0, len(m.items)) 205 for _, tx := range m.items { 206 m.cache = append(m.cache, tx) 207 } 208 sort.Sort(types.TxByNonce(m.cache)) 209 } 210 // Copy the cache to prevent accidental modifications 211 txs := make(types.Transactions, len(m.cache)) 212 copy(txs, m.cache) 213 return txs 214 } 215 216 // txList is a "list" of transactions belonging to an account, sorted by account 217 // nonce. The same type can be used both for storing contiguous transactions for 218 // the executable/pending queue; and for storing gapped transactions for the non- 219 // executable/future queue, with minor behavioral changes. 220 type txList struct { 221 strict bool // Whether nonces are strictly continuous or not 222 txs *txSortedMap // Heap indexed sorted hash map of the transactions 223 costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) 224 } 225 226 // newTxList create a new transaction list for maintaining nonce-indexable fast, 227 // gapped, sortable transaction lists. 228 func newTxList(strict bool) *txList { 229 return &txList{ 230 strict: strict, 231 txs: newTxSortedMap(), 232 costcap: new(big.Int), 233 } 234 } 235 236 // Add tries to insert a new transaction into the list, returning whether the 237 // transaction was accepted, and if yes, any previous transaction it replaced. 238 // 239 // If the new transaction is accepted into the list, the lists' cost threshold 240 // is also potentially updated. 241 func (l *txList) Add(tx *types.Transaction) (bool, *types.Transaction) { 242 // If there's an older better transaction, abort 243 old := l.txs.Get(tx.Nonce()) 244 if old != nil && old.GasPrice().Cmp(tx.GasPrice()) >= 0 { 245 return false, nil 246 } 247 // Otherwise overwrite the old transaction with the current one 248 l.txs.Put(tx) 249 if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { 250 l.costcap = cost 251 } 252 return true, old 253 } 254 255 // Forward removes all transactions from the list with a nonce lower than the 256 // provided threshold. Every removed transaction is returned for any post-removal 257 // maintenance. 258 func (l *txList) Forward(threshold uint64) types.Transactions { 259 return l.txs.Forward(threshold) 260 } 261 262 // Filter removes all transactions from the list with a cost higher than the 263 // provided threshold. Every removed transaction is returned for any post-removal 264 // maintenance. Strict-mode invalidated transactions are also returned. 265 // 266 // This method uses the cached costcap to quickly decide if there's even a point 267 // in calculating all the costs or if the balance covers all. If the threshold is 268 // lower than the costcap, the costcap will be reset to a new high after removing 269 // expensive the too transactions. 270 func (l *txList) Filter(threshold *big.Int) (types.Transactions, types.Transactions) { 271 // If all transactions are below the threshold, short circuit 272 if l.costcap.Cmp(threshold) <= 0 { 273 return nil, nil 274 } 275 l.costcap = new(big.Int).Set(threshold) // Lower the cap to the threshold 276 277 // Filter out all the transactions above the account's funds 278 removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(threshold) > 0 }) 279 280 // If the list was strict, filter anything above the lowest nonce 281 var invalids types.Transactions 282 if l.strict && len(removed) > 0 { 283 lowest := uint64(math.MaxUint64) 284 for _, tx := range removed { 285 if nonce := tx.Nonce(); lowest > nonce { 286 lowest = nonce 287 } 288 } 289 invalids = l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest }) 290 } 291 return removed, invalids 292 } 293 294 // Cap places a hard limit on the number of items, returning all transactions 295 // exceeding that limit. 296 func (l *txList) Cap(threshold int) types.Transactions { 297 return l.txs.Cap(threshold) 298 } 299 300 // Remove deletes a transaction from the maintained list, returning whether the 301 // transaction was found, and also returning any transaction invalidated due to 302 // the deletion (strict mode only). 303 func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) { 304 // Remove the transaction from the set 305 nonce := tx.Nonce() 306 if removed := l.txs.Remove(nonce); !removed { 307 return false, nil 308 } 309 // In strict mode, filter out non-executable transactions 310 if l.strict { 311 return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) 312 } 313 return true, nil 314 } 315 316 // Ready retrieves a sequentially increasing list of transactions starting at the 317 // provided nonce that is ready for processing. The returned transactions will be 318 // removed from the list. 319 // 320 // Note, all transactions with nonces lower than start will also be returned to 321 // prevent getting into and invalid state. This is not something that should ever 322 // happen but better to be self correcting than failing! 323 func (l *txList) Ready(start uint64) types.Transactions { 324 return l.txs.Ready(start) 325 } 326 327 // Len returns the length of the transaction list. 328 func (l *txList) Len() int { 329 return l.txs.Len() 330 } 331 332 // Empty returns whether the list of transactions is empty or not. 333 func (l *txList) Empty() bool { 334 return l.Len() == 0 335 } 336 337 // Flatten creates a nonce-sorted slice of transactions based on the loosely 338 // sorted internal representation. The result of the sorting is cached in case 339 // it's requested again before any modifications are made to the contents. 340 func (l *txList) Flatten() types.Transactions { 341 return l.txs.Flatten() 342 }