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 }