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  }