github.com/jimmyx0x/go-ethereum@v1.10.28/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, nil, newHasher()) // 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.Transaction{tx}, nil, nil, newHasher()) 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, nil, newHasher()) 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.Transaction{tx}, nil, nil, newHasher()) 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) 166 verify(5, 11, true, 5) 167 verify(0, 5, false, 5) 168 169 IndexTransactions(chainDb, 0, 5, nil) 170 verify(0, 11, true, 0) 171 172 UnindexTransactions(chainDb, 0, 5, nil) 173 verify(5, 11, true, 5) 174 verify(0, 5, false, 5) 175 176 UnindexTransactions(chainDb, 5, 11, nil) 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) 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 }