github.com/ethereum/go-ethereum@v1.16.1/core/txpool/locals/tx_tracker_test.go (about)

     1  // Copyright 2025 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package locals
    18  
    19  import (
    20  	"math/big"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/consensus/ethash"
    26  	"github.com/ethereum/go-ethereum/core"
    27  	"github.com/ethereum/go-ethereum/core/rawdb"
    28  	"github.com/ethereum/go-ethereum/core/txpool"
    29  	"github.com/ethereum/go-ethereum/core/txpool/legacypool"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/crypto"
    32  	"github.com/ethereum/go-ethereum/ethdb"
    33  	"github.com/ethereum/go-ethereum/params"
    34  )
    35  
    36  var (
    37  	key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    38  	address = crypto.PubkeyToAddress(key.PublicKey)
    39  	funds   = big.NewInt(1000000000000000)
    40  	gspec   = &core.Genesis{
    41  		Config: params.TestChainConfig,
    42  		Alloc: types.GenesisAlloc{
    43  			address: {Balance: funds},
    44  		},
    45  		BaseFee: big.NewInt(params.InitialBaseFee),
    46  	}
    47  	signer = types.LatestSigner(gspec.Config)
    48  )
    49  
    50  type testEnv struct {
    51  	chain   *core.BlockChain
    52  	pool    *txpool.TxPool
    53  	tracker *TxTracker
    54  	genDb   ethdb.Database
    55  }
    56  
    57  func newTestEnv(t *testing.T, n int, gasTip uint64, journal string) *testEnv {
    58  	genDb, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), n, func(i int, gen *core.BlockGen) {
    59  		tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.BaseFee(), nil), signer, key)
    60  		if err != nil {
    61  			panic(err)
    62  		}
    63  		gen.AddTx(tx)
    64  	})
    65  
    66  	db := rawdb.NewMemoryDatabase()
    67  	chain, _ := core.NewBlockChain(db, gspec, ethash.NewFaker(), nil)
    68  
    69  	legacyPool := legacypool.New(legacypool.DefaultConfig, chain)
    70  	pool, err := txpool.New(gasTip, chain, []txpool.SubPool{legacyPool})
    71  	if err != nil {
    72  		t.Fatalf("Failed to create tx pool: %v", err)
    73  	}
    74  	if n, err := chain.InsertChain(blocks); err != nil {
    75  		t.Fatalf("Failed to process block %d: %v", n, err)
    76  	}
    77  	if err := pool.Sync(); err != nil {
    78  		t.Fatalf("Failed to sync the txpool, %v", err)
    79  	}
    80  	return &testEnv{
    81  		chain:   chain,
    82  		pool:    pool,
    83  		tracker: New(journal, time.Minute, gspec.Config, pool),
    84  		genDb:   genDb,
    85  	}
    86  }
    87  
    88  func (env *testEnv) close() {
    89  	env.chain.Stop()
    90  }
    91  
    92  // nolint:unused
    93  func (env *testEnv) setGasTip(gasTip uint64) {
    94  	env.pool.SetGasTip(new(big.Int).SetUint64(gasTip))
    95  }
    96  
    97  // nolint:unused
    98  func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction {
    99  	if nonce == 0 {
   100  		head := env.chain.CurrentHeader()
   101  		state, _ := env.chain.StateAt(head.Root)
   102  		nonce = state.GetNonce(address)
   103  	}
   104  	if gasPrice == nil {
   105  		gasPrice = big.NewInt(params.GWei)
   106  	}
   107  	tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{0x00}, big.NewInt(1000), params.TxGas, gasPrice, nil), signer, key)
   108  	return tx
   109  }
   110  
   111  func (env *testEnv) makeTxs(n int) []*types.Transaction {
   112  	head := env.chain.CurrentHeader()
   113  	state, _ := env.chain.StateAt(head.Root)
   114  	nonce := state.GetNonce(address)
   115  
   116  	var txs []*types.Transaction
   117  	for i := 0; i < n; i++ {
   118  		tx, _ := types.SignTx(types.NewTransaction(nonce+uint64(i), common.Address{0x00}, big.NewInt(1000), params.TxGas, big.NewInt(params.GWei), nil), signer, key)
   119  		txs = append(txs, tx)
   120  	}
   121  	return txs
   122  }
   123  
   124  // nolint:unused
   125  func (env *testEnv) commit() {
   126  	head := env.chain.CurrentBlock()
   127  	block := env.chain.GetBlock(head.Hash(), head.Number.Uint64())
   128  	blocks, _ := core.GenerateChain(env.chain.Config(), block, ethash.NewFaker(), env.genDb, 1, func(i int, gen *core.BlockGen) {
   129  		tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.BaseFee(), nil), signer, key)
   130  		if err != nil {
   131  			panic(err)
   132  		}
   133  		gen.AddTx(tx)
   134  	})
   135  	env.chain.InsertChain(blocks)
   136  	if err := env.pool.Sync(); err != nil {
   137  		panic(err)
   138  	}
   139  }
   140  
   141  func TestResubmit(t *testing.T) {
   142  	env := newTestEnv(t, 10, 0, "")
   143  	defer env.close()
   144  
   145  	txs := env.makeTxs(10)
   146  	txsA := txs[:len(txs)/2]
   147  	txsB := txs[len(txs)/2:]
   148  	env.pool.Add(txsA, true)
   149  	pending, queued := env.pool.ContentFrom(address)
   150  	if len(pending) != len(txsA) || len(queued) != 0 {
   151  		t.Fatalf("Unexpected txpool content: %d, %d", len(pending), len(queued))
   152  	}
   153  	env.tracker.TrackAll(txs)
   154  
   155  	resubmit, all := env.tracker.recheck(true)
   156  	if len(resubmit) != len(txsB) {
   157  		t.Fatalf("Unexpected transactions to resubmit, got: %d, want: %d", len(resubmit), len(txsB))
   158  	}
   159  	if len(all) == 0 || len(all[address]) == 0 {
   160  		t.Fatalf("Unexpected transactions being tracked, got: %d, want: %d", 0, len(txs))
   161  	}
   162  	if len(all[address]) != len(txs) {
   163  		t.Fatalf("Unexpected transactions being tracked, got: %d, want: %d", len(all[address]), len(txs))
   164  	}
   165  }