github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/core/tx_pool.go (about) 1 // Copyright 2014 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 "errors" 21 "fmt" 22 "math/big" 23 "sort" 24 "sync" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/event" 31 "github.com/ethereum/go-ethereum/logger" 32 "github.com/ethereum/go-ethereum/logger/glog" 33 "github.com/ethereum/go-ethereum/metrics" 34 "github.com/ethereum/go-ethereum/params" 35 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 36 ) 37 38 var ( 39 // Transaction Pool Errors 40 ErrInvalidSender = errors.New("Invalid sender") 41 ErrNonce = errors.New("Nonce too low") 42 ErrCheap = errors.New("Gas price too low for acceptance") 43 ErrBalance = errors.New("Insufficient balance") 44 ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value") 45 ErrIntrinsicGas = errors.New("Intrinsic gas too low") 46 ErrGasLimit = errors.New("Exceeds block gas limit") 47 ErrNegativeValue = errors.New("Negative value") 48 ) 49 50 var ( 51 minPendingPerAccount = uint64(16) // Min number of guaranteed transaction slots per address 52 maxPendingTotal = uint64(4096) // Max limit of pending transactions from all accounts (soft) 53 maxQueuedPerAccount = uint64(64) // Max limit of queued transactions per address 54 maxQueuedInTotal = uint64(1024) // Max limit of queued transactions from all accounts 55 maxQueuedLifetime = 3 * time.Hour // Max amount of time transactions from idle accounts are queued 56 evictionInterval = time.Minute // Time interval to check for evictable transactions 57 ) 58 59 var ( 60 // Metrics for the pending pool 61 pendingDiscardCounter = metrics.NewCounter("txpool/pending/discard") 62 pendingReplaceCounter = metrics.NewCounter("txpool/pending/replace") 63 pendingRLCounter = metrics.NewCounter("txpool/pending/ratelimit") // Dropped due to rate limiting 64 pendingNofundsCounter = metrics.NewCounter("txpool/pending/nofunds") // Dropped due to out-of-funds 65 66 // Metrics for the queued pool 67 queuedDiscardCounter = metrics.NewCounter("txpool/queued/discard") 68 queuedReplaceCounter = metrics.NewCounter("txpool/queued/replace") 69 queuedRLCounter = metrics.NewCounter("txpool/queued/ratelimit") // Dropped due to rate limiting 70 queuedNofundsCounter = metrics.NewCounter("txpool/queued/nofunds") // Dropped due to out-of-funds 71 72 // General tx metrics 73 invalidTxCounter = metrics.NewCounter("txpool/invalid") 74 ) 75 76 type stateFn func() (*state.StateDB, error) 77 78 // TxPool contains all currently known transactions. Transactions 79 // enter the pool when they are received from the network or submitted 80 // locally. They exit the pool when they are included in the blockchain. 81 // 82 // The pool separates processable transactions (which can be applied to the 83 // current state) and future transactions. Transactions move between those 84 // two states over time as they are received and processed. 85 type TxPool struct { 86 config *params.ChainConfig 87 currentState stateFn // The state function which will allow us to do some pre checks 88 pendingState *state.ManagedState 89 gasLimit func() *big.Int // The current gas limit function callback 90 minGasPrice *big.Int 91 eventMux *event.TypeMux 92 events event.Subscription 93 localTx *txSet 94 signer types.Signer 95 mu sync.RWMutex 96 97 pending map[common.Address]*txList // All currently processable transactions 98 queue map[common.Address]*txList // Queued but non-processable transactions 99 all map[common.Hash]*types.Transaction // All transactions to allow lookups 100 beats map[common.Address]time.Time // Last heartbeat from each known account 101 102 wg sync.WaitGroup // for shutdown sync 103 quit chan struct{} 104 105 homestead bool 106 } 107 108 func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { 109 pool := &TxPool{ 110 config: config, 111 signer: types.NewEIP155Signer(config.ChainId), 112 pending: make(map[common.Address]*txList), 113 queue: make(map[common.Address]*txList), 114 all: make(map[common.Hash]*types.Transaction), 115 beats: make(map[common.Address]time.Time), 116 eventMux: eventMux, 117 currentState: currentStateFn, 118 gasLimit: gasLimitFn, 119 minGasPrice: new(big.Int), 120 pendingState: nil, 121 localTx: newTxSet(), 122 events: eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}), 123 quit: make(chan struct{}), 124 } 125 126 pool.resetState() 127 128 pool.wg.Add(2) 129 go pool.eventLoop() 130 go pool.expirationLoop() 131 132 return pool 133 } 134 135 func (pool *TxPool) eventLoop() { 136 defer pool.wg.Done() 137 138 // Track chain events. When a chain events occurs (new chain canon block) 139 // we need to know the new state. The new state will help us determine 140 // the nonces in the managed state 141 for ev := range pool.events.Chan() { 142 switch ev := ev.Data.(type) { 143 case ChainHeadEvent: 144 pool.mu.Lock() 145 if ev.Block != nil { 146 if pool.config.IsHomestead(ev.Block.Number()) { 147 pool.homestead = true 148 } 149 } 150 151 pool.resetState() 152 pool.mu.Unlock() 153 case GasPriceChanged: 154 pool.mu.Lock() 155 pool.minGasPrice = ev.Price 156 pool.mu.Unlock() 157 case RemovedTransactionEvent: 158 pool.AddBatch(ev.Txs) 159 } 160 } 161 } 162 163 func (pool *TxPool) resetState() { 164 currentState, err := pool.currentState() 165 if err != nil { 166 glog.V(logger.Error).Infof("Failed to get current state: %v", err) 167 return 168 } 169 managedState := state.ManageState(currentState) 170 if err != nil { 171 glog.V(logger.Error).Infof("Failed to get managed state: %v", err) 172 return 173 } 174 pool.pendingState = managedState 175 176 // validate the pool of pending transactions, this will remove 177 // any transactions that have been included in the block or 178 // have been invalidated because of another transaction (e.g. 179 // higher gas price) 180 pool.demoteUnexecutables(currentState) 181 182 // Update all accounts to the latest known pending nonce 183 for addr, list := range pool.pending { 184 txs := list.Flatten() // Heavy but will be cached and is needed by the miner anyway 185 pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1) 186 } 187 // Check the queue and move transactions over to the pending if possible 188 // or remove those that have become invalid 189 pool.promoteExecutables(currentState) 190 } 191 192 func (pool *TxPool) Stop() { 193 pool.events.Unsubscribe() 194 close(pool.quit) 195 pool.wg.Wait() 196 glog.V(logger.Info).Infoln("Transaction pool stopped") 197 } 198 199 func (pool *TxPool) State() *state.ManagedState { 200 pool.mu.RLock() 201 defer pool.mu.RUnlock() 202 203 return pool.pendingState 204 } 205 206 // Stats retrieves the current pool stats, namely the number of pending and the 207 // number of queued (non-executable) transactions. 208 func (pool *TxPool) Stats() (pending int, queued int) { 209 pool.mu.RLock() 210 defer pool.mu.RUnlock() 211 212 for _, list := range pool.pending { 213 pending += list.Len() 214 } 215 for _, list := range pool.queue { 216 queued += list.Len() 217 } 218 return 219 } 220 221 // Content retrieves the data content of the transaction pool, returning all the 222 // pending as well as queued transactions, grouped by account and sorted by nonce. 223 func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { 224 pool.mu.RLock() 225 defer pool.mu.RUnlock() 226 227 pending := make(map[common.Address]types.Transactions) 228 for addr, list := range pool.pending { 229 pending[addr] = list.Flatten() 230 } 231 queued := make(map[common.Address]types.Transactions) 232 for addr, list := range pool.queue { 233 queued[addr] = list.Flatten() 234 } 235 return pending, queued 236 } 237 238 // Pending retrieves all currently processable transactions, groupped by origin 239 // account and sorted by nonce. The returned transaction set is a copy and can be 240 // freely modified by calling code. 241 func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { 242 pool.mu.Lock() 243 defer pool.mu.Unlock() 244 245 state, err := pool.currentState() 246 if err != nil { 247 return nil, err 248 } 249 250 // check queue first 251 pool.promoteExecutables(state) 252 253 // invalidate any txs 254 pool.demoteUnexecutables(state) 255 256 pending := make(map[common.Address]types.Transactions) 257 for addr, list := range pool.pending { 258 pending[addr] = list.Flatten() 259 } 260 return pending, nil 261 } 262 263 // SetLocal marks a transaction as local, skipping gas price 264 // check against local miner minimum in the future 265 func (pool *TxPool) SetLocal(tx *types.Transaction) { 266 pool.mu.Lock() 267 defer pool.mu.Unlock() 268 pool.localTx.add(tx.Hash()) 269 } 270 271 // validateTx checks whether a transaction is valid according 272 // to the consensus rules. 273 func (pool *TxPool) validateTx(tx *types.Transaction) error { 274 local := pool.localTx.contains(tx.Hash()) 275 // Drop transactions under our own minimal accepted gas price 276 if !local && pool.minGasPrice.Cmp(tx.GasPrice()) > 0 { 277 return ErrCheap 278 } 279 280 currentState, err := pool.currentState() 281 if err != nil { 282 return err 283 } 284 285 from, err := types.Sender(pool.signer, tx) 286 if err != nil { 287 return ErrInvalidSender 288 } 289 // Last but not least check for nonce errors 290 if currentState.GetNonce(from) > tx.Nonce() { 291 return ErrNonce 292 } 293 294 // Check the transaction doesn't exceed the current 295 // block limit gas. 296 if pool.gasLimit().Cmp(tx.Gas()) < 0 { 297 return ErrGasLimit 298 } 299 300 // Transactions can't be negative. This may never happen 301 // using RLP decoded transactions but may occur if you create 302 // a transaction using the RPC for example. 303 if tx.Value().Cmp(common.Big0) < 0 { 304 return ErrNegativeValue 305 } 306 307 // Transactor should have enough funds to cover the costs 308 // cost == V + GP * GL 309 if currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { 310 return ErrInsufficientFunds 311 } 312 313 intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) 314 if tx.Gas().Cmp(intrGas) < 0 { 315 return ErrIntrinsicGas 316 } 317 318 return nil 319 } 320 321 // add validates a transaction and inserts it into the non-executable queue for 322 // later pending promotion and execution. 323 func (pool *TxPool) add(tx *types.Transaction) error { 324 // If the transaction is already known, discard it 325 hash := tx.Hash() 326 if pool.all[hash] != nil { 327 return fmt.Errorf("Known transaction: %x", hash[:4]) 328 } 329 // Otherwise ensure basic validation passes and queue it up 330 if err := pool.validateTx(tx); err != nil { 331 invalidTxCounter.Inc(1) 332 return err 333 } 334 pool.enqueueTx(hash, tx) 335 336 // Print a log message if low enough level is set 337 if glog.V(logger.Debug) { 338 rcpt := "[NEW_CONTRACT]" 339 if to := tx.To(); to != nil { 340 rcpt = common.Bytes2Hex(to[:4]) 341 } 342 from, _ := types.Sender(pool.signer, tx) // from already verified during tx validation 343 glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash) 344 } 345 return nil 346 } 347 348 // enqueueTx inserts a new transaction into the non-executable transaction queue. 349 // 350 // Note, this method assumes the pool lock is held! 351 func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) { 352 // Try to insert the transaction into the future queue 353 from, _ := types.Sender(pool.signer, tx) // already validated 354 if pool.queue[from] == nil { 355 pool.queue[from] = newTxList(false) 356 } 357 inserted, old := pool.queue[from].Add(tx) 358 if !inserted { 359 queuedDiscardCounter.Inc(1) 360 return // An older transaction was better, discard this 361 } 362 // Discard any previous transaction and mark this 363 if old != nil { 364 delete(pool.all, old.Hash()) 365 queuedReplaceCounter.Inc(1) 366 } 367 pool.all[hash] = tx 368 } 369 370 // promoteTx adds a transaction to the pending (processable) list of transactions. 371 // 372 // Note, this method assumes the pool lock is held! 373 func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { 374 // Try to insert the transaction into the pending queue 375 if pool.pending[addr] == nil { 376 pool.pending[addr] = newTxList(true) 377 } 378 list := pool.pending[addr] 379 380 inserted, old := list.Add(tx) 381 if !inserted { 382 // An older transaction was better, discard this 383 delete(pool.all, hash) 384 pendingDiscardCounter.Inc(1) 385 return 386 } 387 // Otherwise discard any previous transaction and mark this 388 if old != nil { 389 delete(pool.all, old.Hash()) 390 pendingReplaceCounter.Inc(1) 391 } 392 pool.all[hash] = tx // Failsafe to work around direct pending inserts (tests) 393 394 // Set the potentially new pending nonce and notify any subsystems of the new tx 395 pool.beats[addr] = time.Now() 396 pool.pendingState.SetNonce(addr, tx.Nonce()+1) 397 go pool.eventMux.Post(TxPreEvent{tx}) 398 } 399 400 // Add queues a single transaction in the pool if it is valid. 401 func (pool *TxPool) Add(tx *types.Transaction) error { 402 pool.mu.Lock() 403 defer pool.mu.Unlock() 404 405 if err := pool.add(tx); err != nil { 406 return err 407 } 408 409 state, err := pool.currentState() 410 if err != nil { 411 return err 412 } 413 414 pool.promoteExecutables(state) 415 416 return nil 417 } 418 419 // AddBatch attempts to queue a batch of transactions. 420 func (pool *TxPool) AddBatch(txs []*types.Transaction) error { 421 pool.mu.Lock() 422 defer pool.mu.Unlock() 423 424 for _, tx := range txs { 425 if err := pool.add(tx); err != nil { 426 glog.V(logger.Debug).Infoln("tx error:", err) 427 } 428 } 429 430 state, err := pool.currentState() 431 if err != nil { 432 return err 433 } 434 435 pool.promoteExecutables(state) 436 437 return nil 438 } 439 440 // Get returns a transaction if it is contained in the pool 441 // and nil otherwise. 442 func (pool *TxPool) Get(hash common.Hash) *types.Transaction { 443 pool.mu.RLock() 444 defer pool.mu.RUnlock() 445 446 return pool.all[hash] 447 } 448 449 // Remove removes the transaction with the given hash from the pool. 450 func (pool *TxPool) Remove(hash common.Hash) { 451 pool.mu.Lock() 452 defer pool.mu.Unlock() 453 454 pool.removeTx(hash) 455 } 456 457 // RemoveBatch removes all given transactions from the pool. 458 func (pool *TxPool) RemoveBatch(txs types.Transactions) { 459 pool.mu.Lock() 460 defer pool.mu.Unlock() 461 462 for _, tx := range txs { 463 pool.removeTx(tx.Hash()) 464 } 465 } 466 467 // removeTx removes a single transaction from the queue, moving all subsequent 468 // transactions back to the future queue. 469 func (pool *TxPool) removeTx(hash common.Hash) { 470 // Fetch the transaction we wish to delete 471 tx, ok := pool.all[hash] 472 if !ok { 473 return 474 } 475 addr, _ := types.Sender(pool.signer, tx) // already validated during insertion 476 477 // Remove it from the list of known transactions 478 delete(pool.all, hash) 479 480 // Remove the transaction from the pending lists and reset the account nonce 481 if pending := pool.pending[addr]; pending != nil { 482 if removed, invalids := pending.Remove(tx); removed { 483 // If no more transactions are left, remove the list 484 if pending.Empty() { 485 delete(pool.pending, addr) 486 delete(pool.beats, addr) 487 } else { 488 // Otherwise postpone any invalidated transactions 489 for _, tx := range invalids { 490 pool.enqueueTx(tx.Hash(), tx) 491 } 492 } 493 // Update the account nonce if needed 494 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 495 pool.pendingState.SetNonce(addr, tx.Nonce()) 496 } 497 } 498 } 499 // Transaction is in the future queue 500 if future := pool.queue[addr]; future != nil { 501 future.Remove(tx) 502 if future.Empty() { 503 delete(pool.queue, addr) 504 } 505 } 506 } 507 508 // promoteExecutables moves transactions that have become processable from the 509 // future queue to the set of pending transactions. During this process, all 510 // invalidated transactions (low nonce, low balance) are deleted. 511 func (pool *TxPool) promoteExecutables(state *state.StateDB) { 512 // Iterate over all accounts and promote any executable transactions 513 queued := uint64(0) 514 for addr, list := range pool.queue { 515 // Drop all transactions that are deemed too old (low nonce) 516 for _, tx := range list.Forward(state.GetNonce(addr)) { 517 if glog.V(logger.Core) { 518 glog.Infof("Removed old queued transaction: %v", tx) 519 } 520 delete(pool.all, tx.Hash()) 521 } 522 // Drop all transactions that are too costly (low balance) 523 drops, _ := list.Filter(state.GetBalance(addr)) 524 for _, tx := range drops { 525 if glog.V(logger.Core) { 526 glog.Infof("Removed unpayable queued transaction: %v", tx) 527 } 528 delete(pool.all, tx.Hash()) 529 queuedNofundsCounter.Inc(1) 530 } 531 // Gather all executable transactions and promote them 532 for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { 533 if glog.V(logger.Core) { 534 glog.Infof("Promoting queued transaction: %v", tx) 535 } 536 pool.promoteTx(addr, tx.Hash(), tx) 537 } 538 // Drop all transactions over the allowed limit 539 for _, tx := range list.Cap(int(maxQueuedPerAccount)) { 540 if glog.V(logger.Core) { 541 glog.Infof("Removed cap-exceeding queued transaction: %v", tx) 542 } 543 delete(pool.all, tx.Hash()) 544 queuedRLCounter.Inc(1) 545 } 546 queued += uint64(list.Len()) 547 548 // Delete the entire queue entry if it became empty. 549 if list.Empty() { 550 delete(pool.queue, addr) 551 } 552 } 553 // If the pending limit is overflown, start equalizing allowances 554 pending := uint64(0) 555 for _, list := range pool.pending { 556 pending += uint64(list.Len()) 557 } 558 if pending > maxPendingTotal { 559 pendingBeforeCap := pending 560 // Assemble a spam order to penalize large transactors first 561 spammers := prque.New() 562 for addr, list := range pool.pending { 563 // Only evict transactions from high rollers 564 if uint64(list.Len()) > minPendingPerAccount { 565 // Skip local accounts as pools should maintain backlogs for themselves 566 for _, tx := range list.txs.items { 567 if !pool.localTx.contains(tx.Hash()) { 568 spammers.Push(addr, float32(list.Len())) 569 } 570 break // Checking on transaction for locality is enough 571 } 572 } 573 } 574 // Gradually drop transactions from offenders 575 offenders := []common.Address{} 576 for pending > maxPendingTotal && !spammers.Empty() { 577 // Retrieve the next offender if not local address 578 offender, _ := spammers.Pop() 579 offenders = append(offenders, offender.(common.Address)) 580 581 // Equalize balances until all the same or below threshold 582 if len(offenders) > 1 { 583 // Calculate the equalization threshold for all current offenders 584 threshold := pool.pending[offender.(common.Address)].Len() 585 586 // Iteratively reduce all offenders until below limit or threshold reached 587 for pending > maxPendingTotal && pool.pending[offenders[len(offenders)-2]].Len() > threshold { 588 for i := 0; i < len(offenders)-1; i++ { 589 list := pool.pending[offenders[i]] 590 list.Cap(list.Len() - 1) 591 pending-- 592 } 593 } 594 } 595 } 596 // If still above threshold, reduce to limit or min allowance 597 if pending > maxPendingTotal && len(offenders) > 0 { 598 for pending > maxPendingTotal && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > minPendingPerAccount { 599 for _, addr := range offenders { 600 list := pool.pending[addr] 601 list.Cap(list.Len() - 1) 602 pending-- 603 } 604 } 605 } 606 pendingRLCounter.Inc(int64(pendingBeforeCap - pending)) 607 } 608 // If we've queued more transactions than the hard limit, drop oldest ones 609 if queued > maxQueuedInTotal { 610 // Sort all accounts with queued transactions by heartbeat 611 addresses := make(addresssByHeartbeat, 0, len(pool.queue)) 612 for addr := range pool.queue { 613 addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) 614 } 615 sort.Sort(addresses) 616 617 // Drop transactions until the total is below the limit 618 for drop := queued - maxQueuedInTotal; drop > 0; { 619 addr := addresses[len(addresses)-1] 620 list := pool.queue[addr.address] 621 622 addresses = addresses[:len(addresses)-1] 623 624 // Drop all transactions if they are less than the overflow 625 if size := uint64(list.Len()); size <= drop { 626 for _, tx := range list.Flatten() { 627 pool.removeTx(tx.Hash()) 628 } 629 drop -= size 630 queuedRLCounter.Inc(int64(size)) 631 continue 632 } 633 // Otherwise drop only last few transactions 634 txs := list.Flatten() 635 for i := len(txs) - 1; i >= 0 && drop > 0; i-- { 636 pool.removeTx(txs[i].Hash()) 637 drop-- 638 queuedRLCounter.Inc(1) 639 } 640 } 641 } 642 } 643 644 // demoteUnexecutables removes invalid and processed transactions from the pools 645 // executable/pending queue and any subsequent transactions that become unexecutable 646 // are moved back into the future queue. 647 func (pool *TxPool) demoteUnexecutables(state *state.StateDB) { 648 // Iterate over all accounts and demote any non-executable transactions 649 for addr, list := range pool.pending { 650 nonce := state.GetNonce(addr) 651 652 // Drop all transactions that are deemed too old (low nonce) 653 for _, tx := range list.Forward(nonce) { 654 if glog.V(logger.Core) { 655 glog.Infof("Removed old pending transaction: %v", tx) 656 } 657 delete(pool.all, tx.Hash()) 658 } 659 // Drop all transactions that are too costly (low balance), and queue any invalids back for later 660 drops, invalids := list.Filter(state.GetBalance(addr)) 661 for _, tx := range drops { 662 if glog.V(logger.Core) { 663 glog.Infof("Removed unpayable pending transaction: %v", tx) 664 } 665 delete(pool.all, tx.Hash()) 666 pendingNofundsCounter.Inc(1) 667 } 668 for _, tx := range invalids { 669 if glog.V(logger.Core) { 670 glog.Infof("Demoting pending transaction: %v", tx) 671 } 672 pool.enqueueTx(tx.Hash(), tx) 673 } 674 // Delete the entire queue entry if it became empty. 675 if list.Empty() { 676 delete(pool.pending, addr) 677 delete(pool.beats, addr) 678 } 679 } 680 } 681 682 // expirationLoop is a loop that periodically iterates over all accounts with 683 // queued transactions and drop all that have been inactive for a prolonged amount 684 // of time. 685 func (pool *TxPool) expirationLoop() { 686 defer pool.wg.Done() 687 688 evict := time.NewTicker(evictionInterval) 689 defer evict.Stop() 690 691 for { 692 select { 693 case <-evict.C: 694 pool.mu.Lock() 695 for addr := range pool.queue { 696 if time.Since(pool.beats[addr]) > maxQueuedLifetime { 697 for _, tx := range pool.queue[addr].Flatten() { 698 pool.removeTx(tx.Hash()) 699 } 700 } 701 } 702 pool.mu.Unlock() 703 704 case <-pool.quit: 705 return 706 } 707 } 708 } 709 710 // addressByHeartbeat is an account address tagged with its last activity timestamp. 711 type addressByHeartbeat struct { 712 address common.Address 713 heartbeat time.Time 714 } 715 716 type addresssByHeartbeat []addressByHeartbeat 717 718 func (a addresssByHeartbeat) Len() int { return len(a) } 719 func (a addresssByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } 720 func (a addresssByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 721 722 // txSet represents a set of transaction hashes in which entries 723 // are automatically dropped after txSetDuration time 724 type txSet struct { 725 txMap map[common.Hash]struct{} 726 txOrd map[uint64]txOrdType 727 addPtr, delPtr uint64 728 } 729 730 const txSetDuration = time.Hour * 2 731 732 // txOrdType represents an entry in the time-ordered list of transaction hashes 733 type txOrdType struct { 734 hash common.Hash 735 time time.Time 736 } 737 738 // newTxSet creates a new transaction set 739 func newTxSet() *txSet { 740 return &txSet{ 741 txMap: make(map[common.Hash]struct{}), 742 txOrd: make(map[uint64]txOrdType), 743 } 744 } 745 746 // contains returns true if the set contains the given transaction hash 747 // (not thread safe, should be called from a locked environment) 748 func (self *txSet) contains(hash common.Hash) bool { 749 _, ok := self.txMap[hash] 750 return ok 751 } 752 753 // add adds a transaction hash to the set, then removes entries older than txSetDuration 754 // (not thread safe, should be called from a locked environment) 755 func (self *txSet) add(hash common.Hash) { 756 self.txMap[hash] = struct{}{} 757 now := time.Now() 758 self.txOrd[self.addPtr] = txOrdType{hash: hash, time: now} 759 self.addPtr++ 760 delBefore := now.Add(-txSetDuration) 761 for self.delPtr < self.addPtr && self.txOrd[self.delPtr].time.Before(delBefore) { 762 delete(self.txMap, self.txOrd[self.delPtr].hash) 763 delete(self.txOrd, self.delPtr) 764 self.delPtr++ 765 } 766 }