Merge pull request #14523 from karalabe/txpool-cli-flags
cmd, core, eth: configurable txpool parameters
This commit is contained in:
		@@ -66,6 +66,13 @@ var (
 | 
			
		||||
		utils.EthashDatasetDirFlag,
 | 
			
		||||
		utils.EthashDatasetsInMemoryFlag,
 | 
			
		||||
		utils.EthashDatasetsOnDiskFlag,
 | 
			
		||||
		utils.TxPoolPriceLimitFlag,
 | 
			
		||||
		utils.TxPoolPriceBumpFlag,
 | 
			
		||||
		utils.TxPoolAccountSlotsFlag,
 | 
			
		||||
		utils.TxPoolGlobalSlotsFlag,
 | 
			
		||||
		utils.TxPoolAccountQueueFlag,
 | 
			
		||||
		utils.TxPoolGlobalQueueFlag,
 | 
			
		||||
		utils.TxPoolLifetimeFlag,
 | 
			
		||||
		utils.FastSyncFlag,
 | 
			
		||||
		utils.LightModeFlag,
 | 
			
		||||
		utils.SyncModeFlag,
 | 
			
		||||
 
 | 
			
		||||
@@ -92,6 +92,18 @@ var AppHelpFlagGroups = []flagGroup{
 | 
			
		||||
			utils.EthashDatasetsOnDiskFlag,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "TRANSACTION POOL",
 | 
			
		||||
		Flags: []cli.Flag{
 | 
			
		||||
			utils.TxPoolPriceLimitFlag,
 | 
			
		||||
			utils.TxPoolPriceBumpFlag,
 | 
			
		||||
			utils.TxPoolAccountSlotsFlag,
 | 
			
		||||
			utils.TxPoolGlobalSlotsFlag,
 | 
			
		||||
			utils.TxPoolAccountQueueFlag,
 | 
			
		||||
			utils.TxPoolGlobalQueueFlag,
 | 
			
		||||
			utils.TxPoolLifetimeFlag,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "PERFORMANCE TUNING",
 | 
			
		||||
		Flags: []cli.Flag{
 | 
			
		||||
 
 | 
			
		||||
@@ -123,35 +123,6 @@ var (
 | 
			
		||||
		Name:  "nousb",
 | 
			
		||||
		Usage: "Disables monitoring for and managine USB hardware wallets",
 | 
			
		||||
	}
 | 
			
		||||
	EthashCacheDirFlag = DirectoryFlag{
 | 
			
		||||
		Name:  "ethash.cachedir",
 | 
			
		||||
		Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
 | 
			
		||||
	}
 | 
			
		||||
	EthashCachesInMemoryFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.cachesinmem",
 | 
			
		||||
		Usage: "Number of recent ethash caches to keep in memory (16MB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashCachesInMem,
 | 
			
		||||
	}
 | 
			
		||||
	EthashCachesOnDiskFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.cachesondisk",
 | 
			
		||||
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashCachesOnDisk,
 | 
			
		||||
	}
 | 
			
		||||
	EthashDatasetDirFlag = DirectoryFlag{
 | 
			
		||||
		Name:  "ethash.dagdir",
 | 
			
		||||
		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
 | 
			
		||||
		Value: DirectoryString{eth.DefaultConfig.EthashDatasetDir},
 | 
			
		||||
	}
 | 
			
		||||
	EthashDatasetsInMemoryFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.dagsinmem",
 | 
			
		||||
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashDatasetsInMem,
 | 
			
		||||
	}
 | 
			
		||||
	EthashDatasetsOnDiskFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.dagsondisk",
 | 
			
		||||
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashDatasetsOnDisk,
 | 
			
		||||
	}
 | 
			
		||||
	NetworkIdFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "networkid",
 | 
			
		||||
		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
 | 
			
		||||
