github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/core/txindexer_test.go (about) 1 // Copyright 2024 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 core 18 19 import ( 20 "math/big" 21 "testing" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/consensus/ethash" 25 "github.com/ethereum/go-ethereum/core/rawdb" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/ethdb" 29 "github.com/ethereum/go-ethereum/params" 30 ) 31 32 // TestTxIndexer tests the functionalities for managing transaction indexes. 33 func TestTxIndexer(t *testing.T) { 34 var ( 35 testBankKey, _ = crypto.GenerateKey() 36 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 37 testBankFunds = big.NewInt(1000000000000000000) 38 39 gspec = &Genesis{ 40 Config: params.TestChainConfig, 41 Alloc: types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, 42 BaseFee: big.NewInt(params.InitialBaseFee), 43 } 44 engine = ethash.NewFaker() 45 nonce = uint64(0) 46 chainHead = uint64(128) 47 ) 48 _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(chainHead), func(i int, gen *BlockGen) { 49 tx, _ := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("0xdeadbeef"), big.NewInt(1000), params.TxGas, big.NewInt(10*params.InitialBaseFee), nil), types.HomesteadSigner{}, testBankKey) 50 gen.AddTx(tx) 51 nonce += 1 52 }) 53 54 // verifyIndexes checks if the transaction indexes are present or not 55 // of the specified block. 56 verifyIndexes := func(db ethdb.Database, number uint64, exist bool) { 57 if number == 0 { 58 return 59 } 60 block := blocks[number-1] 61 for _, tx := range block.Transactions() { 62 lookup := rawdb.ReadTxLookupEntry(db, tx.Hash()) 63 if exist && lookup == nil { 64 t.Fatalf("missing %d %x", number, tx.Hash().Hex()) 65 } 66 if !exist && lookup != nil { 67 t.Fatalf("unexpected %d %x", number, tx.Hash().Hex()) 68 } 69 } 70 } 71 verify := func(db ethdb.Database, expTail uint64, indexer *txIndexer) { 72 tail := rawdb.ReadTxIndexTail(db) 73 if tail == nil { 74 t.Fatal("Failed to write tx index tail") 75 } 76 if *tail != expTail { 77 t.Fatalf("Unexpected tx index tail, want %v, got %d", expTail, *tail) 78 } 79 if *tail != 0 { 80 for number := uint64(0); number < *tail; number += 1 { 81 verifyIndexes(db, number, false) 82 } 83 } 84 for number := *tail; number <= chainHead; number += 1 { 85 verifyIndexes(db, number, true) 86 } 87 progress := indexer.report(chainHead, tail) 88 if !progress.Done() { 89 t.Fatalf("Expect fully indexed") 90 } 91 } 92 93 var cases = []struct { 94 limitA uint64 95 tailA uint64 96 limitB uint64 97 tailB uint64 98 limitC uint64 99 tailC uint64 100 }{ 101 { 102 // LimitA: 0 103 // TailA: 0 104 // 105 // all blocks are indexed 106 limitA: 0, 107 tailA: 0, 108 109 // LimitB: 1 110 // TailB: 128 111 // 112 // block-128 is indexed 113 limitB: 1, 114 tailB: 128, 115 116 // LimitB: 64 117 // TailB: 65 118 // 119 // block [65, 128] are indexed 120 limitC: 64, 121 tailC: 65, 122 }, 123 { 124 // LimitA: 64 125 // TailA: 65 126 // 127 // block [65, 128] are indexed 128 limitA: 64, 129 tailA: 65, 130 131 // LimitB: 1 132 // TailB: 128 133 // 134 // block-128 is indexed 135 limitB: 1, 136 tailB: 128, 137 138 // LimitB: 64 139 // TailB: 65 140 // 141 // block [65, 128] are indexed 142 limitC: 64, 143 tailC: 65, 144 }, 145 { 146 // LimitA: 127 147 // TailA: 2 148 // 149 // block [2, 128] are indexed 150 limitA: 127, 151 tailA: 2, 152 153 // LimitB: 1 154 // TailB: 128 155 // 156 // block-128 is indexed 157 limitB: 1, 158 tailB: 128, 159 160 // LimitB: 64 161 // TailB: 65 162 // 163 // block [65, 128] are indexed 164 limitC: 64, 165 tailC: 65, 166 }, 167 { 168 // LimitA: 128 169 // TailA: 1 170 // 171 // block [2, 128] are indexed 172 limitA: 128, 173 tailA: 1, 174 175 // LimitB: 1 176 // TailB: 128 177 // 178 // block-128 is indexed 179 limitB: 1, 180 tailB: 128, 181 182 // LimitB: 64 183 // TailB: 65 184 // 185 // block [65, 128] are indexed 186 limitC: 64, 187 tailC: 65, 188 }, 189 { 190 // LimitA: 129 191 // TailA: 0 192 // 193 // block [0, 128] are indexed 194 limitA: 129, 195 tailA: 0, 196 197 // LimitB: 1 198 // TailB: 128 199 // 200 // block-128 is indexed 201 limitB: 1, 202 tailB: 128, 203 204 // LimitB: 64 205 // TailB: 65 206 // 207 // block [65, 128] are indexed 208 limitC: 64, 209 tailC: 65, 210 }, 211 } 212 for _, c := range cases { 213 db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) 214 rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) 215 216 // Index the initial blocks from ancient store 217 indexer := &txIndexer{ 218 limit: c.limitA, 219 db: db, 220 progress: make(chan chan TxIndexProgress), 221 } 222 indexer.run(nil, 128, make(chan struct{}), make(chan struct{})) 223 verify(db, c.tailA, indexer) 224 225 indexer.limit = c.limitB 226 indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{})) 227 verify(db, c.tailB, indexer) 228 229 indexer.limit = c.limitC 230 indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{})) 231 verify(db, c.tailC, indexer) 232 233 // Recover all indexes 234 indexer.limit = 0 235 indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{})) 236 verify(db, 0, indexer) 237 238 db.Close() 239 } 240 }