| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2018-09-03 23:33:21 +08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common/prque" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// txSlotSize is used to calculate how many data slots a single transaction | 
					
						
							|  |  |  | 	// takes up based on its size. The slots are used as DoS protection, ensuring | 
					
						
							|  |  |  | 	// that validating a new transaction remains a constant operation (in reality | 
					
						
							|  |  |  | 	// O(maxslots), where max slots are 4 currently). | 
					
						
							|  |  |  | 	txSlotSize = 32 * 1024 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// txMaxSize is the maximum size a single transaction can have. This field has | 
					
						
							|  |  |  | 	// non-trivial consequences: larger transactions are significantly harder and | 
					
						
							|  |  |  | 	// more expensive to propagate; larger transactions also take more resources | 
					
						
							|  |  |  | 	// to validate whether they fit into the pool or not. | 
					
						
							| 
									
										
										
										
											2020-03-30 10:46:05 +02:00
										 |  |  | 	txMaxSize = 4 * txSlotSize // 128KB | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2020-01-22 16:39:43 +02:00
										 |  |  | 	// ErrAlreadyKnown is returned if the transactions is already contained | 
					
						
							|  |  |  | 	// within the pool. | 
					
						
							|  |  |  | 	ErrAlreadyKnown = errors.New("already known") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 	// ErrInvalidSender is returned if the transaction contains an invalid signature. | 
					
						
							|  |  |  | 	ErrInvalidSender = errors.New("invalid sender") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 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") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-25 16:21:28 +08:00
										 |  |  | 	// ErrNegativeValue is a sanity error to ensure no one is able to specify a | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 	// 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 | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 	pendingDiscardMeter   = metrics.NewRegisteredMeter("txpool/pending/discard", nil) | 
					
						
							|  |  |  | 	pendingReplaceMeter   = metrics.NewRegisteredMeter("txpool/pending/replace", nil) | 
					
						
							|  |  |  | 	pendingRateLimitMeter = metrics.NewRegisteredMeter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting | 
					
						
							|  |  |  | 	pendingNofundsMeter   = metrics.NewRegisteredMeter("txpool/pending/nofunds", nil)   // Dropped due to out-of-funds | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Metrics for the queued pool | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 	queuedDiscardMeter   = metrics.NewRegisteredMeter("txpool/queued/discard", nil) | 
					
						
							|  |  |  | 	queuedReplaceMeter   = metrics.NewRegisteredMeter("txpool/queued/replace", nil) | 
					
						
							|  |  |  | 	queuedRateLimitMeter = metrics.NewRegisteredMeter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting | 
					
						
							|  |  |  | 	queuedNofundsMeter   = metrics.NewRegisteredMeter("txpool/queued/nofunds", nil)   // Dropped due to out-of-funds | 
					
						
							| 
									
										
										
										
											2020-05-22 21:15:01 -04:00
										 |  |  | 	queuedEvictionMeter  = metrics.NewRegisteredMeter("txpool/queued/eviction", nil)  // Dropped due to lifetime | 
					
						
							| 
									
										
										
										
											2016-11-01 13:46:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// General tx metrics | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 	knownTxMeter       = metrics.NewRegisteredMeter("txpool/known", nil) | 
					
						
							|  |  |  | 	validTxMeter       = metrics.NewRegisteredMeter("txpool/valid", nil) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 	invalidTxMeter     = metrics.NewRegisteredMeter("txpool/invalid", nil) | 
					
						
							|  |  |  | 	underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 	pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil) | 
					
						
							|  |  |  | 	queuedGauge  = metrics.NewRegisteredGauge("txpool/queued", nil) | 
					
						
							|  |  |  | 	localGauge   = metrics.NewRegisteredGauge("txpool/local", nil) | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 	slotsGauge   = metrics.NewRegisteredGauge("txpool/slots", 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 { | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | 	Locals    []common.Address // Addresses that should be treated by default as local | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-25 00:44:41 +09:00
										 |  |  | 	AccountSlots uint64 // Number of executable transaction slots guaranteed per account | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-20 07:00:58 -06:00
										 |  |  | 	if conf.AccountSlots < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultTxPoolConfig.AccountSlots) | 
					
						
							|  |  |  | 		conf.AccountSlots = DefaultTxPoolConfig.AccountSlots | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conf.GlobalSlots < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultTxPoolConfig.GlobalSlots) | 
					
						
							|  |  |  | 		conf.GlobalSlots = DefaultTxPoolConfig.GlobalSlots | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conf.AccountQueue < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultTxPoolConfig.AccountQueue) | 
					
						
							|  |  |  | 		conf.AccountQueue = DefaultTxPoolConfig.AccountQueue | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conf.GlobalQueue < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultTxPoolConfig.GlobalQueue) | 
					
						
							|  |  |  | 		conf.GlobalQueue = DefaultTxPoolConfig.GlobalQueue | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conf.Lifetime < 1 { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime) | 
					
						
							|  |  |  | 		conf.Lifetime = DefaultTxPoolConfig.Lifetime | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-26 13:40:47 +03:00
										 |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	config      TxPoolConfig | 
					
						
							|  |  |  | 	chainconfig *params.ChainConfig | 
					
						
							|  |  |  | 	chain       blockChain | 
					
						
							|  |  |  | 	gasPrice    *big.Int | 
					
						
							|  |  |  | 	txFeed      event.Feed | 
					
						
							|  |  |  | 	scope       event.SubscriptionScope | 
					
						
							|  |  |  | 	signer      types.Signer | 
					
						
							|  |  |  | 	mu          sync.RWMutex | 
					
						
							| 
									
										
										
										
											2016-06-27 18:28:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 20:53:21 +08:00
										 |  |  | 	istanbul bool // Fork indicator whether we are in the istanbul stage. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | 	currentState  *state.StateDB // Current state in the blockchain head | 
					
						
							|  |  |  | 	pendingNonces *txNoncer      // Pending state tracking virtual nonces | 
					
						
							|  |  |  | 	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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	chainHeadCh     chan ChainHeadEvent | 
					
						
							|  |  |  | 	chainHeadSub    event.Subscription | 
					
						
							|  |  |  | 	reqResetCh      chan *txpoolResetRequest | 
					
						
							|  |  |  | 	reqPromoteCh    chan *accountSet | 
					
						
							|  |  |  | 	queueTxEventCh  chan *types.Transaction | 
					
						
							|  |  |  | 	reorgDoneCh     chan chan struct{} | 
					
						
							|  |  |  | 	reorgShutdownCh chan struct{}  // requests shutdown of scheduleReorgLoop | 
					
						
							|  |  |  | 	wg              sync.WaitGroup // tracks loop, scheduleReorgLoop | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | type txpoolResetRequest struct { | 
					
						
							|  |  |  | 	oldHead, newHead *types.Header | 
					
						
							| 
									
										
										
										
											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{ | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		config:          config, | 
					
						
							|  |  |  | 		chainconfig:     chainconfig, | 
					
						
							|  |  |  | 		chain:           chain, | 
					
						
							|  |  |  | 		signer:          types.NewEIP155Signer(chainconfig.ChainID), | 
					
						
							|  |  |  | 		pending:         make(map[common.Address]*txList), | 
					
						
							|  |  |  | 		queue:           make(map[common.Address]*txList), | 
					
						
							|  |  |  | 		beats:           make(map[common.Address]time.Time), | 
					
						
							|  |  |  | 		all:             newTxLookup(), | 
					
						
							|  |  |  | 		chainHeadCh:     make(chan ChainHeadEvent, chainHeadChanSize), | 
					
						
							|  |  |  | 		reqResetCh:      make(chan *txpoolResetRequest), | 
					
						
							|  |  |  | 		reqPromoteCh:    make(chan *accountSet), | 
					
						
							|  |  |  | 		queueTxEventCh:  make(chan *types.Transaction), | 
					
						
							|  |  |  | 		reorgDoneCh:     make(chan chan struct{}), | 
					
						
							|  |  |  | 		reorgShutdownCh: make(chan struct{}), | 
					
						
							|  |  |  | 		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-08-21 20:30:06 +03:00
										 |  |  | 	for _, addr := range config.Locals { | 
					
						
							|  |  |  | 		log.Info("Setting new local account", "address", addr) | 
					
						
							|  |  |  | 		pool.locals.add(addr) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	// Start the reorg loop early so it can handle requests generated during journal loading. | 
					
						
							|  |  |  | 	pool.wg.Add(1) | 
					
						
							|  |  |  | 	go pool.scheduleReorgLoop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-09-04 22:35:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	// Subscribe events from blockchain and start the main event loop. | 
					
						
							|  |  |  | 	pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		prevPending, prevQueued, prevStales int | 
					
						
							|  |  |  | 		// Start the stats reporting and transaction eviction tickers | 
					
						
							|  |  |  | 		report  = time.NewTicker(statsReportInterval) | 
					
						
							|  |  |  | 		evict   = time.NewTicker(evictionInterval) | 
					
						
							|  |  |  | 		journal = time.NewTicker(pool.config.Rejournal) | 
					
						
							|  |  |  | 		// Track the previous head headers for transaction reorgs | 
					
						
							|  |  |  | 		head = pool.chain.CurrentBlock() | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	defer report.Stop() | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 	defer evict.Stop() | 
					
						
							|  |  |  | 	defer journal.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 				pool.requestReset(head.Header(), ev.Block.Header()) | 
					
						
							| 
									
										
										
										
											2017-09-05 19:49:37 +03:00
										 |  |  | 				head = ev.Block | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// System shutdown. | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 		case <-pool.chainHeadSub.Err(): | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 			close(pool.reorgShutdownCh) | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 			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 { | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 					list := pool.queue[addr].Flatten() | 
					
						
							|  |  |  | 					for _, tx := range list { | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 						pool.removeTx(tx.Hash(), true) | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 					queuedEvictionMeter.Mark(int64(len(list))) | 
					
						
							| 
									
										
										
										
											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-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) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | // Nonce returns the next nonce of an account, with all transactions executable | 
					
						
							|  |  |  | // by the pool already applied on top. | 
					
						
							|  |  |  | func (pool *TxPool) Nonce(addr common.Address) uint64 { | 
					
						
							| 
									
										
										
										
											2016-12-13 10:13:07 +01:00
										 |  |  | 	pool.mu.RLock() | 
					
						
							|  |  |  | 	defer pool.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | 	return pool.pendingNonces.get(addr) | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 18:45:42 +08:00
										 |  |  | // Pending retrieves all currently processable transactions, grouped by origin | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | // 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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | // Locals retrieves the accounts currently considered local by the pool. | 
					
						
							|  |  |  | func (pool *TxPool) Locals() []common.Address { | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	defer pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pool.locals.flatten() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 18:45:42 +08:00
										 |  |  | // local retrieves all currently known local transactions, grouped by origin | 
					
						
							| 
									
										
										
										
											2017-07-28 15:09:39 +02:00
										 |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 	// Reject transactions over defined size to prevent DOS attacks | 
					
						
							|  |  |  | 	if uint64(tx.Size()) > txMaxSize { | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 		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 | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 	if !local && tx.GasPriceIntCmp(pool.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 | 
					
						
							| 
									
										
										
										
											2020-07-09 14:02:03 +02:00
										 |  |  | 	if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 		return ErrInsufficientFunds | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	// Ensure the transaction has more gas than the basic tx fee. | 
					
						
							| 
									
										
										
										
											2019-08-14 20:53:21 +08:00
										 |  |  | 	intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul) | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // add validates a transaction and inserts it into the non-executable queue for later | 
					
						
							|  |  |  | // pending promotion and execution. If the transaction is a replacement for an already | 
					
						
							|  |  |  | // pending or queued one, it overwrites the previous transaction if its price is higher. | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | // | 
					
						
							|  |  |  | // If a newly added transaction is marked as local, its sending account will be | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // 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) (replaced bool, err 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) | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 		knownTxMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2020-01-22 16:39:43 +02:00
										 |  |  | 		return false, ErrAlreadyKnown | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		invalidTxMeter.Mark(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()) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			underpricedTxMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			return false, ErrUnderpriced | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// New transaction is better than our worse ones, make room for it | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 		drop := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), 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()) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			underpricedTxMeter.Mark(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
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	// Try to replace an existing transaction in the pending pool | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			pendingDiscardMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 			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()) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			pool.priced.Removed(1) | 
					
						
							|  |  |  | 			pendingReplaceMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		pool.queueTxEvent(tx) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Successful promotion, bump the heartbeat | 
					
						
							|  |  |  | 		pool.beats[from] = time.Now() | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	replaced, err = pool.enqueueTx(hash, tx) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | 		if !pool.locals.contains(from) { | 
					
						
							|  |  |  | 			log.Info("Setting new local account", "address", from) | 
					
						
							|  |  |  | 			pool.locals.add(from) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 	if local || pool.locals.contains(from) { | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		localGauge.Inc(1) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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()) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	return replaced, 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 | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		queuedDiscardMeter.Mark(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()) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		pool.priced.Removed(1) | 
					
						
							|  |  |  | 		queuedReplaceMeter.Mark(1) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Nothing was replaced, bump the queued counter | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		queuedGauge.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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 	// If we never record the heartbeat, do it right now. | 
					
						
							|  |  |  | 	if _, exist := pool.beats[from]; !exist { | 
					
						
							|  |  |  | 		pool.beats[from] = time.Now() | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		pool.priced.Removed(1) | 
					
						
							|  |  |  | 		pendingDiscardMeter.Mark(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()) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		pool.priced.Removed(1) | 
					
						
							|  |  |  | 		pendingReplaceMeter.Mark(1) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Nothing was replaced, bump the pending counter | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		pendingGauge.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 | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | 	pool.pendingNonces.set(addr, tx.Nonce()+1) | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 	// Successful promotion, bump the heartbeat | 
					
						
							|  |  |  | 	pool.beats[addr] = time.Now() | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 	return true | 
					
						
							| 
									
										
										
										
											2015-06-09 23:46:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // AddLocals enqueues a batch of transactions into the pool if they are valid, marking the | 
					
						
							|  |  |  | // senders as a local ones, ensuring they go around the local pricing constraints. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This method is used to add transactions from the RPC API and performs synchronous pool | 
					
						
							|  |  |  | // reorganization and event propagation. | 
					
						
							|  |  |  | func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { | 
					
						
							|  |  |  | 	return pool.addTxs(txs, !pool.config.NoLocals, true) | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // AddLocal enqueues a single local transaction into the pool if it is valid. This is | 
					
						
							|  |  |  | // a convenience wrapper aroundd AddLocals. | 
					
						
							|  |  |  | func (pool *TxPool) AddLocal(tx *types.Transaction) error { | 
					
						
							|  |  |  | 	errs := pool.AddLocals([]*types.Transaction{tx}) | 
					
						
							|  |  |  | 	return errs[0] | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02: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. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This method is used to add transactions from the p2p network and does not wait for pool | 
					
						
							|  |  |  | // reorganization and internal event propagation. | 
					
						
							| 
									
										
										
										
											2017-10-25 12:18:44 +03:00
										 |  |  | func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	return pool.addTxs(txs, false, false) | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // This is like AddRemotes, but waits for pool reorganization. Tests use this method. | 
					
						
							| 
									
										
										
										
											2019-07-22 20:45:40 +08:00
										 |  |  | func (pool *TxPool) AddRemotesSync(txs []*types.Transaction) []error { | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	return pool.addTxs(txs, false, true) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-08 00:31:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // This is like AddRemotes with a single transaction, but waits for pool reorganization. Tests use this method. | 
					
						
							|  |  |  | func (pool *TxPool) addRemoteSync(tx *types.Transaction) error { | 
					
						
							| 
									
										
										
										
											2019-07-22 20:45:40 +08:00
										 |  |  | 	errs := pool.AddRemotesSync([]*types.Transaction{tx}) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	return errs[0] | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // AddRemote enqueues a single transaction into the pool if it is valid. This is a convenience | 
					
						
							|  |  |  | // wrapper around AddRemotes. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Deprecated: use AddRemotes | 
					
						
							|  |  |  | func (pool *TxPool) AddRemote(tx *types.Transaction) error { | 
					
						
							|  |  |  | 	errs := pool.AddRemotes([]*types.Transaction{tx}) | 
					
						
							|  |  |  | 	return errs[0] | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error { | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 	// Filter out known ones without obtaining the pool lock or recovering signatures | 
					
						
							| 
									
										
										
										
											2019-09-18 10:53:01 +03:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		errs = make([]error, len(txs)) | 
					
						
							|  |  |  | 		news = make([]*types.Transaction, 0, len(txs)) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	for i, tx := range txs { | 
					
						
							|  |  |  | 		// If the transaction is known, pre-set the error slot | 
					
						
							|  |  |  | 		if pool.all.Get(tx.Hash()) != nil { | 
					
						
							| 
									
										
										
										
											2020-01-22 16:39:43 +02:00
										 |  |  | 			errs[i] = ErrAlreadyKnown | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 			knownTxMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2019-09-18 10:53:01 +03:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-03 11:55:14 +08:00
										 |  |  | 		// Exclude transactions with invalid signatures as soon as | 
					
						
							|  |  |  | 		// possible and cache senders in transactions before | 
					
						
							|  |  |  | 		// obtaining lock | 
					
						
							|  |  |  | 		_, err := types.Sender(pool.signer, tx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errs[i] = ErrInvalidSender | 
					
						
							|  |  |  | 			invalidTxMeter.Mark(1) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-09-18 10:53:01 +03:00
										 |  |  | 		// Accumulate all unknown transactions for deeper processing | 
					
						
							|  |  |  | 		news = append(news, tx) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(news) == 0 { | 
					
						
							|  |  |  | 		return errs | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-03 11:55:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-18 10:53:01 +03:00
										 |  |  | 	// Process all the new transaction and merge any errors into the original slice | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 	pool.mu.Lock() | 
					
						
							| 
									
										
										
										
											2019-09-18 10:53:01 +03:00
										 |  |  | 	newErrs, dirtyAddrs := pool.addTxsLocked(news, local) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	pool.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-02-19 22:33:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-18 10:53:01 +03:00
										 |  |  | 	var nilSlot = 0 | 
					
						
							|  |  |  | 	for _, err := range newErrs { | 
					
						
							|  |  |  | 		for errs[nilSlot] != nil { | 
					
						
							|  |  |  | 			nilSlot++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		errs[nilSlot] = err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Reorg the pool internals if needed and return | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	done := pool.requestPromoteExecutables(dirtyAddrs) | 
					
						
							|  |  |  | 	if sync { | 
					
						
							|  |  |  | 		<-done | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return errs | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // addTxsLocked attempts to queue a batch of transactions if they are valid. | 
					
						
							|  |  |  | // The transaction pool lock must be held. | 
					
						
							|  |  |  | func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error, *accountSet) { | 
					
						
							|  |  |  | 	dirty := newAccountSet(pool.signer) | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		replaced, err := pool.add(tx, local) | 
					
						
							|  |  |  | 		errs[i] = err | 
					
						
							|  |  |  | 		if err == nil && !replaced { | 
					
						
							|  |  |  | 			dirty.addTx(tx) | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-10 23:54:58 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-17 15:50:34 +03:00
										 |  |  | 	validTxMeter.Mark(int64(len(dirty.accounts))) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	return errs, dirty | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							|  |  |  | 	status := make([]TxStatus, len(hashes)) | 
					
						
							|  |  |  | 	for i, hash := range hashes { | 
					
						
							| 
									
										
										
										
											2019-09-17 09:34:28 +02:00
										 |  |  | 		tx := pool.Get(hash) | 
					
						
							|  |  |  | 		if tx == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		from, _ := types.Sender(pool.signer, tx) // already validated | 
					
						
							|  |  |  | 		pool.mu.RLock() | 
					
						
							|  |  |  | 		if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { | 
					
						
							|  |  |  | 			status[i] = TxStatusPending | 
					
						
							|  |  |  | 		} else if txList := pool.queue[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil { | 
					
						
							|  |  |  | 			status[i] = TxStatusQueued | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-09-17 09:34:28 +02:00
										 |  |  | 		// implicit else: the tx may have been included into a block between | 
					
						
							|  |  |  | 		// checking pool.Get and obtaining the lock. In that case, TxStatusUnknown is correct | 
					
						
							|  |  |  | 		pool.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return status | 
					
						
							| 
									
										
										
										
											2014-12-14 18:15:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // Get returns a transaction if it is contained in the pool 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
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-28 19:59:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Has returns an indicator whether txpool has a transaction cached with the | 
					
						
							|  |  |  | // given hash. | 
					
						
							|  |  |  | func (pool *TxPool) Has(hash common.Hash) bool { | 
					
						
							|  |  |  | 	return pool.all.Get(hash) != nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		pool.priced.Removed(1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if pool.locals.contains(addr) { | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		localGauge.Dec(1) | 
					
						
							| 
									
										
										
										
											2018-04-12 12:17:52 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2019-07-17 18:39:41 +08:00
										 |  |  | 			pool.pendingNonces.setIfLower(addr, tx.Nonce()) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			// Reduce the pending counter | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 			pendingGauge.Dec(int64(1 + len(invalids))) | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		if removed, _ := future.Remove(tx); removed { | 
					
						
							|  |  |  | 			// Reduce the queued counter | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 			queuedGauge.Dec(1) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		if future.Empty() { | 
					
						
							|  |  |  | 			delete(pool.queue, addr) | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 			delete(pool.beats, addr) | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-30 11:04:30 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // requestPromoteExecutables requests a pool reset to the new head block. | 
					
						
							|  |  |  | // The returned channel is closed when the reset has occurred. | 
					
						
							|  |  |  | func (pool *TxPool) requestReset(oldHead *types.Header, newHead *types.Header) chan struct{} { | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case pool.reqResetCh <- &txpoolResetRequest{oldHead, newHead}: | 
					
						
							|  |  |  | 		return <-pool.reorgDoneCh | 
					
						
							|  |  |  | 	case <-pool.reorgShutdownCh: | 
					
						
							|  |  |  | 		return pool.reorgShutdownCh | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // requestPromoteExecutables requests transaction promotion checks for the given addresses. | 
					
						
							|  |  |  | // The returned channel is closed when the promotion checks have occurred. | 
					
						
							|  |  |  | func (pool *TxPool) requestPromoteExecutables(set *accountSet) chan struct{} { | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case pool.reqPromoteCh <- set: | 
					
						
							|  |  |  | 		return <-pool.reorgDoneCh | 
					
						
							|  |  |  | 	case <-pool.reorgShutdownCh: | 
					
						
							|  |  |  | 		return pool.reorgShutdownCh | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // queueTxEvent enqueues a transaction event to be sent in the next reorg run. | 
					
						
							|  |  |  | func (pool *TxPool) queueTxEvent(tx *types.Transaction) { | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case pool.queueTxEventCh <- tx: | 
					
						
							|  |  |  | 	case <-pool.reorgShutdownCh: | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // scheduleReorgLoop schedules runs of reset and promoteExecutables. Code above should not | 
					
						
							|  |  |  | // call those methods directly, but request them being run using requestReset and | 
					
						
							|  |  |  | // requestPromoteExecutables instead. | 
					
						
							|  |  |  | func (pool *TxPool) scheduleReorgLoop() { | 
					
						
							|  |  |  | 	defer pool.wg.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		curDone       chan struct{} // non-nil while runReorg is active | 
					
						
							|  |  |  | 		nextDone      = make(chan struct{}) | 
					
						
							|  |  |  | 		launchNextRun bool | 
					
						
							|  |  |  | 		reset         *txpoolResetRequest | 
					
						
							|  |  |  | 		dirtyAccounts *accountSet | 
					
						
							|  |  |  | 		queuedEvents  = make(map[common.Address]*txSortedMap) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		// Launch next background reorg if needed | 
					
						
							|  |  |  | 		if curDone == nil && launchNextRun { | 
					
						
							|  |  |  | 			// Run the background reorg and announcements | 
					
						
							|  |  |  | 			go pool.runReorg(nextDone, reset, dirtyAccounts, queuedEvents) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Prepare everything for the next round of reorg | 
					
						
							|  |  |  | 			curDone, nextDone = nextDone, make(chan struct{}) | 
					
						
							|  |  |  | 			launchNextRun = false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			reset, dirtyAccounts = nil, nil | 
					
						
							|  |  |  | 			queuedEvents = make(map[common.Address]*txSortedMap) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case req := <-pool.reqResetCh: | 
					
						
							|  |  |  | 			// Reset request: update head if request is already pending. | 
					
						
							|  |  |  | 			if reset == nil { | 
					
						
							|  |  |  | 				reset = req | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				reset.newHead = req.newHead | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			launchNextRun = true | 
					
						
							|  |  |  | 			pool.reorgDoneCh <- nextDone | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case req := <-pool.reqPromoteCh: | 
					
						
							|  |  |  | 			// Promote request: update address set if request is already pending. | 
					
						
							|  |  |  | 			if dirtyAccounts == nil { | 
					
						
							|  |  |  | 				dirtyAccounts = req | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				dirtyAccounts.merge(req) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			launchNextRun = true | 
					
						
							|  |  |  | 			pool.reorgDoneCh <- nextDone | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case tx := <-pool.queueTxEventCh: | 
					
						
							|  |  |  | 			// Queue up the event, but don't schedule a reorg. It's up to the caller to | 
					
						
							|  |  |  | 			// request one later if they want the events sent. | 
					
						
							|  |  |  | 			addr, _ := types.Sender(pool.signer, tx) | 
					
						
							|  |  |  | 			if _, ok := queuedEvents[addr]; !ok { | 
					
						
							|  |  |  | 				queuedEvents[addr] = newTxSortedMap() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			queuedEvents[addr].Put(tx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-curDone: | 
					
						
							|  |  |  | 			curDone = nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-pool.reorgShutdownCh: | 
					
						
							|  |  |  | 			// Wait for current run to finish. | 
					
						
							|  |  |  | 			if curDone != nil { | 
					
						
							|  |  |  | 				<-curDone | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			close(nextDone) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop. | 
					
						
							|  |  |  | func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*txSortedMap) { | 
					
						
							|  |  |  | 	defer close(done) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var promoteAddrs []common.Address | 
					
						
							| 
									
										
										
										
											2020-08-04 17:51:53 +08:00
										 |  |  | 	if dirtyAccounts != nil && reset == nil { | 
					
						
							|  |  |  | 		// Only dirty accounts need to be promoted, unless we're resetting. | 
					
						
							|  |  |  | 		// For resets, all addresses in the tx queue will be promoted and | 
					
						
							|  |  |  | 		// the flatten operation can be avoided. | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		promoteAddrs = dirtyAccounts.flatten() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pool.mu.Lock() | 
					
						
							|  |  |  | 	if reset != nil { | 
					
						
							|  |  |  | 		// Reset from the old head to the new, rescheduling any reorged transactions | 
					
						
							|  |  |  | 		pool.reset(reset.oldHead, reset.newHead) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Nonces were reset, discard any events that became stale | 
					
						
							|  |  |  | 		for addr := range events { | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | 			events[addr].Forward(pool.pendingNonces.get(addr)) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 			if events[addr].Len() == 0 { | 
					
						
							|  |  |  | 				delete(events, addr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Reset needs promote for all addresses | 
					
						
							| 
									
										
										
										
											2020-08-04 17:51:53 +08:00
										 |  |  | 		promoteAddrs = make([]common.Address, 0, len(pool.queue)) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		for addr := range pool.queue { | 
					
						
							|  |  |  | 			promoteAddrs = append(promoteAddrs, addr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Check for pending transactions for every account that sent new ones | 
					
						
							|  |  |  | 	promoted := pool.promoteExecutables(promoteAddrs) | 
					
						
							| 
									
										
										
										
											2020-06-03 00:52:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	// If a new block appeared, validate the pool of pending transactions. This will | 
					
						
							|  |  |  | 	// remove any transaction that has been included in the block or was invalidated | 
					
						
							|  |  |  | 	// because of another transaction (e.g. higher gas price). | 
					
						
							|  |  |  | 	if reset != nil { | 
					
						
							|  |  |  | 		pool.demoteUnexecutables() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure pool.queue and pool.pending sizes stay within the configured limits. | 
					
						
							|  |  |  | 	pool.truncatePending() | 
					
						
							|  |  |  | 	pool.truncateQueue() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Update all accounts to the latest known pending nonce | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							| 
									
										
										
										
											2020-07-14 21:42:32 +02:00
										 |  |  | 		highestPending := list.LastElement() | 
					
						
							|  |  |  | 		pool.pendingNonces.set(addr, highestPending.Nonce()+1) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	pool.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Notify subsystems for newly added transactions | 
					
						
							| 
									
										
										
										
											2020-06-03 00:52:20 +08:00
										 |  |  | 	for _, tx := range promoted { | 
					
						
							|  |  |  | 		addr, _ := types.Sender(pool.signer, tx) | 
					
						
							|  |  |  | 		if _, ok := events[addr]; !ok { | 
					
						
							|  |  |  | 			events[addr] = newTxSortedMap() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		events[addr].Put(tx) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	if len(events) > 0 { | 
					
						
							|  |  |  | 		var txs []*types.Transaction | 
					
						
							|  |  |  | 		for _, set := range events { | 
					
						
							|  |  |  | 			txs = append(txs, set.Flatten()...) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		pool.txFeed.Send(NewTxsEvent{txs}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // reset retrieves the current state of the blockchain and ensures the content | 
					
						
							|  |  |  | // of the transaction pool is valid with regard to the chain state. | 
					
						
							|  |  |  | 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 { | 
					
						
							|  |  |  | 		// 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 { | 
					
						
							|  |  |  | 			log.Debug("Skipping deep transaction reorg", "depth", depth) | 
					
						
							|  |  |  | 		} 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()) | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 			if rem == nil { | 
					
						
							|  |  |  | 				// This can happen if a setHead is performed, where we simply discard the old | 
					
						
							|  |  |  | 				// head from the chain. | 
					
						
							|  |  |  | 				// If that is the case, we don't have the lost transactions any more, and | 
					
						
							|  |  |  | 				// there's nothing to add | 
					
						
							|  |  |  | 				if newNum < oldNum { | 
					
						
							|  |  |  | 					// If the reorg ended up on a lower number, it's indicative of setHead being the cause | 
					
						
							|  |  |  | 					log.Debug("Skipping transaction reset caused by setHead", | 
					
						
							|  |  |  | 						"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// If we reorged to a same or higher number, then it's not a case of setHead | 
					
						
							|  |  |  | 					log.Warn("Transaction pool reset with missing oldhead", | 
					
						
							|  |  |  | 						"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			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 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			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 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			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 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			reinject = types.TxDifference(discarded, included) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Initialize the internal state to the current head | 
					
						
							|  |  |  | 	if newHead == nil { | 
					
						
							|  |  |  | 		newHead = pool.chain.CurrentBlock().Header() // Special case during testing | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	statedb, err := pool.chain.StateAt(newHead.Root) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		log.Error("Failed to reset txpool state", "err", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pool.currentState = statedb | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | 	pool.pendingNonces = newTxNoncer(statedb) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	pool.currentMaxGas = newHead.GasLimit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Inject any transactions discarded due to reorgs | 
					
						
							|  |  |  | 	log.Debug("Reinjecting stale transactions", "count", len(reinject)) | 
					
						
							|  |  |  | 	senderCacher.recover(pool.signer, reinject) | 
					
						
							|  |  |  | 	pool.addTxsLocked(reinject, false) | 
					
						
							| 
									
										
										
										
											2019-08-14 20:53:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Update all fork indicator by next pending block number. | 
					
						
							|  |  |  | 	next := new(big.Int).Add(newHead.Number, big.NewInt(1)) | 
					
						
							|  |  |  | 	pool.istanbul = pool.chainconfig.IsIstanbul(next) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +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. | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Transaction { | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	// Track the promoted transactions to broadcast them at once | 
					
						
							|  |  |  | 	var promoted []*types.Transaction | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		forwards := list.Forward(pool.currentState.GetNonce(addr)) | 
					
						
							|  |  |  | 		for _, tx := range forwards { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 		log.Trace("Removed old queued transactions", "count", len(forwards)) | 
					
						
							| 
									
										
										
										
											2017-05-30 00:31:37 +03:00
										 |  |  | 		// Drop all transactions that are too costly (low balance or out of gas) | 
					
						
							| 
									
										
										
										
											2020-07-09 14:02:03 +02: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() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 		log.Trace("Removed unpayable queued transactions", "count", len(drops)) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		queuedNofundsMeter.Mark(int64(len(drops))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// Gather all executable transactions and promote them | 
					
						
							| 
									
										
										
										
											2019-07-09 10:34:35 +03:00
										 |  |  | 		readies := list.Ready(pool.pendingNonces.get(addr)) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		for _, tx := range readies { | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 				promoted = append(promoted, tx) | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 		log.Trace("Promoted queued transactions", "count", len(promoted)) | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		queuedGauge.Dec(int64(len(readies))) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		// Drop all transactions over the allowed limit | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		var caps types.Transactions | 
					
						
							| 
									
										
										
										
											2017-07-05 16:51:55 +03:00
										 |  |  | 		if !pool.locals.contains(addr) { | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			caps = list.Cap(int(pool.config.AccountQueue)) | 
					
						
							|  |  |  | 			for _, tx := range caps { | 
					
						
							| 
									
										
										
										
											2017-06-30 22:55:10 +02:00
										 |  |  | 				hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 				pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2017-06-30 22:55:10 +02:00
										 |  |  | 				log.Trace("Removed cap-exceeding queued transaction", "hash", hash) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			queuedRateLimitMeter.Mark(int64(len(caps))) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Mark all the items dropped as removed | 
					
						
							|  |  |  | 		pool.priced.Removed(len(forwards) + len(drops) + len(caps)) | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		queuedGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		if pool.locals.contains(addr) { | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 			localGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2020-07-08 16:27:04 +08:00
										 |  |  | 			delete(pool.beats, addr) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	return promoted | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // truncatePending removes transactions from the pending queue if the pool is above the | 
					
						
							|  |  |  | // pending limit. The algorithm tries to reduce transaction counts by an approximately | 
					
						
							|  |  |  | // equal number for all for accounts with many pending transactions. | 
					
						
							|  |  |  | func (pool *TxPool) truncatePending() { | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 	pending := uint64(0) | 
					
						
							|  |  |  | 	for _, list := range pool.pending { | 
					
						
							|  |  |  | 		pending += uint64(list.Len()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	if pending <= pool.config.GlobalSlots { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pendingBeforeCap := pending | 
					
						
							|  |  |  | 	// Assemble a spam order to penalize large transactors first | 
					
						
							|  |  |  | 	spammers := prque.New(nil) | 
					
						
							|  |  |  | 	for addr, list := range pool.pending { | 
					
						
							|  |  |  | 		// Only evict transactions from high rollers | 
					
						
							|  |  |  | 		if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { | 
					
						
							|  |  |  | 			spammers.Push(addr, int64(list.Len())) | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Gradually drop transactions from offenders | 
					
						
							|  |  |  | 	offenders := []common.Address{} | 
					
						
							|  |  |  | 	for pending > pool.config.GlobalSlots && !spammers.Empty() { | 
					
						
							|  |  |  | 		// Retrieve the next offender if not local address | 
					
						
							|  |  |  | 		offender, _ := spammers.Pop() | 
					
						
							|  |  |  | 		offenders = append(offenders, offender.(common.Address)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Equalize balances until all the same or below threshold | 
					
						
							|  |  |  | 		if len(offenders) > 1 { | 
					
						
							|  |  |  | 			// Calculate the equalization threshold for all current offenders | 
					
						
							|  |  |  | 			threshold := pool.pending[offender.(common.Address)].Len() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Iteratively reduce all offenders until below limit or threshold reached | 
					
						
							|  |  |  | 			for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { | 
					
						
							|  |  |  | 				for i := 0; i < len(offenders)-1; i++ { | 
					
						
							|  |  |  | 					list := pool.pending[offenders[i]] | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					caps := list.Cap(list.Len() - 1) | 
					
						
							|  |  |  | 					for _, tx := range caps { | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 						// 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
										 |  |  | 
 | 
					
						
							|  |  |  | 						// Update the account nonce to the dropped transaction | 
					
						
							| 
									
										
										
										
											2019-07-17 18:39:41 +08:00
										 |  |  | 						pool.pendingNonces.setIfLower(offenders[i], tx.Nonce()) | 
					
						
							| 
									
										
										
										
											2017-06-22 17:01:49 +03:00
										 |  |  | 						log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 					pool.priced.Removed(len(caps)) | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 					pendingGauge.Dec(int64(len(caps))) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 					if pool.locals.contains(offenders[i]) { | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 						localGauge.Dec(int64(len(caps))) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-10-14 15:32:06 +03:00
										 |  |  | 					pending-- | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If still above threshold, reduce to limit or min allowance | 
					
						
							|  |  |  | 	if pending > pool.config.GlobalSlots && len(offenders) > 0 { | 
					
						
							|  |  |  | 		for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { | 
					
						
							|  |  |  | 			for _, addr := range offenders { | 
					
						
							|  |  |  | 				list := pool.pending[addr] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				caps := list.Cap(list.Len() - 1) | 
					
						
							|  |  |  | 				for _, tx := range caps { | 
					
						
							|  |  |  | 					// Drop the transaction from the global pools too | 
					
						
							|  |  |  | 					hash := tx.Hash() | 
					
						
							|  |  |  | 					pool.all.Remove(hash) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// Update the account nonce to the dropped transaction | 
					
						
							| 
									
										
										
										
											2019-07-17 18:39:41 +08:00
										 |  |  | 					pool.pendingNonces.setIfLower(addr, tx.Nonce()) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 					log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				pool.priced.Removed(len(caps)) | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 				pendingGauge.Dec(int64(len(caps))) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 				if pool.locals.contains(addr) { | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 					localGauge.Dec(int64(len(caps))) | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				pending-- | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pendingRateLimitMeter.Mark(int64(pendingBeforeCap - pending)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // truncateQueue drops the oldes transactions in the queue if the pool is above the global queue limit. | 
					
						
							|  |  |  | func (pool *TxPool) truncateQueue() { | 
					
						
							| 
									
										
										
										
											2017-07-06 11:51:59 +03:00
										 |  |  | 	queued := uint64(0) | 
					
						
							|  |  |  | 	for _, list := range pool.queue { | 
					
						
							|  |  |  | 		queued += uint64(list.Len()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	if queued <= pool.config.GlobalQueue { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Sort all accounts with queued transactions by heartbeat | 
					
						
							|  |  |  | 	addresses := make(addressesByHeartbeat, 0, len(pool.queue)) | 
					
						
							|  |  |  | 	for addr := range pool.queue { | 
					
						
							|  |  |  | 		if !pool.locals.contains(addr) { // don't drop locals | 
					
						
							|  |  |  | 			addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	sort.Sort(addresses) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02: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; { | 
					
						
							|  |  |  | 		addr := addresses[len(addresses)-1] | 
					
						
							|  |  |  | 		list := pool.queue[addr.address] | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		addresses = addresses[:len(addresses)-1] | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 		// Drop all transactions if they are less than the overflow | 
					
						
							|  |  |  | 		if size := uint64(list.Len()); size <= drop { | 
					
						
							|  |  |  | 			for _, tx := range list.Flatten() { | 
					
						
							|  |  |  | 				pool.removeTx(tx.Hash(), true) | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 			drop -= size | 
					
						
							|  |  |  | 			queuedRateLimitMeter.Mark(int64(size)) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Otherwise drop only last few transactions | 
					
						
							|  |  |  | 		txs := list.Flatten() | 
					
						
							|  |  |  | 		for i := len(txs) - 1; i >= 0 && drop > 0; i-- { | 
					
						
							|  |  |  | 			pool.removeTx(txs[i].Hash(), true) | 
					
						
							|  |  |  | 			drop-- | 
					
						
							|  |  |  | 			queuedRateLimitMeter.Mark(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) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		olds := list.Forward(nonce) | 
					
						
							|  |  |  | 		for _, tx := range olds { | 
					
						
							| 
									
										
										
										
											2017-02-28 13:35:17 +02:00
										 |  |  | 			hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 			pool.all.Remove(hash) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			log.Trace("Removed old pending transaction", "hash", hash) | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2020-07-09 14:02:03 +02: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) | 
					
						
							| 
									
										
										
										
											2015-12-30 18:31:37 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		pool.priced.Removed(len(olds) + len(drops)) | 
					
						
							|  |  |  | 		pendingNofundsMeter.Mark(int64(len(drops))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 		pendingGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 		if pool.locals.contains(addr) { | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 			localGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +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 { | 
					
						
							| 
									
										
										
										
											2019-06-10 14:21:02 +03:00
										 |  |  | 			gapped := list.Cap(0) | 
					
						
							|  |  |  | 			for _, tx := range gapped { | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 				hash := tx.Hash() | 
					
						
							|  |  |  | 				log.Error("Demoting invalidated transaction", "hash", hash) | 
					
						
							|  |  |  | 				pool.enqueueTx(hash, tx) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-09-10 14:39:07 +03:00
										 |  |  | 			pendingGauge.Dec(int64(len(gapped))) | 
					
						
							| 
									
										
										
										
											2020-08-20 09:49:35 +02:00
										 |  |  | 			// This might happen in a reorg, so log it to the metering | 
					
						
							|  |  |  | 			blockReorgInvalidatedTx.Mark(int64(len(gapped))) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:35:00 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-22 21:15:01 -04:00
										 |  |  | 		// Delete the entire pending entry if it became empty. | 
					
						
							| 
									
										
										
										
											2016-07-01 18:59:55 +03:00
										 |  |  | 		if list.Empty() { | 
					
						
							|  |  |  | 			delete(pool.pending, 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-25 12:25:14 +01:00
										 |  |  | type addressesByHeartbeat []addressByHeartbeat | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-25 12:25:14 +01:00
										 |  |  | func (a addressesByHeartbeat) Len() int           { return len(a) } | 
					
						
							|  |  |  | func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } | 
					
						
							|  |  |  | func (a addressesByHeartbeat) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | 
					
						
							| 
									
										
										
										
											2016-08-17 16:53:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | 	cache    *[]common.Address | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | func newAccountSet(signer types.Signer, addrs ...common.Address) *accountSet { | 
					
						
							|  |  |  | 	as := &accountSet{ | 
					
						
							| 
									
										
										
										
											2017-06-30 22:43:26 +02:00
										 |  |  | 		accounts: make(map[common.Address]struct{}), | 
					
						
							|  |  |  | 		signer:   signer, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | 	for _, addr := range addrs { | 
					
						
							|  |  |  | 		as.add(addr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return as | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 21:42:32 +02:00
										 |  |  | func (as *accountSet) empty() bool { | 
					
						
							|  |  |  | 	return len(as.accounts) == 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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{}{} | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | 	as.cache = nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // addTx adds the sender of tx into the set. | 
					
						
							|  |  |  | func (as *accountSet) addTx(tx *types.Transaction) { | 
					
						
							|  |  |  | 	if addr, err := types.Sender(as.signer, tx); err == nil { | 
					
						
							|  |  |  | 		as.add(addr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | // flatten returns the list of addresses within this set, also caching it for later | 
					
						
							|  |  |  | // reuse. The returned slice should not be changed! | 
					
						
							|  |  |  | func (as *accountSet) flatten() []common.Address { | 
					
						
							|  |  |  | 	if as.cache == nil { | 
					
						
							|  |  |  | 		accounts := make([]common.Address, 0, len(as.accounts)) | 
					
						
							|  |  |  | 		for account := range as.accounts { | 
					
						
							|  |  |  | 			accounts = append(accounts, account) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		as.cache = &accounts | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return *as.cache | 
					
						
							| 
									
										
										
										
											2015-11-21 00:40:36 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 10:29:14 +02:00
										 |  |  | // merge adds all addresses from the 'other' set into 'as'. | 
					
						
							|  |  |  | func (as *accountSet) merge(other *accountSet) { | 
					
						
							|  |  |  | 	for addr := range other.accounts { | 
					
						
							|  |  |  | 		as.accounts[addr] = struct{}{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	as.cache = nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 	all   map[common.Hash]*types.Transaction | 
					
						
							|  |  |  | 	slots int | 
					
						
							|  |  |  | 	lock  sync.RWMutex | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | // Slots returns the current number of slots used in the lookup. | 
					
						
							|  |  |  | func (t *txLookup) Slots() int { | 
					
						
							|  |  |  | 	t.lock.RLock() | 
					
						
							|  |  |  | 	defer t.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return t.slots | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | // Add adds a transaction to the lookup. | 
					
						
							|  |  |  | func (t *txLookup) Add(tx *types.Transaction) { | 
					
						
							|  |  |  | 	t.lock.Lock() | 
					
						
							|  |  |  | 	defer t.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 	t.slots += numSlots(tx) | 
					
						
							|  |  |  | 	slotsGauge.Update(int64(t.slots)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 	t.slots -= numSlots(t.all[hash]) | 
					
						
							|  |  |  | 	slotsGauge.Update(int64(t.slots)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-23 08:55:42 -04:00
										 |  |  | 	delete(t.all, hash) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-01-10 11:40:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // numSlots calculates the number of slots needed for a single transaction. | 
					
						
							|  |  |  | func numSlots(tx *types.Transaction) int { | 
					
						
							|  |  |  | 	return int((tx.Size() + txSlotSize - 1) / txSlotSize) | 
					
						
							|  |  |  | } |