@@ -207,6 +178,72 @@ var (
 | 
			
		||||
		Name:  "lightkdf",
 | 
			
		||||
		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
 | 
			
		||||
	}
 | 
			
		||||
	// Ethash settings
 | 
			
		||||
	EthashCacheDirFlag = DirectoryFlag{
 | 
			
		||||
		Name:  "ethash.cachedir",
 | 
			
		||||
		Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
 | 
			
		||||
	}
 | 
			
		||||
	EthashCachesInMemoryFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.cachesinmem",
 | 
			
		||||
		Usage: "Number of recent ethash caches to keep in memory (16MB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashCachesInMem,
 | 
			
		||||
	}
 | 
			
		||||
	EthashCachesOnDiskFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.cachesondisk",
 | 
			
		||||
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashCachesOnDisk,
 | 
			
		||||
	}
 | 
			
		||||
	EthashDatasetDirFlag = DirectoryFlag{
 | 
			
		||||
		Name:  "ethash.dagdir",
 | 
			
		||||
		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
 | 
			
		||||
		Value: DirectoryString{eth.DefaultConfig.EthashDatasetDir},
 | 
			
		||||
	}
 | 
			
		||||
	EthashDatasetsInMemoryFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.dagsinmem",
 | 
			
		||||
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashDatasetsInMem,
 | 
			
		||||
	}
 | 
			
		||||
	EthashDatasetsOnDiskFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "ethash.dagsondisk",
 | 
			
		||||
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
 | 
			
		||||
		Value: eth.DefaultConfig.EthashDatasetsOnDisk,
 | 
			
		||||
	}
 | 
			
		||||
	// Transaction pool settings
 | 
			
		||||
	TxPoolPriceLimitFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "txpool.pricelimit",
 | 
			
		||||
		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.PriceLimit,
 | 
			
		||||
	}
 | 
			
		||||
	TxPoolPriceBumpFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "txpool.pricebump",
 | 
			
		||||
		Usage: "Price bump percentage to replace an already existing transaction",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.PriceBump,
 | 
			
		||||
	}
 | 
			
		||||
	TxPoolAccountSlotsFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "txpool.accountslots",
 | 
			
		||||
		Usage: "Minimum number of executable transaction slots guaranteed per account",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.AccountSlots,
 | 
			
		||||
	}
 | 
			
		||||
	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "txpool.globalslots",
 | 
			
		||||
		Usage: "Maximum number of executable transaction slots for all accounts",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.GlobalSlots,
 | 
			
		||||
	}
 | 
			
		||||
	TxPoolAccountQueueFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "txpool.accountqueue",
 | 
			
		||||
		Usage: "Maximum number of non-executable transaction slots permitted per account",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.AccountQueue,
 | 
			
		||||
	}
 | 
			
		||||
	TxPoolGlobalQueueFlag = cli.Uint64Flag{
 | 
			
		||||
		Name:  "txpool.globalqueue",
 | 
			
		||||
		Usage: "Maximum number of non-executable transaction slots for all accounts",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.GlobalQueue,
 | 
			
		||||
	}
 | 
			
		||||
	TxPoolLifetimeFlag = cli.DurationFlag{
 | 
			
		||||
		Name:  "txpool.lifetime",
 | 
			
		||||
		Usage: "Maximum amount of time non-executable transaction are queued",
 | 
			
		||||
		Value: eth.DefaultConfig.TxPool.Lifetime,
 | 
			
		||||
	}
 | 
			
		||||
	// Performance tuning settings
 | 
			
		||||
	CacheFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "cache",
 | 
			
		||||
