| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 	"math" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											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
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// chainHeadChanSize is the size of channel listening to ChainHeadEvent. | 
					
						
							|  |  |  | 	chainHeadChanSize = 10 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 	// ErrInvalidSender is returned if the transaction contains an invalid signature. | 
					
						
							|  |  |  | 	ErrInvalidSender = errors.New("invalid sender") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrNonceTooLow is returned if the nonce of a transaction is lower than the | 
					
						
							|  |  |  | 	// one present in the local chain. | 
					
						
							|  |  |  | 	ErrNonceTooLow = errors.New("nonce too low") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrUnderpriced is returned if a transaction's gas price is below the minimum | 
					
						
							|  |  |  | 	// configured for the transaction pool. | 
					
						
							|  |  |  | 	ErrUnderpriced = errors.New("transaction underpriced") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced | 
					
						
							|  |  |  | 	// with a different one without the required price bump. | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// ErrInsufficientFunds is returned if the total cost of executing a transaction | 
					
						
							|  |  |  | 	// is higher than the balance of the user's account. | 
					
						
							|  |  |  | 	ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrIntrinsicGas is returned if the transaction is specified to use less gas | 
					
						
							|  |  |  | 	// than required to start the invocation. | 
					
						
							|  |  |  | 	ErrIntrinsicGas = errors.New("intrinsic gas too low") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrGasLimit is returned if a transaction's requested gas limit exceeds the | 
					
						
							|  |  |  | 	// maximum allowance of the current block. | 
					
						
							|  |  |  | 	ErrGasLimit = errors.New("exceeds block gas limit") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrNegativeValue is a sanity error to ensure noone is able to specify a | 
					
						
							|  |  |  | 	// transaction with a negative value. | 
					
						
							|  |  |  | 	ErrNegativeValue = errors.New("negative value") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrOversizedData is returned if the input data of a transaction is greater | 
					
						
							|  |  |  | 	// than some meaningful limit a user might use. This is not a consensus error | 
					
						
							|  |  |  | 	// making the transaction invalid, rather a DOS protection. | 
					
						
							|  |  |  | 	ErrOversizedData = errors.New("oversized data") | 
					
						
							| 
									
										
										
										
											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 ( | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	evictionInterval    = time.Minute     // Time interval to check for evictable transactions | 
					
						
							|  |  |  | 	statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats | 
					
						
							| 
									
										
										
										
											2015-06-15 12:16:29 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	// Metrics for the pending pool | 
					
						
							| 
									
										
										
										
											2018-02-23 10:56:08 +01:00
										 |  |  | 	pendingDiscardCounter   = metrics.NewRegisteredCounter("txpool/pending/discard", nil) | 
					
						
							|  |  |  | 	pendingReplaceCounter   = metrics.NewRegisteredCounter("txpool/pending/replace", nil) | 
					
						
							|  |  |  | 	pendingRateLimitCounter = metrics.NewRegisteredCounter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting | 
					
						
							|  |  |  | 	pendingNofundsCounter   = metrics.NewRegisteredCounter("txpool/pending/nofunds", nil)   // Dropped due to out-of-funds | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Metrics for the queued pool | 
					
						
							| 
									
										
										
										
											2018-02-23 10:56:08 +01:00
										 |  |  | 	queuedDiscardCounter   = metrics.NewRegisteredCounter("txpool/queued/discard", nil) | 
					
						
							|  |  |  | 	queuedReplaceCounter   = metrics.NewRegisteredCounter("txpool/queued/replace", nil) | 
					
						
							|  |  |  | 	queuedRateLimitCounter = metrics.NewRegisteredCounter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting | 
					
						
							|  |  |  | 	queuedNofundsCounter   = metrics.NewRegisteredCounter("txpool/queued/nofunds", nil)   // Dropped due to out-of-funds | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// General tx metrics | 
					
						
							| 
									
										
										
										
											2018-02-23 10:56:08 +01:00
										 |  |  | 	invalidTxCounter     = metrics.NewRegisteredCounter("txpool/invalid", nil) | 
					
						
							|  |  |  | 	underpricedTxCounter = metrics.NewRegisteredCounter("txpool/underpriced", nil) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-20 19:08:51 +02:00
										 |  |  | // TxStatus is the current status of a transaction as seen by the pool. | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | type TxStatus uint | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	TxStatusUnknown TxStatus = iota | 
					
						
							|  |  |  | 	TxStatusQueued | 
					
						
							|  |  |  | 	TxStatusPending | 
					
						
							|  |  |  | 	TxStatusIncluded | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | // blockChain provides the state of blockchain and current gas limit to do | 
					
						
							|  |  |  | // some pre checks in tx pool and event subscribers. | 
					
						
							|  |  |  | type blockChain interface { | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 	CurrentBlock() *types.Block | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	GetBlock(hash common.Hash, number uint64) *types.Block | 
					
						
							|  |  |  | 	StateAt(root common.Hash) (*state.StateDB, error) | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-21 11:27:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | // TxPoolConfig are the configuration parameters of the transaction pool. | 
					
						
							|  |  |  | type TxPoolConfig struct { | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	NoLocals  bool          // Whether local transaction handling should be disabled | 
					
						
							|  |  |  | 	Journal   string        // Journal of local transactions to survive node restarts | 
					
						
							|  |  |  | 	Rejournal time.Duration // Time interval to regenerate the local transaction journal | 
					
						
							| 
									
										
										
										
											2017-07-05 17:06:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool | 
					
						
							|  |  |  | 	PriceBump  uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account | 
					
						
							|  |  |  | 	GlobalSlots  uint64 // Maximum number of executable transaction slots for all accounts | 
					
						
							|  |  |  | 	AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account | 
					
						
							|  |  |  | 	GlobalQueue  uint64 // Maximum number of non-executable transaction slots for all accounts | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Lifetime time.Duration // Maximum amount of time non-executable transaction are queued | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DefaultTxPoolConfig contains the default configurations for the transaction | 
					
						
							|  |  |  | // pool. | 
					
						
							|  |  |  | var DefaultTxPoolConfig = TxPoolConfig{ | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	Journal:   "transactions.rlp", | 
					
						
							|  |  |  | 	Rejournal: time.Hour, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	PriceLimit: 1, | 
					
						
							|  |  |  | 	PriceBump:  10, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AccountSlots: 16, | 
					
						
							|  |  |  | 	GlobalSlots:  4096, | 
					
						
							|  |  |  | 	AccountQueue: 64, | 
					
						
							|  |  |  | 	GlobalQueue:  1024, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Lifetime: 3 * time.Hour, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // sanitize checks the provided user configurations and changes anything that's | 
					
						
							|  |  |  | // unreasonable or unworkable. | 
					
						
							|  |  |  | func (config *TxPoolConfig) sanitize() TxPoolConfig { | 
					
						
							|  |  |  | 	conf := *config | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	if conf.Rejournal < time.Second { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) | 
					
						
							|  |  |  | 		conf.Rejournal = time.Second | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	if conf.PriceLimit < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) | 
					
						
							|  |  |  | 		conf.PriceLimit = DefaultTxPoolConfig.PriceLimit | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conf.PriceBump < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) | 
					
						
							|  |  |  | 		conf.PriceBump = DefaultTxPoolConfig.PriceBump | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return conf | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	config       TxPoolConfig | 
					
						
							|  |  |  | 	chainconfig  *params.ChainConfig | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	chain        blockChain | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	gasPrice     *big.Int | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	txFeed       event.Feed | 
					
						
							|  |  |  | 	scope        event.SubscriptionScope | 
					
						
							|  |  |  | 	chainHeadCh  chan ChainHeadEvent | 
					
						
							|  |  |  | 	chainHeadSub event.Subscription | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	currentState  *state.StateDB      // Current state in the blockchain head | 
					
						
							|  |  |  | 	pendingState  *state.ManagedState // Pending state tracking virtual nonces | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	currentMaxGas uint64              // Current gas limit for transaction caps | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-20 19:08:51 +02:00
										 |  |  | 	locals  *accountSet // Set of local transaction to exempt from eviction rules | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	journal *txJournal  // Journal of local transaction to back up to disk | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	pending map[common.Address]*txList   // All currently processable transactions | 
					
						
							|  |  |  | 	queue   map[common.Address]*txList   // Queued but non-processable transactions | 
					
						
							|  |  |  | 	beats   map[common.Address]time.Time // Last heartbeat from each known account | 
					
						
							|  |  |  | 	all     *txLookup                    // All transactions to allow lookups | 
					
						
							|  |  |  | 	priced  *txPricedList                // All transactions sorted by price | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	wg sync.WaitGroup // for shutdown sync | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | // NewTxPool creates a new transaction pool to gather, sort and filter inbound | 
					
						
							| 
									
										
										
										
											2017-12-20 19:08:51 +02:00
										 |  |  | // transactions from the network. | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	// Sanitize the input to ensure no vulnerable gas prices are set | 
					
						
							|  |  |  | 	config = (&config).sanitize() | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	// Create the transaction pool with its initial settings | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 	pool := &TxPool{ | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		config:      config, | 
					
						
							|  |  |  | 		chainconfig: chainconfig, | 
					
						
							|  |  |  | 		chain:       chain, | 
					
						
							| 
									
										
										
										
											2018-06-05 03:31:34 -07:00
										 |  |  | 		signer:      types.NewEIP155Signer(chainconfig.ChainID), | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		pending:     make(map[common.Address]*txList), | 
					
						
							|  |  |  | 		queue:       make(map[common.Address]*txList), | 
					
						
							|  |  |  | 		beats:       make(map[common.Address]time.Time), | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		all:         newTxLookup(), | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), | 
					
						
							|  |  |  | 		gasPrice:    new(big.Int).SetUint64(config.PriceLimit), | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 	pool.locals = newAccountSet(pool.signer) | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	pool.priced = newTxPricedList(pool.all) | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 	pool.reset(nil, chain.CurrentBlock().Header()) | 
					
						
							| 
									
										
										
										
											2016-12-13 10:13:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	// If local transactions and journaling is enabled, load from disk | 
					
						
							|  |  |  | 	if !config.NoLocals && config.Journal != "" { | 
					
						
							|  |  |  | 		pool.journal = newTxJournal(config.Journal) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 		if err := pool.journal.load(pool.AddLocals); err != nil { | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 			log.Warn("Failed to load transaction journal", "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := pool.journal.rotate(pool.local()); err != nil { | 
					
						
							|  |  |  | 			log.Warn("Failed to rotate transaction journal", "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// Subscribe events from blockchain | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	// Start the event loop and return | 
					
						
							|  |  |  | 	pool.wg.Add(1) | 
					
						
							|  |  |  | 	go pool.loop() | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return pool | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | // loop is the transaction pool's main event loop, waiting for and reacting to | 
					
						
							|  |  |  | // outside blockchain events as well as for various reporting and transaction | 
					
						
							|  |  |  | // eviction events. | 
					
						
							|  |  |  | func (pool *TxPool) loop() { | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 	defer pool.wg.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	// Start the stats reporting and transaction eviction tickers | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	var prevPending, prevQueued, prevStales int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	report := time.NewTicker(statsReportInterval) | 
					
						
							|  |  |  | 	defer report.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	evict := time.NewTicker(evictionInterval) | 
					
						
							|  |  |  | 	defer evict.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	journal := time.NewTicker(pool.config.Rejournal) | 
					
						
							|  |  |  | 	defer journal.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	// Track the previous head headers for transaction reorgs | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 	head := pool.chain.CurrentBlock() | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	// Keep waiting for and reacting to the various events | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 		// Handle ChainHeadEvent | 
					
						
							|  |  |  | 		case ev := <-pool.chainHeadCh: | 
					
						
							|  |  |  | 			if ev.Block != nil { | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 				pool.mu.Lock() | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 				if pool.chainconfig.IsHomestead(ev.Block.Number()) { | 
					
						
							|  |  |  | 					pool.homestead = true | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 				pool.reset(head.Header(), ev.Block.Header()) | 
					
						
							|  |  |  | 				head = ev.Block | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 				pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 		// Be unsubscribed due to system stopped | 
					
						
							|  |  |  | 		case <-pool.chainHeadSub.Err(): | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		// Handle stats reporting ticks | 
					
						
							|  |  |  | 		case <-report.C: | 
					
						
							|  |  |  | 			pool.mu.RLock() | 
					
						
							|  |  |  | 			pending, queued := pool.stats() | 
					
						
							|  |  |  | 			stales := pool.priced.stales | 
					
						
							|  |  |  | 			pool.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if pending != prevPending || queued != prevQueued || stales != prevStales { | 
					
						
							|  |  |  | 				log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) | 
					
						
							|  |  |  | 				prevPending, prevQueued, prevStales = pending, queued, stales | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Handle inactive account transaction eviction | 
					
						
							|  |  |  | 		case <-evict.C: | 
					
						
							|  |  |  | 			pool.mu.Lock() | 
					
						
							|  |  |  | 			for addr := range pool.queue { | 
					
						
							|  |  |  | 				// Skip local transactions from the eviction mechanism | 
					
						
							|  |  |  | 				if pool.locals.contains(addr) { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Any non-locals old enough should be removed | 
					
						
							|  |  |  | 				if time.Since(pool.beats[addr]) > pool.config.Lifetime { | 
					
						
							|  |  |  | 					for _, tx := range pool.queue[addr].Flatten() { | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 						pool.removeTx(tx.Hash(), true) | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Handle local transaction journal rotation | 
					
						
							|  |  |  | 		case <-journal.C: | 
					
						
							|  |  |  | 			if pool.journal != nil { | 
					
						
							| 
									
										
										
										
											2017-08-08 11:59:34 +03:00
										 |  |  | 				pool.mu.Lock() | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 				if err := pool.journal.rotate(pool.local()); err != nil { | 
					
						
							|  |  |  | 					log.Warn("Failed to rotate local tx journal", "err", err) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-08-08 11:59:34 +03:00
										 |  |  | 				pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 11:59:34 +03:00
										 |  |  | // lockedReset is a wrapper around reset to allow calling it in a thread safe | 
					
						
							|  |  |  | // manner. This method is only ever used in the tester! | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | func (pool *TxPool) lockedReset(oldHead, newHead *types.Header) { | 
					
						
							| 
									
										
										
										
											2017-08-08 11:59:34 +03:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.reset(oldHead, newHead) | 
					
						
							| 
									
										
										
										
											2017-08-08 11:59:34 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // reset retrieves the current state of the blockchain and ensures the content | 
					
						
							|  |  |  | // of the transaction pool is valid with regard to the chain state. | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | func (pool *TxPool) reset(oldHead, newHead *types.Header) { | 
					
						
							|  |  |  | 	// If we're reorging an old state, reinject all dropped transactions | 
					
						
							|  |  |  | 	var reinject types.Transactions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if oldHead != nil && oldHead.Hash() != newHead.ParentHash { | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 		// If the reorg is too deep, avoid doing it (will happen during fast sync) | 
					
						
							|  |  |  | 		oldNum := oldHead.Number.Uint64() | 
					
						
							|  |  |  | 		newNum := newHead.Number.Uint64() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { | 
					
						
							| 
									
										
										
										
											2017-12-21 10:20:10 +02:00
										 |  |  | 			log.Debug("Skipping deep transaction reorg", "depth", depth) | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			// Reorg seems shallow enough to pull in all transactions into memory | 
					
						
							|  |  |  | 			var discarded, included types.Transactions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var ( | 
					
						
							|  |  |  | 				rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) | 
					
						
							|  |  |  | 				add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 			for rem.NumberU64() > add.NumberU64() { | 
					
						
							|  |  |  | 				discarded = append(discarded, rem.Transactions()...) | 
					
						
							|  |  |  | 				if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { | 
					
						
							|  |  |  | 					log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 			for add.NumberU64() > rem.NumberU64() { | 
					
						
							|  |  |  | 				included = append(included, add.Transactions()...) | 
					
						
							|  |  |  | 				if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { | 
					
						
							|  |  |  | 					log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 			for rem.Hash() != add.Hash() { | 
					
						
							|  |  |  | 				discarded = append(discarded, rem.Transactions()...) | 
					
						
							|  |  |  | 				if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { | 
					
						
							|  |  |  | 					log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				included = append(included, add.Transactions()...) | 
					
						
							|  |  |  | 				if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { | 
					
						
							|  |  |  | 					log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 			reinject = types.TxDifference(discarded, included) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Initialize the internal state to the current head | 
					
						
							|  |  |  | 	if newHead == nil { | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 		newHead = pool.chain.CurrentBlock().Header() // Special case during testing | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	statedb, err := pool.chain.StateAt(newHead.Root) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		log.Error("Failed to reset txpool state", "err", err) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.currentState = statedb | 
					
						
							|  |  |  | 	pool.pendingState = state.ManageState(statedb) | 
					
						
							|  |  |  | 	pool.currentMaxGas = newHead.GasLimit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Inject any transactions discarded due to reorgs | 
					
						
							|  |  |  | 	log.Debug("Reinjecting stale transactions", "count", len(reinject)) | 
					
						
							| 
									
										
										
										
											2018-06-04 14:09:16 +03:00
										 |  |  | 	senderCacher.recover(pool.signer, reinject) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.addTxsLocked(reinject, false) | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.demoteUnexecutables() | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 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 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.promoteExecutables(nil) | 
					
						
							| 
									
										
										
										
											2015-06-04 17:28:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-25 17:21:20 +03:00
										 |  |  | // Stop terminates the transaction pool. | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | func (pool *TxPool) Stop() { | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// Unsubscribe all subscriptions registered from txpool | 
					
						
							|  |  |  | 	pool.scope.Close() | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// Unsubscribe subscriptions registered from blockchain | 
					
						
							|  |  |  | 	pool.chainHeadSub.Unsubscribe() | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 	pool.wg.Wait() | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	if pool.journal != nil { | 
					
						
							|  |  |  | 		pool.journal.close() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 	log.Info("Transaction pool stopped") | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | // SubscribeNewTxsEvent registers a subscription of NewTxsEvent and | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | // starts sending event to the given channel. | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription { | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	return pool.scope.Track(pool.txFeed.Subscribe(ch)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | // GasPrice returns the current gas price enforced by the transaction pool. | 
					
						
							|  |  |  | func (pool *TxPool) GasPrice() *big.Int { | 
					
						
							|  |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return new(big.Int).Set(pool.gasPrice) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetGasPrice updates the minimum price required by the transaction pool for a | 
					
						
							|  |  |  | // new transaction, and drops all transactions below this threshold. | 
					
						
							|  |  |  | func (pool *TxPool) SetGasPrice(price *big.Int) { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pool.gasPrice = price | 
					
						
							|  |  |  | 	for _, tx := range pool.priced.Cap(price, pool.locals) { | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 		pool.removeTx(tx.Hash(), false) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	log.Info("Transaction pool price threshold updated", "price", price) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-25 17:21:20 +03:00
										 |  |  | // State returns the virtual managed state of the transaction pool. | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | func (pool *TxPool) State() *state.ManagedState { | 
					
						
							| 
									
										
										
										
											2016-12-13 10:13:07 +01:00
										 |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | func (pool *TxPool) Stats() (int, int) { | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	return pool.stats() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // stats retrieves the current pool stats, namely the number of pending and the | 
					
						
							|  |  |  | // number of queued (non-executable) transactions. | 
					
						
							|  |  |  | func (pool *TxPool) stats() (int, int) { | 
					
						
							|  |  |  | 	pending := 0 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	for _, list := range pool.pending { | 
					
						
							|  |  |  | 		pending += list.Len() | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	queued := 0 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	for _, list := range pool.queue { | 
					
						
							|  |  |  | 		queued += list.Len() | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	return pending, queued | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-12-30 13:32:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2016-12-10 23:54:58 +01:00
										 |  |  | func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pending := make(map[common.Address]types.Transactions) | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							|  |  |  | 		pending[addr] = list.Flatten() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-10 23:54:58 +01:00
										 |  |  | 	return pending, nil | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | // local retrieves all currently known local 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) local() map[common.Address]types.Transactions { | 
					
						
							|  |  |  | 	txs := make(map[common.Address]types.Transactions) | 
					
						
							|  |  |  | 	for addr := range pool.locals.accounts { | 
					
						
							|  |  |  | 		if pending := pool.pending[addr]; pending != nil { | 
					
						
							|  |  |  | 			txs[addr] = append(txs[addr], pending.Flatten()...) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if queued := pool.queue[addr]; queued != nil { | 
					
						
							|  |  |  | 			txs[addr] = append(txs[addr], queued.Flatten()...) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return txs | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // validateTx checks whether a transaction is valid according to the consensus | 
					
						
							|  |  |  | // rules and adheres to some heuristic limits of the local node (price and size). | 
					
						
							|  |  |  | func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { | 
					
						
							|  |  |  | 	// Heuristic limit, reject transactions over 32KB to prevent DOS attacks | 
					
						
							|  |  |  | 	if tx.Size() > 32*1024 { | 
					
						
							|  |  |  | 		return ErrOversizedData | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Transactions can't be negative. This may never happen using RLP decoded | 
					
						
							|  |  |  | 	// transactions but may occur if you create a transaction using the RPC. | 
					
						
							|  |  |  | 	if tx.Value().Sign() < 0 { | 
					
						
							|  |  |  | 		return ErrNegativeValue | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure the transaction doesn't exceed the current block limit gas. | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	if pool.currentMaxGas < tx.Gas() { | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 		return ErrGasLimit | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Make sure the transaction is signed properly | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | 	from, err := types.Sender(pool.signer, tx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return ErrInvalidSender | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 	// Drop non-local transactions under our own minimal accepted gas price | 
					
						
							|  |  |  | 	local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network | 
					
						
							| 
									
										
										
										
											2017-07-05 17:16:42 +03:00
										 |  |  | 	if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		return ErrUnderpriced | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 	// Ensure the transaction adheres to nonce ordering | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	if pool.currentState.GetNonce(from) > tx.Nonce() { | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 		return ErrNonceTooLow | 
					
						
							| 
									
										
										
										
											2015-06-17 17:09:39 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-04 16:19:22 +02:00
										 |  |  | 	// Transactor should have enough funds to cover the costs | 
					
						
							|  |  |  | 	// cost == V + GP * GL | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 		return ErrInsufficientFunds | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if tx.Gas() < intrGas { | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | // later pending promotion and execution. If the transaction is a replacement for | 
					
						
							|  |  |  | // an already pending or queued one, it overwrites the previous and returns this | 
					
						
							|  |  |  | // so outer code doesn't uselessly call promote. | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // | 
					
						
							|  |  |  | // If a newly added transaction is marked as local, its sending account will be | 
					
						
							|  |  |  | // whitelisted, preventing any associated transaction from being dropped out of | 
					
						
							|  |  |  | // the pool due to pricing constraints. | 
					
						
							|  |  |  | func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { | 
					
						
							| 
									
										
										
										
											2017-01-06 19:44:35 +02:00
										 |  |  | 	// If the transaction is already known, discard it | 
					
						
							| 
									
										
										
										
											2015-03-17 12:16:21 +01:00
										 |  |  | 	hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	if pool.all.Get(hash) != nil { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 		log.Trace("Discarding already known transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		return false, fmt.Errorf("known transaction: %x", hash) | 
					
						
							| 
									
										
										
										
											2015-01-07 01:21:45 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	// If the transaction fails basic validation, discard it | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 	if err := pool.validateTx(tx, local); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 		log.Trace("Discarding invalid transaction", "hash", hash, "err", err) | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		invalidTxCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		return false, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// If the transaction pool is full, discard underpriced transactions | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue { | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		// If the new transaction is underpriced, don't accept it | 
					
						
							| 
									
										
										
										
											2018-04-26 16:43:18 -07:00
										 |  |  | 		if !local && pool.priced.Underpriced(tx, pool.locals) { | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) | 
					
						
							|  |  |  | 			underpricedTxCounter.Inc(1) | 
					
						
							|  |  |  | 			return false, ErrUnderpriced | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// New transaction is better than our worse ones, make room for it | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		for _, tx := range drop { | 
					
						
							|  |  |  | 			log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) | 
					
						
							|  |  |  | 			underpricedTxCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 			pool.removeTx(tx.Hash(), false) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-12-01 20:18:09 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	// If the transaction is replacing an already pending one, do directly | 
					
						
							|  |  |  | 	from, _ := types.Sender(pool.signer, tx) // already validated | 
					
						
							|  |  |  | 	if list := pool.pending[from]; list != nil && list.Overlaps(tx) { | 
					
						
							|  |  |  | 		// Nonce already pending, check if required price bump is met | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 		inserted, old := list.Add(tx, pool.config.PriceBump) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		if !inserted { | 
					
						
							|  |  |  | 			pendingDiscardCounter.Inc(1) | 
					
						
							|  |  |  | 			return false, ErrReplaceUnderpriced | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// New transaction is better, replace old one | 
					
						
							|  |  |  | 		if old != nil { | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(old.Hash()) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			pool.priced.Removed() | 
					
						
							|  |  |  | 			pendingReplaceCounter.Inc(1) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		pool.all.Add(tx) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		pool.priced.Put(tx) | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 		pool.journalTx(from, tx) | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) | 
					
						
							| 
									
										
										
										
											2017-10-20 12:34:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// We've directly injected a replacement transaction, notify subsystems | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 		go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}}) | 
					
						
							| 
									
										
										
										
											2017-10-20 12:34:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		return old != nil, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	// New transaction isn't replacing a pending one, push into queue | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	replace, err := pool.enqueueTx(hash, tx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return false, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	// Mark local addresses and journal local transactions | 
					
						
							| 
									
										
										
										
											2017-07-05 17:16:42 +03:00
										 |  |  | 	if local { | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 		pool.locals.add(from) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	pool.journalTx(from, tx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) | 
					
						
							|  |  |  | 	return replace, nil | 
					
						
							| 
									
										
										
										
											2014-12-01 20:18:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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! | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, error) { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// 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
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	if !inserted { | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		// An older transaction was better, discard this | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		queuedDiscardCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		return false, ErrReplaceUnderpriced | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Discard any previous transaction and mark this | 
					
						
							|  |  |  | 	if old != nil { | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		pool.all.Remove(old.Hash()) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		pool.priced.Removed() | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		queuedReplaceCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	if pool.all.Get(hash) == nil { | 
					
						
							|  |  |  | 		pool.all.Add(tx) | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 		pool.priced.Put(tx) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	return old != nil, nil | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | // journalTx adds the specified transaction to the local disk journal if it is | 
					
						
							|  |  |  | // deemed to have been sent from a local account. | 
					
						
							|  |  |  | func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { | 
					
						
							|  |  |  | 	// Only journal if it's enabled and the transaction is local | 
					
						
							|  |  |  | 	if pool.journal == nil || !pool.locals.contains(from) { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := pool.journal.insert(tx); err != nil { | 
					
						
							|  |  |  | 		log.Warn("Failed to journal local transaction", "err", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | // promoteTx adds a transaction to the pending (processable) list of transactions | 
					
						
							|  |  |  | // and returns whether it was inserted or an older was better. | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // | 
					
						
							|  |  |  | // Note, this method assumes the pool lock is held! | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	inserted, old := list.Add(tx, pool.config.PriceBump) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	if !inserted { | 
					
						
							|  |  |  | 		// An older transaction was better, discard this | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		pool.priced.Removed() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		pendingDiscardCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 		return false | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		pool.all.Remove(old.Hash()) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		pool.priced.Removed() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 		pendingReplaceCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 	// Failsafe to work around direct pending inserts (tests) | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	if pool.all.Get(hash) == nil { | 
					
						
							|  |  |  | 		pool.all.Add(tx) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		pool.priced.Put(tx) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 	return true | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // AddLocal enqueues a single transaction into the pool if it is valid, marking | 
					
						
							|  |  |  | // the sender as a local one in the mean time, ensuring it goes around the local | 
					
						
							|  |  |  | // pricing constraints. | 
					
						
							|  |  |  | func (pool *TxPool) AddLocal(tx *types.Transaction) error { | 
					
						
							| 
									
										
										
										
											2017-07-05 17:16:42 +03:00
										 |  |  | 	return pool.addTx(tx, !pool.config.NoLocals) | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AddRemote enqueues a single transaction into the pool if it is valid. If the | 
					
						
							|  |  |  | // sender is not among the locally tracked ones, full pricing constraints will | 
					
						
							|  |  |  | // apply. | 
					
						
							|  |  |  | func (pool *TxPool) AddRemote(tx *types.Transaction) error { | 
					
						
							|  |  |  | 	return pool.addTx(tx, false) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AddLocals enqueues a batch of transactions into the pool if they are valid, | 
					
						
							|  |  |  | // marking the senders as a local ones in the mean time, ensuring they go around | 
					
						
							|  |  |  | // the local pricing constraints. | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { | 
					
						
							|  |  |  | 	return pool.addTxs(txs, !pool.config.NoLocals) | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AddRemotes enqueues a batch of transactions into the pool if they are valid. | 
					
						
							|  |  |  | // If the senders are not among the locally tracked ones, full pricing constraints | 
					
						
							|  |  |  | // will apply. | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { | 
					
						
							|  |  |  | 	return pool.addTxs(txs, false) | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // addTx enqueues a single transaction into the pool if it is valid. | 
					
						
							|  |  |  | func (pool *TxPool) addTx(tx *types.Transaction, local bool) error { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-04-08 00:31:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	// Try to inject the transaction and update any state | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 	replace, err := pool.add(tx, local) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	// If we added a new transaction, run promotion checks and return | 
					
						
							|  |  |  | 	if !replace { | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 		from, _ := types.Sender(pool.signer, tx) // already validated | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		pool.promoteExecutables([]common.Address{from}) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // addTxs attempts to queue a batch of transactions if they are valid. | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-02-19 22:33:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 	return pool.addTxsLocked(txs, local) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // addTxsLocked attempts to queue a batch of transactions if they are valid, | 
					
						
							|  |  |  | // whilst assuming the transaction pool lock is already held. | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 	// Add the batch of transaction, tracking the accepted ones | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 	dirty := make(map[common.Address]struct{}) | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 	errs := make([]error, len(txs)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	for i, tx := range txs { | 
					
						
							|  |  |  | 		var replace bool | 
					
						
							| 
									
										
										
										
											2018-06-14 18:46:43 +08:00
										 |  |  | 		if replace, errs[i] = pool.add(tx, local); errs[i] == nil && !replace { | 
					
						
							|  |  |  | 			from, _ := types.Sender(pool.signer, tx) // already validated | 
					
						
							|  |  |  | 			dirty[from] = struct{}{} | 
					
						
							| 
									
										
										
										
											2014-12-14 18:15:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 	// Only reprocess the internal state if something was actually added | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 	if len(dirty) > 0 { | 
					
						
							|  |  |  | 		addrs := make([]common.Address, 0, len(dirty)) | 
					
						
							| 
									
										
										
										
											2017-11-08 11:45:52 +01:00
										 |  |  | 		for addr := range dirty { | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 			addrs = append(addrs, addr) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		pool.promoteExecutables(addrs) | 
					
						
							| 
									
										
										
										
											2016-12-10 23:54:58 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 	return errs | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | // Status returns the status (unknown/pending/queued) of a batch of transactions | 
					
						
							|  |  |  | // identified by their hashes. | 
					
						
							|  |  |  | func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { | 
					
						
							|  |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 	status := make([]TxStatus, len(hashes)) | 
					
						
							|  |  |  | 	for i, hash := range hashes { | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 		if tx := pool.all.Get(hash); tx != nil { | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 			from, _ := types.Sender(pool.signer, tx) // already validated | 
					
						
							| 
									
										
										
										
											2017-12-20 12:34:43 +02:00
										 |  |  | 			if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 				status[i] = TxStatusPending | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | 				status[i] = TxStatusQueued | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return status | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	return pool.all.Get(hash) | 
					
						
							| 
									
										
										
										
											2015-04-23 10:51:13 +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. | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 	// Fetch the transaction we wish to delete | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	tx := pool.all.Get(hash) | 
					
						
							|  |  |  | 	if tx == nil { | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 		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 | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 	if outofbound { | 
					
						
							|  |  |  | 		pool.priced.Removed() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2018-03-07 10:55:59 +02:00
										 |  |  | 			// If no more pending 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
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-07 10:55:59 +02:00
										 |  |  | 			// Postpone any invalidated transactions | 
					
						
							| 
									
										
										
										
											2018-03-03 18:09:36 +08: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 { | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 				pool.pendingState.SetNonce(addr, nonce) | 
					
						
							| 
									
										
										
										
											2016-08-25 19:04:40 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | func (pool *TxPool) promoteExecutables(accounts []common.Address) { | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	// Track the promoted transactions to broadcast them at once | 
					
						
							|  |  |  | 	var promoted []*types.Transaction | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 	// Gather all the accounts potentially needing updates | 
					
						
							|  |  |  | 	if accounts == nil { | 
					
						
							|  |  |  | 		accounts = make([]common.Address, 0, len(pool.queue)) | 
					
						
							| 
									
										
										
										
											2017-11-08 11:45:52 +01:00
										 |  |  | 		for addr := range pool.queue { | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 			accounts = append(accounts, addr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Iterate over all accounts and promote any executable transactions | 
					
						
							| 
									
										
										
										
											2017-05-31 21:49:20 +03:00
										 |  |  | 	for _, addr := range accounts { | 
					
						
							|  |  |  | 		list := pool.queue[addr] | 
					
						
							|  |  |  | 		if list == nil { | 
					
						
							|  |  |  | 			continue // Just in case someone calls with a non existing account | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// Drop all transactions that are deemed too old (low nonce) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			log.Trace("Removed old queued transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			pool.priced.Removed() | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-05-30 00:31:37 +03:00
										 |  |  | 		// Drop all transactions that are too costly (low balance or out of gas) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		for _, tx := range drops { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			log.Trace("Removed unpayable queued transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			pool.priced.Removed() | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 		for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 			if pool.promoteTx(addr, hash, tx) { | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 				log.Trace("Promoting queued transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 				promoted = append(promoted, tx) | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// Drop all transactions over the allowed limit | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 		if !pool.locals.contains(addr) { | 
					
						
							| 
									
										
										
										
											2017-06-30 22:55:10 +02:00
										 |  |  | 			for _, tx := range list.Cap(int(pool.config.AccountQueue)) { | 
					
						
							|  |  |  | 				hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 				pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-06-30 22:55:10 +02:00
										 |  |  | 				pool.priced.Removed() | 
					
						
							|  |  |  | 				queuedRateLimitCounter.Inc(1) | 
					
						
							|  |  |  | 				log.Trace("Removed cap-exceeding queued transaction", "hash", hash) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 	// Notify subsystem for new promoted transactions. | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	if len(promoted) > 0 { | 
					
						
							| 
									
										
										
										
											2018-05-30 10:14:00 +03:00
										 |  |  | 		go pool.txFeed.Send(NewTxsEvent{promoted}) | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08: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()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	if pending > pool.config.GlobalSlots { | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 			if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | 				spammers.Push(addr, float32(list.Len())) | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Gradually drop transactions from offenders | 
					
						
							|  |  |  | 		offenders := []common.Address{} | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 		for pending > pool.config.GlobalSlots && !spammers.Empty() { | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 			// 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 | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 				for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 					for i := 0; i < len(offenders)-1; i++ { | 
					
						
							|  |  |  | 						list := pool.pending[offenders[i]] | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 						for _, tx := range list.Cap(list.Len() - 1) { | 
					
						
							|  |  |  | 							// Drop the transaction from the global pools too | 
					
						
							|  |  |  | 							hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 							pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 							pool.priced.Removed() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// Update the account nonce to the dropped transaction | 
					
						
							|  |  |  | 							if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce { | 
					
						
							|  |  |  | 								pool.pendingState.SetNonce(offenders[i], nonce) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 						pending-- | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If still above threshold, reduce to limit or min allowance | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 		if pending > pool.config.GlobalSlots && len(offenders) > 0 { | 
					
						
							|  |  |  | 			for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 				for _, addr := range offenders { | 
					
						
							|  |  |  | 					list := pool.pending[addr] | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 					for _, tx := range list.Cap(list.Len() - 1) { | 
					
						
							|  |  |  | 						// Drop the transaction from the global pools too | 
					
						
							|  |  |  | 						hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 						pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 						pool.priced.Removed() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// Update the account nonce to the dropped transaction | 
					
						
							|  |  |  | 						if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { | 
					
						
							|  |  |  | 							pool.pendingState.SetNonce(addr, nonce) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 					pending-- | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 		pendingRateLimitCounter.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 | 
					
						
							| 
									
										
										
										
											2017-07-06 11:51:59 +03:00
										 |  |  | 	queued := uint64(0) | 
					
						
							|  |  |  | 	for _, list := range pool.queue { | 
					
						
							|  |  |  | 		queued += uint64(list.Len()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	if queued > pool.config.GlobalQueue { | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		// Sort all accounts with queued transactions by heartbeat | 
					
						
							|  |  |  | 		addresses := make(addresssByHeartbeat, 0, len(pool.queue)) | 
					
						
							| 
									
										
										
										
											2017-01-06 15:52:03 +01:00
										 |  |  | 		for addr := range pool.queue { | 
					
						
							| 
									
										
										
										
											2017-07-06 11:51:59 +03:00
										 |  |  | 			if !pool.locals.contains(addr) { // don't drop locals | 
					
						
							| 
									
										
										
										
											2017-06-30 22:55:10 +02:00
										 |  |  | 				addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		sort.Sort(addresses) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-06 11:51:59 +03:00
										 |  |  | 		// Drop transactions until the total is below the limit or only locals remain | 
					
						
							|  |  |  | 		for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 			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() { | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 					pool.removeTx(tx.Hash(), true) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				drop -= size | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 				queuedRateLimitCounter.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-- { | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 				pool.removeTx(txs[i].Hash(), true) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 				drop-- | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 				queuedRateLimitCounter.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. | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | func (pool *TxPool) demoteUnexecutables() { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	// Iterate over all accounts and demote any non-executable transactions | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		nonce := pool.currentState.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) { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			log.Trace("Removed old pending transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			pool.priced.Removed() | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-05-30 00:31:37 +03:00
										 |  |  | 		// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		for _, tx := range drops { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			log.Trace("Removed unpayable pending transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			pool.priced.Removed() | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			log.Trace("Demoting pending transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			pool.enqueueTx(hash, tx) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-13 03:14:15 -04:00
										 |  |  | 		// If there's a gap in front, alert (should never happen) and postpone all transactions | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		if list.Len() > 0 && list.txs.Get(nonce) == nil { | 
					
						
							|  |  |  | 			for _, tx := range list.Cap(0) { | 
					
						
							|  |  |  | 				hash := tx.Hash() | 
					
						
							|  |  |  | 				log.Error("Demoting invalidated transaction", "hash", hash) | 
					
						
							|  |  |  | 				pool.enqueueTx(hash, tx) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// 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
										 |  |  | // 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] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | // accountSet is simply a set of addresses to check for existence, and a signer | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // capable of deriving addresses from transactions. | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | type accountSet struct { | 
					
						
							|  |  |  | 	accounts map[common.Address]struct{} | 
					
						
							|  |  |  | 	signer   types.Signer | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // newAccountSet creates a new address set with an associated signer for sender | 
					
						
							|  |  |  | // derivations. | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | func newAccountSet(signer types.Signer) *accountSet { | 
					
						
							|  |  |  | 	return &accountSet{ | 
					
						
							|  |  |  | 		accounts: make(map[common.Address]struct{}), | 
					
						
							|  |  |  | 		signer:   signer, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // contains checks if a given address is contained within the set. | 
					
						
							|  |  |  | func (as *accountSet) contains(addr common.Address) bool { | 
					
						
							|  |  |  | 	_, exist := as.accounts[addr] | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | 	return exist | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // containsTx checks if the sender of a given tx is within the set. If the sender | 
					
						
							|  |  |  | // cannot be derived, this method returns false. | 
					
						
							|  |  |  | func (as *accountSet) containsTx(tx *types.Transaction) bool { | 
					
						
							|  |  |  | 	if addr, err := types.Sender(as.signer, tx); err == nil { | 
					
						
							|  |  |  | 		return as.contains(addr) | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // add inserts a new address into the set to track. | 
					
						
							|  |  |  | func (as *accountSet) add(addr common.Address) { | 
					
						
							|  |  |  | 	as.accounts[addr] = struct{}{} | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // txLookup is used internally by TxPool to track transactions while allowing lookup without | 
					
						
							|  |  |  | // mutex contention. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note, although this type is properly protected against concurrent access, it | 
					
						
							|  |  |  | // is **not** a type that should ever be mutated or even exposed outside of the | 
					
						
							|  |  |  | // transaction pool, since its internal state is tightly coupled with the pools | 
					
						
							|  |  |  | // internal mechanisms. The sole purpose of the type is to permit out-of-bound | 
					
						
							|  |  |  | // peeking into the pool in TxPool.Get without having to acquire the widely scoped | 
					
						
							|  |  |  | // TxPool.mu mutex. | 
					
						
							|  |  |  | type txLookup struct { | 
					
						
							|  |  |  | 	all  map[common.Hash]*types.Transaction | 
					
						
							|  |  |  | 	lock sync.RWMutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newTxLookup returns a new txLookup structure. | 
					
						
							|  |  |  | func newTxLookup() *txLookup { | 
					
						
							|  |  |  | 	return &txLookup{ | 
					
						
							|  |  |  | 		all: make(map[common.Hash]*types.Transaction), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Range calls f on each key and value present in the map. | 
					
						
							|  |  |  | func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) { | 
					
						
							|  |  |  | 	t.lock.RLock() | 
					
						
							|  |  |  | 	defer t.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for key, value := range t.all { | 
					
						
							|  |  |  | 		if !f(key, value) { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get returns a transaction if it exists in the lookup, or nil if not found. | 
					
						
							|  |  |  | func (t *txLookup) Get(hash common.Hash) *types.Transaction { | 
					
						
							|  |  |  | 	t.lock.RLock() | 
					
						
							|  |  |  | 	defer t.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return t.all[hash] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Count returns the current number of items in the lookup. | 
					
						
							|  |  |  | func (t *txLookup) Count() int { | 
					
						
							|  |  |  | 	t.lock.RLock() | 
					
						
							|  |  |  | 	defer t.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return len(t.all) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Add adds a transaction to the lookup. | 
					
						
							|  |  |  | func (t *txLookup) Add(tx *types.Transaction) { | 
					
						
							|  |  |  | 	t.lock.Lock() | 
					
						
							|  |  |  | 	defer t.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.all[tx.Hash()] = tx | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Remove removes a transaction from the lookup. | 
					
						
							|  |  |  | func (t *txLookup) Remove(hash common.Hash) { | 
					
						
							|  |  |  | 	t.lock.Lock() | 
					
						
							|  |  |  | 	defer t.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	delete(t.all, hash) | 
					
						
							|  |  |  | } |