all: refactor txpool into it's own package in prep for 4844 (#26038)

This commit is contained in:
Daniel Liu 2024-06-10 20:14:49 +08:00
parent 05797846fc
commit 8b2e8d9b3a
29 changed files with 425 additions and 506 deletions

View file

@ -38,6 +38,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
@ -261,12 +262,12 @@ var (
TxPoolJournalFlag = cli.StringFlag{ TxPoolJournalFlag = cli.StringFlag{
Name: "txpool.journal", Name: "txpool.journal",
Usage: "Disk journal for local transaction to survive node restarts", Usage: "Disk journal for local transaction to survive node restarts",
Value: core.DefaultTxPoolConfig.Journal, Value: txpool.DefaultConfig.Journal,
} }
TxPoolRejournalFlag = cli.DurationFlag{ TxPoolRejournalFlag = cli.DurationFlag{
Name: "txpool.rejournal", Name: "txpool.rejournal",
Usage: "Time interval to regenerate the local transaction journal", Usage: "Time interval to regenerate the local transaction journal",
Value: core.DefaultTxPoolConfig.Rejournal, Value: txpool.DefaultConfig.Rejournal,
} }
TxPoolPriceLimitFlag = cli.Uint64Flag{ TxPoolPriceLimitFlag = cli.Uint64Flag{
Name: "txpool.pricelimit", Name: "txpool.pricelimit",
@ -1032,7 +1033,7 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) {
} }
} }
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { func setTxPool(ctx *cli.Context, cfg *txpool.Config) {
if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
} }

View file

