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 }