github.com/gilgames000/kcc-geth@v1.0.6/core/rawdb/chain_iterator_test.go (about)

     1  // Copyright 2019 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 rawdb
    18  
    19  import (
    20  	"math/big"
    21  	"reflect"
    22  	"sort"
    23  	"sync"
    24  	"testing"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  )
    29  
    30  func TestChainIterator(t *testing.T) {
    31  	// Construct test chain db
    32  	chainDb := NewMemoryDatabase()
    33  
    34  	var block *types.Block
    35  	var txs []*types.Transaction
    36  	for i := uint64(0); i <= 10; i++ {
    37  		if i == 0 {
    38  			block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, nil, nil, nil, newHasher()) // Empty genesis block
    39  		} else {
    40  			tx := types.NewTransaction(i, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
    41  			txs = append(txs, tx)
    42  			block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
    43  		}
    44  		WriteBlock(chainDb, block)
    45  		WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
    46  	}
    47  
    48  	var cases = []struct {
    49  		from, to uint64
    50  		reverse  bool
    51  		expect   []int
    52  	}{
    53  		{0, 11, true, []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
    54  		{0, 0, true, nil},
    55  		{0, 5, true, []int{4, 3, 2, 1, 0}},
    56  		{10, 11, true, []int{10}},
    57  		{0, 11, false, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
    58  		{0, 0, false, nil},
    59  		{10, 11, false, []int{10}},
    60  	}
    61  	for i, c := range cases {
    62  		var numbers []int
    63  		hashCh := iterateTransactions(chainDb, c.from, c.to, c.reverse, nil)
    64  		if hashCh != nil {
    65  			for h := range hashCh {
    66  				numbers = append(numbers, int(h.number))
    67  				if len(h.hashes) > 0 {
    68  					if got, exp := h.hashes[0], txs[h.number-1].Hash(); got != exp {
    69  						t.Fatalf("hash wrong, got %x exp %x", got, exp)
    70  					}
    71  				}
    72  			}
    73  		}
    74  		if !c.reverse {
    75  			sort.Ints(numbers)
    76  		} else {
    77  			sort.Sort(sort.Reverse(sort.IntSlice(numbers)))
    78  		}
    79  		if !reflect.DeepEqual(numbers, c.expect) {
    80  			t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers)
    81  		}
    82  	}
    83  }
    84  
    85  func TestIndexTransactions(t *testing.T) {
    86  	// Construct test chain db
    87  	chainDb := NewMemoryDatabase()
    88  
    89  	var block *types.Block
    90  	var txs []*types.Transaction
    91  	for i := uint64(0); i <= 10; i++ {
    92  		if i == 0 {
    93  			block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, nil, nil, nil, newHasher()) // Empty genesis block
    94  		} else {
    95  			tx := types.NewTransaction(i, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
    96  			txs = append(txs, tx)
    97  			block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
    98  		}
    99  		WriteBlock(chainDb, block)
   100  		WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
   101  	}
   102  	// verify checks whether the tx indices in the range [from, to)
   103  	// is expected.
   104  	verify := func(from, to int, exist bool, tail uint64) {
   105  		for i := from; i < to; i++ {
   106  			if i == 0 {
   107  				continue
   108  			}
   109  			number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
   110  			if exist && number == nil {
   111  				t.Fatalf("Transaction indice missing")
   112  			}
   113  			if !exist && number != nil {
   114  				t.Fatalf("Transaction indice is not deleted")
   115  			}
   116  		}
   117  		number := ReadTxIndexTail(chainDb)
   118  		if number == nil || *number != tail {
   119  			t.Fatalf("Transaction tail mismatch")
   120  		}
   121  	}
   122  	IndexTransactions(chainDb, 5, 11, nil)
   123  	verify(5, 11, true, 5)
   124  	verify(0, 5, false, 5)
   125  
   126  	IndexTransactions(chainDb, 0, 5, nil)
   127  	verify(0, 11, true, 0)
   128  
   129  	UnindexTransactions(chainDb, 0, 5, nil)
   130  	verify(5, 11, true, 5)
   131  	verify(0, 5, false, 5)
   132  
   133  	UnindexTransactions(chainDb, 5, 11, nil)
   134  	verify(0, 11, false, 11)
   135  
   136  	// Testing corner cases
   137  	signal := make(chan struct{})
   138  	var once sync.Once
   139  	indexTransactionsForTesting(chainDb, 5, 11, signal, func(n uint64) bool {
   140  		if n <= 8 {
   141  			once.Do(func() {
   142  				close(signal)
   143  			})
   144  			return false
   145  		}
   146  		return true
   147  	})
   148  	verify(9, 11, true, 9)
   149  	verify(0, 9, false, 9)
   150  	IndexTransactions(chainDb, 0, 9, nil)
   151  
   152  	signal = make(chan struct{})
   153  	var once2 sync.Once
   154  	unindexTransactionsForTesting(chainDb, 0, 11, signal, func(n uint64) bool {
   155  		if n >= 8 {
   156  			once2.Do(func() {
   157  				close(signal)
   158  			})
   159  			return false
   160  		}
   161  		return true
   162  	})
   163  	verify(8, 11, true, 8)
   164  	verify(0, 8, false, 8)
   165  }