| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 10:28:02 +01:00
										 |  |  | package core | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2015-02-19 22:33:22 +01:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-07-30 00:31:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-16 11:27:38 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							| 
									
										
										
										
											2015-03-17 11:59:26 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2014-12-18 13:12:54 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							| 
									
										
										
										
											2014-10-31 12:56:05 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger/glog" | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/metrics" | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 	"gopkg.in/karalabe/cookiejar.v2/collections/prque" | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2015-06-03 15:23:31 +02:00
										 |  |  | 	// Transaction Pool Errors | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	ErrInvalidSender      = errors.New("Invalid sender") | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	ErrNonce              = errors.New("Nonce too low") | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	ErrCheap              = errors.New("Gas price too low for acceptance") | 
					
						
							| 
									
										
										
										
											2015-04-26 11:19:40 +02:00
										 |  |  | 	ErrBalance            = errors.New("Insufficient balance") | 
					
						
							| 
									
										
										
										
											2015-05-11 01:28:15 +02:00
										 |  |  | 	ErrNonExistentAccount = errors.New("Account does not exist or account balance too low") | 
					
						
							| 
									
										
										
										
											2015-04-26 11:19:40 +02:00
										 |  |  | 	ErrInsufficientFunds  = errors.New("Insufficient funds for gas * price + value") | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	ErrIntrinsicGas       = errors.New("Intrinsic gas too low") | 
					
						
							| 
									
										
										
										
											2015-04-24 17:45:51 +02:00
										 |  |  | 	ErrGasLimit           = errors.New("Exceeds block gas limit") | 
					
						
							| 
									
										
										
										
											2015-05-26 19:50:42 +02:00
										 |  |  | 	ErrNegativeValue      = errors.New("Negative value") | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 	minPendingPerAccount = uint64(16)    // Min number of guaranteed transaction slots per address | 
					
						
							|  |  |  | 	maxPendingTotal      = uint64(4096)  // Max limit of pending transactions from all accounts (soft) | 
					
						
							|  |  |  | 	maxQueuedPerAccount  = uint64(64)    // Max limit of queued transactions per address | 
					
						
							|  |  |  | 	maxQueuedInTotal     = uint64(1024)  // Max limit of queued transactions from all accounts | 
					
						
							|  |  |  | 	maxQueuedLifetime    = 3 * time.Hour // Max amount of time transactions from idle accounts are queued | 
					
						
							|  |  |  | 	evictionInterval     = time.Minute   // Time interval to check for evictable transactions | 
					
						
							| 
									
										
										
										
											2015-06-15 12:16:29 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	// Metrics for the pending pool | 
					
						
							|  |  |  | 	pendingDiscardCounter = metrics.NewCounter("txpool/pending/discard") | 
					
						
							|  |  |  | 	pendingReplaceCounter = metrics.NewCounter("txpool/pending/replace") | 
					
						
							|  |  |  | 	pendingRLCounter      = metrics.NewCounter("txpool/pending/ratelimit") // Dropped due to rate limiting | 
					
						
							|  |  |  | 	pendingNofundsCounter = metrics.NewCounter("txpool/pending/nofunds")   // Dropped due to out-of-funds | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Metrics for the queued pool | 
					
						
							|  |  |  | 	queuedDiscardCounter = metrics.NewCounter("txpool/queued/discard") | 
					
						
							|  |  |  | 	queuedReplaceCounter = metrics.NewCounter("txpool/queued/replace") | 
					
						
							|  |  |  | 	queuedRLCounter      = metrics.NewCounter("txpool/queued/ratelimit") // Dropped due to rate limiting | 
					
						
							|  |  |  | 	queuedNofundsCounter = metrics.NewCounter("txpool/queued/nofunds")   // Dropped due to out-of-funds | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// General tx metrics | 
					
						
							|  |  |  | 	invalidTxCounter = metrics.NewCounter("txpool/invalid") | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | type stateFn func() (*state.StateDB, error) | 
					
						
							| 
									
										
										
										
											2015-04-21 11:27:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 15:23:31 +02:00
										 |  |  | // TxPool contains all currently known transactions. Transactions | 
					
						
							|  |  |  | // enter the pool when they are received from the network or submitted | 
					
						
							|  |  |  | // locally. They exit the pool when they are included in the blockchain. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The pool separates processable transactions (which can be applied to the | 
					
						
							|  |  |  | // current state) and future transactions. Transactions move between those | 
					
						
							|  |  |  | // two states over time as they are received and processed. | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | type TxPool struct { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	config       *params.ChainConfig | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 	currentState stateFn // The state function which will allow us to do some pre checks | 
					
						
							| 
									
										
										
										
											2015-06-09 18:14:46 +02:00
										 |  |  | 	pendingState *state.ManagedState | 
					
						
							| 
									
										
										
										
											2015-06-03 14:20:44 +02:00
										 |  |  | 	gasLimit     func() *big.Int // The current gas limit function callback | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	minGasPrice  *big.Int | 
					
						
							| 
									
										
										
										
											2015-06-03 14:20:44 +02:00
										 |  |  | 	eventMux     *event.TypeMux | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	events       event.Subscription | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | 	localTx      *txSet | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	signer       types.Signer | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | 	mu           sync.RWMutex | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pending map[common.Address]*txList         // All currently processable transactions | 
					
						
							|  |  |  | 	queue   map[common.Address]*txList         // Queued but non-processable transactions | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	all     map[common.Hash]*types.Transaction // All transactions to allow lookups | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	beats   map[common.Address]time.Time       // Last heartbeat from each known account | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	wg   sync.WaitGroup // for shutdown sync | 
					
						
							|  |  |  | 	quit chan struct{} | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	homestead bool | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 	pool := &TxPool{ | 
					
						
							| 
									
										
										
										
											2016-03-01 23:32:43 +01:00
										 |  |  | 		config:       config, | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 		signer:       types.NewEIP155Signer(config.ChainId), | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		pending:      make(map[common.Address]*txList), | 
					
						
							|  |  |  | 		queue:        make(map[common.Address]*txList), | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 		all:          make(map[common.Hash]*types.Transaction), | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		beats:        make(map[common.Address]time.Time), | 
					
						
							| 
									
										
										
										
											2015-06-03 14:20:44 +02:00
										 |  |  | 		eventMux:     eventMux, | 
					
						
							|  |  |  | 		currentState: currentStateFn, | 
					
						
							|  |  |  | 		gasLimit:     gasLimitFn, | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 		minGasPrice:  new(big.Int), | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		pendingState: nil, | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | 		localTx:      newTxSet(), | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 		events:       eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}), | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		quit:         make(chan struct{}), | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	pool.wg.Add(2) | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 	go pool.eventLoop() | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	go pool.expirationLoop() | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return pool | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | func (pool *TxPool) eventLoop() { | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 	defer pool.wg.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 16:19:22 +02:00
										 |  |  | 	// Track chain events. When a chain events occurs (new chain canon block) | 
					
						
							|  |  |  | 	// we need to know the new state. The new state will help us determine | 
					
						
							|  |  |  | 	// the nonces in the managed state | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	for ev := range pool.events.Chan() { | 
					
						
							| 
									
										
										
										
											2015-10-12 15:04:38 +03:00
										 |  |  | 		switch ev := ev.Data.(type) { | 
					
						
							| 
									
										
										
										
											2015-06-30 15:42:20 +02:00
										 |  |  | 		case ChainHeadEvent: | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			pool.mu.Lock() | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 			if ev.Block != nil { | 
					
						
							|  |  |  | 				if pool.config.IsHomestead(ev.Block.Number()) { | 
					
						
							|  |  |  | 					pool.homestead = true | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 			pool.resetState() | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 		case GasPriceChanged: | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			pool.mu.Lock() | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 			pool.minGasPrice = ev.Price | 
					
						
							| 
									
										
										
										
											2015-08-17 14:01:41 +02:00
										 |  |  | 			pool.mu.Unlock() | 
					
						
							|  |  |  | 		case RemovedTransactionEvent: | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			pool.AddBatch(ev.Txs) | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 17:28:09 +02:00
										 |  |  | func (pool *TxPool) resetState() { | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	currentState, err := pool.currentState() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		glog.V(logger.Error).Infof("Failed to get current state: %v", err) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	managedState := state.ManageState(currentState) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		glog.V(logger.Error).Infof("Failed to get managed state: %v", err) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pool.pendingState = managedState | 
					
						
							| 
									
										
										
										
											2015-06-04 17:28:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// validate the pool of pending transactions, this will remove | 
					
						
							|  |  |  | 	// any transactions that have been included in the block or | 
					
						
							|  |  |  | 	// have been invalidated because of another transaction (e.g. | 
					
						
							|  |  |  | 	// higher gas price) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.demoteUnexecutables() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Update all accounts to the latest known pending nonce | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							| 
									
										
										
										
											2016-08-25 19:04:40 +03:00
										 |  |  | 		txs := list.Flatten() // Heavy but will be cached and is needed by the miner anyway | 
					
						
							|  |  |  | 		pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1) | 
					
						
							| 
									
										
										
										
											2015-06-04 17:28:09 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Check the queue and move transactions over to the pending if possible | 
					
						
							|  |  |  | 	// or remove those that have become invalid | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.promoteExecutables() | 
					
						
							| 
									
										
										
										
											2015-06-04 17:28:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | func (pool *TxPool) Stop() { | 
					
						
							|  |  |  | 	pool.events.Unsubscribe() | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	close(pool.quit) | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 	pool.wg.Wait() | 
					
						
							| 
									
										
										
										
											2015-08-01 17:34:48 +02:00
										 |  |  | 	glog.V(logger.Info).Infoln("Transaction pool stopped") | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) State() *state.ManagedState { | 
					
						
							|  |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 18:14:46 +02:00
										 |  |  | 	return pool.pendingState | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // Stats retrieves the current pool stats, namely the number of pending and the | 
					
						
							|  |  |  | // number of queued (non-executable) transactions. | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | func (pool *TxPool) Stats() (pending int, queued int) { | 
					
						
							|  |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	for _, list := range pool.pending { | 
					
						
							|  |  |  | 		pending += list.Len() | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	for _, list := range pool.queue { | 
					
						
							|  |  |  | 		queued += list.Len() | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-30 13:32:15 +02:00
										 |  |  | // Content retrieves the data content of the transaction pool, returning all the | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // pending as well as queued transactions, grouped by account and sorted by nonce. | 
					
						
							|  |  |  | func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { | 
					
						
							| 
									
										
										
										
											2015-12-30 13:32:15 +02:00
										 |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pending := make(map[common.Address]types.Transactions) | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							|  |  |  | 		pending[addr] = list.Flatten() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	queued := make(map[common.Address]types.Transactions) | 
					
						
							|  |  |  | 	for addr, list := range pool.queue { | 
					
						
							|  |  |  | 		queued[addr] = list.Flatten() | 
					
						
							| 
									
										
										
										
											2015-12-30 13:32:15 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return pending, queued | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // Pending retrieves all currently processable transactions, groupped by origin | 
					
						
							|  |  |  | // account and sorted by nonce. The returned transaction set is a copy and can be | 
					
						
							|  |  |  | // freely modified by calling code. | 
					
						
							|  |  |  | func (pool *TxPool) Pending() map[common.Address]types.Transactions { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// check queue first | 
					
						
							|  |  |  | 	pool.promoteExecutables() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// invalidate any txs | 
					
						
							|  |  |  | 	pool.demoteUnexecutables() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pending := make(map[common.Address]types.Transactions) | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							|  |  |  | 		pending[addr] = list.Flatten() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return pending | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | // SetLocal marks a transaction as local, skipping gas price | 
					
						
							|  |  |  | //  check against local miner minimum in the future | 
					
						
							|  |  |  | func (pool *TxPool) SetLocal(tx *types.Transaction) { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							|  |  |  | 	pool.localTx.add(tx.Hash()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 15:23:31 +02:00
										 |  |  | // validateTx checks whether a transaction is valid according | 
					
						
							|  |  |  | // to the consensus rules. | 
					
						
							|  |  |  | func (pool *TxPool) validateTx(tx *types.Transaction) error { | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | 	local := pool.localTx.contains(tx.Hash()) | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	// Drop transactions under our own minimal accepted gas price | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | 	if !local && pool.minGasPrice.Cmp(tx.GasPrice()) > 0 { | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 		return ErrCheap | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	currentState, err := pool.currentState() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	from, err := types.Sender(pool.signer, tx) | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-18 13:38:47 +01:00
										 |  |  | 		return ErrInvalidSender | 
					
						
							| 
									
										
										
										
											2014-12-02 00:14:34 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-17 16:22:35 +02:00
										 |  |  | 	// Make sure the account exist. Non existent accounts | 
					
						
							| 
									
										
										
										
											2015-06-04 16:19:22 +02:00
										 |  |  | 	// haven't got funds and well therefor never pass. | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	if !currentState.Exist(from) { | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 		return ErrNonExistentAccount | 
					
						
							| 
									
										
										
										
											2014-06-10 15:02:41 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-17 17:09:39 +02:00
										 |  |  | 	// Last but not least check for nonce errors | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if currentState.GetNonce(from) > tx.Nonce() { | 
					
						
							| 
									
										
										
										
											2015-06-17 17:09:39 +02:00
										 |  |  | 		return ErrNonce | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 16:19:22 +02:00
										 |  |  | 	// Check the transaction doesn't exceed the current | 
					
						
							|  |  |  | 	// block limit gas. | 
					
						
							| 
									
										
										
										
											2015-06-11 14:05:32 +02:00
										 |  |  | 	if pool.gasLimit().Cmp(tx.Gas()) < 0 { | 
					
						
							| 
									
										
										
										
											2015-04-24 17:45:51 +02:00
										 |  |  | 		return ErrGasLimit | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 16:19:22 +02:00
										 |  |  | 	// Transactions can't be negative. This may never happen | 
					
						
							|  |  |  | 	// using RLP decoded transactions but may occur if you create | 
					
						
							|  |  |  | 	// a transaction using the RPC for example. | 
					
						
							| 
									
										
										
										
											2015-06-11 14:05:32 +02:00
										 |  |  | 	if tx.Value().Cmp(common.Big0) < 0 { | 
					
						
							| 
									
										
										
										
											2015-05-26 19:50:42 +02:00
										 |  |  | 		return ErrNegativeValue | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 16:19:22 +02:00
										 |  |  | 	// Transactor should have enough funds to cover the costs | 
					
						
							|  |  |  | 	// cost == V + GP * GL | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 		return ErrInsufficientFunds | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	if tx.Gas().Cmp(intrGas) < 0 { | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 		return ErrIntrinsicGas | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // add validates a transaction and inserts it into the non-executable queue for | 
					
						
							|  |  |  | // later pending promotion and execution. | 
					
						
							|  |  |  | func (pool *TxPool) add(tx *types.Transaction) error { | 
					
						
							|  |  |  | 	// If the transaction is alreayd known, discard it | 
					
						
							| 
									
										
										
										
											2015-03-17 12:16:21 +01:00
										 |  |  | 	hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	if pool.all[hash] != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("Known transaction: %x", hash[:4]) | 
					
						
							| 
									
										
										
										
											2015-01-07 01:21:45 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	// Otherwise ensure basic validation passes and queue it up | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	if err := pool.validateTx(tx); err != nil { | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		invalidTxCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2014-12-01 20:18:09 +01:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.enqueueTx(hash, tx) | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Print a log message if low enough level is set | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	if glog.V(logger.Debug) { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		rcpt := "[NEW_CONTRACT]" | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 		if to := tx.To(); to != nil { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			rcpt = common.Bytes2Hex(to[:4]) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 		from, _ := types.Sender(pool.signer, tx) // from already verified during tx validation | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash) | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-12-01 20:18:09 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | // enqueueTx inserts a new transaction into the non-executable transaction queue. | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // | 
					
						
							|  |  |  | // Note, this method assumes the pool lock is held! | 
					
						
							|  |  |  | func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) { | 
					
						
							|  |  |  | 	// Try to insert the transaction into the future queue | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	from, _ := types.Sender(pool.signer, tx) // already validated | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	if pool.queue[from] == nil { | 
					
						
							|  |  |  | 		pool.queue[from] = newTxList(false) | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	inserted, old := pool.queue[from].Add(tx) | 
					
						
							|  |  |  | 	if !inserted { | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		queuedDiscardCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		return // An older transaction was better, discard this | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Discard any previous transaction and mark this | 
					
						
							|  |  |  | 	if old != nil { | 
					
						
							|  |  |  | 		delete(pool.all, old.Hash()) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		queuedReplaceCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.all[hash] = tx | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // promoteTx adds a transaction to the pending (processable) list of transactions. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note, this method assumes the pool lock is held! | 
					
						
							|  |  |  | func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	// Init delayed since tx pool could have been started before any state sync | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if pool.pendingState == nil { | 
					
						
							|  |  |  | 		pool.resetState() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Try to insert the transaction into the pending queue | 
					
						
							|  |  |  | 	if pool.pending[addr] == nil { | 
					
						
							|  |  |  | 		pool.pending[addr] = newTxList(true) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	list := pool.pending[addr] | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	inserted, old := list.Add(tx) | 
					
						
							|  |  |  | 	if !inserted { | 
					
						
							|  |  |  | 		// An older transaction was better, discard this | 
					
						
							|  |  |  | 		delete(pool.all, hash) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		pendingDiscardCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Otherwise discard any previous transaction and mark this | 
					
						
							|  |  |  | 	if old != nil { | 
					
						
							|  |  |  | 		delete(pool.all, old.Hash()) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		pendingReplaceCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.all[hash] = tx // Failsafe to work around direct pending inserts (tests) | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Set the potentially new pending nonce and notify any subsystems of the new tx | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	pool.beats[addr] = time.Now() | 
					
						
							| 
									
										
										
										
											2016-08-25 19:04:40 +03:00
										 |  |  | 	pool.pendingState.SetNonce(addr, tx.Nonce()+1) | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	go pool.eventMux.Post(TxPreEvent{tx}) | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 15:23:31 +02:00
										 |  |  | // Add queues a single transaction in the pool if it is valid. | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | func (pool *TxPool) Add(tx *types.Transaction) error { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-04-08 00:31:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	if err := pool.add(tx); err != nil { | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.promoteExecutables() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-02-19 22:33:22 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-17 11:59:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // AddBatch attempts to queue a batch of transactions. | 
					
						
							|  |  |  | func (pool *TxPool) AddBatch(txs []*types.Transaction) { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-02-19 22:33:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-14 18:15:48 +00:00
										 |  |  | 	for _, tx := range txs { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		if err := pool.add(tx); err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 11:19:40 +02:00
										 |  |  | 			glog.V(logger.Debug).Infoln("tx error:", err) | 
					
						
							| 
									
										
										
										
											2014-12-14 18:15:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.promoteExecutables() | 
					
						
							| 
									
										
										
										
											2014-12-14 18:15:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // Get returns a transaction if it is contained in the pool | 
					
						
							| 
									
										
										
										
											2015-06-03 15:23:31 +02:00
										 |  |  | // and nil otherwise. | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | func (pool *TxPool) Get(hash common.Hash) *types.Transaction { | 
					
						
							|  |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2015-02-19 22:33:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	return pool.all[hash] | 
					
						
							| 
									
										
										
										
											2015-04-23 10:51:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // Remove removes the transaction with the given hash from the pool. | 
					
						
							|  |  |  | func (pool *TxPool) Remove(hash common.Hash) { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.removeTx(hash) | 
					
						
							| 
									
										
										
										
											2014-10-27 16:52:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // RemoveBatch removes all given transactions from the pool. | 
					
						
							|  |  |  | func (pool *TxPool) RemoveBatch(txs types.Transactions) { | 
					
						
							| 
									
										
										
										
											2016-06-02 20:33:45 +02:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	for _, tx := range txs { | 
					
						
							|  |  |  | 		pool.removeTx(tx.Hash()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-02 20:33:45 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | // removeTx removes a single transaction from the queue, moving all subsequent | 
					
						
							|  |  |  | // transactions back to the future queue. | 
					
						
							| 
									
										
										
										
											2016-06-02 20:33:45 +02:00
										 |  |  | func (pool *TxPool) removeTx(hash common.Hash) { | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	// Fetch the transaction we wish to delete | 
					
						
							|  |  |  | 	tx, ok := pool.all[hash] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	addr, _ := types.Sender(pool.signer, tx) // already validated during insertion | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Remove it from the list of known transactions | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	delete(pool.all, hash) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Remove the transaction from the pending lists and reset the account nonce | 
					
						
							|  |  |  | 	if pending := pool.pending[addr]; pending != nil { | 
					
						
							|  |  |  | 		if removed, invalids := pending.Remove(tx); removed { | 
					
						
							| 
									
										
										
										
											2016-08-25 19:04:40 +03:00
										 |  |  | 			// If no more transactions are left, remove the list | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			if pending.Empty() { | 
					
						
							|  |  |  | 				delete(pool.pending, addr) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 				delete(pool.beats, addr) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2016-08-25 19:04:40 +03:00
										 |  |  | 				// Otherwise postpone any invalidated transactions | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 				for _, tx := range invalids { | 
					
						
							|  |  |  | 					pool.enqueueTx(tx.Hash(), tx) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-08-25 19:04:40 +03:00
										 |  |  | 			// Update the account nonce if needed | 
					
						
							|  |  |  | 			if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { | 
					
						
							|  |  |  | 				pool.pendingState.SetNonce(addr, tx.Nonce()) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Transaction is in the future queue | 
					
						
							|  |  |  | 	if future := pool.queue[addr]; future != nil { | 
					
						
							|  |  |  | 		future.Remove(tx) | 
					
						
							|  |  |  | 		if future.Empty() { | 
					
						
							|  |  |  | 			delete(pool.queue, addr) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // promoteExecutables moves transactions that have become processable from the | 
					
						
							|  |  |  | // future queue to the set of pending transactions. During this process, all | 
					
						
							|  |  |  | // invalidated transactions (low nonce, low balance) are deleted. | 
					
						
							|  |  |  | func (pool *TxPool) promoteExecutables() { | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	// Init delayed since tx pool could have been started before any state sync | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if pool.pendingState == nil { | 
					
						
							|  |  |  | 		pool.resetState() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Retrieve the current state to allow nonce and balance checking | 
					
						
							|  |  |  | 	state, err := pool.currentState() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		glog.Errorf("Could not get current state: %v", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Iterate over all accounts and promote any executable transactions | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	queued := uint64(0) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	for addr, list := range pool.queue { | 
					
						
							|  |  |  | 		// Drop all transactions that are deemed too old (low nonce) | 
					
						
							|  |  |  | 		for _, tx := range list.Forward(state.GetNonce(addr)) { | 
					
						
							|  |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Removed old queued transaction: %v", tx) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			delete(pool.all, tx.Hash()) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// Drop all transactions that are too costly (low balance) | 
					
						
							|  |  |  | 		drops, _ := list.Filter(state.GetBalance(addr)) | 
					
						
							|  |  |  | 		for _, tx := range drops { | 
					
						
							|  |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Removed unpayable queued transaction: %v", tx) | 
					
						
							| 
									
										
										
										
											2015-06-15 16:46:45 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			delete(pool.all, tx.Hash()) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 			queuedNofundsCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// Gather all executable transactions and promote them | 
					
						
							|  |  |  | 		for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { | 
					
						
							|  |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Promoting queued transaction: %v", tx) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			pool.promoteTx(addr, tx.Hash(), tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Drop all transactions over the allowed limit | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		for _, tx := range list.Cap(int(maxQueuedPerAccount)) { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Removed cap-exceeding queued transaction: %v", tx) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			delete(pool.all, tx.Hash()) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 			queuedRLCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		queued += uint64(list.Len()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 		// Delete the entire queue entry if it became empty. | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		if list.Empty() { | 
					
						
							|  |  |  | 			delete(pool.queue, addr) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 	// If the pending limit is overflown, start equalizing allowances | 
					
						
							|  |  |  | 	pending := uint64(0) | 
					
						
							|  |  |  | 	for _, list := range pool.pending { | 
					
						
							|  |  |  | 		pending += uint64(list.Len()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if pending > maxPendingTotal { | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		pendingBeforeCap := pending | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 		// Assemble a spam order to penalize large transactors first | 
					
						
							|  |  |  | 		spammers := prque.New() | 
					
						
							|  |  |  | 		for addr, list := range pool.pending { | 
					
						
							|  |  |  | 			// Only evict transactions from high rollers | 
					
						
							|  |  |  | 			if uint64(list.Len()) > minPendingPerAccount { | 
					
						
							|  |  |  | 				// Skip local accounts as pools should maintain backlogs for themselves | 
					
						
							|  |  |  | 				for _, tx := range list.txs.items { | 
					
						
							|  |  |  | 					if !pool.localTx.contains(tx.Hash()) { | 
					
						
							|  |  |  | 						spammers.Push(addr, float32(list.Len())) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break // Checking on transaction for locality is enough | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Gradually drop transactions from offenders | 
					
						
							|  |  |  | 		offenders := []common.Address{} | 
					
						
							|  |  |  | 		for pending > maxPendingTotal && !spammers.Empty() { | 
					
						
							|  |  |  | 			// Retrieve the next offender if not local address | 
					
						
							|  |  |  | 			offender, _ := spammers.Pop() | 
					
						
							|  |  |  | 			offenders = append(offenders, offender.(common.Address)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Equalize balances until all the same or below threshold | 
					
						
							|  |  |  | 			if len(offenders) > 1 { | 
					
						
							|  |  |  | 				// Calculate the equalization threshold for all current offenders | 
					
						
							|  |  |  | 				threshold := pool.pending[offender.(common.Address)].Len() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Iteratively reduce all offenders until below limit or threshold reached | 
					
						
							|  |  |  | 				for pending > maxPendingTotal && pool.pending[offenders[len(offenders)-2]].Len() > threshold { | 
					
						
							|  |  |  | 					for i := 0; i < len(offenders)-1; i++ { | 
					
						
							|  |  |  | 						list := pool.pending[offenders[i]] | 
					
						
							|  |  |  | 						list.Cap(list.Len() - 1) | 
					
						
							|  |  |  | 						pending-- | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If still above threshold, reduce to limit or min allowance | 
					
						
							|  |  |  | 		if pending > maxPendingTotal && len(offenders) > 0 { | 
					
						
							|  |  |  | 			for pending > maxPendingTotal && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > minPendingPerAccount { | 
					
						
							|  |  |  | 				for _, addr := range offenders { | 
					
						
							|  |  |  | 					list := pool.pending[addr] | 
					
						
							|  |  |  | 					list.Cap(list.Len() - 1) | 
					
						
							|  |  |  | 					pending-- | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		pendingRLCounter.Inc(int64(pendingBeforeCap - pending)) | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 	// If we've queued more transactions than the hard limit, drop oldest ones | 
					
						
							|  |  |  | 	if queued > maxQueuedInTotal { | 
					
						
							|  |  |  | 		// Sort all accounts with queued transactions by heartbeat | 
					
						
							|  |  |  | 		addresses := make(addresssByHeartbeat, 0, len(pool.queue)) | 
					
						
							|  |  |  | 		for addr, _ := range pool.queue { | 
					
						
							|  |  |  | 			addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		sort.Sort(addresses) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Drop transactions until the total is below the limit | 
					
						
							|  |  |  | 		for drop := queued - maxQueuedInTotal; drop > 0; { | 
					
						
							|  |  |  | 			addr := addresses[len(addresses)-1] | 
					
						
							|  |  |  | 			list := pool.queue[addr.address] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			addresses = addresses[:len(addresses)-1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Drop all transactions if they are less than the overflow | 
					
						
							|  |  |  | 			if size := uint64(list.Len()); size <= drop { | 
					
						
							|  |  |  | 				for _, tx := range list.Flatten() { | 
					
						
							|  |  |  | 					pool.removeTx(tx.Hash()) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				drop -= size | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 				queuedRLCounter.Inc(int64(size)) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Otherwise drop only last few transactions | 
					
						
							|  |  |  | 			txs := list.Flatten() | 
					
						
							|  |  |  | 			for i := len(txs) - 1; i >= 0 && drop > 0; i-- { | 
					
						
							|  |  |  | 				pool.removeTx(txs[i].Hash()) | 
					
						
							|  |  |  | 				drop-- | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 				queuedRLCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-23 11:09:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // demoteUnexecutables removes invalid and processed transactions from the pools | 
					
						
							|  |  |  | // executable/pending queue and any subsequent transactions that become unexecutable | 
					
						
							|  |  |  | // are moved back into the future queue. | 
					
						
							|  |  |  | func (pool *TxPool) demoteUnexecutables() { | 
					
						
							|  |  |  | 	// Retrieve the current state to allow nonce and balance checking | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	state, err := pool.currentState() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		glog.V(logger.Info).Infoln("failed to get current state: %v", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Iterate over all accounts and demote any non-executable transactions | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							|  |  |  | 		nonce := state.GetNonce(addr) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// Drop all transactions that are deemed too old (low nonce) | 
					
						
							|  |  |  | 		for _, tx := range list.Forward(nonce) { | 
					
						
							|  |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Removed old pending transaction: %v", tx) | 
					
						
							| 
									
										
										
										
											2015-04-23 11:09:58 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			delete(pool.all, tx.Hash()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Drop all transactions that are too costly (low balance), and queue any invalids back for later | 
					
						
							|  |  |  | 		drops, invalids := list.Filter(state.GetBalance(addr)) | 
					
						
							|  |  |  | 		for _, tx := range drops { | 
					
						
							|  |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Removed unpayable pending transaction: %v", tx) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			delete(pool.all, tx.Hash()) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 			pendingNofundsCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		for _, tx := range invalids { | 
					
						
							|  |  |  | 			if glog.V(logger.Core) { | 
					
						
							|  |  |  | 				glog.Infof("Demoting pending transaction: %v", tx) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 			pool.enqueueTx(tx.Hash(), tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Delete the entire queue entry if it became empty. | 
					
						
							|  |  |  | 		if list.Empty() { | 
					
						
							|  |  |  | 			delete(pool.pending, addr) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 			delete(pool.beats, addr) | 
					
						
							| 
									
										
										
										
											2015-04-23 11:09:58 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | // expirationLoop is a loop that periodically iterates over all accounts with | 
					
						
							|  |  |  | // queued transactions and drop all that have been inactive for a prolonged amount | 
					
						
							|  |  |  | // of time. | 
					
						
							|  |  |  | func (pool *TxPool) expirationLoop() { | 
					
						
							|  |  |  | 	defer pool.wg.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	evict := time.NewTicker(evictionInterval) | 
					
						
							|  |  |  | 	defer evict.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-evict.C: | 
					
						
							|  |  |  | 			pool.mu.Lock() | 
					
						
							|  |  |  | 			for addr := range pool.queue { | 
					
						
							|  |  |  | 				if time.Since(pool.beats[addr]) > maxQueuedLifetime { | 
					
						
							|  |  |  | 					for _, tx := range pool.queue[addr].Flatten() { | 
					
						
							|  |  |  | 						pool.removeTx(tx.Hash()) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-pool.quit: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // addressByHeartbeat is an account address tagged with its last activity timestamp. | 
					
						
							|  |  |  | type addressByHeartbeat struct { | 
					
						
							|  |  |  | 	address   common.Address | 
					
						
							|  |  |  | 	heartbeat time.Time | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type addresssByHeartbeat []addressByHeartbeat | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a addresssByHeartbeat) Len() int           { return len(a) } | 
					
						
							|  |  |  | func (a addresssByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } | 
					
						
							|  |  |  | func (a addresssByHeartbeat) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | // txSet represents a set of transaction hashes in which entries | 
					
						
							|  |  |  | //  are automatically dropped after txSetDuration time | 
					
						
							|  |  |  | type txSet struct { | 
					
						
							|  |  |  | 	txMap          map[common.Hash]struct{} | 
					
						
							|  |  |  | 	txOrd          map[uint64]txOrdType | 
					
						
							|  |  |  | 	addPtr, delPtr uint64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const txSetDuration = time.Hour * 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // txOrdType represents an entry in the time-ordered list of transaction hashes | 
					
						
							|  |  |  | type txOrdType struct { | 
					
						
							|  |  |  | 	hash common.Hash | 
					
						
							|  |  |  | 	time time.Time | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newTxSet creates a new transaction set | 
					
						
							|  |  |  | func newTxSet() *txSet { | 
					
						
							|  |  |  | 	return &txSet{ | 
					
						
							|  |  |  | 		txMap: make(map[common.Hash]struct{}), | 
					
						
							|  |  |  | 		txOrd: make(map[uint64]txOrdType), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // contains returns true if the set contains the given transaction hash | 
					
						
							|  |  |  | // (not thread safe, should be called from a locked environment) | 
					
						
							|  |  |  | func (self *txSet) contains(hash common.Hash) bool { | 
					
						
							|  |  |  | 	_, ok := self.txMap[hash] | 
					
						
							|  |  |  | 	return ok | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // add adds a transaction hash to the set, then removes entries older than txSetDuration | 
					
						
							|  |  |  | // (not thread safe, should be called from a locked environment) | 
					
						
							|  |  |  | func (self *txSet) add(hash common.Hash) { | 
					
						
							|  |  |  | 	self.txMap[hash] = struct{}{} | 
					
						
							|  |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 	self.txOrd[self.addPtr] = txOrdType{hash: hash, time: now} | 
					
						
							|  |  |  | 	self.addPtr++ | 
					
						
							|  |  |  | 	delBefore := now.Add(-txSetDuration) | 
					
						
							|  |  |  | 	for self.delPtr < self.addPtr && self.txOrd[self.delPtr].time.Before(delBefore) { | 
					
						
							|  |  |  | 		delete(self.txMap, self.txOrd[self.delPtr].hash) | 
					
						
							|  |  |  | 		delete(self.txOrd, self.delPtr) | 
					
						
							|  |  |  | 		self.delPtr++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |