all: EIP-1559 tx pool support (#22898)
This pull request implements EIP-1559 compatible transaction pool with dual heap eviction ordering. It is based on #22791 The eviction ordering scheme and the reasoning behind it is described here: https://gist.github.com/zsfelfoldi/9607ad248707a925b701f49787904fd6
This commit is contained in:
@ -37,13 +37,23 @@ import (
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
// testTxPoolConfig is a transaction pool configuration without stateful disk
|
||||
// sideeffects used during testing.
|
||||
var testTxPoolConfig TxPoolConfig
|
||||
var (
|
||||
// testTxPoolConfig is a transaction pool configuration without stateful disk
|
||||
// sideeffects used during testing.
|
||||
testTxPoolConfig TxPoolConfig
|
||||
|
||||
// eip1559Config is a chain config with EIP-1559 enabled at block 0.
|
||||
eip1559Config *params.ChainConfig
|
||||
)
|
||||
|
||||
func init() {
|
||||
testTxPoolConfig = DefaultTxPoolConfig
|
||||
testTxPoolConfig.Journal = ""
|
||||
|
||||
cpy := *params.TestChainConfig
|
||||
eip1559Config = &cpy
|
||||
eip1559Config.BerlinBlock = common.Big0
|
||||
eip1559Config.LondonBlock = common.Big0
|
||||
}
|
||||
|
||||
type testBlockChain struct {
|
||||
@ -87,12 +97,31 @@ func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key
|
||||
return tx
|
||||
}
|
||||
|
||||
func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||
tx, _ := types.SignNewTx(key, types.LatestSignerForChainID(params.TestChainConfig.ChainID), &types.DynamicFeeTx{
|
||||
ChainID: params.TestChainConfig.ChainID,
|
||||
Nonce: nonce,
|
||||
Tip: tip,
|
||||
FeeCap: gasFee,
|
||||
Gas: gaslimit,
|
||||
To: &common.Address{},
|
||||
Value: big.NewInt(100),
|
||||
Data: nil,
|
||||
AccessList: nil,
|
||||
})
|
||||
return tx
|
||||
}
|
||||
|
||||
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
|
||||
return setupTxPoolWithConfig(params.TestChainConfig)
|
||||
}
|
||||
|
||||
func setupTxPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) {
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)}
|
||||
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||
pool := NewTxPool(testTxPoolConfig, config, blockchain)
|
||||
|
||||
return pool, key
|
||||
}
|
||||
@ -108,7 +137,7 @@ func validateTxPoolInternals(pool *TxPool) error {
|
||||
return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued)
|
||||
}
|
||||
pool.priced.Reheap()
|
||||
priced, remote := pool.priced.remotes.Len(), pool.all.RemoteCount()
|
||||
priced, remote := pool.priced.urgent.Len()+pool.priced.floating.Len(), pool.all.RemoteCount()
|
||||
if priced != remote {
|
||||
return fmt.Errorf("total priced transaction count %d != %d", priced, remote)
|
||||
}
|
||||
@ -233,6 +262,18 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testAddBalance(pool *TxPool, addr common.Address, amount *big.Int) {
|
||||
pool.mu.Lock()
|
||||
pool.currentState.AddBalance(addr, amount)
|
||||
pool.mu.Unlock()
|
||||
}
|
||||
|
||||
func testSetNonce(pool *TxPool, addr common.Address, nonce uint64) {
|
||||
pool.mu.Lock()
|
||||
pool.currentState.SetNonce(addr, nonce)
|
||||
pool.mu.Unlock()
|
||||
}
|
||||
|
||||
func TestInvalidTransactions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -242,19 +283,19 @@ func TestInvalidTransactions(t *testing.T) {
|
||||
tx := transaction(0, 100, key)
|
||||
from, _ := deriveSender(tx)
|
||||
|
||||
pool.currentState.AddBalance(from, big.NewInt(1))
|
||||
testAddBalance(pool, from, big.NewInt(1))
|
||||
if err := pool.AddRemote(tx); !errors.Is(err, ErrInsufficientFunds) {
|
||||
t.Error("expected", ErrInsufficientFunds)
|
||||
}
|
||||
|
||||
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice()))
|
||||
pool.currentState.AddBalance(from, balance)
|
||||
testAddBalance(pool, from, balance)
|
||||
if err := pool.AddRemote(tx); !errors.Is(err, ErrIntrinsicGas) {
|
||||
t.Error("expected", ErrIntrinsicGas, "got", err)
|
||||
}
|
||||
|
||||
pool.currentState.SetNonce(from, 1)
|
||||
pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff))
|
||||
testSetNonce(pool, from, 1)
|
||||
testAddBalance(pool, from, big.NewInt(0xffffffffffffff))
|
||||
tx = transaction(0, 100000, key)
|
||||
if err := pool.AddRemote(tx); !errors.Is(err, ErrNonceTooLow) {
|
||||
t.Error("expected", ErrNonceTooLow)
|
||||
@ -278,7 +319,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||
|
||||
tx := transaction(0, 100, key)
|
||||
from, _ := deriveSender(tx)
|
||||
pool.currentState.AddBalance(from, big.NewInt(1000))
|
||||
testAddBalance(pool, from, big.NewInt(1000))
|
||||
<-pool.requestReset(nil, nil)
|
||||
|
||||
pool.enqueueTx(tx.Hash(), tx, false, true)
|
||||
@ -289,7 +330,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||
|
||||
tx = transaction(1, 100, key)
|
||||
from, _ = deriveSender(tx)
|
||||
pool.currentState.SetNonce(from, 2)
|
||||
testSetNonce(pool, from, 2)
|
||||
pool.enqueueTx(tx.Hash(), tx, false, true)
|
||||
|
||||
<-pool.requestPromoteExecutables(newAccountSet(pool.signer, from))
|
||||
@ -311,7 +352,7 @@ func TestTransactionQueue2(t *testing.T) {
|
||||
tx2 := transaction(10, 100, key)
|
||||
tx3 := transaction(11, 100, key)
|
||||
from, _ := deriveSender(tx1)
|
||||
pool.currentState.AddBalance(from, big.NewInt(1000))
|
||||
testAddBalance(pool, from, big.NewInt(1000))
|
||||
pool.reset(nil, nil)
|
||||
|
||||
pool.enqueueTx(tx1.Hash(), tx1, false, true)
|
||||
@ -335,12 +376,25 @@ func TestTransactionNegativeValue(t *testing.T) {
|
||||
|
||||
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||
from, _ := deriveSender(tx)
|
||||
pool.currentState.AddBalance(from, big.NewInt(1))
|
||||
testAddBalance(pool, from, big.NewInt(1))
|
||||
if err := pool.AddRemote(tx); err != ErrNegativeValue {
|
||||
t.Error("expected", ErrNegativeValue, "got", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransactionTipAboveFeeCap(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pool, key := setupTxPoolWithConfig(eip1559Config)
|
||||
defer pool.Stop()
|
||||
|
||||
tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key)
|
||||
|
||||
if err := pool.AddRemote(tx); err != ErrTipAboveFeeCap {
|
||||
t.Error("expected", ErrTipAboveFeeCap, "got", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransactionChainFork(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -428,7 +482,7 @@ func TestTransactionMissingNonce(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(addr, big.NewInt(100000000000000))
|
||||
testAddBalance(pool, addr, big.NewInt(100000000000000))
|
||||
tx := transaction(1, 100000, key)
|
||||
if _, err := pool.add(tx, false); err != nil {
|
||||
t.Error("didn't expect error", err)
|
||||
@ -452,8 +506,8 @@ func TestTransactionNonceRecovery(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.SetNonce(addr, n)
|
||||
pool.currentState.AddBalance(addr, big.NewInt(100000000000000))
|
||||
testSetNonce(pool, addr, n)
|
||||
testAddBalance(pool, addr, big.NewInt(100000000000000))
|
||||
<-pool.requestReset(nil, nil)
|
||||
|
||||
tx := transaction(n, 100000, key)
|
||||
@ -461,7 +515,7 @@ func TestTransactionNonceRecovery(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
// simulate some weird re-order of transactions and missing nonce(s)
|
||||
pool.currentState.SetNonce(addr, n-1)
|
||||
testSetNonce(pool, addr, n-1)
|
||||
<-pool.requestReset(nil, nil)
|
||||
if fn := pool.Nonce(addr); fn != n-1 {
|
||||
t.Errorf("expected nonce to be %d, got %d", n-1, fn)
|
||||
@ -478,7 +532,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000))
|
||||
testAddBalance(pool, account, big.NewInt(1000))
|
||||
|
||||
// Add some pending and some queued transactions
|
||||
var (
|
||||
@ -526,7 +580,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6)
|
||||
}
|
||||
// Reduce the balance of the account, and check that invalidated transactions are dropped
|
||||
pool.currentState.AddBalance(account, big.NewInt(-650))
|
||||
testAddBalance(pool, account, big.NewInt(-650))
|
||||
<-pool.requestReset(nil, nil)
|
||||
|
||||
if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok {
|
||||
@ -592,7 +646,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey)
|
||||
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100))
|
||||
}
|
||||
// Add a batch consecutive pending transactions for validation
|
||||
txs := []*types.Transaction{}
|
||||
@ -635,7 +689,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||
}
|
||||
// Reduce the balance of the account, and check that transactions are reorganised
|
||||
for _, addr := range accs {
|
||||
pool.currentState.AddBalance(addr, big.NewInt(-1))
|
||||
testAddBalance(pool, addr, big.NewInt(-1))
|
||||
}
|
||||
<-pool.requestReset(nil, nil)
|
||||
|
||||
@ -696,7 +750,7 @@ func TestTransactionGapFilling(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5)
|
||||
@ -750,7 +804,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
|
||||
// Keep queuing up transactions and make sure all above a limit are dropped
|
||||
for i := uint64(1); i <= testTxPoolConfig.AccountQueue+5; i++ {
|
||||
@ -805,7 +859,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) {
|
||||
keys := make([]*ecdsa.PrivateKey, 5)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
local := keys[len(keys)-1]
|
||||
|
||||
@ -897,8 +951,8 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
|
||||
local, _ := crypto.GenerateKey()
|
||||
remote, _ := crypto.GenerateKey()
|
||||
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000))
|
||||
|
||||
// Add the two transactions and ensure they both are queued up
|
||||
if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil {
|
||||
@ -1031,7 +1085,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5)
|
||||
@ -1081,7 +1135,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 5)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Generate and queue a batch of transactions
|
||||
nonces := make(map[common.Address]uint64)
|
||||
@ -1120,7 +1174,7 @@ func TestTransactionAllowedTxSize(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000000))
|
||||
|
||||
// Compute maximal data size for transactions (lower bound).
|
||||
//
|
||||
@ -1184,7 +1238,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
|
||||
// Create a number of test accounts and fund them
|
||||
key, _ := crypto.GenerateKey()
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(addr, big.NewInt(1000000))
|
||||
testAddBalance(pool, addr, big.NewInt(1000000))
|
||||
|
||||
txs := types.Transactions{}
|
||||
for j := 0; j < int(config.GlobalSlots)*2; j++ {
|
||||
@ -1217,7 +1271,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 5)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Generate and queue a batch of transactions
|
||||
nonces := make(map[common.Address]uint64)
|
||||
@ -1267,7 +1321,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Generate and queue a batch of transactions, both pending and queued
|
||||
txs := types.Transactions{}
|
||||
@ -1367,8 +1421,135 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that setting the transaction pool gas price to a higher value correctly
|
||||
// discards everything cheaper (legacy & dynamic fee) than that and moves any
|
||||
// gapped transactions back from the pending pool to the queue.
|
||||
//
|
||||
// Note, local transactions are never allowed to be dropped.
|
||||
func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create the pool to test the pricing enforcement with
|
||||
pool, _ := setupTxPoolWithConfig(eip1559Config)
|
||||
defer pool.Stop()
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
events := make(chan NewTxsEvent, 32)
|
||||
sub := pool.txFeed.Subscribe(events)
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Generate and queue a batch of transactions, both pending and queued
|
||||
txs := types.Transactions{}
|
||||
|
||||
txs = append(txs, pricedTransaction(0, 100000, big.NewInt(2), keys[0]))
|
||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0]))
|
||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0]))
|
||||
|
||||
txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]))
|
||||
txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(3), big.NewInt(2), keys[1]))
|
||||
txs = append(txs, dynamicFeeTx(2, 100000, big.NewInt(3), big.NewInt(2), keys[1]))
|
||||
|
||||
txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(2), big.NewInt(2), keys[2]))
|
||||
txs = append(txs, dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2]))
|
||||
txs = append(txs, dynamicFeeTx(3, 100000, big.NewInt(2), big.NewInt(2), keys[2]))
|
||||
|
||||
ltx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[3])
|
||||
|
||||
// Import the batch and that both pending and queued transactions match up
|
||||
pool.AddRemotesSync(txs)
|
||||
pool.AddLocal(ltx)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
if pending != 7 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||
}
|
||||
if queued != 3 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
||||
}
|
||||
if err := validateEvents(events, 7); err != nil {
|
||||
t.Fatalf("original event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// Reprice the pool and check that underpriced transactions get dropped
|
||||
pool.SetGasPrice(big.NewInt(2))
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
if queued != 5 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5)
|
||||
}
|
||||
if err := validateEvents(events, 0); err != nil {
|
||||
t.Fatalf("reprice event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// Check that we can't add the old transactions back
|
||||
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[0])
|
||||
if err := pool.AddRemote(tx); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
tx = dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1])
|
||||
if err := pool.AddRemote(tx); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
tx = dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2])
|
||||
if err := pool.AddRemote(tx); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
if err := validateEvents(events, 0); err != nil {
|
||||
t.Fatalf("post-reprice event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// However we can add local underpriced transactions
|
||||
tx = dynamicFeeTx(1, 100000, big.NewInt(1), big.NewInt(1), keys[3])
|
||||
if err := pool.AddLocal(tx); err != nil {
|
||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||
}
|
||||
if pending, _ = pool.Stats(); pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
t.Fatalf("post-reprice local event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// And we can fill gaps with properly priced transactions
|
||||
tx = pricedTransaction(1, 100000, big.NewInt(2), keys[0])
|
||||
if err := pool.AddRemote(tx); err != nil {
|
||||
t.Fatalf("failed to add pending transaction: %v", err)
|
||||
}
|
||||
tx = dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[1])
|
||||
if err := pool.AddRemote(tx); err != nil {
|
||||
t.Fatalf("failed to add pending transaction: %v", err)
|
||||
}
|
||||
tx = dynamicFeeTx(2, 100000, big.NewInt(2), big.NewInt(2), keys[2])
|
||||
if err := pool.AddRemote(tx); err != nil {
|
||||
t.Fatalf("failed to add queued transaction: %v", err)
|
||||
}
|
||||
if err := validateEvents(events, 5); err != nil {
|
||||
t.Fatalf("post-reprice event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that setting the transaction pool gas price to a higher value does not
|
||||
// remove local transactions.
|
||||
// remove local transactions (legacy & dynamic fee).
|
||||
func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -1376,14 +1557,14 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||
|
||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
keys := make([]*ecdsa.PrivateKey, 3)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000*1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000*1000000))
|
||||
}
|
||||
// Create transaction (both pending and queued) with a linearly growing gasprice
|
||||
for i := uint64(0); i < 500; i++ {
|
||||
@ -1397,9 +1578,20 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
|
||||
if err := pool.AddLocal(queuedTx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Add pending dynamic fee transaction.
|
||||
pendingTx = dynamicFeeTx(i, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1])
|
||||
if err := pool.AddLocal(pendingTx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Add queued dynamic fee transaction.
|
||||
queuedTx = dynamicFeeTx(i+501, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1])
|
||||
if err := pool.AddLocal(queuedTx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
pending, queued := pool.Stats()
|
||||
expPending, expQueued := 500, 500
|
||||
expPending, expQueued := 1000, 1000
|
||||
validate := func() {
|
||||
pending, queued = pool.Stats()
|
||||
if pending != expPending {
|
||||
@ -1454,7 +1646,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Generate and queue a batch of transactions, both pending and queued
|
||||
txs := types.Transactions{}
|
||||
@ -1560,7 +1752,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 2)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Fill up the entire queue with the same transaction price points
|
||||
txs := types.Transactions{}
|
||||
@ -1601,6 +1793,173 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that when the pool reaches its global transaction limit, underpriced
|
||||
// transactions (legacy & dynamic fee) are gradually shifted out for more
|
||||
// expensive ones and any gapped pending transactions are moved into the queue.
|
||||
//
|
||||
// Note, local transactions are never allowed to be dropped.
|
||||
func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pool, _ := setupTxPoolWithConfig(eip1559Config)
|
||||
defer pool.Stop()
|
||||
|
||||
pool.config.GlobalSlots = 2
|
||||
pool.config.GlobalQueue = 2
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
events := make(chan NewTxsEvent, 32)
|
||||
sub := pool.txFeed.Subscribe(events)
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
|
||||
// Generate and queue a batch of transactions, both pending and queued
|
||||
txs := types.Transactions{}
|
||||
|
||||
txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[0]))
|
||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0]))
|
||||
txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(2), big.NewInt(1), keys[1]))
|
||||
|
||||
ltx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[2])
|
||||
|
||||
// Import the batch and that both pending and queued transactions match up
|
||||
pool.AddRemotes(txs) // Pend K0:0, K0:1; Que K1:1
|
||||
pool.AddLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
if queued != 1 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
|
||||
}
|
||||
if err := validateEvents(events, 3); err != nil {
|
||||
t.Fatalf("original event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
||||
// Ensure that adding an underpriced transaction fails
|
||||
tx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1])
|
||||
if err := pool.AddRemote(tx); err != ErrUnderpriced { // Pend K0:0, K0:1, K2:0; Que K1:1
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
|
||||
// Ensure that adding high priced transactions drops cheap ones, but not own
|
||||
tx = pricedTransaction(0, 100000, big.NewInt(2), keys[1])
|
||||
if err := pool.AddRemote(tx); err != nil { // +K1:0, -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que -
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
|
||||
tx = pricedTransaction(2, 100000, big.NewInt(3), keys[1])
|
||||
if err := pool.AddRemote(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
tx = dynamicFeeTx(3, 100000, big.NewInt(4), big.NewInt(1), keys[1])
|
||||
if err := pool.AddRemote(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
if queued != 2 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
t.Fatalf("additional event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// Ensure that adding local transactions can push out even higher priced ones
|
||||
ltx = dynamicFeeTx(1, 100000, big.NewInt(0), big.NewInt(0), keys[2])
|
||||
if err := pool.AddLocal(ltx); err != nil {
|
||||
t.Fatalf("failed to append underpriced local transaction: %v", err)
|
||||
}
|
||||
ltx = dynamicFeeTx(0, 100000, big.NewInt(0), big.NewInt(0), keys[3])
|
||||
if err := pool.AddLocal(ltx); err != nil {
|
||||
t.Fatalf("failed to add new underpriced local transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
if queued != 1 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
|
||||
}
|
||||
if err := validateEvents(events, 2); err != nil {
|
||||
t.Fatalf("local event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests whether highest fee cap transaction is retained after a batch of high effective
|
||||
// tip transactions are added and vice versa
|
||||
func TestDualHeapEviction(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pool, _ := setupTxPoolWithConfig(eip1559Config)
|
||||
defer pool.Stop()
|
||||
|
||||
pool.config.GlobalSlots = 10
|
||||
pool.config.GlobalQueue = 10
|
||||
|
||||
var (
|
||||
highTip, highCap *types.Transaction
|
||||
baseFee int
|
||||
)
|
||||
|
||||
check := func(tx *types.Transaction, name string) {
|
||||
if pool.all.GetRemote(tx.Hash()) == nil {
|
||||
t.Fatalf("highest %s transaction evicted from the pool", name)
|
||||
}
|
||||
}
|
||||
|
||||
add := func(urgent bool) {
|
||||
txs := make([]*types.Transaction, 20)
|
||||
for i := range txs {
|
||||
// Create a test accounts and fund it
|
||||
key, _ := crypto.GenerateKey()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000000))
|
||||
if urgent {
|
||||
txs[i] = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+1+i)), big.NewInt(int64(1+i)), key)
|
||||
highTip = txs[i]
|
||||
} else {
|
||||
txs[i] = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key)
|
||||
highCap = txs[i]
|
||||
}
|
||||
}
|
||||
pool.AddRemotes(txs)
|
||||
pending, queued := pool.Stats()
|
||||
if pending+queued != 20 {
|
||||
t.Fatalf("transaction count mismatch: have %d, want %d", pending+queued, 10)
|
||||
}
|
||||
}
|
||||
|
||||
add(false)
|
||||
for baseFee = 0; baseFee <= 1000; baseFee += 100 {
|
||||
pool.priced.SetBaseFee(big.NewInt(int64(baseFee)))
|
||||
add(true)
|
||||
check(highCap, "fee cap")
|
||||
add(false)
|
||||
check(highTip, "effective tip")
|
||||
}
|
||||
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the pool rejects duplicate transactions.
|
||||
func TestTransactionDeduplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
@ -1614,7 +1973,7 @@ func TestTransactionDeduplication(t *testing.T) {
|
||||
|
||||
// Create a test account to add transactions with
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||
|
||||
// Create a batch of transactions and add a few of them
|
||||
txs := make([]*types.Transaction, 16)
|
||||
@ -1685,7 +2044,7 @@ func TestTransactionReplacement(t *testing.T) {
|
||||
|
||||
// Create a test account to add transactions with
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||
|
||||
// Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too)
|
||||
price := int64(100)
|
||||
@ -1746,6 +2105,116 @@ func TestTransactionReplacement(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the pool rejects replacement dynamic fee transactions that don't
|
||||
// meet the minimum price bump required.
|
||||
func TestTransactionReplacementDynamicFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create the pool to test the pricing enforcement with
|
||||
pool, key := setupTxPoolWithConfig(eip1559Config)
|
||||
defer pool.Stop()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
events := make(chan NewTxsEvent, 32)
|
||||
sub := pool.txFeed.Subscribe(events)
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too)
|
||||
feeCap := int64(100)
|
||||
feeCapThreshold := (feeCap * (100 + int64(testTxPoolConfig.PriceBump))) / 100
|
||||
tip := int64(60)
|
||||
tipThreshold := (tip * (100 + int64(testTxPoolConfig.PriceBump))) / 100
|
||||
|
||||
// Run the following identical checks for both the pending and queue pools:
|
||||
// 1. Send initial tx => accept
|
||||
// 2. Don't bump tip or fee cap => discard
|
||||
// 3. Bump both more than min => accept
|
||||
// 4. Check events match expected (2 new executable txs during pending, 0 during queue)
|
||||
// 5. Send new tx with larger tip and feeCap => accept
|
||||
// 6. Bump tip max allowed so it's still underpriced => discard
|
||||
// 7. Bump fee cap max allowed so it's still underpriced => discard
|
||||
// 8. Bump tip min for acceptance => discard
|
||||
// 9. Bump feecap min for acceptance => discard
|
||||
// 10. Bump feecap and tip min for acceptance => accept
|
||||
// 11. Check events match expected (2 new executable txs during pending, 0 during queue)
|
||||
stages := []string{"pending", "queued"}
|
||||
for _, stage := range stages {
|
||||
// Since state is empty, 0 nonce txs are "executable" and can go
|
||||
// into pending immediately. 2 nonce txs are "happed
|
||||
nonce := uint64(0)
|
||||
if stage == "queued" {
|
||||
nonce = 2
|
||||
}
|
||||
|
||||
// 1. Send initial tx => accept
|
||||
tx := dynamicFeeTx(nonce, 100000, big.NewInt(2), big.NewInt(1), key)
|
||||
if err := pool.addRemoteSync(tx); err != nil {
|
||||
t.Fatalf("failed to add original cheap %s transaction: %v", stage, err)
|
||||
}
|
||||
// 2. Don't bump tip or feecap => discard
|
||||
tx = dynamicFeeTx(nonce, 100001, big.NewInt(2), big.NewInt(1), key)
|
||||
if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced {
|
||||
t.Fatalf("original cheap %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced)
|
||||
}
|
||||
// 3. Bump both more than min => accept
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(3), big.NewInt(2), key)
|
||||
if err := pool.AddRemote(tx); err != nil {
|
||||
t.Fatalf("failed to replace original cheap %s transaction: %v", stage, err)
|
||||
}
|
||||
// 4. Check events match expected (2 new executable txs during pending, 0 during queue)
|
||||
count := 2
|
||||
if stage == "queued" {
|
||||
count = 0
|
||||
}
|
||||
if err := validateEvents(events, count); err != nil {
|
||||
t.Fatalf("cheap %s replacement event firing failed: %v", stage, err)
|
||||
}
|
||||
// 5. Send new tx with larger tip and feeCap => accept
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCap), big.NewInt(tip), key)
|
||||
if err := pool.addRemoteSync(tx); err != nil {
|
||||
t.Fatalf("failed to add original proper %s transaction: %v", stage, err)
|
||||
}
|
||||
// 6. Bump tip max allowed so it's still underpriced => discard
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCap), big.NewInt(tipThreshold-1), key)
|
||||
if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced {
|
||||
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced)
|
||||
}
|
||||
// 7. Bump fee cap max allowed so it's still underpriced => discard
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold-1), big.NewInt(tip), key)
|
||||
if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced {
|
||||
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced)
|
||||
}
|
||||
// 8. Bump tip min for acceptance => accept
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCap), big.NewInt(tipThreshold), key)
|
||||
if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced {
|
||||
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced)
|
||||
}
|
||||
// 9. Bump fee cap min for acceptance => accept
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(tip), key)
|
||||
if err := pool.AddRemote(tx); err != ErrReplaceUnderpriced {
|
||||
t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, ErrReplaceUnderpriced)
|
||||
}
|
||||
// 10. Check events match expected (3 new executable txs during pending, 0 during queue)
|
||||
tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(tipThreshold), key)
|
||||
if err := pool.AddRemote(tx); err != nil {
|
||||
t.Fatalf("failed to replace original cheap %s transaction: %v", stage, err)
|
||||
}
|
||||
// 11. Check events match expected (3 new executable txs during pending, 0 during queue)
|
||||
count = 2
|
||||
if stage == "queued" {
|
||||
count = 0
|
||||
}
|
||||
if err := validateEvents(events, count); err != nil {
|
||||
t.Fatalf("replacement %s event firing failed: %v", stage, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that local transactions are journaled to disk, but remote transactions
|
||||
// get discarded between restarts.
|
||||
func TestTransactionJournaling(t *testing.T) { testTransactionJournaling(t, false) }
|
||||
@ -1781,8 +2250,8 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
|
||||
local, _ := crypto.GenerateKey()
|
||||
remote, _ := crypto.GenerateKey()
|
||||
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000))
|
||||
|
||||
// Add three local and a remote transactions and ensure they are queued up
|
||||
if err := pool.AddLocal(pricedTransaction(0, 100000, big.NewInt(1), local)); err != nil {
|
||||
@ -1875,7 +2344,7 @@ func TestTransactionStatusCheck(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 3)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
// Generate and queue a batch of transactions, both pending and queued
|
||||
txs := types.Transactions{}
|
||||
@ -1945,7 +2414,7 @@ func benchmarkPendingDemotion(b *testing.B, size int) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
tx := transaction(uint64(i), 100000, key)
|
||||
@ -1970,7 +2439,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
tx := transaction(uint64(1+i), 100000, key)
|
||||
@ -1998,7 +2467,7 @@ func benchmarkPoolBatchInsert(b *testing.B, size int, local bool) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
|
||||
batches := make([]types.Transactions, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -2039,13 +2508,13 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
pool, _ := setupTxPool()
|
||||
pool.currentState.AddBalance(account, big.NewInt(100000000))
|
||||
testAddBalance(pool, account, big.NewInt(100000000))
|
||||
for _, local := range locals {
|
||||
pool.AddLocal(local)
|
||||
}
|
||||
b.StartTimer()
|
||||
// Assign a high enough balance for testing
|
||||
pool.currentState.AddBalance(remoteAddr, big.NewInt(100000000))
|
||||
testAddBalance(pool, remoteAddr, big.NewInt(100000000))
|
||||
for i := 0; i < len(remotes); i++ {
|
||||
pool.AddRemotes([]*types.Transaction{remotes[i]})
|
||||
}
|
||||
|
Reference in New Issue
Block a user