@ -41,6 +41,7 @@ import (
randomizeContract "github.com/XinFinOrg/XDPoSChain/contracts/randomize/contract" randomizeContract "github.com/XinFinOrg/XDPoSChain/contracts/randomize/contract"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
@ -60,7 +61,7 @@ type RewardLog struct {
var TxSignMu sync.RWMutex var TxSignMu sync.RWMutex
// Send tx sign for block number to smart contract blockSigner. // Send tx sign for block number to smart contract blockSigner.
func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, manager *accounts.Manager, block *types.Block, chainDb ethdb.Database, eb common.Address) error { func CreateTransactionSign(chainConfig *params.ChainConfig, pool *txpool.TxPool, manager *accounts.Manager, block *types.Block, chainDb ethdb.Database, eb common.Address) error {
TxSignMu.Lock() TxSignMu.Lock()
defer TxSignMu.Unlock() defer TxSignMu.Unlock()
if chainConfig.XDPoS != nil { if chainConfig.XDPoS != nil {

View file

@ -60,10 +60,9 @@ var (
CheckpointCh = make(chan int) CheckpointCh = make(chan int)
ErrNoGenesis = errors.New("Genesis not found in chain") ErrNoGenesis = errors.New("Genesis not found in chain")
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
blockReorgInvalidatedTx = metrics.NewRegisteredMeter("chain/reorg/invalidTx", nil)
) )
const ( const (
@ -1440,7 +1439,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []
defer close(abort) defer close(abort)
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain)
// Iterate over the blocks and insert when the verifier permits // Iterate over the blocks and insert when the verifier permits
for i, block := range chain { for i, block := range chain {

View file

@ -26,13 +26,13 @@ var (
// ErrKnownBlock is returned when a block to import is already known locally. // ErrKnownBlock is returned when a block to import is already known locally.
ErrKnownBlock = errors.New("block already known") ErrKnownBlock = errors.New("block already known")
// ErrGasLimitReached is returned by the gas pool if the amount of gas required
// by a transaction is higher than what's left in the block.
ErrGasLimitReached = errors.New("gas limit reached")
// ErrBlacklistedHash is returned if a block to import is on the blacklist. // ErrBlacklistedHash is returned if a block to import is on the blacklist.
ErrBlacklistedHash = errors.New("blacklisted hash") ErrBlacklistedHash = errors.New("blacklisted hash")
// ErrNonceTooLow is returned if the nonce of a transaction is lower than the
// one present in the local chain.
ErrNonceTooLow = errors.New("nonce too low")
// ErrNonceTooHigh is returned if the nonce of a transaction is higher than the // ErrNonceTooHigh is returned if the nonce of a transaction is higher than the
// next one expected based on the local chain. // next one expected based on the local chain.
ErrNonceTooHigh = errors.New("nonce too high") ErrNonceTooHigh = errors.New("nonce too high")
@ -41,19 +41,25 @@ var (
// maximum allowed value and would become invalid if incremented. // maximum allowed value and would become invalid if incremented.
ErrNonceMax = errors.New("nonce has max value") ErrNonceMax = errors.New("nonce has max value")
ErrNotXDPoS = errors.New("XDPoS not found in config") // ErrGasLimitReached is returned by the gas pool if the amount of gas required
// by a transaction is higher than what's left in the block.
ErrGasLimitReached = errors.New("gas limit reached")
ErrNotFoundM1 = errors.New("list M1 not found ") // ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
ErrStopPreparingBlock = errors.New("stop calculating a block not verified by M2") // ErrGasUintOverflow is returned when calculating gas usage.
ErrGasUintOverflow = errors.New("gas uint64 overflow")
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")
// ErrTxTypeNotSupported is returned if a transaction is not supported in the // ErrTxTypeNotSupported is returned if a transaction is not supported in the
// current network configuration. // current network configuration.
ErrTxTypeNotSupported = types.ErrTxTypeNotSupported ErrTxTypeNotSupported = types.ErrTxTypeNotSupported
// ErrGasUintOverflow is returned when calculating gas usage.
ErrGasUintOverflow = errors.New("gas uint64 overflow")
// ErrTipAboveFeeCap is a sanity error to ensure no one is able to specify a // ErrTipAboveFeeCap is a sanity error to ensure no one is able to specify a
// transaction with a tip higher than the total fee cap. // transaction with a tip higher than the total fee cap.
ErrTipAboveFeeCap = errors.New("max priority fee per gas higher than max fee per gas") ErrTipAboveFeeCap = errors.New("max priority fee per gas higher than max fee per gas")
@ -72,4 +78,10 @@ var (
// ErrSenderNoEOA is returned if the sender of a transaction is a contract. // ErrSenderNoEOA is returned if the sender of a transaction is a contract.
ErrSenderNoEOA = errors.New("sender not an eoa") ErrSenderNoEOA = errors.New("sender not an eoa")
ErrNotXDPoS = errors.New("XDPoS not found in config")
ErrNotFoundM1 = errors.New("list M1 not found ")
ErrStopPreparingBlock = errors.New("stop calculating a block not verified by M2")
) )

View file

@ -1,91 +0,0 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// 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.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"container/list"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/event"
)
// Implement our EthTest Manager
type TestManager struct {
// stateManager *StateManager
eventMux *event.TypeMux
db ethdb.Database
txPool *TxPool
blockChain *BlockChain
Blocks []*types.Block
}
func (tm *TestManager) IsListening() bool {
return false
}
func (tm *TestManager) IsMining() bool {
return false
}
func (tm *TestManager) PeerCount() int {
return 0
}
func (tm *TestManager) Peers() *list.List {
return list.New()
}
func (tm *TestManager) BlockChain() *BlockChain {
return tm.blockChain
}
func (tm *TestManager) TxPool() *TxPool {
return tm.txPool
}
// func (tm *TestManager) StateManager() *StateManager {
// return tm.stateManager
// }
func (tm *TestManager) EventMux() *event.TypeMux {
return tm.eventMux
}
// func (tm *TestManager) KeyManager() *crypto.KeyManager {
// return nil
// }
func (tm *TestManager) Db() ethdb.Database {
return tm.db
}
func NewTestManager() *TestManager {
db := rawdb.NewMemoryDatabase()
testManager := &TestManager{}
testManager.eventMux = new(event.TypeMux)
testManager.db = db
// testManager.txPool = NewTxPool(testManager)
// testManager.blockChain = NewBlockChain(testManager)
// testManager.stateManager = NewStateManager(testManager)
return testManager
}

View file

@ -22,8 +22,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
) )
// senderCacher is a concurrent tranaction sender recoverer anc cacher. // SenderCacher is a concurrent transaction sender recoverer and cacher.
var senderCacher = newTxSenderCacher(runtime.NumCPU()) var SenderCacher = newTxSenderCacher(runtime.NumCPU())
// txSenderCacherRequest is a request for recovering transaction senders with a // txSenderCacherRequest is a request for recovering transaction senders with a
// specific signature scheme and caching it into the transactions themselves. // specific signature scheme and caching it into the transactions themselves.
@ -67,10 +67,10 @@ func (cacher *txSenderCacher) cache() {
} }
} }
// recover recovers the senders from a batch of transactions and caches them // Recover recovers the senders from a batch of transactions and caches them
// back into the same data structures. There is no validation being done, nor // back into the same data structures. There is no validation being done, nor
// any reaction to invalid signatures. That is up to calling code later. // any reaction to invalid signatures. That is up to calling code later.
func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transaction) { func (cacher *txSenderCacher) Recover(signer types.Signer, txs []*types.Transaction) {
// If there's nothing to recover, abort // If there's nothing to recover, abort
if len(txs) == 0 { if len(txs) == 0 {
return return
@ -89,10 +89,10 @@ func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transact
} }
} }
// recoverFromBlocks recovers the senders from a batch of blocks and caches them // RecoverFromBlocks recovers the senders from a batch of blocks and caches them
// back into the same data structures. There is no validation being done, nor // back into the same data structures. There is no validation being done, nor
// any reaction to invalid signatures. That is up to calling code later. // any reaction to invalid signatures. That is up to calling code later.
func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*types.Block) { func (cacher *txSenderCacher) RecoverFromBlocks(signer types.Signer, blocks []*types.Block) {
count := 0 count := 0
for _, block := range blocks { for _, block := range blocks {
count += len(block.Transactions()) count += len(block.Transactions())
@ -101,5 +101,5 @@ func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*t
for _, block := range blocks { for _, block := range blocks {
txs = append(txs, block.Transactions()...) txs = append(txs, block.Transactions()...)
} }
cacher.recover(signer, txs) cacher.Recover(signer, txs)
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"errors" "errors"
@ -40,23 +40,23 @@ type devNull struct{}
func (*devNull) Write(p []byte) (n int, err error) { return len(p), nil } func (*devNull) Write(p []byte) (n int, err error) { return len(p), nil }
func (*devNull) Close() error { return nil } func (*devNull) Close() error { return nil }
// txJournal is a rotating log of transactions with the aim of storing locally // journal is a rotating log of transactions with the aim of storing locally
// created transactions to allow non-executed ones to survive node restarts. // created transactions to allow non-executed ones to survive node restarts.
type txJournal struct { type journal struct {
path string // Filesystem path to store the transactions at path string // Filesystem path to store the transactions at
writer io.WriteCloser // Output stream to write new transactions into writer io.WriteCloser // Output stream to write new transactions into
} }
// newTxJournal creates a new transaction journal to // newTxJournal creates a new transaction journal to
func newTxJournal(path string) *txJournal { func newTxJournal(path string) *journal {
return &txJournal{ return &journal{
path: path, path: path,
} }
} }
// load parses a transaction journal dump from disk, loading its contents into // load parses a transaction journal dump from disk, loading its contents into
// the specified pool. // the specified pool.
func (journal *txJournal) load(add func([]*types.Transaction) []error) error { func (journal *journal) load(add func([]*types.Transaction) []error) error {
// Skip the parsing if the journal file doens't exist at all // Skip the parsing if the journal file doens't exist at all
if _, err := os.Stat(journal.path); os.IsNotExist(err) { if _, err := os.Stat(journal.path); os.IsNotExist(err) {
return nil return nil
@ -116,7 +116,7 @@ func (journal *txJournal) load(add func([]*types.Transaction) []error) error {
} }
// insert adds the specified transaction to the local disk journal. // insert adds the specified transaction to the local disk journal.
func (journal *txJournal) insert(tx *types.Transaction) error { func (journal *journal) insert(tx *types.Transaction) error {
if journal.writer == nil { if journal.writer == nil {
return errNoActiveJournal return errNoActiveJournal
} }
@ -128,7 +128,7 @@ func (journal *txJournal) insert(tx *types.Transaction) error {
// rotate regenerates the transaction journal based on the current contents of // rotate regenerates the transaction journal based on the current contents of
// the transaction pool. // the transaction pool.
func (journal *txJournal) rotate(all map[common.Address]types.Transactions) error { func (journal *journal) rotate(all map[common.Address]types.Transactions) error {
// Close the current journal (if any is open) // Close the current journal (if any is open)
if journal.writer != nil { if journal.writer != nil {
if err := journal.writer.Close(); err != nil { if err := journal.writer.Close(); err != nil {
@ -168,7 +168,7 @@ func (journal *txJournal) rotate(all map[common.Address]types.Transactions) erro
} }
// close flushes the transaction journal contents to disk and closes the file. // close flushes the transaction journal contents to disk and closes the file.
func (journal *txJournal) close() error { func (journal *journal) close() error {
var err error var err error
if journal.writer != nil { if journal.writer != nil {

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"errors" "errors"
@ -29,6 +29,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/event"
@ -75,7 +76,7 @@ type blockChainLending interface {
GetBlock(hash common.Hash, number uint64) *types.Block GetBlock(hash common.Hash, number uint64) *types.Block
LendingStateAt(block *types.Block) (*lendingstate.LendingStateDB, error) LendingStateAt(block *types.Block) (*lendingstate.LendingStateDB, error)
StateAt(root common.Hash) (*state.StateDB, error) StateAt(root common.Hash) (*state.StateDB, error)
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
Engine() consensus.Engine Engine() consensus.Engine
// GetHeader returns the hash corresponding to their hash. // GetHeader returns the hash corresponding to their hash.
GetHeader(common.Hash, uint64) *types.Header GetHeader(common.Hash, uint64) *types.Header
@ -124,7 +125,7 @@ type LendingPool struct {
txFeed event.Feed txFeed event.Feed
scope event.SubscriptionScope scope event.SubscriptionScope
chainHeadCh chan ChainHeadEvent chainHeadCh chan core.ChainHeadEvent
chainHeadSub event.Subscription chainHeadSub event.Subscription
signer types.LendingSigner signer types.LendingSigner
mu sync.RWMutex mu sync.RWMutex
@ -161,7 +162,7 @@ func NewLendingPool(chainconfig *params.ChainConfig, chain blockChainLending) *L
queue: make(map[common.Address]*lendingtxList), queue: make(map[common.Address]*lendingtxList),
beats: make(map[common.Address]time.Time), beats: make(map[common.Address]time.Time),
all: make(map[common.Hash]*types.LendingTransaction), all: make(map[common.Hash]*types.LendingTransaction),
chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
} }
pool.locals = newLendingAccountSet(pool.signer) pool.locals = newLendingAccountSet(pool.signer)
pool.reset(nil, chain.CurrentBlock()) pool.reset(nil, chain.CurrentBlock())
@ -334,7 +335,7 @@ func (pool *LendingPool) Stop() {
// SubscribeTxPreEvent registers a subscription of TxPreEvent and // SubscribeTxPreEvent registers a subscription of TxPreEvent and
// starts sending event to the given channel. // starts sending event to the given channel.
func (pool *LendingPool) SubscribeTxPreEvent(ch chan<- LendingTxPreEvent) event.Subscription { func (pool *LendingPool) SubscribeTxPreEvent(ch chan<- core.LendingTxPreEvent) event.Subscription {
return pool.scope.Track(pool.txFeed.Subscribe(ch)) return pool.scope.Track(pool.txFeed.Subscribe(ch))
} }
@ -514,7 +515,7 @@ func (pool *LendingPool) validateTopupLending(cloneStateDb *state.StateDB, clone
func (pool *LendingPool) validateBalance(cloneStateDb *state.StateDB, cloneLendingStateDb *lendingstate.LendingStateDB, tx *types.LendingTransaction, collateralToken common.Address) error { func (pool *LendingPool) validateBalance(cloneStateDb *state.StateDB, cloneLendingStateDb *lendingstate.LendingStateDB, tx *types.LendingTransaction, collateralToken common.Address) error {
XDPoSEngine, ok := pool.chain.Engine().(*XDPoS.XDPoS) XDPoSEngine, ok := pool.chain.Engine().(*XDPoS.XDPoS)
if !ok { if !ok {
return ErrNotXDPoS return core.ErrNotXDPoS
} }
XDCXServ := XDPoSEngine.GetXDCXService() XDCXServ := XDPoSEngine.GetXDCXService()
lendingServ := XDPoSEngine.GetLendingService() lendingServ := XDPoSEngine.GetLendingService()
@ -641,10 +642,10 @@ func (pool *LendingPool) validateTx(tx *types.LendingTransaction, local bool) er
} }
// Ensure the transaction adheres to nonce lending // Ensure the transaction adheres to nonce lending
if pool.currentLendingState.GetNonce(from.Hash()) > tx.Nonce() { if pool.currentLendingState.GetNonce(from.Hash()) > tx.Nonce() {
return ErrNonceTooLow return core.ErrNonceTooLow
} }
if pool.pendingState.GetNonce(from.Hash())+common.LimitThresholdNonceInQueue < tx.Nonce() { if pool.pendingState.GetNonce(from.Hash())+common.LimitThresholdNonceInQueue < tx.Nonce() {
return ErrNonceTooHigh return core.ErrNonceTooHigh
} }
return nil return nil
@ -778,7 +779,7 @@ func (pool *LendingPool) promoteTx(addr common.Address, hash common.Hash, tx *ty
pool.beats[addr] = time.Now() pool.beats[addr] = time.Now()
pool.pendingState.SetNonce(addr.Hash(), tx.Nonce()+1) pool.pendingState.SetNonce(addr.Hash(), tx.Nonce()+1)
go pool.txFeed.Send(LendingTxPreEvent{tx}) go pool.txFeed.Send(core.LendingTxPreEvent{Tx: tx})
} }
// AddLocal enqueues a single transaction into the pool if it is valid, marking // AddLocal enqueues a single transaction into the pool if it is valid, marking

View file

@ -1,4 +1,4 @@
package core package txpool
import ( import (
"context" "context"

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"io" "io"

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"container/heap" "container/heap"

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"container/heap" "container/heap"
@ -49,30 +49,30 @@ func (h *nonceHeap) Pop() interface{} {
return x return x
} }
// txSortedMap is a nonce->transaction hash map with a heap based index to allow // sortedMap is a nonce->transaction hash map with a heap based index to allow
// iterating over the contents in a nonce-incrementing way. // iterating over the contents in a nonce-incrementing way.
type txSortedMap struct { type sortedMap struct {
items map[uint64]*types.Transaction // Hash map storing the transaction data items map[uint64]*types.Transaction // Hash map storing the transaction data
index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
cache types.Transactions // Cache of the transactions already sorted cache types.Transactions // Cache of the transactions already sorted
} }
// newTxSortedMap creates a new nonce-sorted transaction map. // newSortedMap creates a new nonce-sorted transaction map.
func newTxSortedMap() *txSortedMap { func newSortedMap() *sortedMap {
return &txSortedMap{ return &sortedMap{
items: make(map[uint64]*types.Transaction), items: make(map[uint64]*types.Transaction),
index: new(nonceHeap), index: new(nonceHeap),
} }
} }
// Get retrieves the current transactions associated with the given nonce. // Get retrieves the current transactions associated with the given nonce.
func (m *txSortedMap) Get(nonce uint64) *types.Transaction { func (m *sortedMap) Get(nonce uint64) *types.Transaction {
return m.items[nonce] return m.items[nonce]
} }
// Put inserts a new transaction into the map, also updating the map's nonce // Put inserts a new transaction into the map, also updating the map's nonce
// index. If a transaction already exists with the same nonce, it's overwritten. // index. If a transaction already exists with the same nonce, it's overwritten.
func (m *txSortedMap) Put(tx *types.Transaction) { func (m *sortedMap) Put(tx *types.Transaction) {
nonce := tx.Nonce() nonce := tx.Nonce()
if m.items[nonce] == nil { if m.items[nonce] == nil {
heap.Push(m.index, nonce) heap.Push(m.index, nonce)
@ -83,7 +83,7 @@ func (m *txSortedMap) Put(tx *types.Transaction) {
// Forward removes all transactions from the map with a nonce lower than the // Forward removes all transactions from the map with a nonce lower than the
// provided threshold. Every removed transaction is returned for any post-removal // provided threshold. Every removed transaction is returned for any post-removal
// maintenance. // maintenance.
func (m *txSortedMap) Forward(threshold uint64) types.Transactions { func (m *sortedMap) Forward(threshold uint64) types.Transactions {
var removed types.Transactions var removed types.Transactions
// Pop off heap items until the threshold is reached // Pop off heap items until the threshold is reached
@ -104,7 +104,7 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
// Filter, as opposed to 'filter', re-initialises the heap after the operation is done. // Filter, as opposed to 'filter', re-initialises the heap after the operation is done.
// If you want to do several consecutive filterings, it's therefore better to first // If you want to do several consecutive filterings, it's therefore better to first
// do a .filter(func1) followed by .Filter(func2) or reheap() // do a .filter(func1) followed by .Filter(func2) or reheap()
func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions {
removed := m.filter(filter) removed := m.filter(filter)
// If transactions were removed, the heap and cache are ruined // If transactions were removed, the heap and cache are ruined
if len(removed) > 0 { if len(removed) > 0 {
@ -113,7 +113,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac
return removed return removed
} }
func (m *txSortedMap) reheap() { func (m *sortedMap) reheap() {
*m.index = make([]uint64, 0, len(m.items)) *m.index = make([]uint64, 0, len(m.items))
for nonce := range m.items { for nonce := range m.items {
*m.index = append(*m.index, nonce) *m.index = append(*m.index, nonce)
@ -124,7 +124,7 @@ func (m *txSortedMap) reheap() {
// filter is identical to Filter, but **does not** regenerate the heap. This method // filter is identical to Filter, but **does not** regenerate the heap. This method
// should only be used if followed immediately by a call to Filter or reheap() // should only be used if followed immediately by a call to Filter or reheap()
func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transactions {
var removed types.Transactions var removed types.Transactions
// Collect all the transactions to filter out // Collect all the transactions to filter out
@ -142,7 +142,7 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac
// Cap places a hard limit on the number of items, returning all transactions // Cap places a hard limit on the number of items, returning all transactions
// exceeding that limit. // exceeding that limit.
func (m *txSortedMap) Cap(threshold int) types.Transactions { func (m *sortedMap) Cap(threshold int) types.Transactions {
// Short circuit if the number of items is under the limit // Short circuit if the number of items is under the limit
if len(m.items) <= threshold { if len(m.items) <= threshold {
return nil return nil
@ -167,7 +167,7 @@ func (m *txSortedMap) Cap(threshold int) types.Transactions {
// Remove deletes a transaction from the maintained map, returning whether the // Remove deletes a transaction from the maintained map, returning whether the
// transaction was found. // transaction was found.
func (m *txSortedMap) Remove(nonce uint64) bool { func (m *sortedMap) Remove(nonce uint64) bool {
// Short circuit if no transaction is present // Short circuit if no transaction is present
_, ok := m.items[nonce] _, ok := m.items[nonce]
if !ok { if !ok {
@ -193,7 +193,7 @@ func (m *txSortedMap) Remove(nonce uint64) bool {
// Note, all transactions with nonces lower than start will also be returned to // Note, all transactions with nonces lower than start will also be returned to
// prevent getting into and invalid state. This is not something that should ever // prevent getting into and invalid state. This is not something that should ever
// happen but better to be self correcting than failing! // happen but better to be self correcting than failing!
func (m *txSortedMap) Ready(start uint64) types.Transactions { func (m *sortedMap) Ready(start uint64) types.Transactions {
// Short circuit if no transactions are available // Short circuit if no transactions are available
if m.index.Len() == 0 || (*m.index)[0] > start { if m.index.Len() == 0 || (*m.index)[0] > start {
return nil return nil
@ -211,11 +211,11 @@ func (m *txSortedMap) Ready(start uint64) types.Transactions {
} }
// Len returns the length of the transaction map. // Len returns the length of the transaction map.
func (m *txSortedMap) Len() int { func (m *sortedMap) Len() int {
return len(m.items) return len(m.items)
} }
func (m *txSortedMap) flatten() types.Transactions { func (m *sortedMap) flatten() types.Transactions {
// If the sorting was not cached yet, create and cache it // If the sorting was not cached yet, create and cache it
if m.cache == nil { if m.cache == nil {
m.cache = make(types.Transactions, 0, len(m.items)) m.cache = make(types.Transactions, 0, len(m.items))
@ -230,7 +230,7 @@ func (m *txSortedMap) flatten() types.Transactions {
// Flatten creates a nonce-sorted slice of transactions based on the loosely // Flatten creates a nonce-sorted slice of transactions based on the loosely
// sorted internal representation. The result of the sorting is cached in case // sorted internal representation. The result of the sorting is cached in case
// it's requested again before any modifications are made to the contents. // it's requested again before any modifications are made to the contents.
func (m *txSortedMap) Flatten() types.Transactions { func (m *sortedMap) Flatten() types.Transactions {
// Copy the cache to prevent accidental modifications // Copy the cache to prevent accidental modifications
cache := m.flatten() cache := m.flatten()
txs := make(types.Transactions, len(cache)) txs := make(types.Transactions, len(cache))
@ -240,36 +240,36 @@ func (m *txSortedMap) Flatten() types.Transactions {
// LastElement returns the last element of a flattened list, thus, the // LastElement returns the last element of a flattened list, thus, the
// transaction with the highest nonce // transaction with the highest nonce
func (m *txSortedMap) LastElement() *types.Transaction { func (m *sortedMap) LastElement() *types.Transaction {
cache := m.flatten() cache := m.flatten()
return cache[len(cache)-1] return cache[len(cache)-1]
} }
// txList is a "list" of transactions belonging to an account, sorted by account // list is a "list" of transactions belonging to an account, sorted by account
// nonce. The same type can be used both for storing contiguous transactions for // nonce. The same type can be used both for storing contiguous transactions for
// the executable/pending queue; and for storing gapped transactions for the non- // the executable/pending queue; and for storing gapped transactions for the non-
// executable/future queue, with minor behavioral changes. // executable/future queue, with minor behavioral changes.
type txList struct { type list struct {
strict bool // Whether nonces are strictly continuous or not strict bool // Whether nonces are strictly continuous or not
txs *txSortedMap // Heap indexed sorted hash map of the transactions txs *sortedMap // Heap indexed sorted hash map of the transactions
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
} }
// newTxList create a new transaction list for maintaining nonce-indexable fast, // newList create a new transaction list for maintaining nonce-indexable fast,
// gapped, sortable transaction lists. // gapped, sortable transaction lists.
func newTxList(strict bool) *txList { func newList(strict bool) *list {
return &txList{ return &list{
strict: strict, strict: strict,
txs: newTxSortedMap(), txs: newSortedMap(),
costcap: new(big.Int), costcap: new(big.Int),
} }
} }
// Overlaps returns whether the transaction specified has the same nonce as one // Overlaps returns whether the transaction specified has the same nonce as one
// already contained within the list. // already contained within the list.
func (l *txList) Overlaps(tx *types.Transaction) bool { func (l *list) Overlaps(tx *types.Transaction) bool {
return l.txs.Get(tx.Nonce()) != nil return l.txs.Get(tx.Nonce()) != nil
} }
@ -278,7 +278,7 @@ func (l *txList) Overlaps(tx *types.Transaction) bool {
// //
// If the new transaction is accepted into the list, the lists' cost and gas // If the new transaction is accepted into the list, the lists' cost and gas
// thresholds are also potentially updated. // thresholds are also potentially updated.
func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) { func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) {
// If there's an older better transaction, abort // If there's an older better transaction, abort
old := l.txs.Get(tx.Nonce()) old := l.txs.Get(tx.Nonce())
if old != nil && old.IsSpecialTransaction() { if old != nil && old.IsSpecialTransaction() {
@ -319,7 +319,7 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
// Forward removes all transactions from the list with a nonce lower than the // Forward removes all transactions from the list with a nonce lower than the
// provided threshold. Every removed transaction is returned for any post-removal // provided threshold. Every removed transaction is returned for any post-removal
// maintenance. // maintenance.
func (l *txList) Forward(threshold uint64) types.Transactions { func (l *list) Forward(threshold uint64) types.Transactions {
return l.txs.Forward(threshold) return l.txs.Forward(threshold)
} }
@ -332,7 +332,7 @@ func (l *txList) Forward(threshold uint64) types.Transactions {
// a point in calculating all the costs or if the balance covers all. If the threshold // a point in calculating all the costs or if the balance covers all. If the threshold
// is lower than the costgas cap, the caps will be reset to a new high after removing // is lower than the costgas cap, the caps will be reset to a new high after removing
// the newly invalidated transactions. // the newly invalidated transactions.
func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[common.Address]*big.Int, number *big.Int) (types.Transactions, types.Transactions) { func (l *list) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[common.Address]*big.Int, number *big.Int) (types.Transactions, types.Transactions) {
// If all transactions are below the threshold, short circuit // If all transactions are below the threshold, short circuit
if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
return nil, nil return nil, nil
@ -371,14 +371,14 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[co
// Cap places a hard limit on the number of items, returning all transactions // Cap places a hard limit on the number of items, returning all transactions
// exceeding that limit. // exceeding that limit.
func (l *txList) Cap(threshold int) types.Transactions { func (l *list) Cap(threshold int) types.Transactions {
return l.txs.Cap(threshold) return l.txs.Cap(threshold)
} }
// Remove deletes a transaction from the maintained list, returning whether the // Remove deletes a transaction from the maintained list, returning whether the
// transaction was found, and also returning any transaction invalidated due to // transaction was found, and also returning any transaction invalidated due to
// the deletion (strict mode only). // the deletion (strict mode only).
func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) { func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) {
// Remove the transaction from the set // Remove the transaction from the set
nonce := tx.Nonce() nonce := tx.Nonce()
if removed := l.txs.Remove(nonce); !removed { if removed := l.txs.Remove(nonce); !removed {
@ -398,30 +398,30 @@ func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) {
// Note, all transactions with nonces lower than start will also be returned to // Note, all transactions with nonces lower than start will also be returned to
// prevent getting into and invalid state. This is not something that should ever // prevent getting into and invalid state. This is not something that should ever
// happen but better to be self correcting than failing! // happen but better to be self correcting than failing!
func (l *txList) Ready(start uint64) types.Transactions { func (l *list) Ready(start uint64) types.Transactions {
return l.txs.Ready(start) return l.txs.Ready(start)
} }
// Len returns the length of the transaction list. // Len returns the length of the transaction list.
func (l *txList) Len() int { func (l *list) Len() int {
return l.txs.Len() return l.txs.Len()
} }
// Empty returns whether the list of transactions is empty or not. // Empty returns whether the list of transactions is empty or not.
func (l *txList) Empty() bool { func (l *list) Empty() bool {
return l.Len() == 0 return l.Len() == 0
} }
// Flatten creates a nonce-sorted slice of transactions based on the loosely // Flatten creates a nonce-sorted slice of transactions based on the loosely
// sorted internal representation. The result of the sorting is cached in case // sorted internal representation. The result of the sorting is cached in case
// it's requested again before any modifications are made to the contents. // it's requested again before any modifications are made to the contents.
func (l *txList) Flatten() types.Transactions { func (l *list) Flatten() types.Transactions {
return l.txs.Flatten() return l.txs.Flatten()
} }
// LastElement returns the last element of a flattened list, thus, the // LastElement returns the last element of a flattened list, thus, the
// transaction with the highest nonce // transaction with the highest nonce
func (l *txList) LastElement() *types.Transaction { func (l *list) LastElement() *types.Transaction {
return l.txs.LastElement() return l.txs.LastElement()
} }
@ -477,7 +477,7 @@ func (h *priceHeap) Pop() interface{} {
return x return x
} }
// txPricedList is a price-sorted heap to allow operating on transactions pool // pricedList is a price-sorted heap to allow operating on transactions pool
// contents in a price-incrementing way. It's built opon the all transactions // contents in a price-incrementing way. It's built opon the all transactions
// in txpool but only interested in the remote part. It means only remote transactions // in txpool but only interested in the remote part. It means only remote transactions
// will be considered for tracking, sorting, eviction, etc. // will be considered for tracking, sorting, eviction, etc.
@ -488,8 +488,8 @@ func (h *priceHeap) Pop() interface{} {
// In some cases (during a congestion, when blocks are full) the urgent heap can provide // In some cases (during a congestion, when blocks are full) the urgent heap can provide
// better candidates for inclusion while in other cases (at the top of the baseFee peak) // better candidates for inclusion while in other cases (at the top of the baseFee peak)
// the floating heap is better. When baseFee is decreasing they behave similarly. // the floating heap is better. When baseFee is decreasing they behave similarly.
type txPricedList struct { type pricedList struct {
all *txLookup // Pointer to the map of all transactions all *lookup // Pointer to the map of all transactions
urgent, floating priceHeap // Heaps of prices of all the stored **remote** transactions urgent, floating priceHeap // Heaps of prices of all the stored **remote** transactions
stales int64 // Number of stale price points to (re-heap trigger) stales int64 // Number of stale price points to (re-heap trigger)
reheapMu sync.Mutex // Mutex asserts that only one routine is reheaping the list reheapMu sync.Mutex // Mutex asserts that only one routine is reheaping the list
@ -501,15 +501,15 @@ const (
floatingRatio = 1 floatingRatio = 1
) )
// newTxPricedList creates a new price-sorted transaction heap. // newPricedList creates a new price-sorted transaction heap.
func newTxPricedList(all *txLookup) *txPricedList { func newPricedList(all *lookup) *pricedList {
return &txPricedList{ return &pricedList{
all: all, all: all,
} }
} }
// Put inserts a new transaction into the heap. // Put inserts a new transaction into the heap.
func (l *txPricedList) Put(tx *types.Transaction, local bool) { func (l *pricedList) Put(tx *types.Transaction, local bool) {
if local { if local {
return return
} }
@ -520,7 +520,7 @@ func (l *txPricedList) Put(tx *types.Transaction, local bool) {
// Removed notifies the prices transaction list that an old transaction dropped // Removed notifies the prices transaction list that an old transaction dropped
// from the pool. The list will just keep a counter of stale objects and update // from the pool. The list will just keep a counter of stale objects and update
// the heap if a large enough ratio of transactions go stale. // the heap if a large enough ratio of transactions go stale.
func (l *txPricedList) Removed(count int) { func (l *pricedList) Removed(count int) {
// Bump the stale counter, but exit if still too low (< 25%) // Bump the stale counter, but exit if still too low (< 25%)
stales := atomic.AddInt64(&l.stales, int64(count)) stales := atomic.AddInt64(&l.stales, int64(count))
if int(stales) <= (len(l.urgent.list)+len(l.floating.list))/4 { if int(stales) <= (len(l.urgent.list)+len(l.floating.list))/4 {
@ -532,7 +532,7 @@ func (l *txPricedList) Removed(count int) {
// Underpriced checks whether a transaction is cheaper than (or as cheap as) the // Underpriced checks whether a transaction is cheaper than (or as cheap as) the
// lowest priced (remote) transaction currently being tracked. // lowest priced (remote) transaction currently being tracked.
func (l *txPricedList) Underpriced(tx *types.Transaction) bool { func (l *pricedList) Underpriced(tx *types.Transaction) bool {
// Note: with two queues, being underpriced is defined as being worse than the worst item // Note: with two queues, being underpriced is defined as being worse than the worst item
// in all non-empty queues if there is any. If both queues are empty then nothing is underpriced. // in all non-empty queues if there is any. If both queues are empty then nothing is underpriced.
return (l.underpricedFor(&l.urgent, tx) || len(l.urgent.list) == 0) && return (l.underpricedFor(&l.urgent, tx) || len(l.urgent.list) == 0) &&
@ -542,7 +542,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction) bool {
// underpricedFor checks whether a transaction is cheaper than (or as cheap as) the // underpricedFor checks whether a transaction is cheaper than (or as cheap as) the
// lowest priced (remote) transaction in the given heap. // lowest priced (remote) transaction in the given heap.
func (l *txPricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool {
// Discard stale price points if found at the heap start // Discard stale price points if found at the heap start
for len(h.list) > 0 { for len(h.list) > 0 {
head := h.list[0] head := h.list[0]
@ -566,7 +566,7 @@ func (l *txPricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool
// priced list and returns them for further removal from the entire pool. // priced list and returns them for further removal from the entire pool.
// //
// Note local transaction won't be considered for eviction. // Note local transaction won't be considered for eviction.
func (l *txPricedList) Discard(slots int, force bool) (types.Transactions, bool) { func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) {
drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop
for slots > 0 { for slots > 0 {
if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio || floatingRatio == 0 { if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio || floatingRatio == 0 {
@ -605,7 +605,7 @@ func (l *txPricedList) Discard(slots int, force bool) (types.Transactions, bool)
} }
// Reheap forcibly rebuilds the heap based on the current remote transaction set. // Reheap forcibly rebuilds the heap based on the current remote transaction set.
func (l *txPricedList) Reheap() { func (l *pricedList) Reheap() {
l.reheapMu.Lock() l.reheapMu.Lock()
defer l.reheapMu.Unlock() defer l.reheapMu.Unlock()
start := time.Now() start := time.Now()
@ -633,7 +633,7 @@ func (l *txPricedList) Reheap() {
// SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not // SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not
// necessary to call right before SetBaseFee when processing a new block. // necessary to call right before SetBaseFee when processing a new block.
func (l *txPricedList) SetBaseFee(baseFee *big.Int) { func (l *pricedList) SetBaseFee(baseFee *big.Int) {
l.urgent.baseFee = baseFee l.urgent.baseFee = baseFee
l.Reheap() l.Reheap()
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"math/big" "math/big"
@ -27,7 +27,7 @@ import (
// Tests that transactions can be added to strict lists and list contents and // Tests that transactions can be added to strict lists and list contents and
// nonce boundaries are correctly maintained. // nonce boundaries are correctly maintained.
func TestStrictTxListAdd(t *testing.T) { func TestStrictListAdd(t *testing.T) {
// Generate a list of transactions to insert // Generate a list of transactions to insert
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
@ -36,9 +36,9 @@ func TestStrictTxListAdd(t *testing.T) {
txs[i] = transaction(uint64(i), 0, key) txs[i] = transaction(uint64(i), 0, key)
} }
// Insert the transactions in a random order // Insert the transactions in a random order
list := newTxList(true) list := newList(true)
for _, v := range rand.Perm(len(txs)) { for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultTxPoolConfig.PriceBump) list.Add(txs[v], DefaultConfig.PriceBump)
} }
// Verify internal state // Verify internal state
if len(list.txs.items) != len(txs) { if len(list.txs.items) != len(txs) {
@ -51,7 +51,7 @@ func TestStrictTxListAdd(t *testing.T) {
} }
} }
func BenchmarkTxListAdd(t *testing.B) { func BenchmarkListAdd(t *testing.B) {
// Generate a list of transactions to insert // Generate a list of transactions to insert
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
@ -60,11 +60,11 @@ func BenchmarkTxListAdd(t *testing.B) {
txs[i] = transaction(uint64(i), 0, key) txs[i] = transaction(uint64(i), 0, key)
} }
// Insert the transactions in a random order // Insert the transactions in a random order
list := newTxList(true) list := newList(true)
priceLimit := big.NewInt(int64(DefaultTxPoolConfig.PriceLimit)) priceLimit := big.NewInt(int64(DefaultConfig.PriceLimit))
t.ResetTimer() t.ResetTimer()
for _, v := range rand.Perm(len(txs)) { for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultTxPoolConfig.PriceBump) list.Add(txs[v], DefaultConfig.PriceBump)
list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump, nil, nil) list.Filter(priceLimit, DefaultConfig.PriceBump, nil, nil)
} }
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"sync" "sync"
@ -23,18 +23,18 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
) )
// txNoncer is a tiny virtual state database to manage the executable nonces of // noncer is a tiny virtual state database to manage the executable nonces of
// accounts in the pool, falling back to reading from a real state database if // accounts in the pool, falling back to reading from a real state database if
// an account is unknown. // an account is unknown.
type txNoncer struct { type noncer struct {
fallback *state.StateDB fallback *state.StateDB
nonces map[common.Address]uint64 nonces map[common.Address]uint64
lock sync.Mutex lock sync.Mutex
} }
// newTxNoncer creates a new virtual state database to track the pool nonces. // newNoncer creates a new virtual state database to track the pool nonces.
func newTxNoncer(statedb *state.StateDB) *txNoncer { func newNoncer(statedb *state.StateDB) *noncer {
return &txNoncer{ return &noncer{
fallback: statedb.Copy(), fallback: statedb.Copy(),
nonces: make(map[common.Address]uint64), nonces: make(map[common.Address]uint64),
} }
@ -42,7 +42,7 @@ func newTxNoncer(statedb *state.StateDB) *txNoncer {
// get returns the current nonce of an account, falling back to a real state // get returns the current nonce of an account, falling back to a real state
// database if the account is unknown. // database if the account is unknown.
func (txn *txNoncer) get(addr common.Address) uint64 { func (txn *noncer) get(addr common.Address) uint64 {
// We use mutex for get operation is the underlying // We use mutex for get operation is the underlying
// state will mutate db even for read access. // state will mutate db even for read access.
txn.lock.Lock() txn.lock.Lock()
@ -58,7 +58,7 @@ func (txn *txNoncer) get(addr common.Address) uint64 {
// set inserts a new virtual nonce into the virtual state database to be returned // set inserts a new virtual nonce into the virtual state database to be returned
// whenever the pool requests it instead of reaching into the real state database. // whenever the pool requests it instead of reaching into the real state database.
func (txn *txNoncer) set(addr common.Address, nonce uint64) { func (txn *noncer) set(addr common.Address, nonce uint64) {
txn.lock.Lock() txn.lock.Lock()
defer txn.lock.Unlock() defer txn.lock.Unlock()
@ -67,7 +67,7 @@ func (txn *txNoncer) set(addr common.Address, nonce uint64) {
// setIfLower updates a new virtual nonce into the virtual state database if the // setIfLower updates a new virtual nonce into the virtual state database if the
// the new one is lower. // the new one is lower.
func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) { func (txn *noncer) setIfLower(addr common.Address, nonce uint64) {
txn.lock.Lock() txn.lock.Lock()
defer txn.lock.Unlock() defer txn.lock.Unlock()
@ -83,7 +83,7 @@ func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) {
} }
// setAll sets the nonces for all accounts to the given map. // setAll sets the nonces for all accounts to the given map.
func (txn *txNoncer) setAll(all map[common.Address]uint64) { func (txn *noncer) setAll(all map[common.Address]uint64) {
txn.lock.Lock() txn.lock.Lock()
defer txn.lock.Unlock() defer txn.lock.Unlock()

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"errors" "errors"
@ -29,6 +29,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/event"
@ -84,7 +85,7 @@ type blockChainXDCx interface {
GetBlock(hash common.Hash, number uint64) *types.Block GetBlock(hash common.Hash, number uint64) *types.Block
OrderStateAt(block *types.Block) (*tradingstate.TradingStateDB, error) OrderStateAt(block *types.Block) (*tradingstate.TradingStateDB, error)
StateAt(root common.Hash) (*state.StateDB, error) StateAt(root common.Hash) (*state.StateDB, error)
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
Engine() consensus.Engine Engine() consensus.Engine
// GetHeader returns the hash corresponding to their hash. // GetHeader returns the hash corresponding to their hash.
GetHeader(common.Hash, uint64) *types.Header GetHeader(common.Hash, uint64) *types.Header
@ -133,7 +134,7 @@ type OrderPool struct {
txFeed event.Feed txFeed event.Feed
scope event.SubscriptionScope scope event.SubscriptionScope
chainHeadCh chan ChainHeadEvent chainHeadCh chan core.ChainHeadEvent
chainHeadSub event.Subscription chainHeadSub event.Subscription
signer types.OrderSigner signer types.OrderSigner
mu sync.RWMutex mu sync.RWMutex
@ -170,7 +171,7 @@ func NewOrderPool(chainconfig *params.ChainConfig, chain blockChainXDCx) *OrderP
queue: make(map[common.Address]*ordertxList), queue: make(map[common.Address]*ordertxList),
beats: make(map[common.Address]time.Time), beats: make(map[common.Address]time.Time),
all: make(map[common.Hash]*types.OrderTransaction), all: make(map[common.Hash]*types.OrderTransaction),
chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
} }
pool.locals = newOrderAccountSet(pool.signer) pool.locals = newOrderAccountSet(pool.signer)
pool.reset(nil, chain.CurrentBlock()) pool.reset(nil, chain.CurrentBlock())
@ -340,7 +341,7 @@ func (pool *OrderPool) Stop() {
// SubscribeTxPreEvent registers a subscription of TxPreEvent and // SubscribeTxPreEvent registers a subscription of TxPreEvent and
// starts sending event to the given channel. // starts sending event to the given channel.
func (pool *OrderPool) SubscribeTxPreEvent(ch chan<- OrderTxPreEvent) event.Subscription { func (pool *OrderPool) SubscribeTxPreEvent(ch chan<- core.OrderTxPreEvent) event.Subscription {
return pool.scope.Track(pool.txFeed.Subscribe(ch)) return pool.scope.Track(pool.txFeed.Subscribe(ch))
} }
@ -464,7 +465,7 @@ func (pool *OrderPool) validateOrder(tx *types.OrderTransaction) error {
if orderType == OrderTypeLimit { if orderType == OrderTypeLimit {
XDPoSEngine, ok := pool.chain.Engine().(*XDPoS.XDPoS) XDPoSEngine, ok := pool.chain.Engine().(*XDPoS.XDPoS)
if !ok { if !ok {
return ErrNotXDPoS return core.ErrNotXDPoS
} }
XDCXServ := XDPoSEngine.GetXDCXService() XDCXServ := XDPoSEngine.GetXDCXService()
if XDCXServ == nil { if XDCXServ == nil {
@ -550,10 +551,10 @@ func (pool *OrderPool) validateTx(tx *types.OrderTransaction, local bool) error
} }
// Ensure the transaction adheres to nonce ordering // Ensure the transaction adheres to nonce ordering
if pool.currentOrderState.GetNonce(from.Hash()) > tx.Nonce() { if pool.currentOrderState.GetNonce(from.Hash()) > tx.Nonce() {
return ErrNonceTooLow return core.ErrNonceTooLow
} }
if pool.pendingState.GetNonce(from.Hash())+common.LimitThresholdNonceInQueue < tx.Nonce() { if pool.pendingState.GetNonce(from.Hash())+common.LimitThresholdNonceInQueue < tx.Nonce() {
return ErrNonceTooHigh return core.ErrNonceTooHigh
} }
return nil return nil
@ -603,7 +604,7 @@ func (pool *OrderPool) add(tx *types.OrderTransaction, local bool) (bool, error)
pool.journalTx(from, tx) pool.journalTx(from, tx)
log.Debug("Pooled new executable transaction", "hash", hash, "useraddress", tx.UserAddress().Hex(), "nonce", tx.Nonce(), "status", tx.Status(), "orderid", tx.OrderID()) log.Debug("Pooled new executable transaction", "hash", hash, "useraddress", tx.UserAddress().Hex(), "nonce", tx.Nonce(), "status", tx.Status(), "orderid", tx.OrderID())
go pool.txFeed.Send(OrderTxPreEvent{tx}) go pool.txFeed.Send(core.OrderTxPreEvent{Tx: tx})
return old != nil, nil return old != nil, nil
} }
@ -690,7 +691,7 @@ func (pool *OrderPool) promoteTx(addr common.Address, hash common.Hash, tx *type
pool.beats[addr] = time.Now() pool.beats[addr] = time.Now()
pool.pendingState.SetNonce(addr.Hash(), tx.Nonce()+1) pool.pendingState.SetNonce(addr.Hash(), tx.Nonce()+1)
log.Debug("promoteTx txFeed.Send", "addr", tx.UserAddress().Hex(), "nonce", tx.Nonce(), "ohash", tx.OrderHash().Hex(), "status", tx.Status(), "orderid", tx.OrderID()) log.Debug("promoteTx txFeed.Send", "addr", tx.UserAddress().Hex(), "nonce", tx.Nonce(), "ohash", tx.OrderHash().Hex(), "status", tx.Status(), "orderid", tx.OrderID())
go pool.txFeed.Send(OrderTxPreEvent{tx}) go pool.txFeed.Send(core.OrderTxPreEvent{Tx: tx})
} }
// AddLocal enqueues a single transaction into the pool if it is valid, marking // AddLocal enqueues a single transaction into the pool if it is valid, marking

View file

@ -1,4 +1,4 @@
package core package txpool
import ( import (
"context" "context"

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"io" "io"

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"container/heap" "container/heap"

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"errors" "errors"
@ -30,6 +30,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/misc" "github.com/XinFinOrg/XDPoSChain/consensus/misc"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/event"
@ -63,10 +64,6 @@ var (
// ErrInvalidSender is returned if the transaction contains an invalid signature. // ErrInvalidSender is returned if the transaction contains an invalid signature.
ErrInvalidSender = errors.New("invalid sender") ErrInvalidSender = errors.New("invalid sender")
// ErrNonceTooLow is returned if the nonce of a transaction is lower than the
// one present in the local chain.
ErrNonceTooLow = errors.New("nonce too low")
// ErrUnderpriced is returned if a transaction's gas price is below the minimum // ErrUnderpriced is returned if a transaction's gas price is below the minimum
// configured for the transaction pool. // configured for the transaction pool.
ErrUnderpriced = errors.New("transaction underpriced") ErrUnderpriced = errors.New("transaction underpriced")
@ -79,14 +76,6 @@ var (
// with a different one without the required price bump. // with a different one without the required price bump.
ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") ErrReplaceUnderpriced = errors.New("replacement transaction underpriced")
// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the // ErrGasLimit is returned if a transaction's requested gas limit exceeds the
// maximum allowance of the current block. // maximum allowance of the current block.
ErrGasLimit = errors.New("exceeds block gas limit") ErrGasLimit = errors.New("exceeds block gas limit")
@ -134,6 +123,7 @@ var (
invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil) invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil)
underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil) underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil)
overflowedTxMeter = metrics.NewRegisteredMeter("txpool/overflowed", nil) overflowedTxMeter = metrics.NewRegisteredMeter("txpool/overflowed", nil)
// throttleTxMeter counts how many transactions are rejected due to too-many-changes between // throttleTxMeter counts how many transactions are rejected due to too-many-changes between
// txpool reorgs. // txpool reorgs.
throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil) throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil)
@ -167,7 +157,7 @@ type blockChain interface {
CurrentBlock() *types.Block CurrentBlock() *types.Block
GetBlock(hash common.Hash, number uint64) *types.Block GetBlock(hash common.Hash, number uint64) *types.Block
StateAt(root common.Hash) (*state.StateDB, error) StateAt(root common.Hash) (*state.StateDB, error)
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
// Engine retrieves the chain's consensus engine. // Engine retrieves the chain's consensus engine.
Engine() consensus.Engine Engine() consensus.Engine
@ -182,8 +172,8 @@ type blockChain interface {
Config() *params.ChainConfig Config() *params.ChainConfig
} }
// TxPoolConfig are the configuration parameters of the transaction pool. // Config are the configuration parameters of the transaction pool.
type TxPoolConfig struct { type Config struct {
Locals []common.Address // Addresses that should be treated by default as local Locals []common.Address // Addresses that should be treated by default as local
NoLocals bool // Whether local transaction handling should be disabled NoLocals bool // Whether local transaction handling should be disabled
Journal string // Journal of local transactions to survive node restarts Journal string // Journal of local transactions to survive node restarts
@ -200,9 +190,9 @@ type TxPoolConfig struct {
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
} }
// DefaultTxPoolConfig contains the default configurations for the transaction // DefaultConfig contains the default configurations for the transaction
// pool. // pool.
var DefaultTxPoolConfig = TxPoolConfig{ var DefaultConfig = Config{
Journal: "transactions.rlp", Journal: "transactions.rlp",
Rejournal: time.Hour, Rejournal: time.Hour,
@ -219,39 +209,39 @@ var DefaultTxPoolConfig = TxPoolConfig{
// sanitize checks the provided user configurations and changes anything that's // sanitize checks the provided user configurations and changes anything that's
// unreasonable or unworkable. // unreasonable or unworkable.
func (config *TxPoolConfig) sanitize() TxPoolConfig { func (config *Config) sanitize() Config {
conf := *config conf := *config
if conf.Rejournal < time.Second { if conf.Rejournal < time.Second {
log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second)
conf.Rejournal = time.Second conf.Rejournal = time.Second
} }
if conf.PriceLimit < 1 { if conf.PriceLimit < 1 {
log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultConfig.PriceLimit)
conf.PriceLimit = DefaultTxPoolConfig.PriceLimit conf.PriceLimit = DefaultConfig.PriceLimit
} }
if conf.PriceBump < 1 { if conf.PriceBump < 1 {
log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultConfig.PriceBump)
conf.PriceBump = DefaultTxPoolConfig.PriceBump conf.PriceBump = DefaultConfig.PriceBump
} }
if conf.AccountSlots < 1 { if conf.AccountSlots < 1 {
log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultTxPoolConfig.AccountSlots) log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultConfig.AccountSlots)
conf.AccountSlots = DefaultTxPoolConfig.AccountSlots conf.AccountSlots = DefaultConfig.AccountSlots
} }
if conf.GlobalSlots < 1 { if conf.GlobalSlots < 1 {
log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultTxPoolConfig.GlobalSlots) log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultConfig.GlobalSlots)
conf.GlobalSlots = DefaultTxPoolConfig.GlobalSlots conf.GlobalSlots = DefaultConfig.GlobalSlots
} }
if conf.AccountQueue < 1 { if conf.AccountQueue < 1 {
log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultTxPoolConfig.AccountQueue) log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultConfig.AccountQueue)
conf.AccountQueue = DefaultTxPoolConfig.AccountQueue conf.AccountQueue = DefaultConfig.AccountQueue
} }
if conf.GlobalQueue < 1 { if conf.GlobalQueue < 1 {
log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultTxPoolConfig.GlobalQueue) log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultConfig.GlobalQueue)
conf.GlobalQueue = DefaultTxPoolConfig.GlobalQueue conf.GlobalQueue = DefaultConfig.GlobalQueue
} }
if conf.Lifetime < 1 { if conf.Lifetime < 1 {
log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime) log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultConfig.Lifetime)
conf.Lifetime = DefaultTxPoolConfig.Lifetime conf.Lifetime = DefaultConfig.Lifetime
} }
return conf return conf
} }
@ -264,7 +254,7 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig {
// current state) and future transactions. Transactions move between those // current state) and future transactions. Transactions move between those
// two states over time as they are received and processed. // two states over time as they are received and processed.
type TxPool struct { type TxPool struct {
config TxPoolConfig config Config
chainconfig *params.ChainConfig chainconfig *params.ChainConfig
chain blockChain chain blockChain
gasPrice *big.Int gasPrice *big.Int
@ -277,19 +267,19 @@ type TxPool struct {
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions.
currentState *state.StateDB // Current state in the blockchain head currentState *state.StateDB // Current state in the blockchain head
pendingNonces *txNoncer // Pending state tracking virtual nonces pendingNonces *noncer // Pending state tracking virtual nonces
currentMaxGas uint64 // Current gas limit for transaction caps currentMaxGas uint64 // Current gas limit for transaction caps
locals *accountSet // Set of local transaction to exempt from eviction rules locals *accountSet // Set of local transaction to exempt from eviction rules
journal *txJournal // Journal of local transaction to back up to disk journal *journal // Journal of local transaction to back up to disk
pending map[common.Address]*txList // All currently processable transactions pending map[common.Address]*list // All currently processable transactions
queue map[common.Address]*txList // Queued but non-processable transactions queue map[common.Address]*list // Queued but non-processable transactions
beats map[common.Address]time.Time // Last heartbeat from each known account beats map[common.Address]time.Time // Last heartbeat from each known account
all *txLookup // All transactions to allow lookups all *lookup // All transactions to allow lookups
priced *txPricedList // All transactions sorted by price priced *pricedList // All transactions sorted by price
chainHeadCh chan ChainHeadEvent chainHeadCh chan core.ChainHeadEvent
chainHeadSub event.Subscription chainHeadSub event.Subscription
reqResetCh chan *txpoolResetRequest reqResetCh chan *txpoolResetRequest
reqPromoteCh chan *accountSet reqPromoteCh chan *accountSet
@ -311,7 +301,7 @@ type txpoolResetRequest struct {
// NewTxPool creates a new transaction pool to gather, sort and filter inbound // NewTxPool creates a new transaction pool to gather, sort and filter inbound
// transactions from the network. // transactions from the network.
func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain) *TxPool {
// Sanitize the input to ensure no vulnerable gas prices are set // Sanitize the input to ensure no vulnerable gas prices are set
config = (&config).sanitize() config = (&config).sanitize()
@ -321,11 +311,11 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
chainconfig: chainconfig, chainconfig: chainconfig,
chain: chain, chain: chain,
signer: types.LatestSigner(chainconfig), signer: types.LatestSigner(chainconfig),
pending: make(map[common.Address]*txList), pending: make(map[common.Address]*list),
queue: make(map[common.Address]*txList), queue: make(map[common.Address]*list),
beats: make(map[common.Address]time.Time), beats: make(map[common.Address]time.Time),
all: newTxLookup(), all: newLookup(),
chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
reqResetCh: make(chan *txpoolResetRequest), reqResetCh: make(chan *txpoolResetRequest),
reqPromoteCh: make(chan *accountSet), reqPromoteCh: make(chan *accountSet),
queueTxEventCh: make(chan *types.Transaction), queueTxEventCh: make(chan *types.Transaction),
@ -340,7 +330,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
log.Info("Setting new local account", "address", addr) log.Info("Setting new local account", "address", addr)
pool.locals.add(addr) pool.locals.add(addr)
} }
pool.priced = newTxPricedList(pool.all) pool.priced = newPricedList(pool.all)
pool.reset(nil, chain.CurrentBlock().Header()) pool.reset(nil, chain.CurrentBlock().Header())
// Start the reorg loop early so it can handle requests generated during journal loading. // Start the reorg loop early so it can handle requests generated during journal loading.
@ -463,7 +453,7 @@ func (pool *TxPool) Stop() {
// SubscribeNewTxsEvent registers a subscription of NewTxsEvent and // SubscribeNewTxsEvent registers a subscription of NewTxsEvent and
// starts sending event to the given channel. // starts sending event to the given channel.
func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription { func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return pool.scope.Track(pool.txFeed.Subscribe(ch)) return pool.scope.Track(pool.txFeed.Subscribe(ch))
} }
@ -630,11 +620,11 @@ func (pool *TxPool) GetSender(tx *types.Transaction) (common.Address, error) {
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Accept only legacy transactions until EIP-2718/2930 activates. // Accept only legacy transactions until EIP-2718/2930 activates.
if !pool.eip2718 && tx.Type() != types.LegacyTxType { if !pool.eip2718 && tx.Type() != types.LegacyTxType {
return ErrTxTypeNotSupported return core.ErrTxTypeNotSupported
} }
// Reject dynamic fee transactions until EIP-1559 activates. // Reject dynamic fee transactions until EIP-1559 activates.
if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType { if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType {
return ErrTxTypeNotSupported return core.ErrTxTypeNotSupported
} }
// Reject transactions over defined size to prevent DOS attacks // Reject transactions over defined size to prevent DOS attacks
if uint64(tx.Size()) > txMaxSize { if uint64(tx.Size()) > txMaxSize {
@ -659,14 +649,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
} }
// Sanity check for extremely large numbers // Sanity check for extremely large numbers
if tx.GasFeeCap().BitLen() > 256 { if tx.GasFeeCap().BitLen() > 256 {
return ErrFeeCapVeryHigh return core.ErrFeeCapVeryHigh
} }
if tx.GasTipCap().BitLen() > 256 { if tx.GasTipCap().BitLen() > 256 {
return ErrTipVeryHigh return core.ErrTipVeryHigh
} }
// Ensure gasFeeCap is greater than or equal to gasTipCap. // Ensure gasFeeCap is greater than or equal to gasTipCap.
if tx.GasFeeCapIntCmp(tx.GasTipCap()) < 0 { if tx.GasFeeCapIntCmp(tx.GasTipCap()) < 0 {
return ErrTipAboveFeeCap return core.ErrTipAboveFeeCap
} }
// Make sure the transaction is signed properly. // Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx) from, err := types.Sender(pool.signer, tx)
@ -681,10 +671,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
} }
// Ensure the transaction adheres to nonce ordering // Ensure the transaction adheres to nonce ordering
if pool.currentState.GetNonce(from) > tx.Nonce() { if pool.currentState.GetNonce(from) > tx.Nonce() {
return ErrNonceTooLow return core.ErrNonceTooLow
} }
if pool.pendingNonces.get(from)+common.LimitThresholdNonceInQueue < tx.Nonce() { if pool.pendingNonces.get(from)+common.LimitThresholdNonceInQueue < tx.Nonce() {
return ErrNonceTooHigh return core.ErrNonceTooHigh
} }
// Transactor should have enough funds to cover the costs // Transactor should have enough funds to cover the costs
// cost == V + GP * GL // cost == V + GP * GL
@ -701,24 +691,24 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if value, ok := pool.trc21FeeCapacity[*tx.To()]; ok { if value, ok := pool.trc21FeeCapacity[*tx.To()]; ok {
feeCapacity = value feeCapacity = value
if !state.ValidateTRC21Tx(pool.currentState, from, *tx.To(), tx.Data()) { if !state.ValidateTRC21Tx(pool.currentState, from, *tx.To(), tx.Data()) {
return ErrInsufficientFunds return core.ErrInsufficientFunds
} }
cost = tx.TxCost(number) cost = tx.TxCost(number)
} }
} }
if new(big.Int).Add(balance, feeCapacity).Cmp(cost) < 0 { if new(big.Int).Add(balance, feeCapacity).Cmp(cost) < 0 {
return ErrInsufficientFunds return core.ErrInsufficientFunds
} }
if tx.To() == nil || (tx.To() != nil && !tx.IsSpecialTransaction()) { if tx.To() == nil || (tx.To() != nil && !tx.IsSpecialTransaction()) {
// Ensure the transaction has more gas than the basic tx fee. // Ensure the transaction has more gas than the basic tx fee.
intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true) intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true)
if err != nil { if err != nil {
return err return err
} }
// Exclude check smart contract sign address. // Exclude check smart contract sign address.
if tx.Gas() < intrGas { if tx.Gas() < intrGas {
return ErrIntrinsicGas return core.ErrIntrinsicGas
} }
// Check zero gas price. // Check zero gas price.
@ -742,13 +732,13 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// validate minFee slot for XDCZ // validate minFee slot for XDCZ
if tx.IsXDCZApplyTransaction() { if tx.IsXDCZApplyTransaction() {
copyState := pool.currentState.Copy() copyState := pool.currentState.Copy()
return ValidateXDCZApplyTransaction(pool.chain, nil, copyState, common.BytesToAddress(tx.Data()[4:])) return core.ValidateXDCZApplyTransaction(pool.chain, nil, copyState, common.BytesToAddress(tx.Data()[4:]))
} }
// validate balance slot, token decimal for XDCX // validate balance slot, token decimal for XDCX
if tx.IsXDCXApplyTransaction() { if tx.IsXDCXApplyTransaction() {
copyState := pool.currentState.Copy() copyState := pool.currentState.Copy()
return ValidateXDCXApplyTransaction(pool.chain, nil, copyState, common.BytesToAddress(tx.Data()[4:])) return core.ValidateXDCXApplyTransaction(pool.chain, nil, copyState, common.BytesToAddress(tx.Data()[4:]))
} }
return nil return nil
} }
@ -870,7 +860,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction, local boo
// Try to insert the transaction into the future queue // Try to insert the transaction into the future queue
from, _ := types.Sender(pool.signer, tx) // already validated from, _ := types.Sender(pool.signer, tx) // already validated
if pool.queue[from] == nil { if pool.queue[from] == nil {
pool.queue[from] = newTxList(false) pool.queue[from] = newList(false)
} }
inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump)
if !inserted { if !inserted {
@ -922,7 +912,7 @@ func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) {
func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool {
// Try to insert the transaction into the pending queue // Try to insert the transaction into the pending queue
if pool.pending[addr] == nil { if pool.pending[addr] == nil {
pool.pending[addr] = newTxList(true) pool.pending[addr] = newList(true)
} }
list := pool.pending[addr] list := pool.pending[addr]
@ -955,7 +945,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
func (pool *TxPool) promoteSpecialTx(addr common.Address, tx *types.Transaction, isLocal bool) (bool, error) { func (pool *TxPool) promoteSpecialTx(addr common.Address, tx *types.Transaction, isLocal bool) (bool, error) {
// Try to insert the transaction into the pending queue // Try to insert the transaction into the pending queue
if pool.pending[addr] == nil { if pool.pending[addr] == nil {
pool.pending[addr] = newTxList(true) pool.pending[addr] = newList(true)
} }
list := pool.pending[addr] list := pool.pending[addr]
@ -986,7 +976,7 @@ func (pool *TxPool) promoteSpecialTx(addr common.Address, tx *types.Transaction,
// Set the potentially new pending nonce and notify any subsystems of the new tx // Set the potentially new pending nonce and notify any subsystems of the new tx
pool.beats[addr] = time.Now() pool.beats[addr] = time.Now()
pool.pendingNonces.set(addr, tx.Nonce()+1) pool.pendingNonces.set(addr, tx.Nonce()+1)
go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}}) go pool.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}})
return true, nil return true, nil
} }
@ -1228,7 +1218,7 @@ func (pool *TxPool) scheduleReorgLoop() {
launchNextRun bool launchNextRun bool
reset *txpoolResetRequest reset *txpoolResetRequest
dirtyAccounts *accountSet dirtyAccounts *accountSet
queuedEvents = make(map[common.Address]*txSortedMap) queuedEvents = make(map[common.Address]*sortedMap)
) )
for { for {
// Launch next background reorg if needed // Launch next background reorg if needed
@ -1241,7 +1231,7 @@ func (pool *TxPool) scheduleReorgLoop() {
launchNextRun = false launchNextRun = false
reset, dirtyAccounts = nil, nil reset, dirtyAccounts = nil, nil
queuedEvents = make(map[common.Address]*txSortedMap) queuedEvents = make(map[common.Address]*sortedMap)
} }
select { select {
@ -1270,7 +1260,7 @@ func (pool *TxPool) scheduleReorgLoop() {
// request one later if they want the events sent. // request one later if they want the events sent.
addr, _ := types.Sender(pool.signer, tx) addr, _ := types.Sender(pool.signer, tx)
if _, ok := queuedEvents[addr]; !ok { if _, ok := queuedEvents[addr]; !ok {
queuedEvents[addr] = newTxSortedMap() queuedEvents[addr] = newSortedMap()
} }
queuedEvents[addr].Put(tx) queuedEvents[addr].Put(tx)
@ -1289,7 +1279,7 @@ func (pool *TxPool) scheduleReorgLoop() {
} }
// runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop. // 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) { func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*sortedMap) {
defer func(t0 time.Time) { defer func(t0 time.Time) {
reorgDurationTimer.Update(time.Since(t0)) reorgDurationTimer.Update(time.Since(t0))
}(time.Now()) }(time.Now())
@ -1352,7 +1342,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
for _, tx := range promoted { for _, tx := range promoted {
addr, _ := types.Sender(pool.signer, tx) addr, _ := types.Sender(pool.signer, tx)
if _, ok := events[addr]; !ok { if _, ok := events[addr]; !ok {
events[addr] = newTxSortedMap() events[addr] = newSortedMap()
} }
events[addr].Put(tx) events[addr].Put(tx)
} }
@ -1361,7 +1351,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
for _, set := range events { for _, set := range events {
txs = append(txs, set.Flatten()...) txs = append(txs, set.Flatten()...)
} }
pool.txFeed.Send(NewTxsEvent{txs}) pool.txFeed.Send(core.NewTxsEvent{Txs: txs})
} }
} }
@ -1388,7 +1378,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
if rem == nil { if rem == nil {
// This can happen if a setHead is performed, where we simply discard the old // This can happen if a setHead is performed, where we simply discard the old
// head from the chain. // head from the chain.
// If that is the case, we don't have the lost transactions any more, and // If that is the case, we don't have the lost transactions anymore, and
// there's nothing to add // there's nothing to add
if newNum >= oldNum { if newNum >= oldNum {
// If we reorged to a same or higher number, then it's not a case of setHead // If we reorged to a same or higher number, then it's not a case of setHead
@ -1442,12 +1432,12 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
} }
pool.currentState = statedb pool.currentState = statedb
pool.trc21FeeCapacity = state.GetTRC21FeeCapacityFromStateWithCache(newHead.Root, statedb) pool.trc21FeeCapacity = state.GetTRC21FeeCapacityFromStateWithCache(newHead.Root, statedb)
pool.pendingNonces = newTxNoncer(statedb) pool.pendingNonces = newNoncer(statedb)
pool.currentMaxGas = newHead.GasLimit pool.currentMaxGas = newHead.GasLimit
// Inject any transactions discarded due to reorgs // Inject any transactions discarded due to reorgs
log.Debug("Reinjecting stale transactions", "count", len(reinject)) log.Debug("Reinjecting stale transactions", "count", len(reinject))
senderCacher.recover(pool.signer, reinject) core.SenderCacher.Recover(pool.signer, reinject)
pool.addTxsLocked(reinject, false) pool.addTxsLocked(reinject, false)
// Update all fork indicator by next pending block number. // Update all fork indicator by next pending block number.
@ -1718,8 +1708,6 @@ func (pool *TxPool) demoteUnexecutables() {
pool.enqueueTx(hash, tx, false, false) pool.enqueueTx(hash, tx, false, false)
} }
pendingGauge.Dec(int64(len(gapped))) pendingGauge.Dec(int64(len(gapped)))
// This might happen in a reorg, so log it to the metering
blockReorgInvalidatedTx.Mark(int64(len(gapped)))
} }
// Delete the entire pending entry if it became empty. // Delete the entire pending entry if it became empty.
if list.Empty() { if list.Empty() {
@ -1814,7 +1802,7 @@ func (as *accountSet) merge(other *accountSet) {
as.cache = nil as.cache = nil
} }
// txLookup is used internally by TxPool to track transactions while allowing // lookup is used internally by TxPool to track transactions while allowing
// lookup without mutex contention. // lookup without mutex contention.
// //
// Note, although this type is properly protected against concurrent access, it // Note, although this type is properly protected against concurrent access, it
@ -1826,16 +1814,16 @@ func (as *accountSet) merge(other *accountSet) {
// //
// This lookup set combines the notion of "local transactions", which is useful // This lookup set combines the notion of "local transactions", which is useful
// to build upper-level structure. // to build upper-level structure.
type txLookup struct { type lookup struct {
slots int slots int
lock sync.RWMutex lock sync.RWMutex
locals map[common.Hash]*types.Transaction locals map[common.Hash]*types.Transaction
remotes map[common.Hash]*types.Transaction remotes map[common.Hash]*types.Transaction
} }
// newTxLookup returns a new txLookup structure. // newLookup returns a new lookup structure.
func newTxLookup() *txLookup { func newLookup() *lookup {
return &txLookup{ return &lookup{
locals: make(map[common.Hash]*types.Transaction), locals: make(map[common.Hash]*types.Transaction),
remotes: make(map[common.Hash]*types.Transaction), remotes: make(map[common.Hash]*types.Transaction),
} }
@ -1844,7 +1832,7 @@ func newTxLookup() *txLookup {
// Range calls f on each key and value present in the map. The callback passed // Range calls f on each key and value present in the map. The callback passed
// should return the indicator whether the iteration needs to be continued. // should return the indicator whether the iteration needs to be continued.
// Callers need to specify which set (or both) to be iterated. // Callers need to specify which set (or both) to be iterated.
func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) { func (t *lookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1865,7 +1853,7 @@ func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction, local b
} }
// Get returns a transaction if it exists in the lookup, or nil if not found. // Get returns a transaction if it exists in the lookup, or nil if not found.
func (t *txLookup) Get(hash common.Hash) *types.Transaction { func (t *lookup) Get(hash common.Hash) *types.Transaction {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1876,7 +1864,7 @@ func (t *txLookup) Get(hash common.Hash) *types.Transaction {
} }
// GetLocal returns a transaction if it exists in the lookup, or nil if not found. // GetLocal returns a transaction if it exists in the lookup, or nil if not found.
func (t *txLookup) GetLocal(hash common.Hash) *types.Transaction { func (t *lookup) GetLocal(hash common.Hash) *types.Transaction {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1884,7 +1872,7 @@ func (t *txLookup) GetLocal(hash common.Hash) *types.Transaction {
} }
// GetRemote returns a transaction if it exists in the lookup, or nil if not found. // GetRemote returns a transaction if it exists in the lookup, or nil if not found.
func (t *txLookup) GetRemote(hash common.Hash) *types.Transaction { func (t *lookup) GetRemote(hash common.Hash) *types.Transaction {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1892,7 +1880,7 @@ func (t *txLookup) GetRemote(hash common.Hash) *types.Transaction {
} }
// Count returns the current number of transactions in the lookup. // Count returns the current number of transactions in the lookup.
func (t *txLookup) Count() int { func (t *lookup) Count() int {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1900,7 +1888,7 @@ func (t *txLookup) Count() int {
} }
// LocalCount returns the current number of local transactions in the lookup. // LocalCount returns the current number of local transactions in the lookup.
func (t *txLookup) LocalCount() int { func (t *lookup) LocalCount() int {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1908,7 +1896,7 @@ func (t *txLookup) LocalCount() int {
} }
// RemoteCount returns the current number of remote transactions in the lookup. // RemoteCount returns the current number of remote transactions in the lookup.
func (t *txLookup) RemoteCount() int { func (t *lookup) RemoteCount() int {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1916,7 +1904,7 @@ func (t *txLookup) RemoteCount() int {
} }
// Slots returns the current number of slots used in the lookup. // Slots returns the current number of slots used in the lookup.
func (t *txLookup) Slots() int { func (t *lookup) Slots() int {
t.lock.RLock() t.lock.RLock()
defer t.lock.RUnlock() defer t.lock.RUnlock()
@ -1924,7 +1912,7 @@ func (t *txLookup) Slots() int {
} }
// Add adds a transaction to the lookup. // Add adds a transaction to the lookup.
func (t *txLookup) Add(tx *types.Transaction, local bool) { func (t *lookup) Add(tx *types.Transaction, local bool) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
@ -1939,7 +1927,7 @@ func (t *txLookup) Add(tx *types.Transaction, local bool) {
} }
// Remove removes a transaction from the lookup. // Remove removes a transaction from the lookup.
func (t *txLookup) Remove(hash common.Hash) { func (t *lookup) Remove(hash common.Hash) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
@ -1960,7 +1948,7 @@ func (t *txLookup) Remove(hash common.Hash) {
// RemoteToLocals migrates the transactions belongs to the given locals to locals // RemoteToLocals migrates the transactions belongs to the given locals to locals
// set. The assumption is held the locals set is thread-safe to be used. // set. The assumption is held the locals set is thread-safe to be used.
func (t *txLookup) RemoteToLocals(locals *accountSet) int { func (t *lookup) RemoteToLocals(locals *accountSet) int {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
@ -1976,7 +1964,7 @@ func (t *txLookup) RemoteToLocals(locals *accountSet) int {
} }
// RemotesBelowTip finds all remote transactions below the given tip threshold. // RemotesBelowTip finds all remote transactions below the given tip threshold.
func (t *txLookup) RemotesBelowTip(threshold *big.Int) types.Transactions { func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
found := make(types.Transactions, 0, 128) found := make(types.Transactions, 0, 128)
t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool {
if tx.GasTipCapIntCmp(threshold) < 0 { if tx.GasTipCapIntCmp(threshold) < 0 {

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package txpool
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
@ -28,6 +28,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
@ -39,14 +40,14 @@ import (
var ( var (
// testTxPoolConfig is a transaction pool configuration without stateful disk // testTxPoolConfig is a transaction pool configuration without stateful disk
// sideeffects used during testing. // sideeffects used during testing.
testTxPoolConfig TxPoolConfig testTxPoolConfig Config
// eip1559Config is a chain config with EIP-1559 enabled at block 0. // eip1559Config is a chain config with EIP-1559 enabled at block 0.
eip1559Config *params.ChainConfig eip1559Config *params.ChainConfig
) )
func init() { func init() {
testTxPoolConfig = DefaultTxPoolConfig testTxPoolConfig = DefaultConfig
testTxPoolConfig.Journal = "" testTxPoolConfig.Journal = ""
cpy := *params.TestChainConfig cpy := *params.TestChainConfig
@ -91,7 +92,7 @@ func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
return bc.statedb, nil return bc.statedb, nil
} }
func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription { func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return bc.chainHeadFeed.Subscribe(ch) return bc.chainHeadFeed.Subscribe(ch)
} }
@ -127,11 +128,11 @@ func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int,
return tx return tx
} }
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { func setupPool() (*TxPool, *ecdsa.PrivateKey) {
return setupTxPoolWithConfig(params.TestChainConfig) return setupPoolWithConfig(params.TestChainConfig)
} }
func setupTxPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { func setupPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) {
diskdb := rawdb.NewMemoryDatabase() diskdb := rawdb.NewMemoryDatabase()
statedb, _ := state.New(common.Hash{}, state.NewDatabase(diskdb)) statedb, _ := state.New(common.Hash{}, state.NewDatabase(diskdb))
blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)}
@ -144,8 +145,8 @@ func setupTxPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateK
return pool, key return pool, key
} }
// validateTxPoolInternals checks various consistency invariants within the pool. // validatePoolInternals checks various consistency invariants within the pool.
func validateTxPoolInternals(pool *TxPool) error { func validatePoolInternals(pool *TxPool) error {
pool.mu.RLock() pool.mu.RLock()
defer pool.mu.RUnlock() defer pool.mu.RUnlock()
@ -177,7 +178,7 @@ func validateTxPoolInternals(pool *TxPool) error {
// validateEvents checks that the correct number of transaction addition events // validateEvents checks that the correct number of transaction addition events
// were fired on the pool's event feed. // were fired on the pool's event feed.
func validateEvents(events chan NewTxsEvent, count int) error { func validateEvents(events chan core.NewTxsEvent, count int) error {
var received []*types.Transaction var received []*types.Transaction
for len(received) < count { for len(received) < count {
@ -235,7 +236,7 @@ func (c *testChain) State() (*state.StateDB, error) {
// This test simulates a scenario where a new block is imported during a // This test simulates a scenario where a new block is imported during a
// state reset and tests whether the pending state is in sync with the // state reset and tests whether the pending state is in sync with the
// block head event that initiated the resetState(). // block head event that initiated the resetState().
func TestStateChangeDuringTransactionPoolReset(t *testing.T) { func TestStateChangeDuringReset(t *testing.T) {
t.Parallel() t.Parallel()
var ( var (
@ -293,28 +294,28 @@ func testSetNonce(pool *TxPool, addr common.Address, nonce uint64) {
func TestInvalidTransactions(t *testing.T) { func TestInvalidTransactions(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
tx := transaction(0, 100, key) tx := transaction(0, 100, key)
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
testAddBalance(pool, from, big.NewInt(1)) testAddBalance(pool, from, big.NewInt(1))
if err := pool.AddRemote(tx); err != ErrInsufficientFunds { if err := pool.AddRemote(tx); err != core.ErrInsufficientFunds {
t.Error("expected", ErrInsufficientFunds) t.Error("expected", core.ErrInsufficientFunds)
} }
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice()))
testAddBalance(pool, from, balance) testAddBalance(pool, from, balance)
if err := pool.AddRemote(tx); err != ErrIntrinsicGas { if err := pool.AddRemote(tx); err != core.ErrIntrinsicGas {
t.Error("expected", ErrIntrinsicGas, "got", err) t.Error("expected", core.ErrIntrinsicGas, "got", err)
} }
testSetNonce(pool, from, 1) testSetNonce(pool, from, 1)
testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) testAddBalance(pool, from, big.NewInt(0xffffffffffffff))
tx = transaction(0, 100000, key) tx = transaction(0, 100000, key)
if err := pool.AddRemote(tx); err != ErrNonceTooLow { if err := pool.AddRemote(tx); err != core.ErrNonceTooLow {
t.Error("expected", ErrNonceTooLow) t.Error("expected", core.ErrNonceTooLow)
} }
tx = transaction(1, 100000, key) tx = transaction(1, 100000, key)
@ -327,10 +328,10 @@ func TestInvalidTransactions(t *testing.T) {
} }
} }
func TestTransactionQueue(t *testing.T) { func TestQueue(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
tx := transaction(0, 100, key) tx := transaction(0, 100, key)
@ -359,10 +360,10 @@ func TestTransactionQueue(t *testing.T) {
} }
} }
func TestTransactionQueue2(t *testing.T) { func TestQueue2(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
tx1 := transaction(0, 100, key) tx1 := transaction(0, 100, key)
@ -385,10 +386,10 @@ func TestTransactionQueue2(t *testing.T) {
} }
} }
func TestTransactionNegativeValue(t *testing.T) { func TestNegativeValue(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
@ -399,43 +400,43 @@ func TestTransactionNegativeValue(t *testing.T) {
} }
} }
func TestTransactionTipAboveFeeCap(t *testing.T) { func TestTipAboveFeeCap(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPoolWithConfig(eip1559Config) pool, key := setupPoolWithConfig(eip1559Config)
defer pool.Stop() defer pool.Stop()
tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key)
if err := pool.AddRemote(tx); err != ErrTipAboveFeeCap { if err := pool.AddRemote(tx); err != core.ErrTipAboveFeeCap {
t.Error("expected", ErrTipAboveFeeCap, "got", err) t.Error("expected", core.ErrTipAboveFeeCap, "got", err)
} }
} }
func TestTransactionVeryHighValues(t *testing.T) { func TestVeryHighValues(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPoolWithConfig(eip1559Config) pool, key := setupPoolWithConfig(eip1559Config)
defer pool.Stop() defer pool.Stop()
veryBigNumber := big.NewInt(1) veryBigNumber := big.NewInt(1)
veryBigNumber.Lsh(veryBigNumber, 300) veryBigNumber.Lsh(veryBigNumber, 300)
tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key) tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key)
if err := pool.AddRemote(tx); err != ErrTipVeryHigh { if err := pool.AddRemote(tx); err != core.ErrTipVeryHigh {
t.Error("expected", ErrTipVeryHigh, "got", err) t.Error("expected", core.ErrTipVeryHigh, "got", err)
} }
tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key) tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key)
if err := pool.AddRemote(tx2); err != ErrFeeCapVeryHigh { if err := pool.AddRemote(tx2); err != core.ErrFeeCapVeryHigh {
t.Error("expected", ErrFeeCapVeryHigh, "got", err) t.Error("expected", core.ErrFeeCapVeryHigh, "got", err)
} }
} }
func TestTransactionChainFork(t *testing.T) { func TestChainFork(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
@ -462,10 +463,10 @@ func TestTransactionChainFork(t *testing.T) {
} }
} }
func TestTransactionDoubleNonce(t *testing.T) { func TestDoubleNonce(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
@ -514,10 +515,10 @@ func TestTransactionDoubleNonce(t *testing.T) {
} }
} }
func TestTransactionMissingNonce(t *testing.T) { func TestMissingNonce(t *testing.T) {
t.Parallel() t.Parallel()
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
@ -537,11 +538,11 @@ func TestTransactionMissingNonce(t *testing.T) {
} }
} }
func TestTransactionNonceRecovery(t *testing.T) { func TestNonceRecovery(t *testing.T) {
t.Parallel() t.Parallel()
const n = 10 const n = 10
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
@ -563,11 +564,11 @@ func TestTransactionNonceRecovery(t *testing.T) {
// Tests that if an account runs out of funds, any pending and queued transactions // Tests that if an account runs out of funds, any pending and queued transactions
// are dropped. // are dropped.
func TestTransactionDropping(t *testing.T) { func TestDropping(t *testing.T) {
t.Parallel() t.Parallel()
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
@ -667,7 +668,7 @@ func TestTransactionDropping(t *testing.T) {
// Tests that if a transaction is dropped from the current pending pool (e.g. out // Tests that if a transaction is dropped from the current pending pool (e.g. out
// of fund), all consecutive (still valid, but not executable) transactions are // of fund), all consecutive (still valid, but not executable) transactions are
// postponed back into the future queue to prevent broadcasting them. // postponed back into the future queue to prevent broadcasting them.
func TestTransactionPostponing(t *testing.T) { func TestPostponing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the postponing with // Create the pool to test the postponing with
@ -782,18 +783,18 @@ func TestTransactionPostponing(t *testing.T) {
// Tests that if the transaction pool has both executable and non-executable // Tests that if the transaction pool has both executable and non-executable
// transactions from an origin account, filling the nonce gap moves all queued // transactions from an origin account, filling the nonce gap moves all queued
// ones into the pending pool. // ones into the pending pool.
func TestTransactionGapFilling(t *testing.T) { func TestGapFilling(t *testing.T) {
t.Parallel() t.Parallel()
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
testAddBalance(pool, account, big.NewInt(1000000)) testAddBalance(pool, account, big.NewInt(1000000))
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5) events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -812,7 +813,7 @@ func TestTransactionGapFilling(t *testing.T) {
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 1); err != nil {
t.Fatalf("original event firing failed: %v", err) t.Fatalf("original event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Fill the nonce gap and ensure all transactions become pending // Fill the nonce gap and ensure all transactions become pending
@ -829,18 +830,18 @@ func TestTransactionGapFilling(t *testing.T) {
if err := validateEvents(events, 2); err != nil { if err := validateEvents(events, 2); err != nil {
t.Fatalf("gap-filling event firing failed: %v", err) t.Fatalf("gap-filling event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that if the transaction count belonging to a single account goes above // Tests that if the transaction count belonging to a single account goes above
// some threshold, the higher transactions are dropped to prevent DOS attacks. // some threshold, the higher transactions are dropped to prevent DOS attacks.
func TestTransactionQueueAccountLimiting(t *testing.T) { func TestQueueAccountLimiting(t *testing.T) {
t.Parallel() t.Parallel()
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
@ -874,14 +875,14 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
// //
// This logic should not hold for local transactions, unless the local tracking // This logic should not hold for local transactions, unless the local tracking
// mechanism is disabled. // mechanism is disabled.
func TestTransactionQueueGlobalLimiting(t *testing.T) { func TestQueueGlobalLimiting(t *testing.T) {
testTransactionQueueGlobalLimiting(t, false) testQueueGlobalLimiting(t, false)
} }
func TestTransactionQueueGlobalLimitingNoLocals(t *testing.T) { func TestQueueGlobalLimitingNoLocals(t *testing.T) {
testTransactionQueueGlobalLimiting(t, true) testQueueGlobalLimiting(t, true)
} }
func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { func testQueueGlobalLimiting(t *testing.T, nolocals bool) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
@ -966,12 +967,12 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) {
// //
// This logic should not hold for local transactions, unless the local tracking // This logic should not hold for local transactions, unless the local tracking
// mechanism is disabled. // mechanism is disabled.
func TestTransactionQueueTimeLimiting(t *testing.T) { testTransactionQueueTimeLimiting(t, false) } func TestQueueTimeLimiting(t *testing.T) { testQueueTimeLimiting(t, false) }
func TestTransactionQueueTimeLimitingNoLocals(t *testing.T) { func TestQueueTimeLimitingNoLocals(t *testing.T) {
testTransactionQueueTimeLimiting(t, true) testQueueTimeLimiting(t, true)
} }
func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { func testQueueTimeLimiting(t *testing.T, nolocals bool) {
common.MinGasPrice = big.NewInt(0) common.MinGasPrice = big.NewInt(0)
// Reduce the eviction interval to a testable amount // Reduce the eviction interval to a testable amount
defer func(old time.Duration) { evictionInterval = old }(evictionInterval) defer func(old time.Duration) { evictionInterval = old }(evictionInterval)
@ -1010,7 +1011,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if queued != 2 { if queued != 2 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
@ -1025,7 +1026,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if queued != 2 { if queued != 2 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
@ -1045,7 +1046,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
} }
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
@ -1062,7 +1063,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if queued != 0 { if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
@ -1092,7 +1093,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if queued != 2 { if queued != 2 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
@ -1111,7 +1112,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
} }
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1119,18 +1120,18 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
// Tests that even if the transaction count belonging to a single account goes // Tests that even if the transaction count belonging to a single account goes
// above some threshold, as long as the transactions are executable, they are // above some threshold, as long as the transactions are executable, they are
// accepted. // accepted.
func TestTransactionPendingLimiting(t *testing.T) { func TestPendingLimiting(t *testing.T) {
t.Parallel() t.Parallel()
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
testAddBalance(pool, account, big.NewInt(1000000)) testAddBalance(pool, account, big.NewInt(1000000))
testTxPoolConfig.AccountQueue = 10 testTxPoolConfig.AccountQueue = 10
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue) events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1152,7 +1153,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
if err := validateEvents(events, int(testTxPoolConfig.AccountQueue)); err != nil { if err := validateEvents(events, int(testTxPoolConfig.AccountQueue)); err != nil {
t.Fatalf("event firing failed: %v", err) t.Fatalf("event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1160,7 +1161,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
// Tests that if the transaction count belonging to multiple accounts go above // Tests that if the transaction count belonging to multiple accounts go above
// some hard threshold, the higher transactions are dropped to prevent DOS // some hard threshold, the higher transactions are dropped to prevent DOS
// attacks. // attacks.
func TestTransactionPendingGlobalLimiting(t *testing.T) { func TestPendingGlobalLimiting(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
@ -1201,7 +1202,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
if pending > int(config.GlobalSlots) { if pending > int(config.GlobalSlots) {
t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, config.GlobalSlots) t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, config.GlobalSlots)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1209,11 +1210,11 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
// Test the limit on transaction size is enforced correctly. // Test the limit on transaction size is enforced correctly.
// This test verifies every transaction having allowed size // This test verifies every transaction having allowed size
// is added to the pool, and longer transactions are rejected. // is added to the pool, and longer transactions are rejected.
func TestTransactionAllowedTxSize(t *testing.T) { func TestAllowedTxSize(t *testing.T) {
t.Parallel() t.Parallel()
// Create a test account and fund it // Create a test account and fund it
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
@ -1257,13 +1258,13 @@ func TestTransactionAllowedTxSize(t *testing.T) {
if queued != 0 { if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that if transactions start being capped, transactions are also removed from 'all' // Tests that if transactions start being capped, transactions are also removed from 'all'
func TestTransactionCapClearsFromAll(t *testing.T) { func TestCapClearsFromAll(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
@ -1290,7 +1291,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
} }
// Import the batch and verify that limits have been enforced // Import the batch and verify that limits have been enforced
pool.AddRemotes(txs) pool.AddRemotes(txs)
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1298,7 +1299,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
// Tests that if the transaction count belonging to multiple accounts go above // Tests that if the transaction count belonging to multiple accounts go above
// some hard threshold, if they are under the minimum guaranteed slot count then // some hard threshold, if they are under the minimum guaranteed slot count then
// the transactions are still kept. // the transactions are still kept.
func TestTransactionPendingMinimumAllowance(t *testing.T) { func TestPendingMinimumAllowance(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the limit enforcement with // Create the pool to test the limit enforcement with
@ -1337,7 +1338,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), config.AccountSlots) t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), config.AccountSlots)
} }
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1347,7 +1348,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
// from the pending pool to the queue. // from the pending pool to the queue.
// //
// Note, local transactions are never allowed to be dropped. // Note, local transactions are never allowed to be dropped.
func TestTransactionPoolRepricing(t *testing.T) { func TestRepricing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
@ -1359,7 +1360,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1400,7 +1401,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
if err := validateEvents(events, 7); err != nil { if err := validateEvents(events, 7); err != nil {
t.Fatalf("original event firing failed: %v", err) t.Fatalf("original event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Reprice the pool and check that underpriced transactions get dropped // Reprice the pool and check that underpriced transactions get dropped
@ -1416,7 +1417,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
if err := validateEvents(events, 0); err != nil { if err := validateEvents(events, 0); err != nil {
t.Fatalf("reprice event firing failed: %v", err) t.Fatalf("reprice event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Check that we can't add the old transactions back // Check that we can't add the old transactions back
@ -1432,7 +1433,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
if err := validateEvents(events, 0); err != nil { if err := validateEvents(events, 0); err != nil {
t.Fatalf("post-reprice event firing failed: %v", err) t.Fatalf("post-reprice event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// However we can add local underpriced transactions // However we can add local underpriced transactions
@ -1446,7 +1447,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 1); err != nil {
t.Fatalf("post-reprice local event firing failed: %v", err) t.Fatalf("post-reprice local event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// And we can fill gaps with properly priced transactions // And we can fill gaps with properly priced transactions
@ -1462,7 +1463,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
if err := validateEvents(events, 5); err != nil { if err := validateEvents(events, 5); err != nil {
t.Fatalf("post-reprice event firing failed: %v", err) t.Fatalf("post-reprice event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1472,15 +1473,15 @@ func TestTransactionPoolRepricing(t *testing.T) {
// gapped transactions back from the pending pool to the queue. // gapped transactions back from the pending pool to the queue.
// //
// Note, local transactions are never allowed to be dropped. // Note, local transactions are never allowed to be dropped.
func TestTransactionPoolRepricingDynamicFee(t *testing.T) { func TestRepricingDynamicFee(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
pool, _ := setupTxPoolWithConfig(eip1559Config) pool, _ := setupPoolWithConfig(eip1559Config)
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1521,7 +1522,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 7); err != nil { if err := validateEvents(events, 7); err != nil {
t.Fatalf("original event firing failed: %v", err) t.Fatalf("original event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Reprice the pool and check that underpriced transactions get dropped // Reprice the pool and check that underpriced transactions get dropped
@ -1537,7 +1538,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 0); err != nil { if err := validateEvents(events, 0); err != nil {
t.Fatalf("reprice event firing failed: %v", err) t.Fatalf("reprice event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Check that we can't add the old transactions back // Check that we can't add the old transactions back
@ -1556,7 +1557,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 0); err != nil { if err := validateEvents(events, 0); err != nil {
t.Fatalf("post-reprice event firing failed: %v", err) t.Fatalf("post-reprice event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// However we can add local underpriced transactions // However we can add local underpriced transactions
@ -1570,7 +1571,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 1); err != nil {
t.Fatalf("post-reprice local event firing failed: %v", err) t.Fatalf("post-reprice local event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// And we can fill gaps with properly priced transactions // And we can fill gaps with properly priced transactions
@ -1589,14 +1590,14 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 5); err != nil { if err := validateEvents(events, 5); err != nil {
t.Fatalf("post-reprice event firing failed: %v", err) t.Fatalf("post-reprice event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that setting the transaction pool gas price to a higher value does not // Tests that setting the transaction pool gas price to a higher value does not
// remove local transactions (legacy & dynamic fee). // remove local transactions (legacy & dynamic fee).
func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { func TestRepricingKeepsLocals(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
@ -1649,7 +1650,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, expQueued) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, expQueued)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1671,7 +1672,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
// pending transactions are moved into the queue. // pending transactions are moved into the queue.
// //
// Note, local transactions are never allowed to be dropped. // Note, local transactions are never allowed to be dropped.
func TestTransactionPoolUnderpricing(t *testing.T) { func TestPoolUnderpricing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
@ -1687,7 +1688,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1721,7 +1722,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
if err := validateEvents(events, 3); err != nil { if err := validateEvents(events, 3); err != nil {
t.Fatalf("original event firing failed: %v", err) t.Fatalf("original event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Ensure that adding an underpriced transaction on block limit fails // Ensure that adding an underpriced transaction on block limit fails
@ -1748,7 +1749,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 1); err != nil {
t.Fatalf("additional event firing failed: %v", err) t.Fatalf("additional event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Ensure that adding local transactions can push out even higher priced ones // Ensure that adding local transactions can push out even higher priced ones
@ -1770,7 +1771,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
if err := validateEvents(events, 2); err != nil { if err := validateEvents(events, 2); err != nil {
t.Fatalf("local event firing failed: %v", err) t.Fatalf("local event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1778,7 +1779,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
// Tests that more expensive transactions push out cheap ones from the pool, but // Tests that more expensive transactions push out cheap ones from the pool, but
// without producing instability by creating gaps that start jumping transactions // without producing instability by creating gaps that start jumping transactions
// back and forth between queued/pending. // back and forth between queued/pending.
func TestTransactionPoolStableUnderpricing(t *testing.T) { func TestPoolStableUnderpricing(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
@ -1795,7 +1796,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1822,7 +1823,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
if err := validateEvents(events, int(config.GlobalSlots)); err != nil { if err := validateEvents(events, int(config.GlobalSlots)); err != nil {
t.Fatalf("original event firing failed: %v", err) t.Fatalf("original event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap // Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap
@ -1839,7 +1840,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 1); err != nil {
t.Fatalf("additional event firing failed: %v", err) t.Fatalf("additional event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1849,17 +1850,17 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
// expensive ones and any gapped pending transactions are moved into the queue. // expensive ones and any gapped pending transactions are moved into the queue.
// //
// Note, local transactions are never allowed to be dropped. // Note, local transactions are never allowed to be dropped.
func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { func TestPoolUnderpricingDynamicFee(t *testing.T) {
t.Parallel() t.Parallel()
pool, _ := setupTxPoolWithConfig(eip1559Config) pool, _ := setupPoolWithConfig(eip1559Config)
defer pool.Stop() defer pool.Stop()
pool.config.GlobalSlots = 2 pool.config.GlobalSlots = 2
pool.config.GlobalQueue = 2 pool.config.GlobalQueue = 2
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -1893,7 +1894,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 3); err != nil { if err := validateEvents(events, 3); err != nil {
t.Fatalf("original event firing failed: %v", err) t.Fatalf("original event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
@ -1927,7 +1928,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 1); err != nil { if err := validateEvents(events, 1); err != nil {
t.Fatalf("additional event firing failed: %v", err) t.Fatalf("additional event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Ensure that adding local transactions can push out even higher priced ones // Ensure that adding local transactions can push out even higher priced ones
@ -1949,7 +1950,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
if err := validateEvents(events, 2); err != nil { if err := validateEvents(events, 2); err != nil {
t.Fatalf("local event firing failed: %v", err) t.Fatalf("local event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
@ -1959,7 +1960,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
func TestDualHeapEviction(t *testing.T) { func TestDualHeapEviction(t *testing.T) {
t.Parallel() t.Parallel()
pool, _ := setupTxPoolWithConfig(eip1559Config) pool, _ := setupPoolWithConfig(eip1559Config)
defer pool.Stop() defer pool.Stop()
pool.config.GlobalSlots = 10 pool.config.GlobalSlots = 10
@ -2006,13 +2007,13 @@ func TestDualHeapEviction(t *testing.T) {
check(highTip, "effective tip") check(highTip, "effective tip")
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that the pool rejects duplicate transactions. // Tests that the pool rejects duplicate transactions.
func TestTransactionDeduplication(t *testing.T) { func TestDeduplication(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
@ -2071,14 +2072,14 @@ func TestTransactionDeduplication(t *testing.T) {
if queued != 0 { if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that the pool rejects replacement transactions that don't meet the minimum // Tests that the pool rejects replacement transactions that don't meet the minimum
// price bump required. // price bump required.
func TestTransactionReplacement(t *testing.T) { func TestReplacement(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
@ -2090,7 +2091,7 @@ func TestTransactionReplacement(t *testing.T) {
defer pool.Stop() defer pool.Stop()
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -2152,23 +2153,23 @@ func TestTransactionReplacement(t *testing.T) {
if err := validateEvents(events, 0); err != nil { if err := validateEvents(events, 0); err != nil {
t.Fatalf("queued replacement event firing failed: %v", err) t.Fatalf("queued replacement event firing failed: %v", err)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that the pool rejects replacement dynamic fee transactions that don't // Tests that the pool rejects replacement dynamic fee transactions that don't
// meet the minimum price bump required. // meet the minimum price bump required.
func TestTransactionReplacementDynamicFee(t *testing.T) { func TestReplacementDynamicFee(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the pricing enforcement with // Create the pool to test the pricing enforcement with
pool, key := setupTxPoolWithConfig(eip1559Config) pool, key := setupPoolWithConfig(eip1559Config)
defer pool.Stop() defer pool.Stop()
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
// Keep track of transaction events to ensure all executables get announced // Keep track of transaction events to ensure all executables get announced
events := make(chan NewTxsEvent, 32) events := make(chan core.NewTxsEvent, 32)
sub := pool.txFeed.Subscribe(events) sub := pool.txFeed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -2262,15 +2263,15 @@ func TestTransactionReplacementDynamicFee(t *testing.T) {
} }
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
} }
// Tests that local transactions are journaled to disk, but remote transactions // Tests that local transactions are journaled to disk, but remote transactions
// get discarded between restarts. // get discarded between restarts.
func TestTransactionJournaling(t *testing.T) { testTransactionJournaling(t, false) } func TestJournaling(t *testing.T) { testTransactionJournaling(t, false) }
func TestTransactionJournalingNoLocals(t *testing.T) { testTransactionJournaling(t, true) } func TestJournalingNoLocals(t *testing.T) { testTransactionJournaling(t, true) }
func testTransactionJournaling(t *testing.T, nolocals bool) { func testTransactionJournaling(t *testing.T, nolocals bool) {
t.Parallel() t.Parallel()
@ -2326,7 +2327,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
if queued != 0 { if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive
@ -2349,7 +2350,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
} }
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Bump the nonce temporarily and ensure the newly invalidated transaction is removed // Bump the nonce temporarily and ensure the newly invalidated transaction is removed
@ -2375,7 +2376,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
} }
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
pool.Stop() pool.Stop()
@ -2383,7 +2384,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
// TestTransactionStatusCheck tests that the pool can correctly retrieve the // TestTransactionStatusCheck tests that the pool can correctly retrieve the
// pending status of individual transactions. // pending status of individual transactions.
func TestTransactionStatusCheck(t *testing.T) { func TestStatusCheck(t *testing.T) {
t.Parallel() t.Parallel()
// Create the pool to test the status retrievals with // Create the pool to test the status retrievals with
@ -2418,7 +2419,7 @@ func TestTransactionStatusCheck(t *testing.T) {
if queued != 2 { if queued != 2 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
} }
if err := validateTxPoolInternals(pool); err != nil { if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err) t.Fatalf("pool internal state corrupted: %v", err)
} }
// Retrieve the status of each transaction and validate them // Retrieve the status of each transaction and validate them
@ -2439,7 +2440,7 @@ func TestTransactionStatusCheck(t *testing.T) {
} }
// Test the transaction slots consumption is computed correctly // Test the transaction slots consumption is computed correctly
func TestTransactionSlotCount(t *testing.T) { func TestSlotCount(t *testing.T) {
t.Parallel() t.Parallel()
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
@ -2464,7 +2465,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1
func benchmarkPendingDemotion(b *testing.B, size int) { func benchmarkPendingDemotion(b *testing.B, size int) {
// Add a batch of transactions to a pool one by one // Add a batch of transactions to a pool one by one
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
@ -2489,7 +2490,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1
func benchmarkFuturePromotion(b *testing.B, size int) { func benchmarkFuturePromotion(b *testing.B, size int) {
// Add a batch of transactions to a pool one by one // Add a batch of transactions to a pool one by one
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
@ -2507,17 +2508,17 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
} }
// Benchmarks the speed of batched transaction insertion. // Benchmarks the speed of batched transaction insertion.
func BenchmarkPoolBatchInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100, false) } func BenchmarkBatchInsert100(b *testing.B) { benchmarkBatchInsert(b, 100, false) }
func BenchmarkPoolBatchInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000, false) } func BenchmarkBatchInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000, false) }
func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000, false) } func BenchmarkBatchInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000, false) }
func BenchmarkPoolBatchLocalInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100, true) } func BenchmarkBatchLocalInsert100(b *testing.B) { benchmarkBatchInsert(b, 100, true) }
func BenchmarkPoolBatchLocalInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000, true) } func BenchmarkBatchLocalInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000, true) }
func BenchmarkPoolBatchLocalInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000, true) } func BenchmarkBatchLocalInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000, true) }
func benchmarkPoolBatchInsert(b *testing.B, size int, local bool) { func benchmarkBatchInsert(b *testing.B, size int, local bool) {
// Generate a batch of transactions to enqueue into the pool // Generate a batch of transactions to enqueue into the pool
pool, key := setupTxPool() pool, key := setupPool()
defer pool.Stop() defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey) account := crypto.PubkeyToAddress(key.PublicKey)
@ -2561,7 +2562,7 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
b.StopTimer() b.StopTimer()
pool, _ := setupTxPool() pool, _ := setupPool()
testAddBalance(pool, account, big.NewInt(100000000)) testAddBalance(pool, account, big.NewInt(100000000))
for _, local := range locals { for _, local := range locals {
pool.AddLocal(local) pool.AddLocal(local)
@ -2577,9 +2578,9 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) {
} }
// Benchmarks the speed of batch transaction insertion in case of multiple accounts. // Benchmarks the speed of batch transaction insertion in case of multiple accounts.
func BenchmarkPoolMultiAccountBatchInsert(b *testing.B) { func BenchmarkMultiAccountBatchInsert(b *testing.B) {
// Generate a batch of transactions to enqueue into the pool // Generate a batch of transactions to enqueue into the pool
pool, _ := setupTxPool() pool, _ := setupPool()
defer pool.Stop() defer pool.Stop()
b.ReportAllocs() b.ReportAllocs()
batches := make(types.Transactions, b.N) batches := make(types.Transactions, b.N)

View file

@ -37,6 +37,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/contracts" "github.com/XinFinOrg/XDPoSChain/contracts"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/bloombits" "github.com/XinFinOrg/XDPoSChain/core/bloombits"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
@ -72,9 +73,9 @@ type Ethereum struct {
shutdownChan chan bool // Channel for shutting down the ethereum shutdownChan chan bool // Channel for shutting down the ethereum
// Handlers // Handlers
txPool *core.TxPool txPool *txpool.TxPool
orderPool *core.OrderPool orderPool *txpool.OrderPool
lendingPool *core.LendingPool lendingPool *txpool.LendingPool
blockchain *core.BlockChain blockchain *core.BlockChain
protocolManager *ProtocolManager protocolManager *ProtocolManager
lesServer LesServer lesServer LesServer
@ -186,9 +187,9 @@ func New(ctx *node.ServiceContext, config *ethconfig.Config, XDCXServ *XDCx.XDCX
if config.TxPool.Journal != "" { if config.TxPool.Journal != "" {
config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
} }
eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) eth.txPool = txpool.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)
eth.orderPool = core.NewOrderPool(eth.chainConfig, eth.blockchain) eth.orderPool = txpool.NewOrderPool(eth.chainConfig, eth.blockchain)
eth.lendingPool = core.NewLendingPool(eth.chainConfig, eth.blockchain) eth.lendingPool = txpool.NewLendingPool(eth.chainConfig, eth.blockchain)
if common.RollbackHash != (common.Hash{}) { if common.RollbackHash != (common.Hash{}) {
curBlock := eth.blockchain.CurrentBlock() curBlock := eth.blockchain.CurrentBlock()
if curBlock == nil { if curBlock == nil {
@ -517,7 +518,7 @@ func (e *Ethereum) Miner() *miner.Miner { return e.miner }
func (e *Ethereum) AccountManager() *accounts.Manager { return e.accountManager } func (e *Ethereum) AccountManager() *accounts.Manager { return e.accountManager }
func (e *Ethereum) BlockChain() *core.BlockChain { return e.blockchain } func (e *Ethereum) BlockChain() *core.BlockChain { return e.blockchain }
func (e *Ethereum) TxPool() *core.TxPool { return e.txPool } func (e *Ethereum) TxPool() *txpool.TxPool { return e.txPool }
func (e *Ethereum) EventMux() *event.TypeMux { return e.eventMux } func (e *Ethereum) EventMux() *event.TypeMux { return e.eventMux }
func (e *Ethereum) Engine() consensus.Engine { return e.engine } func (e *Ethereum) Engine() consensus.Engine { return e.engine }
func (e *Ethereum) ChainDb() ethdb.Database { return e.chainDb } func (e *Ethereum) ChainDb() ethdb.Database { return e.chainDb }
@ -591,7 +592,7 @@ func (e *Ethereum) GetXDCX() *XDCx.XDCX {
return e.XDCX return e.XDCX
} }
func (e *Ethereum) OrderPool() *core.OrderPool { func (e *Ethereum) OrderPool() *txpool.OrderPool {
return e.orderPool return e.orderPool
} }
@ -600,6 +601,6 @@ func (e *Ethereum) GetXDCXLending() *XDCxlending.Lending {
} }
// LendingPool geth eth lending pool // LendingPool geth eth lending pool
func (e *Ethereum) LendingPool() *core.LendingPool { func (e *Ethereum) LendingPool() *txpool.LendingPool {
return e.lendingPool return e.lendingPool
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
"github.com/XinFinOrg/XDPoSChain/eth/gasprice" "github.com/XinFinOrg/XDPoSChain/eth/gasprice"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
@ -72,7 +73,7 @@ var Defaults = Config{
FilterLogCacheSize: 32, FilterLogCacheSize: 32,
GasPrice: big.NewInt(0.25 * params.Shannon), GasPrice: big.NewInt(0.25 * params.Shannon),
TxPool: core.DefaultTxPoolConfig, TxPool: txpool.DefaultConfig,
RPCGasCap: 50000000, RPCGasCap: 50000000,
GPO: FullNodeGPO, GPO: FullNodeGPO,
RPCTxFeeCap: 1, // 1 ether RPCTxFeeCap: 1, // 1 ether
@ -129,7 +130,7 @@ type Config struct {
Ethash ethash.Config Ethash ethash.Config
// Transaction pool options // Transaction pool options
TxPool core.TxPoolConfig TxPool txpool.Config
// Gas Price Oracle options // Gas Price Oracle options
GPO gasprice.Config GPO gasprice.Config

View file

@ -9,6 +9,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
"github.com/XinFinOrg/XDPoSChain/eth/gasprice" "github.com/XinFinOrg/XDPoSChain/eth/gasprice"
) )
@ -33,7 +34,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
GasPrice *big.Int GasPrice *big.Int
FilterLogCacheSize int FilterLogCacheSize int
Ethash ethash.Config Ethash ethash.Config
TxPool core.TxPoolConfig TxPool txpool.Config
GPO gasprice.Config GPO gasprice.Config
EnablePreimageRecording bool EnablePreimageRecording bool
DocRoot string `toml:"-"` DocRoot string `toml:"-"`
@ -87,7 +88,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
GasPrice *big.Int GasPrice *big.Int
FilterLogCacheSize *int FilterLogCacheSize *int
Ethash *ethash.Config Ethash *ethash.Config
TxPool *core.TxPoolConfig TxPool *txpool.Config
GPO *gasprice.Config GPO *gasprice.Config
EnablePreimageRecording *bool EnablePreimageRecording *bool
DocRoot *string `toml:"-"` DocRoot *string `toml:"-"`

View file

@ -27,12 +27,12 @@ import (
"sync" "sync"
"time" "time"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
@ -92,7 +92,7 @@ type BlockChain interface {
type txPool interface { type txPool interface {
AddRemotes(txs []*types.Transaction) []error AddRemotes(txs []*types.Transaction) []error
AddRemotesSync(txs []*types.Transaction) []error AddRemotesSync(txs []*types.Transaction) []error
Status(hashes []common.Hash) []core.TxStatus Status(hashes []common.Hash) []txpool.TxStatus
} }
type ProtocolManager struct { type ProtocolManager struct {
@ -1044,7 +1044,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
stats := pm.txStatus(hashes) stats := pm.txStatus(hashes)
for i, stat := range stats { for i, stat := range stats {
if stat.Status == core.TxStatusUnknown { if stat.Status == txpool.TxStatusUnknown {
if errs := pm.txpool.AddRemotes([]*types.Transaction{req.Txs[i]}); errs[0] != nil { if errs := pm.txpool.AddRemotes([]*types.Transaction{req.Txs[i]}); errs[0] != nil {
stats[i].Error = errs[0].Error() stats[i].Error = errs[0].Error()
continue continue
@ -1160,9 +1160,9 @@ func (pm *ProtocolManager) txStatus(hashes []common.Hash) []txStatus {
stats[i].Status = stat stats[i].Status = stat
// If the transaction is unknown to the pool, try looking it up locally // If the transaction is unknown to the pool, try looking it up locally
if stat == core.TxStatusUnknown { if stat == txpool.TxStatusUnknown {
if block, number, index := core.GetTxLookupEntry(pm.chainDb, hashes[i]); block != (common.Hash{}) { if block, number, index := core.GetTxLookupEntry(pm.chainDb, hashes[i]); block != (common.Hash{}) {
stats[i].Status = core.TxStatusIncluded stats[i].Status = txpool.TxStatusIncluded
stats[i].Lookup = &core.TxLookupEntry{BlockHash: block, BlockIndex: number, Index: index} stats[i].Lookup = &core.TxLookupEntry{BlockHash: block, BlockIndex: number, Index: index}
} }
} }

View file

@ -18,7 +18,6 @@ package les
import ( import (
"encoding/binary" "encoding/binary"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big" "math/big"
"math/rand" "math/rand"
"testing" "testing"
@ -27,6 +26,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
@ -493,10 +494,10 @@ func TestTransactionStatusLes2(t *testing.T) {
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db) pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db)
chain := pm.blockchain.(*core.BlockChain) chain := pm.blockchain.(*core.BlockChain)
config := core.DefaultTxPoolConfig config := txpool.DefaultConfig
config.Journal = "" config.Journal = ""
txpool := core.NewTxPool(config, params.TestChainConfig, chain) txPool := txpool.NewTxPool(config, params.TestChainConfig, chain)
pm.txpool = txpool pm.txpool = txPool
peer, _ := newTestPeer(t, "peer", 2, pm, true) peer, _ := newTestPeer(t, "peer", 2, pm, true)
defer peer.close() defer peer.close()
@ -520,20 +521,20 @@ func TestTransactionStatusLes2(t *testing.T) {
// test error status by sending an underpriced transaction // test error status by sending an underpriced transaction
tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
test(tx0, true, txStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced.Error()}) test(tx0, true, txStatus{Status: txpool.TxStatusUnknown, Error: txpool.ErrUnderpriced.Error()})
tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey)
test(tx1, false, txStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown test(tx1, false, txStatus{Status: txpool.TxStatusUnknown}) // query before sending, should be unknown
test(tx1, true, txStatus{Status: core.TxStatusPending}) // send valid processable tx, should return pending test(tx1, true, txStatus{Status: txpool.TxStatusPending}) // send valid processable tx, should return pending
test(tx1, true, txStatus{Status: core.TxStatusPending}) // adding it again should not return an error test(tx1, true, txStatus{Status: txpool.TxStatusPending}) // adding it again should not return an error
tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey)
tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey)
// send transactions in the wrong order, tx3 should be queued // send transactions in the wrong order, tx3 should be queued
test(tx3, true, txStatus{Status: core.TxStatusQueued}) test(tx3, true, txStatus{Status: txpool.TxStatusQueued})
test(tx2, true, txStatus{Status: core.TxStatusPending}) test(tx2, true, txStatus{Status: txpool.TxStatusPending})
// query again, now tx3 should be pending too // query again, now tx3 should be pending too
test(tx3, false, txStatus{Status: core.TxStatusPending}) test(tx3, false, txStatus{Status: txpool.TxStatusPending})
// generate and add a block with tx1 and tx2 included // generate and add a block with tx1 and tx2 included
gchain, _ := core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) { gchain, _ := core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) {
@ -545,19 +546,19 @@ func TestTransactionStatusLes2(t *testing.T) {
} }
// wait until TxPool processes the inserted block // wait until TxPool processes the inserted block
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
if pending, _ := txpool.Stats(); pending == 1 { if pending, _ := txPool.Stats(); pending == 1 {
break break
} }
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
} }
if pending, _ := txpool.Stats(); pending != 1 { if pending, _ := txPool.Stats(); pending != 1 {
t.Fatalf("pending count mismatch: have %d, want 1", pending) t.Fatalf("pending count mismatch: have %d, want 1", pending)
} }
// check if their status is included now // check if their status is included now
block1hash := core.GetCanonicalHash(db, 1) block1hash := core.GetCanonicalHash(db, 1)
test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) test(tx1, false, txStatus{Status: txpool.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}})
test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) test(tx2, false, txStatus{Status: txpool.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}})
// create a reorg that rolls them back // create a reorg that rolls them back
gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 2, func(i int, block *core.BlockGen) {}) gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 2, func(i int, block *core.BlockGen) {})
@ -566,15 +567,15 @@ func TestTransactionStatusLes2(t *testing.T) {
} }
// wait until TxPool processes the reorg // wait until TxPool processes the reorg
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
if pending, _ := txpool.Stats(); pending == 3 { if pending, _ := txPool.Stats(); pending == 3 {
break break
} }
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
} }
if pending, _ := txpool.Stats(); pending != 3 { if pending, _ := txPool.Stats(); pending != 3 {
t.Fatalf("pending count mismatch: have %d, want 3", pending) t.Fatalf("pending count mismatch: have %d, want 3", pending)
} }
// check if their status is pending again // check if their status is pending again
test(tx1, false, txStatus{Status: core.TxStatusPending}) test(tx1, false, txStatus{Status: txpool.TxStatusPending})
test(tx2, false, txStatus{Status: core.TxStatusPending}) test(tx2, false, txStatus{Status: txpool.TxStatusPending})
} }

View file

@ -28,6 +28,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/secp256k1" "github.com/XinFinOrg/XDPoSChain/crypto/secp256k1"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
@ -223,7 +224,7 @@ type CodeData []struct {
type proofsData [][]rlp.RawValue type proofsData [][]rlp.RawValue
type txStatus struct { type txStatus struct {
Status core.TxStatus Status txpool.TxStatus
Lookup *core.TxLookupEntry `rlp:"nil"` Lookup *core.TxLookupEntry `rlp:"nil"`
Error string Error string
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/event"
@ -378,7 +379,7 @@ func (p *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error {
// Validate the transaction sender and it's sig. Throw // Validate the transaction sender and it's sig. Throw
// if the from fields is invalid. // if the from fields is invalid.
if from, err = types.Sender(p.signer, tx); err != nil { if from, err = types.Sender(p.signer, tx); err != nil {
return core.ErrInvalidSender return txpool.ErrInvalidSender
} }
// Last but not least check for nonce errors // Last but not least check for nonce errors
currentState := p.currentState(ctx) currentState := p.currentState(ctx)
@ -390,14 +391,14 @@ func (p *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error {
// block limit gas. // block limit gas.
header := p.chain.GetHeaderByHash(p.head) header := p.chain.GetHeaderByHash(p.head)
if header.GasLimit < tx.Gas() { if header.GasLimit < tx.Gas() {
return core.ErrGasLimit return txpool.ErrGasLimit
} }
// Transactions can't be negative. This may never happen // Transactions can't be negative. This may never happen
// using RLP decoded transactions but may occur if you create // using RLP decoded transactions but may occur if you create
// a transaction using the RPC for example. // a transaction using the RPC for example.
if tx.Value().Sign() < 0 { if tx.Value().Sign() < 0 {
return core.ErrNegativeValue return txpool.ErrNegativeValue
} }
// Transactor should have enough funds to cover the costs // Transactor should have enough funds to cover the costs

View file

@ -21,14 +21,14 @@ import (
"fmt" "fmt"
"sync/atomic" "sync/atomic"
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
"github.com/XinFinOrg/XDPoSChain/XDCx" "github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
"github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
@ -41,11 +41,11 @@ import (
type Backend interface { type Backend interface {
AccountManager() *accounts.Manager AccountManager() *accounts.Manager
BlockChain() *core.BlockChain BlockChain() *core.BlockChain
TxPool() *core.TxPool TxPool() *txpool.TxPool
ChainDb() ethdb.Database ChainDb() ethdb.Database
GetXDCX() *XDCx.XDCX GetXDCX() *XDCx.XDCX
OrderPool() *core.OrderPool OrderPool() *txpool.OrderPool
LendingPool() *core.LendingPool LendingPool() *txpool.LendingPool
GetXDCXLending() *XDCxlending.Lending GetXDCXLending() *XDCxlending.Lending
} }

View file

@ -1048,7 +1048,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr
w.tcount++ w.tcount++
txs.Shift() txs.Shift()
case errors.Is(err, core.ErrTxTypeNotSupported): case errors.Is(err, types.ErrTxTypeNotSupported):
// Pop the unsupported transaction without shifting in the next from the account // Pop the unsupported transaction without shifting in the next from the account
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type()) log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
txs.Pop() txs.Pop()