@@ -784,6 +821,30 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) {
 | 
			
		||||
		cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) {
 | 
			
		||||
		cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) {
 | 
			
		||||
		cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) {
 | 
			
		||||
		cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) {
 | 
			
		||||
		cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) {
 | 
			
		||||
		cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) {
 | 
			
		||||
		cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setEthash(ctx *cli.Context, cfg *eth.Config) {
 | 
			
		||||
	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
 | 
			
		||||
		cfg.EthashCacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
 | 
			
		||||
@@ -826,6 +887,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
 | 
			
		||||
	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
 | 
			
		||||
	setEtherbase(ctx, ks, cfg)
 | 
			
		||||
	setGPO(ctx, &cfg.GPO)
 | 
			
		||||
	setTxPool(ctx, &cfg.TxPool)
 | 
			
		||||
	setEthash(ctx, cfg)
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
 
 | 
			
		||||
@@ -246,11 +246,11 @@ func (l *txList) Overlaps(tx *types.Transaction) bool {
 | 
			
		||||
//
 | 
			
		||||
// If the new transaction is accepted into the list, the lists' cost threshold
 | 
			
		||||
// is also potentially updated.
 | 
			
		||||
func (l *txList) Add(tx *types.Transaction) (bool, *types.Transaction) {
 | 
			
		||||
func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) {
 | 
			
		||||
	// If there's an older better transaction, abort
 | 
			
		||||
	old := l.txs.Get(tx.Nonce())
 | 
			
		||||
	if old != nil {
 | 
			
		||||
		threshold := new(big.Int).Div(new(big.Int).Mul(old.GasPrice(), big.NewInt(100+minPriceBumpPercent)), big.NewInt(100))
 | 
			
		||||
		threshold := new(big.Int).Div(new(big.Int).Mul(old.GasPrice(), big.NewInt(100+int64(priceBump))), big.NewInt(100))
 | 
			
		||||
		if threshold.Cmp(tx.GasPrice()) >= 0 {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ func TestStrictTxListAdd(t *testing.T) {
 | 
			
		||||
	// Insert the transactions in a random order
 | 
			
		||||
	list := newTxList(true)
 | 
			
		||||
	for _, v := range rand.Perm(len(txs)) {
 | 
			
		||||
		list.Add(txs[v])
 | 
			
		||||
		list.Add(txs[v], DefaultTxPoolConfig.PriceBump)
 | 
			
		||||
	}
 | 
			
		||||
	// Verify internal state
 | 
			
		||||
	if len(list.txs.items) != len(txs) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										101
									
								
								core/tx_pool.go
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								core/tx_pool.go
									
									
									
									
									
								
							@@ -48,14 +48,8 @@ var (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	minPendingPerAccount = uint64(16)      // Min number of guaranteed transaction slots per address
 | 
			
		||||
	maxPendingTotal      = uint64(4096)    // Max limit of pending transactions from all accounts (soft)
 | 
			
		||||
	maxQueuedPerAccount  = uint64(64)      // Max limit of queued transactions per address
 | 
			
		||||
	maxQueuedTotal       = uint64(1024)    // Max limit of queued transactions from all accounts
 | 
			
		||||
	maxQueuedLifetime    = 3 * time.Hour   // Max amount of time transactions from idle accounts are queued
 | 
			
		||||
	minPriceBumpPercent  = int64(10)       // Minimum price bump needed to replace an old transaction
 | 
			
		||||
	evictionInterval     = time.Minute     // Time interval to check for evictable transactions
 | 
			
		||||
	statsReportInterval  = 8 * time.Second // Time interval to report transaction pool stats
 | 
			
		||||
	evictionInterval    = time.Minute     // Time interval to check for evictable transactions
 | 
			
		||||
	statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -78,6 +72,48 @@ var (
 | 
			
		||||
 | 
			
		||||
type stateFn func() (*state.StateDB, error)
 | 
			
		||||
 | 
			
		||||
// TxPoolConfig are the configuration parameters of the transaction pool.
 | 
			
		||||
type TxPoolConfig struct {
 | 
			
		||||
	PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
 | 
			
		||||
	PriceBump  uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)
 | 
			
		||||
 | 
			
		||||
	AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account
 | 
			
		||||
	GlobalSlots  uint64 // Maximum number of executable transaction slots for all accounts
 | 
			
		||||
	AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
 | 
			
		||||
	GlobalQueue  uint64 // Maximum number of non-executable transaction slots for all accounts
 | 
			
		||||
 | 
			
		||||
	Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultTxPoolConfig contains the default configurations for the transaction
 | 
			
		||||
// pool.
 | 
			
		||||
var DefaultTxPoolConfig = TxPoolConfig{
 | 
			
		||||
	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
 | 
			
		||||
	if conf.PriceLimit < 1 {
 | 
			
		||||
		log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit)
 | 
			
		||||
		conf.PriceLimit = DefaultTxPoolConfig.PriceLimit
 | 
			
		||||
	}
 | 
			
		||||
	if conf.PriceBump < 1 {
 | 
			
		||||
		log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump)
 | 
			
		||||
		conf.PriceBump = DefaultTxPoolConfig.PriceBump
 | 
			
		||||
	}
 | 
			
		||||
	return conf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
@@ -86,7 +122,8 @@ type stateFn func() (*state.StateDB, error)
 | 
			
		||||
// current state) and future transactions. Transactions move between those
 | 
			
		||||
// two states over time as they are received and processed.
 | 
			
		||||
type TxPool struct {
 | 
			
		||||
	config       *params.ChainConfig
 | 
			
		||||
	config       TxPoolConfig
 | 
			
		||||
	chainconfig  *params.ChainConfig
 | 
			
		||||
	currentState stateFn // The state function which will allow us to do some pre checks
 | 
			
		||||
	pendingState *state.ManagedState
 | 
			
		||||
	gasLimit     func() *big.Int // The current gas limit function callback
 | 
			
		||||
@@ -109,10 +146,17 @@ type TxPool struct {
 | 
			
		||||
	homestead bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
 | 
			
		||||
// NewTxPool creates a new transaction pool to gather, sort and filter inbound
 | 
			
		||||
// trnsactions from the network.
 | 
			
		||||
func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
 | 
			
		||||
	// Sanitize the input to ensure no vulnerable gas prices are set
 | 
			
		||||
	config = (&config).sanitize()
 | 
			
		||||
 | 
			
		||||
	// Create the transaction pool with its initial settings
 | 
			
		||||
	pool := &TxPool{
 | 
			
		||||
		config:       config,
 | 
			
		||||
		signer:       types.NewEIP155Signer(config.ChainId),
 | 
			
		||||
		chainconfig:  chainconfig,
 | 
			
		||||
		signer:       types.NewEIP155Signer(chainconfig.ChainId),
 | 
			
		||||
		pending:      make(map[common.Address]*txList),
 | 
			
		||||
		queue:        make(map[common.Address]*txList),
 | 
			
		||||
		beats:        make(map[common.Address]time.Time),
 | 
			
		||||
@@ -120,7 +164,7 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState
 | 
			
		||||
		eventMux:     eventMux,
 | 
			
		||||
		currentState: currentStateFn,
 | 
			
		||||
		gasLimit:     gasLimitFn,
 | 
			
		||||
		gasPrice:     big.NewInt(1),
 | 
			
		||||
		gasPrice:     new(big.Int).SetUint64(config.PriceLimit),
 | 
			
		||||
		pendingState: nil,
 | 
			
		||||
		locals:       newTxSet(),
 | 
			
		||||
		events:       eventMux.Subscribe(ChainHeadEvent{}, RemovedTransactionEvent{}),
 | 
			
		||||
@@ -129,6 +173,7 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState
 | 
			
		||||
	pool.priced = newTxPricedList(&pool.all)
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Start the various events loops and return
 | 
			
		||||
	pool.wg.Add(2)
 | 
			
		||||
	go pool.eventLoop()
 | 
			
		||||
	go pool.expirationLoop()
 | 
			
		||||
@@ -159,7 +204,7 @@ func (pool *TxPool) eventLoop() {
 | 
			
		||||
			case ChainHeadEvent:
 | 
			
		||||
				pool.mu.Lock()
 | 
			
		||||
				if ev.Block != nil {
 | 
			
		||||
					if pool.config.IsHomestead(ev.Block.Number()) {
 | 
			
		||||
					if pool.chainconfig.IsHomestead(ev.Block.Number()) {
 | 
			
		||||
						pool.homestead = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
@@ -388,7 +433,7 @@ func (pool *TxPool) add(tx *types.Transaction) (bool, error) {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	// If the transaction pool is full, discard underpriced transactions
 | 
			
		||||
	if uint64(len(pool.all)) >= maxPendingTotal+maxQueuedTotal {
 | 
			
		||||
	if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
 | 
			
		||||
		// If the new transaction is underpriced, don't accept it
 | 
			
		||||
		if pool.priced.Underpriced(tx, pool.locals) {
 | 
			
		||||
			log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
 | 
			
		||||
@@ -396,7 +441,7 @@ func (pool *TxPool) add(tx *types.Transaction) (bool, error) {
 | 
			
		||||
			return false, ErrUnderpriced
 | 
			
		||||
		}
 | 
			
		||||
		// New transaction is better than our worse ones, make room for it
 | 
			
		||||
		drop := pool.priced.Discard(len(pool.all)-int(maxPendingTotal+maxQueuedTotal-1), pool.locals)
 | 
			
		||||
		drop := pool.priced.Discard(len(pool.all)-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals)
 | 
			
		||||
		for _, tx := range drop {
 | 
			
		||||
			log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice())
 | 
			
		||||
			underpricedTxCounter.Inc(1)
 | 
			
		||||
@@ -407,7 +452,7 @@ func (pool *TxPool) add(tx *types.Transaction) (bool, error) {
 | 
			
		||||
	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
 | 
			
		||||
		inserted, old := list.Add(tx)
 | 
			
		||||
		inserted, old := list.Add(tx, pool.config.PriceBump)
 | 
			
		||||
		if !inserted {
 | 
			
		||||
			pendingDiscardCounter.Inc(1)
 | 
			
		||||
			return false, ErrReplaceUnderpriced
 | 
			
		||||
@@ -442,7 +487,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er
 | 
			
		||||
	if pool.queue[from] == nil {
 | 
			
		||||
		pool.queue[from] = newTxList(false)
 | 
			
		||||
	}
 | 
			
		||||
	inserted, old := pool.queue[from].Add(tx)
 | 
			
		||||
	inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump)
 | 
			
		||||
	if !inserted {
 | 
			
		||||
		// An older transaction was better, discard this
 | 
			
		||||
		queuedDiscardCounter.Inc(1)
 | 
			
		||||
@@ -469,7 +514,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
 | 
			
		||||
	}
 | 
			
		||||
	list := pool.pending[addr]
 | 
			
		||||
 | 
			
		||||
	inserted, old := list.Add(tx)
 | 
			
		||||
	inserted, old := list.Add(tx, pool.config.PriceBump)
 | 
			
		||||
	if !inserted {
 | 
			
		||||
		// An older transaction was better, discard this
 | 
			
		||||
		delete(pool.all, hash)
 | 
			
		||||
@@ -644,7 +689,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
			pool.promoteTx(addr, hash, tx)
 | 
			
		||||
		}
 | 
			
		||||
		// Drop all transactions over the allowed limit
 | 
			
		||||
		for _, tx := range list.Cap(int(maxQueuedPerAccount)) {
 | 
			
		||||
		for _, tx := range list.Cap(int(pool.config.AccountQueue)) {
 | 
			
		||||
			hash := tx.Hash()
 | 
			
		||||
			log.Trace("Removed cap-exceeding queued transaction", "hash", hash)
 | 
			
		||||
			delete(pool.all, hash)
 | 
			
		||||
@@ -663,13 +708,13 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
	for _, list := range pool.pending {
 | 
			
		||||
		pending += uint64(list.Len())
 | 
			
		||||
	}
 | 
			
		||||
	if pending > maxPendingTotal {
 | 
			
		||||
	if pending > pool.config.GlobalSlots {
 | 
			
		||||
		pendingBeforeCap := pending
 | 
			
		||||
		// Assemble a spam order to penalize large transactors first
 | 
			
		||||
		spammers := prque.New()
 | 
			
		||||
		for addr, list := range pool.pending {
 | 
			
		||||
			// Only evict transactions from high rollers
 | 
			
		||||
			if uint64(list.Len()) > minPendingPerAccount {
 | 
			
		||||
			if uint64(list.Len()) > pool.config.AccountSlots {
 | 
			
		||||
				// Skip local accounts as pools should maintain backlogs for themselves
 | 
			
		||||
				for _, tx := range list.txs.items {
 | 
			
		||||
					if !pool.locals.contains(tx.Hash()) {
 | 
			
		||||
@@ -681,7 +726,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
		}
 | 
			
		||||
		// Gradually drop transactions from offenders
 | 
			
		||||
		offenders := []common.Address{}
 | 
			
		||||
		for pending > maxPendingTotal && !spammers.Empty() {
 | 
			
		||||
		for pending > pool.config.GlobalSlots && !spammers.Empty() {
 | 
			
		||||
			// Retrieve the next offender if not local address
 | 
			
		||||
			offender, _ := spammers.Pop()
 | 
			
		||||
			offenders = append(offenders, offender.(common.Address))
 | 
			
		||||
@@ -692,7 +737,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
				threshold := pool.pending[offender.(common.Address)].Len()
 | 
			
		||||
 | 
			
		||||
				// Iteratively reduce all offenders until below limit or threshold reached
 | 
			
		||||
				for pending > maxPendingTotal && pool.pending[offenders[len(offenders)-2]].Len() > threshold {
 | 
			
		||||
				for 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]]
 | 
			
		||||
						list.Cap(list.Len() - 1)
 | 
			
		||||
@@ -702,8 +747,8 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// If still above threshold, reduce to limit or min allowance
 | 
			
		||||
		if pending > maxPendingTotal && len(offenders) > 0 {
 | 
			
		||||
			for pending > maxPendingTotal && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > minPendingPerAccount {
 | 
			
		||||
		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]
 | 
			
		||||
					list.Cap(list.Len() - 1)
 | 
			
		||||
@@ -714,7 +759,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
		pendingRLCounter.Inc(int64(pendingBeforeCap - pending))
 | 
			
		||||
	}
 | 
			
		||||
	// If we've queued more transactions than the hard limit, drop oldest ones
 | 
			
		||||
	if queued > maxQueuedTotal {
 | 
			
		||||
	if queued > pool.config.GlobalQueue {
 | 
			
		||||
		// Sort all accounts with queued transactions by heartbeat
 | 
			
		||||
		addresses := make(addresssByHeartbeat, 0, len(pool.queue))
 | 
			
		||||
		for addr := range pool.queue {
 | 
			
		||||
@@ -723,7 +768,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
 | 
			
		||||
		sort.Sort(addresses)
 | 
			
		||||
 | 
			
		||||
		// Drop transactions until the total is below the limit
 | 
			
		||||
		for drop := queued - maxQueuedTotal; drop > 0; {
 | 
			
		||||
		for drop := queued - pool.config.GlobalQueue; drop > 0; {
 | 
			
		||||
			addr := addresses[len(addresses)-1]
 | 
			
		||||
			list := pool.queue[addr.address]
 | 
			
		||||
 | 
			
		||||
@@ -800,7 +845,7 @@ func (pool *TxPool) expirationLoop() {
 | 
			
		||||
		case <-evict.C:
 | 
			
		||||
			pool.mu.Lock()
 | 
			
		||||
			for addr := range pool.queue {
 | 
			
		||||
				if time.Since(pool.beats[addr]) > maxQueuedLifetime {
 | 
			
		||||
				if time.Since(pool.beats[addr]) > pool.config.Lifetime {
 | 
			
		||||
					for _, tx := range pool.queue[addr].Flatten() {
 | 
			
		||||
						pool.removeTx(tx.Hash())
 | 
			
		||||
					}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	key, _ := crypto.GenerateKey()
 | 
			
		||||
	newPool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	newPool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	newPool.resetState()
 | 
			
		||||
 | 
			
		||||
	return newPool, key
 | 
			
		||||
@@ -95,7 +95,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
 | 
			
		||||
 | 
			
		||||
	txpool := NewTxPool(params.TestChainConfig, mux, stateFunc, gasLimitFunc)
 | 
			
		||||
	txpool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, mux, stateFunc, gasLimitFunc)
 | 
			
		||||
	txpool.resetState()
 | 
			
		||||
 | 
			
		||||
	nonce := txpool.State().GetNonce(address)
 | 
			
		||||
@@ -533,25 +533,25 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Keep queuing up transactions and make sure all above a limit are dropped
 | 
			
		||||
	for i := uint64(1); i <= maxQueuedPerAccount+5; i++ {
 | 
			
		||||
	for i := uint64(1); i <= DefaultTxPoolConfig.AccountQueue+5; i++ {
 | 
			
		||||
		if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil {
 | 
			
		||||
			t.Fatalf("tx %d: failed to add transaction: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
		if len(pool.pending) != 0 {
 | 
			
		||||
			t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), 0)
 | 
			
		||||
		}
 | 
			
		||||
		if i <= maxQueuedPerAccount {
 | 
			
		||||
		if i <= DefaultTxPoolConfig.AccountQueue {
 | 
			
		||||
			if pool.queue[account].Len() != int(i) {
 | 
			
		||||
				t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), i)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if pool.queue[account].Len() != int(maxQueuedPerAccount) {
 | 
			
		||||
				t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), maxQueuedPerAccount)
 | 
			
		||||
			if pool.queue[account].Len() != int(DefaultTxPoolConfig.AccountQueue) {
 | 
			
		||||
				t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), DefaultTxPoolConfig.AccountQueue)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(pool.all) != int(maxQueuedPerAccount) {
 | 
			
		||||
		t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), maxQueuedPerAccount)
 | 
			
		||||
	if len(pool.all) != int(DefaultTxPoolConfig.AccountQueue) {
 | 
			
		||||
		t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), DefaultTxPoolConfig.AccountQueue)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -559,14 +559,14 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
 | 
			
		||||
// some threshold, the higher transactions are dropped to prevent DOS attacks.
 | 
			
		||||
func TestTransactionQueueGlobalLimiting(t *testing.T) {
 | 
			
		||||
	// Reduce the queue limits to shorten test time
 | 
			
		||||
	defer func(old uint64) { maxQueuedTotal = old }(maxQueuedTotal)
 | 
			
		||||
	maxQueuedTotal = maxQueuedPerAccount * 3
 | 
			
		||||
	defer func(old uint64) { DefaultTxPoolConfig.GlobalQueue = old }(DefaultTxPoolConfig.GlobalQueue)
 | 
			
		||||
	DefaultTxPoolConfig.GlobalQueue = DefaultTxPoolConfig.AccountQueue * 3
 | 
			
		||||
 | 
			
		||||
	// Create the pool to test the limit enforcement with
 | 
			
		||||
	db, _ := ethdb.NewMemDatabase()
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Create a number of test accounts and fund them
 | 
			
		||||
@@ -580,7 +580,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
 | 
			
		||||
	// Generate and queue a batch of transactions
 | 
			
		||||
	nonces := make(map[common.Address]uint64)
 | 
			
		||||
 | 
			
		||||
	txs := make(types.Transactions, 0, 3*maxQueuedTotal)
 | 
			
		||||
	txs := make(types.Transactions, 0, 3*DefaultTxPoolConfig.GlobalQueue)
 | 
			
		||||
	for len(txs) < cap(txs) {
 | 
			
		||||
		key := keys[rand.Intn(len(keys))]
 | 
			
		||||
		addr := crypto.PubkeyToAddress(key.PublicKey)
 | 
			
		||||
@@ -593,13 +593,13 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	queued := 0
 | 
			
		||||
	for addr, list := range pool.queue {
 | 
			
		||||
		if list.Len() > int(maxQueuedPerAccount) {
 | 
			
		||||
			t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), maxQueuedPerAccount)
 | 
			
		||||
		if list.Len() > int(DefaultTxPoolConfig.AccountQueue) {
 | 
			
		||||
			t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), DefaultTxPoolConfig.AccountQueue)
 | 
			
		||||
		}
 | 
			
		||||
		queued += list.Len()
 | 
			
		||||
	}
 | 
			
		||||
	if queued > int(maxQueuedTotal) {
 | 
			
		||||
		t.Fatalf("total transactions overflow allowance: %d > %d", queued, maxQueuedTotal)
 | 
			
		||||
	if queued > int(DefaultTxPoolConfig.GlobalQueue) {
 | 
			
		||||
		t.Fatalf("total transactions overflow allowance: %d > %d", queued, DefaultTxPoolConfig.GlobalQueue)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -608,9 +608,9 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
 | 
			
		||||
// on shuffling them around.
 | 
			
		||||
func TestTransactionQueueTimeLimiting(t *testing.T) {
 | 
			
		||||
	// Reduce the queue limits to shorten test time
 | 
			
		||||
	defer func(old time.Duration) { maxQueuedLifetime = old }(maxQueuedLifetime)
 | 
			
		||||
	defer func(old time.Duration) { DefaultTxPoolConfig.Lifetime = old }(DefaultTxPoolConfig.Lifetime)
 | 
			
		||||
	defer func(old time.Duration) { evictionInterval = old }(evictionInterval)
 | 
			
		||||
	maxQueuedLifetime = time.Second
 | 
			
		||||
	DefaultTxPoolConfig.Lifetime = time.Second
 | 
			
		||||
	evictionInterval = time.Second
 | 
			
		||||
 | 
			
		||||
	// Create a test account and fund it
 | 
			
		||||
@@ -621,7 +621,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
 | 
			
		||||
	state.AddBalance(account, big.NewInt(1000000))
 | 
			
		||||
 | 
			
		||||
	// Queue up a batch of transactions
 | 
			
		||||
	for i := uint64(1); i <= maxQueuedPerAccount; i++ {
 | 
			
		||||
	for i := uint64(1); i <= DefaultTxPoolConfig.AccountQueue; i++ {
 | 
			
		||||
		if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil {
 | 
			
		||||
			t.Fatalf("tx %d: failed to add transaction: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -646,7 +646,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Keep queuing up transactions and make sure all above a limit are dropped
 | 
			
		||||
	for i := uint64(0); i < maxQueuedPerAccount+5; i++ {
 | 
			
		||||
	for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ {
 | 
			
		||||
		if err := pool.Add(transaction(i, big.NewInt(100000), key)); err != nil {
 | 
			
		||||
			t.Fatalf("tx %d: failed to add transaction: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -657,8 +657,8 @@ func TestTransactionPendingLimiting(t *testing.T) {
 | 
			
		||||
			t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(pool.all) != int(maxQueuedPerAccount+5) {
 | 
			
		||||
		t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), maxQueuedPerAccount+5)
 | 
			
		||||
	if len(pool.all) != int(DefaultTxPoolConfig.AccountQueue+5) {
 | 
			
		||||
		t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), DefaultTxPoolConfig.AccountQueue+5)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -674,7 +674,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
 | 
			
		||||
	state1, _ := pool1.currentState()
 | 
			
		||||
	state1.AddBalance(account1, big.NewInt(1000000))
 | 
			
		||||
 | 
			
		||||
	for i := uint64(0); i < maxQueuedPerAccount+5; i++ {
 | 
			
		||||
	for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ {
 | 
			
		||||
		if err := pool1.Add(transaction(origin+i, big.NewInt(100000), key1)); err != nil {
 | 
			
		||||
			t.Fatalf("tx %d: failed to add transaction: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -686,7 +686,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
 | 
			
		||||
	state2.AddBalance(account2, big.NewInt(1000000))
 | 
			
		||||
 | 
			
		||||
	txns := []*types.Transaction{}
 | 
			
		||||
	for i := uint64(0); i < maxQueuedPerAccount+5; i++ {
 | 
			
		||||
	for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ {
 | 
			
		||||
		txns = append(txns, transaction(origin+i, big.NewInt(100000), key2))
 | 
			
		||||
	}
 | 
			
		||||
	pool2.AddBatch(txns)
 | 
			
		||||
@@ -708,14 +708,14 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
 | 
			
		||||
// attacks.
 | 
			
		||||
func TestTransactionPendingGlobalLimiting(t *testing.T) {
 | 
			
		||||
	// Reduce the queue limits to shorten test time
 | 
			
		||||
	defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal)
 | 
			
		||||
	maxPendingTotal = minPendingPerAccount * 10
 | 
			
		||||
	defer func(old uint64) { DefaultTxPoolConfig.GlobalSlots = old }(DefaultTxPoolConfig.GlobalSlots)
 | 
			
		||||
	DefaultTxPoolConfig.GlobalSlots = DefaultTxPoolConfig.AccountSlots * 10
 | 
			
		||||
 | 
			
		||||
	// Create the pool to test the limit enforcement with
 | 
			
		||||
	db, _ := ethdb.NewMemDatabase()
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Create a number of test accounts and fund them
 | 
			
		||||
@@ -732,7 +732,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
 | 
			
		||||
	txs := types.Transactions{}
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		addr := crypto.PubkeyToAddress(key.PublicKey)
 | 
			
		||||
		for j := 0; j < int(maxPendingTotal)/len(keys)*2; j++ {
 | 
			
		||||
		for j := 0; j < int(DefaultTxPoolConfig.GlobalSlots)/len(keys)*2; j++ {
 | 
			
		||||
			txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key))
 | 
			
		||||
			nonces[addr]++
 | 
			
		||||
		}
 | 
			
		||||
@@ -744,8 +744,8 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
 | 
			
		||||
	for _, list := range pool.pending {
 | 
			
		||||
		pending += list.Len()
 | 
			
		||||
	}
 | 
			
		||||
	if pending > int(maxPendingTotal) {
 | 
			
		||||
		t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, maxPendingTotal)
 | 
			
		||||
	if pending > int(DefaultTxPoolConfig.GlobalSlots) {
 | 
			
		||||
		t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, DefaultTxPoolConfig.GlobalSlots)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -754,14 +754,14 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
 | 
			
		||||
// the transactions are still kept.
 | 
			
		||||
func TestTransactionPendingMinimumAllowance(t *testing.T) {
 | 
			
		||||
	// Reduce the queue limits to shorten test time
 | 
			
		||||
	defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal)
 | 
			
		||||
	maxPendingTotal = 0
 | 
			
		||||
	defer func(old uint64) { DefaultTxPoolConfig.GlobalSlots = old }(DefaultTxPoolConfig.GlobalSlots)
 | 
			
		||||
	DefaultTxPoolConfig.GlobalSlots = 0
 | 
			
		||||
 | 
			
		||||
	// Create the pool to test the limit enforcement with
 | 
			
		||||
	db, _ := ethdb.NewMemDatabase()
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Create a number of test accounts and fund them
 | 
			
		||||
@@ -778,7 +778,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
 | 
			
		||||
	txs := types.Transactions{}
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		addr := crypto.PubkeyToAddress(key.PublicKey)
 | 
			
		||||
		for j := 0; j < int(minPendingPerAccount)*2; j++ {
 | 
			
		||||
		for j := 0; j < int(DefaultTxPoolConfig.AccountSlots)*2; j++ {
 | 
			
		||||
			txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key))
 | 
			
		||||
			nonces[addr]++
 | 
			
		||||
		}
 | 
			
		||||
@@ -787,8 +787,8 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
 | 
			
		||||
	pool.AddBatch(txs)
 | 
			
		||||
 | 
			
		||||
	for addr, list := range pool.pending {
 | 
			
		||||
		if list.Len() != int(minPendingPerAccount) {
 | 
			
		||||
			t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), minPendingPerAccount)
 | 
			
		||||
		if list.Len() != int(DefaultTxPoolConfig.AccountSlots) {
 | 
			
		||||
			t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), DefaultTxPoolConfig.AccountSlots)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -803,7 +803,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
 | 
			
		||||
	db, _ := ethdb.NewMemDatabase()
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Create a number of test accounts and fund them
 | 
			
		||||
@@ -874,17 +874,17 @@ func TestTransactionPoolRepricing(t *testing.T) {
 | 
			
		||||
// Note, local transactions are never allowed to be dropped.
 | 
			
		||||
func TestTransactionPoolUnderpricing(t *testing.T) {
 | 
			
		||||
	// Reduce the queue limits to shorten test time
 | 
			
		||||
	defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal)
 | 
			
		||||
	maxPendingTotal = 2
 | 
			
		||||
	defer func(old uint64) { DefaultTxPoolConfig.GlobalSlots = old }(DefaultTxPoolConfig.GlobalSlots)
 | 
			
		||||
	DefaultTxPoolConfig.GlobalSlots = 2
 | 
			
		||||
 | 
			
		||||
	defer func(old uint64) { maxQueuedTotal = old }(maxQueuedTotal)
 | 
			
		||||
	maxQueuedTotal = 2
 | 
			
		||||
	defer func(old uint64) { DefaultTxPoolConfig.GlobalQueue = old }(DefaultTxPoolConfig.GlobalQueue)
 | 
			
		||||
	DefaultTxPoolConfig.GlobalQueue = 2
 | 
			
		||||
 | 
			
		||||
	// Create the pool to test the pricing enforcement with
 | 
			
		||||
	db, _ := ethdb.NewMemDatabase()
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Create a number of test accounts and fund them
 | 
			
		||||
@@ -960,7 +960,7 @@ func TestTransactionReplacement(t *testing.T) {
 | 
			
		||||
	db, _ := ethdb.NewMemDatabase()
 | 
			
		||||
	statedb, _ := state.New(common.Hash{}, db)
 | 
			
		||||
 | 
			
		||||
	pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
 | 
			
		||||
	pool.resetState()
 | 
			
		||||
 | 
			
		||||
	// Create a a test account to add transactions with
 | 
			
		||||
@@ -971,7 +971,7 @@ func TestTransactionReplacement(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too)
 | 
			
		||||
	price := int64(100)
 | 
			
		||||
	threshold := (price * (100 + minPriceBumpPercent)) / 100
 | 
			
		||||
	threshold := (price * (100 + int64(DefaultTxPoolConfig.PriceBump))) / 100
 | 
			
		||||
 | 
			
		||||
	if err := pool.Add(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), key)); err != nil {
 | 
			
		||||
		t.Fatalf("failed to add original cheap pending transaction: %v", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -150,7 +150,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 | 
			
		||||
		core.WriteChainConfig(chainDb, genesisHash, chainConfig)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
 | 
			
		||||
	newPool := core.NewTxPool(config.TxPool, eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
 | 
			
		||||
	eth.txPool = newPool
 | 
			
		||||
 | 
			
		||||
	maxPeers := config.MaxPeers
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ var DefaultConfig = Config{
 | 
			
		||||
	DatabaseCache:        128,
 | 
			
		||||
	GasPrice:             big.NewInt(18 * params.Shannon),
 | 
			
		||||
 | 
			
		||||
	TxPool: core.DefaultTxPoolConfig,
 | 
			
		||||
	GPO: gasprice.Config{
 | 
			
		||||
		Blocks:     10,
 | 
			
		||||
		Percentile: 50,
 | 
			
		||||
@@ -99,6 +100,9 @@ type Config struct {
 | 
			
		||||
	EthashDatasetsInMem  int
 | 
			
		||||
	EthashDatasetsOnDisk int
 | 
			
		||||
 | 
			
		||||
	// Transaction pool options
 | 
			
		||||
	TxPool core.TxPoolConfig
 | 
			
		||||
 | 
			
		||||
	// Gas Price Oracle options
 | 
			
		||||
	GPO gasprice.Config
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
 | 
			
		||||
		EthashDatasetDir        string
 | 
			
		||||
		EthashDatasetsInMem     int
 | 
			
		||||
		EthashDatasetsOnDisk    int
 | 
			
		||||
		TxPool                  core.TxPoolConfig
 | 
			
		||||
		GPO                     gasprice.Config
 | 
			
		||||
		EnablePreimageRecording bool
 | 
			
		||||
		DocRoot                 string `toml:"-"`
 | 
			
		||||
@@ -60,6 +61,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
 | 
			
		||||
	enc.EthashDatasetDir = c.EthashDatasetDir
 | 
			
		||||
	enc.EthashDatasetsInMem = c.EthashDatasetsInMem
 | 
			
		||||
	enc.EthashDatasetsOnDisk = c.EthashDatasetsOnDisk
 | 
			
		||||
	enc.TxPool = c.TxPool
 | 
			
		||||
	enc.GPO = c.GPO
 | 
			
		||||
	enc.EnablePreimageRecording = c.EnablePreimageRecording
 | 
			
		||||
	enc.DocRoot = c.DocRoot
 | 
			
		||||
@@ -90,6 +92,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
 | 
			
		||||
		EthashDatasetDir        *string
 | 
			
		||||
		EthashDatasetsInMem     *int
 | 
			
		||||
		EthashDatasetsOnDisk    *int
 | 
			
		||||
		TxPool                  *core.TxPoolConfig
 | 
			
		||||
		GPO                     *gasprice.Config
 | 
			
		||||
		EnablePreimageRecording *bool
 | 
			
		||||
		DocRoot                 *string `toml:"-"`
 | 
			
		||||
@@ -158,6 +161,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
 | 
			
		||||
	if dec.EthashDatasetsOnDisk != nil {
 | 
			
		||||
		c.EthashDatasetsOnDisk = *dec.EthashDatasetsOnDisk
 | 
			
		||||
	}
 | 
			
		||||
	if dec.TxPool != nil {
 | 
			
		||||
		c.TxPool = *dec.TxPool
 | 
			
		||||
	}
 | 
			
		||||
	if dec.GPO != nil {
 | 
			
		||||
		c.GPO = *dec.GPO
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user