github.com/MetalBlockchain/subnet-evm@v0.4.9/core/rawdb/chain_iterator_test.go (about)

     1  // (c) 2019-2022, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2020 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package rawdb
    28  
    29  import (
    30  	"math/big"
    31  	"reflect"
    32  	"sort"
    33  	"sync"
    34  	"testing"
    35  
    36  	"github.com/MetalBlockchain/subnet-evm/core/types"
    37  	"github.com/ethereum/go-ethereum/common"
    38  )
    39  
    40  func TestChainIterator(t *testing.T) {
    41  	// Construct test chain db
    42  	chainDb := NewMemoryDatabase()
    43  
    44  	var block *types.Block
    45  	var txs []*types.Transaction
    46  	to := common.BytesToAddress([]byte{0x11})
    47  	block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newHasher()) // Empty genesis block
    48  	WriteBlock(chainDb, block)
    49  	WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
    50  	for i := uint64(1); i <= 10; i++ {
    51  		var tx *types.Transaction
    52  		if i%2 == 0 {
    53  			tx = types.NewTx(&types.LegacyTx{
    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  		} else {
    62  			tx = types.NewTx(&types.AccessListTx{
    63  				ChainID:  big.NewInt(1337),
    64  				Nonce:    i,
    65  				GasPrice: big.NewInt(11111),
    66  				Gas:      1111,
    67  				To:       &to,
    68  				Value:    big.NewInt(111),
    69  				Data:     []byte{0x11, 0x11, 0x11},
    70  			})
    71  		}
    72  		txs = append(txs, tx)
    73  		block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
    74  		WriteBlock(chainDb, block)
    75  		WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
    76  	}
    77  
    78  	cases := []struct {
    79  		from, to uint64
    80  		reverse  bool
    81  		expect   []int
    82  	}{
    83  		{0, 11, true, []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
    84  		{0, 0, true, nil},
    85  		{0, 5, true, []int{4, 3, 2, 1, 0}},
    86  		{10, 11, true, []int{10}},
    87  		{0, 11, false, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
    88  		{0, 0, false, nil},
    89  		{10, 11, false, []int{10}},
    90  	}
    91  	for i, c := range cases {
    92  		var numbers []int
    93  		hashCh := iterateTransactions(chainDb, c.from, c.to, c.reverse, nil)
    94  		if hashCh != nil {
    95  			for h := range hashCh {
    96  				numbers = append(numbers, int(h.number))
    97  				if len(h.hashes) > 0 {
    98  					if got, exp := h.hashes[0], txs[h.number-1].Hash(); got != exp {
    99  						t.Fatalf("block %d: hash wrong, got %x exp %x", h.number, got, exp)
   100  					}
   101  				}
   102  			}
   103  		}
   104  		if !c.reverse {
   105  			sort.Ints(numbers)
   106  		} else {
   107  			sort.Sort(sort.Reverse(sort.IntSlice(numbers)))
   108  		}
   109  		if !reflect.DeepEqual(numbers, c.expect) {
   110  			t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers)
   111  		}
   112  	}
   113  }
   114  
   115  func TestIndexTransactions(t *testing.T) {
   116  	// Construct test chain db
   117  	chainDb := NewMemoryDatabase()
   118  
   119  	var block *types.Block
   120  	var txs []*types.Transaction
   121  	to := common.BytesToAddress([]byte{0x11})
   122  
   123  	// Write empty genesis block
   124  	block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newHasher())
   125  	WriteBlock(chainDb, block)
   126  	WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
   127  
   128  	for i := uint64(1); i <= 10; i++ {
   129  		var tx *types.Transaction
   130  		if i%2 == 0 {
   131  			tx = types.NewTx(&types.LegacyTx{
   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  		} else {
   140  			tx = types.NewTx(&types.AccessListTx{
   141  				ChainID:  big.NewInt(1337),
   142  				Nonce:    i,
   143  				GasPrice: big.NewInt(11111),
   144  				Gas:      1111,
   145  				To:       &to,
   146  				Value:    big.NewInt(111),
   147  				Data:     []byte{0x11, 0x11, 0x11},
   148  			})
   149  		}
   150  		txs = append(txs, tx)
   151  		block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newHasher())
   152  		WriteBlock(chainDb, block)
   153  		WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
   154  	}
   155  	// verify checks whether the tx indices in the range [from, to)
   156  	// is expected.
   157  	verify := func(from, to int, exist bool, tail uint64) {
   158  		for i := from; i < to; i++ {
   159  			if i == 0 {
   160  				continue
   161  			}
   162  			number := ReadTxLookupEntry(chainDb, txs[i-1].Hash())
   163  			if exist && number == nil {
   164  				t.Fatalf("Transaction index %d missing", i)
   165  			}
   166  			if !exist && number != nil {
   167  				t.Fatalf("Transaction index %d is not deleted", i)
   168  			}
   169  		}
   170  		number := ReadTxIndexTail(chainDb)
   171  		if number == nil || *number != tail {
   172  			t.Fatalf("Transaction tail mismatch")
   173  		}
   174  	}
   175  	indexTransactionsForTesting(chainDb, 5, 11, nil, nil)
   176  	verify(5, 11, true, 5)
   177  	verify(0, 5, false, 5)
   178  
   179  	indexTransactionsForTesting(chainDb, 0, 5, nil, nil)
   180  	verify(0, 11, true, 0)
   181  
   182  	UnindexTransactions(chainDb, 0, 5, nil)
   183  	verify(5, 11, true, 5)
   184  	verify(0, 5, false, 5)
   185  
   186  	UnindexTransactions(chainDb, 5, 11, nil)
   187  	verify(0, 11, false, 11)
   188  
   189  	// Testing corner cases
   190  	signal := make(chan struct{})
   191  	var once sync.Once
   192  	indexTransactionsForTesting(chainDb, 5, 11, signal, func(n uint64) bool {
   193  		if n <= 8 {
   194  			once.Do(func() {
   195  				close(signal)
   196  			})
   197  			return false
   198  		}
   199  		return true
   200  	})
   201  	verify(9, 11, true, 9)
   202  	verify(0, 9, false, 9)
   203  	indexTransactionsForTesting(chainDb, 0, 9, nil, nil)
   204  
   205  	signal = make(chan struct{})
   206  	var once2 sync.Once
   207  	unindexTransactionsForTesting(chainDb, 0, 11, signal, func(n uint64) bool {
   208  		if n >= 8 {
   209  			once2.Do(func() {
   210  				close(signal)
   211  			})
   212  			return false
   213  		}
   214  		return true
   215  	})
   216  	verify(8, 11, true, 8)
   217  	verify(0, 8, false, 8)
   218  }