forked from cerc-io/plugeth
all: move main transaction pool into a subpool (#27463)
* all: move main transaction pool into a subpool * go.mod: remove superfluous updates * core/txpool: review fixes, handle txs rejected by all subpools * core/txpool: typos
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
// 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 txpool
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrAlreadyKnown is returned if the transactions is already contained
|
||||
// within the pool.
|
||||
ErrAlreadyKnown = errors.New("already known")
|
||||
|
||||
// ErrInvalidSender is returned if the transaction contains an invalid signature.
|
||||
ErrInvalidSender = errors.New("invalid sender")
|
||||
|
||||
// ErrUnderpriced is returned if a transaction's gas price is below the minimum
|
||||
// configured for the transaction pool.
|
||||
ErrUnderpriced = errors.New("transaction underpriced")
|
||||
|
||||
// ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced
|
||||
// with a different one without the required price bump.
|
||||
ErrReplaceUnderpriced = errors.New("replacement transaction underpriced")
|
||||
|
||||
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
|
||||
// maximum allowance of the current block.
|
||||
ErrGasLimit = errors.New("exceeds block gas limit")
|
||||
|
||||
// ErrNegativeValue is a sanity error to ensure no one is able to specify a
|
||||
// transaction with a negative value.
|
||||
ErrNegativeValue = errors.New("negative value")
|
||||
|
||||
// ErrOversizedData is returned if the input data of a transaction is greater
|
||||
// than some meaningful limit a user might use. This is not a consensus error
|
||||
// making the transaction invalid, rather a DOS protection.
|
||||
ErrOversizedData = errors.New("oversized data")
|
||||
|
||||
// ErrFutureReplacePending is returned if a future transaction replaces a pending
|
||||
// transaction. Future transactions should only be able to replace other future transactions.
|
||||
ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
|
||||
)
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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 txpool
|
||||
package legacypool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// 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 txpool
|
||||
package legacypool
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
@@ -33,7 +33,7 @@ func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gaspric
|
||||
return tx
|
||||
}
|
||||
|
||||
func count(t *testing.T, pool *TxPool) (pending int, queued int) {
|
||||
func count(t *testing.T, pool *LegacyPool) (pending int, queued int) {
|
||||
t.Helper()
|
||||
pending, queued = pool.stats()
|
||||
if err := validatePoolInternals(pool); err != nil {
|
||||
@@ -42,7 +42,7 @@ func count(t *testing.T, pool *TxPool) (pending int, queued int) {
|
||||
return pending, queued
|
||||
}
|
||||
|
||||
func fillPool(t testing.TB, pool *TxPool) {
|
||||
func fillPool(t testing.TB, pool *LegacyPool) {
|
||||
t.Helper()
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
executableTxs := types.Transactions{}
|
||||
@@ -56,8 +56,8 @@ func fillPool(t testing.TB, pool *TxPool) {
|
||||
}
|
||||
}
|
||||
// Import the batch and verify that limits have been enforced
|
||||
pool.AddRemotesSync(executableTxs)
|
||||
pool.AddRemotesSync(nonExecutableTxs)
|
||||
pool.addRemotesSync(executableTxs)
|
||||
pool.addRemotesSync(nonExecutableTxs)
|
||||
pending, queued := pool.Stats()
|
||||
slots := pool.all.Slots()
|
||||
// sanity-check that the test prerequisites are ok (pending full)
|
||||
@@ -79,12 +79,13 @@ func TestTransactionFutureAttack(t *testing.T) {
|
||||
|
||||
// Create the pool to test the limit enforcement with
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := newTestBlockChain(1000000, statedb, new(event.Feed))
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
config := testTxPoolConfig
|
||||
config.GlobalQueue = 100
|
||||
config.GlobalSlots = 100
|
||||
pool := New(config, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock())
|
||||
defer pool.Close()
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
@@ -96,7 +97,7 @@ func TestTransactionFutureAttack(t *testing.T) {
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
pool.addRemotesSync(futureTxs)
|
||||
newPending, newQueued := count(t, pool)
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||
}
|
||||
@@ -115,9 +116,10 @@ func TestTransactionFuture1559(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create the pool to test the pricing enforcement with
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := newTestBlockChain(1000000, statedb, new(event.Feed))
|
||||
pool := New(testTxPoolConfig, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
@@ -131,7 +133,7 @@ func TestTransactionFuture1559(t *testing.T) {
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
|
||||
}
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
pool.addRemotesSync(futureTxs)
|
||||
}
|
||||
newPending, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
@@ -147,9 +149,10 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create the pool to test the pricing enforcement with
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := newTestBlockChain(1000000, statedb, new(event.Feed))
|
||||
pool := New(testTxPoolConfig, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock())
|
||||
defer pool.Close()
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
|
||||
@@ -181,7 +184,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
pool.addRemotesSync(futureTxs)
|
||||
}
|
||||
|
||||
overDraftTxs := types.Transactions{}
|
||||
@@ -192,11 +195,11 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
|
||||
}
|
||||
}
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.addRemotesSync(overDraftTxs)
|
||||
pool.addRemotesSync(overDraftTxs)
|
||||
pool.addRemotesSync(overDraftTxs)
|
||||
pool.addRemotesSync(overDraftTxs)
|
||||
pool.addRemotesSync(overDraftTxs)
|
||||
|
||||
newPending, newQueued := count(t, pool)
|
||||
newIvPending := countInvalidPending()
|
||||
@@ -214,12 +217,13 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
func BenchmarkFutureAttack(b *testing.B) {
|
||||
// Create the pool to test the limit enforcement with
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := newTestBlockChain(1000000, statedb, new(event.Feed))
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
config := testTxPoolConfig
|
||||
config.GlobalQueue = 100
|
||||
config.GlobalSlots = 100
|
||||
pool := New(config, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock())
|
||||
defer pool.Close()
|
||||
fillPool(b, pool)
|
||||
|
||||
key, _ := crypto.GenerateKey()
|
||||
@@ -231,6 +235,6 @@ func BenchmarkFutureAttack(b *testing.B) {
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < 5; i++ {
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
pool.addRemotesSync(futureTxs)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
// 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 txpool
|
||||
package legacypool
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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 txpool
|
||||
package legacypool
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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 txpool
|
||||
package legacypool
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2023 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 txpool
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Transaction is a helper struct to group together a canonical transaction with
|
||||
// satellite data items that are needed by the pool but are not part of the chain.
|
||||
type Transaction struct {
|
||||
Tx *types.Transaction // Canonical transaction
|
||||
|
||||
BlobTxBlobs []kzg4844.Blob // Blobs needed by the blob pool
|
||||
BlobTxCommits []kzg4844.Commitment // Commitments needed by the blob pool
|
||||
BlobTxProofs []kzg4844.Proof // Proofs needed by the blob pool
|
||||
}
|
||||
|
||||
// SubPool represents a specialized transaction pool that lives on its own (e.g.
|
||||
// blob pool). Since independent of how many specialized pools we have, they do
|
||||
// need to be updated in lockstep and assemble into one coherent view for block
|
||||
// production, this interface defines the common methods that allow the primary
|
||||
// transaction pool to manage the subpools.
|
||||
type SubPool interface {
|
||||
// Filter is a selector used to decide whether a transaction whould be added
|
||||
// to this particular subpool.
|
||||
Filter(tx *types.Transaction) bool
|
||||
|
||||
// Init sets the base parameters of the subpool, allowing it to load any saved
|
||||
// transactions from disk and also permitting internal maintenance routines to
|
||||
// start up.
|
||||
//
|
||||
// These should not be passed as a constructor argument - nor should the pools
|
||||
// start by themselves - in order to keep multiple subpools in lockstep with
|
||||
// one another.
|
||||
Init(gasTip *big.Int, head *types.Header) error
|
||||
|
||||
// Close terminates any background processing threads and releases any held
|
||||
// resources.
|
||||
Close() error
|
||||
|
||||
// Reset retrieves the current state of the blockchain and ensures the content
|
||||
// of the transaction pool is valid with regard to the chain state.
|
||||
Reset(oldHead, newHead *types.Header)
|
||||
|
||||
// SetGasTip updates the minimum price required by the subpool for a new
|
||||
// transaction, and drops all transactions below this threshold.
|
||||
SetGasTip(tip *big.Int)
|
||||
|
||||
// Has returns an indicator whether subpool has a transaction cached with the
|
||||
// given hash.
|
||||
Has(hash common.Hash) bool
|
||||
|
||||
// Get returns a transaction if it is contained in the pool, or nil otherwise.
|
||||
Get(hash common.Hash) *Transaction
|
||||
|
||||
// Add enqueues a batch of transactions into the pool if they are valid. Due
|
||||
// to the large transaction churn, add may postpone fully integrating the tx
|
||||
// to a later point to batch multiple ones together.
|
||||
Add(txs []*Transaction, local bool, sync bool) []error
|
||||
|
||||
// Pending retrieves all currently processable transactions, grouped by origin
|
||||
// account and sorted by nonce.
|
||||
Pending(enforceTips bool) map[common.Address][]*types.Transaction
|
||||
|
||||
// SubscribeTransactions subscribes to new transaction events.
|
||||
SubscribeTransactions(ch chan<- core.NewTxsEvent) event.Subscription
|
||||
|
||||
// Nonce returns the next nonce of an account, with all transactions executable
|
||||
// by the pool already applied on top.
|
||||
Nonce(addr common.Address) uint64
|
||||
|
||||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
Stats() (int, int)
|
||||
|
||||
// Content retrieves the data content of the transaction pool, returning all the
|
||||
// pending as well as queued transactions, grouped by account and sorted by nonce.
|
||||
Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction)
|
||||
|
||||
// ContentFrom retrieves the data content of the transaction pool, returning the
|
||||
// pending as well as queued transactions of this address, grouped by nonce.
|
||||
ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction)
|
||||
|
||||
// Locals retrieves the accounts currently considered local by the pool.
|
||||
Locals() []common.Address
|
||||
|
||||
// Status returns the known status (unknown/pending/queued) of a transaction
|
||||
// identified by their hashes.
|
||||
Status(hash common.Hash) TxStatus
|
||||
}
|
||||
+228
-1733
File diff suppressed because it is too large
Load Diff
@@ -555,10 +555,10 @@ func (s *TxByPriceAndTime) Pop() interface{} {
|
||||
// transactions in a profit-maximizing sorted order, while supporting removing
|
||||
// entire batches of transactions for non-executable accounts.
|
||||
type TransactionsByPriceAndNonce struct {
|
||||
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
|
||||
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
||||
signer Signer // Signer for the set of transactions
|
||||
baseFee *big.Int // Current base fee
|
||||
txs map[common.Address][]*Transaction // Per account nonce-sorted list of transactions
|
||||
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
|
||||
signer Signer // Signer for the set of transactions
|
||||
baseFee *big.Int // Current base fee
|
||||
}
|
||||
|
||||
// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
||||
@@ -566,7 +566,7 @@ type TransactionsByPriceAndNonce struct {
|
||||
//
|
||||
// Note, the input map is reowned so the caller should not interact any more with
|
||||
// if after providing it to the constructor.
|
||||
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, baseFee *big.Int) *TransactionsByPriceAndNonce {
|
||||
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address][]*Transaction, baseFee *big.Int) *TransactionsByPriceAndNonce {
|
||||
// Initialize a price and received time based heap with the head transactions
|
||||
heads := make(TxByPriceAndTime, 0, len(txs))
|
||||
for from, accTxs := range txs {
|
||||
|
||||
@@ -57,9 +57,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint
|
||||
}
|
||||
|
||||
// LatestSigner returns the 'most permissive' Signer available for the given chain
|
||||
// configuration. Specifically, this enables support of EIP-155 replay protection and
|
||||
// EIP-2930 access list transactions when their respective forks are scheduled to occur at
|
||||
// any block number in the chain config.
|
||||
// configuration. Specifically, this enables support of all types of transacrions
|
||||
// when their respective forks are scheduled to occur at any block number (or time)
|
||||
// in the chain config.
|
||||
//
|
||||
// Use this in transaction-handling code where the current block number is unknown. If you
|
||||
// have the current block number available, use MakeSigner instead.
|
||||
|
||||
@@ -281,7 +281,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
|
||||
signer := LatestSignerForChainID(common.Big1)
|
||||
|
||||
// Generate a batch of transactions with overlapping values, but shifted nonces
|
||||
groups := map[common.Address]Transactions{}
|
||||
groups := map[common.Address][]*Transaction{}
|
||||
expectedCount := 0
|
||||
for start, key := range keys {
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
@@ -368,7 +368,7 @@ func TestTransactionTimeSort(t *testing.T) {
|
||||
signer := HomesteadSigner{}
|
||||
|
||||
// Generate a batch of transactions with overlapping prices, but different creation times
|
||||
groups := map[common.Address]Transactions{}
|
||||
groups := map[common.Address][]*Transaction{}
|
||||
for start, key := range keys {
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user