github.com/ethereum/go-ethereum@v1.14.3/core/rawdb/chain_iterator_test.go (about)

     1  // Copyright 2020 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  	to := common.BytesToAddress([]byte{0x11})
    37  	block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher()) // Empty genesis block
    38  	WriteBlock(chainDb, block)
    39  	WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
    40  	for i := uint64(1); i <= 10; i++ {
    41  		var tx *types.Transaction
    42  		if i%2 == 0 {
    43  			tx = types.NewTx(&types.LegacyTx{
    44  				Nonce:    i,
    45  				GasPrice: big.NewInt(11111),
    46  				Gas:      1111,
    47  				To:       &to,
    48  				Value:    big.NewInt(111),
    49  				Data:     []byte{0x11, 0x11, 0x11},
    50  			})
    51  		} else {
    52  			tx = types.NewTx(&types.AccessListTx{
    53  				ChainID:  big.NewInt(1337),
    54  				Nonce:    i,
    55  				GasPrice: big.NewInt(11111),
    56  				Gas:      1111,
    57  				To:       &to,
    58  				Value:    big.NewInt(111),
    59  				Data:     []byte{0x11, 0x11, 0x11},
    60  			})
    61  		}
    62  		txs = append(txs, tx)
    63  		block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher())
    64  		WriteBlock(chainDb, block)
    65  		WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
    66  	}
    67  
    68  	var cases = []struct {
    69  		from, to uint64
    70  		reverse  bool
    71  		expect   []int
    72  	}{
    73  		{0, 11, true, []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
    74  		{0, 0, true, nil},
    75  		{0, 5, true, []int{4, 3, 2, 1, 0}},
    76  		{10, 11, true, []int{10}},
    77  		{0, 11, false, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
    78  		{0, 0, false, nil},
    79  		{10, 11, false, []int{10}},
    80  	}
    81  	for i, c := range cases {
    82  		var numbers []int
    83  		hashCh := iterateTransactions(chainDb, c.from, c.to, c.reverse, nil)
    84  		if hashCh != nil {
    85  			for h := range hashCh {
    86  				numbers = append(numbers, int(h.number))
    87  				if len(h.hashes) > 0 {
    88  					if got, exp := h.hashes[0], txs[h.number-1].Hash(); got != exp {
    89  						t.Fatalf("block %d: hash wrong, got %x exp %x", h.number, got, exp)
    90  					}
    91  				}
    92  			}
    93  		}
    94  		if !c.reverse {
    95  			sort.Ints(numbers)
    96  		} else {
    97  			sort.Sort(sort.Reverse(sort.IntSlice(numbers)))
    98  		}
    99  		if !reflect.DeepEqual(numbers, c.expect) {
   100  			t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers)
   101  		}
   102  	}
   103  }
   104  
   105  func TestIndexTransactions(t *testing.T) {
   106  	// Construct test chain db
   107  	chainDb := NewMemoryDatabase()
   108  
   109  	var block *types.Block
   110  	var txs []*types.Transaction
   111  	to := common.BytesToAddress([]byte{0x11})
   112  
   113  	// Write empty genesis block
   114  	block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher())
   115  	WriteBlock(chainDb, block)
   116  	WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
   117  
   118  	for i := uint64(1); i <= 10; i++ {
   119  		var tx *types.Transaction
   120  		if i%2 == 0 {
   121  			tx = types.NewTx(&types.LegacyTx{
   122  				Nonce:    i,
   123  				GasPrice: big.NewInt(11111),
   124  				Gas:      1111,
   125  				To:       &to,
   126  				Value:    big.NewInt(111),
   127  				Data:     []byte{0x11, 0x11, 0x11},
   128  			})
   129  		} else {
   130  			tx = types.NewTx(&types.AccessListTx{
   131  				ChainID:  big.NewInt(1337),
   132  				Nonce:    i,
   133  				GasPrice: big.NewInt(11111),
   134  				Gas:      1111,
   135  				To:       &to,
   136  				Value:    big.NewInt(111),
   137  				Data:     []byte{0x11, 0x11, 0x11},
   138  			})
   139  		}
   140  		txs = append(txs, tx)
   141  		block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher())
   142  		WriteBlock(chainDb, block)
   143  		WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
   144  	}
   145  	// verify checks whether the tx indices in the range [from, to)
   146  	// is expected.
   147  	verify := func(from, to int, exist bool, tail uint64) {
   148  		for i := from; i < to; i++ {
   149  			if i == 0 {
   150  				continue
   151  			}
   152  			number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
   153  			if exist && number == nil {
   154  				t.Fatalf("Transaction index %d missing", i)
   155  			}
   156  			if !exist && number != nil {
   157  				t.Fatalf("Transaction index %d is not deleted", i)
   158  			}
   159  		}
   160  		number := ReadTxIndexTail(chainDb)
   161  		if number == nil || *number != tail {
   162  			t.Fatalf("Transaction tail mismatch")
   163  		}
   164  	}
   165  	IndexTransactions(chainDb, 5, 11, nil, false)
   166  	verify(5, 11, true, 5)
   167  	verify(0, 5, false, 5)
   168  
   169  	IndexTransactions(chainDb, 0, 5, nil, false)
   170  	verify(0, 11, true, 0)
   171  
   172  	UnindexTransactions(chainDb, 0, 5, nil, false)
   173  	verify(5, 11, true, 5)
   174  	verify(0, 5, false, 5)
   175  
   176  	UnindexTransactions(chainDb, 5, 11, nil, false)
   177  	verify(0, 11, false, 11)
   178  
   179  	// Testing corner cases
   180  	signal := make(chan struct{})
   181  	var once sync.Once
   182  	indexTransactionsForTesting(chainDb, 5, 11, signal, func(n uint64) bool {
   183  		if n <= 8 {
   184  			once.Do(func() {
   185  				close(signal)
   186  			})
   187  			return false
   188  		}
   189  		return true
   190  	})
   191  	verify(9, 11, true, 9)
   192  	verify(0, 9, false, 9)
   193  	IndexTransactions(chainDb, 0, 9, nil, false)
   194  
   195  	signal = make(chan struct{})
   196  	var once2 sync.Once
   197  	unindexTransactionsForTesting(chainDb, 0, 11, signal, func(n uint64) bool {
   198  		if n >= 8 {
   199  			once2.Do(func() {
   200  				close(signal)
   201  			})
   202  			return false
   203  		}
   204  		return true
   205  	})
   206  	verify(8, 11, true, 8)
   207  	verify(0, 8, false, 8)
   208  }