github.com/klaytn/klaytn@v1.12.1/node/cn/filters/filter_test.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/filters/filter_system_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package filters 22 23 import ( 24 "context" 25 "math/big" 26 "testing" 27 28 "github.com/golang/mock/gomock" 29 "github.com/klaytn/klaytn/blockchain" 30 "github.com/klaytn/klaytn/blockchain/types" 31 "github.com/klaytn/klaytn/common" 32 "github.com/klaytn/klaytn/consensus/gxhash" 33 "github.com/klaytn/klaytn/crypto" 34 "github.com/klaytn/klaytn/event" 35 "github.com/klaytn/klaytn/networks/rpc" 36 cn "github.com/klaytn/klaytn/node/cn/filters/mock" 37 "github.com/klaytn/klaytn/params" 38 "github.com/klaytn/klaytn/storage/database" 39 "github.com/pkg/errors" 40 "github.com/stretchr/testify/assert" 41 ) 42 43 var ( 44 addr1 = common.HexToAddress("111") 45 addr2 = common.HexToAddress("222") 46 addrs []common.Address 47 ) 48 49 var ( 50 topic1 common.Hash 51 topic2 common.Hash 52 topics [][]common.Hash 53 ) 54 55 var ( 56 begin = int64(12345) 57 end = int64(12345) 58 ) 59 60 var header *types.Header 61 62 var someErr = errors.New("some error") 63 64 func init() { 65 addrs = []common.Address{addr1, addr2} 66 topics = [][]common.Hash{{topic1}, {topic2}} 67 header = &types.Header{ 68 Number: big.NewInt(int64(123)), 69 BlockScore: big.NewInt(int64(1)), 70 Extra: addrs[0][:], 71 Governance: addrs[0][:], 72 Vote: addrs[0][:], 73 } 74 } 75 76 func genFilter(t *testing.T) (*gomock.Controller, *cn.MockBackend, *Filter) { 77 mockCtrl := gomock.NewController(t) 78 mockBackend := cn.NewMockBackend(mockCtrl) 79 mockBackend.EXPECT().BloomStatus().Return(uint64(123), uint64(321)).Times(1) 80 newFilter := NewRangeFilter(mockBackend, begin, end, addrs, topics) 81 return mockCtrl, mockBackend, newFilter 82 } 83 84 func TestFilter_New(t *testing.T) { 85 mockCtrl, mockBackend, newFilter := genFilter(t) 86 defer mockCtrl.Finish() 87 88 assert.NotNil(t, newFilter) 89 assert.Equal(t, mockBackend, newFilter.backend) 90 assert.Equal(t, begin, newFilter.begin) 91 assert.Equal(t, end, newFilter.end) 92 assert.Equal(t, topics, newFilter.topics) 93 assert.Equal(t, addrs, newFilter.addresses) 94 assert.NotNil(t, newFilter.matcher) 95 } 96 97 func TestFilter_Logs(t *testing.T) { 98 ctx := context.Background() 99 { 100 mockCtrl, mockBackend, newFilter := genFilter(t) 101 mockBackend.EXPECT().HeaderByNumber(ctx, rpc.LatestBlockNumber).Times(1).Return(nil, nil) 102 logs, err := newFilter.Logs(ctx) 103 assert.Nil(t, logs) 104 assert.NoError(t, err) 105 mockCtrl.Finish() 106 } 107 } 108 109 func TestFilter_unindexedLogs(t *testing.T) { 110 ctx := context.Background() 111 { 112 mockCtrl, mockBackend, newFilter := genFilter(t) 113 mockBackend.EXPECT().HeaderByNumber(ctx, rpc.BlockNumber(newFilter.begin)).Times(1).Return(nil, nil) 114 logs, err := newFilter.unindexedLogs(ctx, uint64(newFilter.end)) 115 assert.Nil(t, logs) 116 assert.NoError(t, err) 117 mockCtrl.Finish() 118 } 119 { 120 mockCtrl, mockBackend, newFilter := genFilter(t) 121 mockBackend.EXPECT().HeaderByNumber(ctx, rpc.BlockNumber(newFilter.begin)).Times(1).Return(header, nil) 122 logs, err := newFilter.unindexedLogs(ctx, uint64(newFilter.end)) 123 assert.Nil(t, logs) 124 assert.NoError(t, err) 125 mockCtrl.Finish() 126 } 127 } 128 129 func TestFilter_checkMatches(t *testing.T) { 130 ctx := context.Background() 131 { 132 mockCtrl, mockBackend, newFilter := genFilter(t) 133 mockBackend.EXPECT().GetLogs(ctx, header.Hash()).Times(1).Return(nil, someErr) 134 logs, err := newFilter.checkMatches(ctx, header) 135 assert.Nil(t, logs) 136 assert.Equal(t, someErr, err) 137 mockCtrl.Finish() 138 } 139 { 140 mockCtrl, mockBackend, newFilter := genFilter(t) 141 mockBackend.EXPECT().GetLogs(ctx, header.Hash()).Times(1).Return(nil, nil) 142 logs, err := newFilter.checkMatches(ctx, header) 143 assert.Nil(t, logs) 144 assert.NoError(t, err) 145 mockCtrl.Finish() 146 } 147 } 148 149 func TestFilter_bloomFilter(t *testing.T) { 150 { 151 assert.True(t, bloomFilter(types.Bloom{}, nil, nil)) 152 } 153 { 154 assert.False(t, bloomFilter(types.Bloom{}, nil, [][]common.Hash{{topic1}})) 155 } 156 { 157 assert.False(t, bloomFilter(types.Bloom{}, []common.Address{addr1}, nil)) 158 } 159 } 160 161 func makeReceipt(addr common.Address) *types.Receipt { 162 receipt := genReceipt(false, 0) 163 receipt.Logs = []*types.Log{ 164 {Address: addr}, 165 } 166 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 167 return receipt 168 } 169 170 func BenchmarkFilters(b *testing.B) { 171 var ( 172 db = database.NewMemoryDBManager() 173 mux = new(event.TypeMux) 174 txFeed = new(event.Feed) 175 rmLogsFeed = new(event.Feed) 176 logsFeed = new(event.Feed) 177 chainFeed = new(event.Feed) 178 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed, params.TestChainConfig} 179 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 180 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 181 addr2 = common.BytesToAddress([]byte("jeff")) 182 addr3 = common.BytesToAddress([]byte("ethereum")) 183 addr4 = common.BytesToAddress([]byte("random addresses please")) 184 ) 185 defer db.Close() 186 187 genesis := blockchain.GenesisBlockForTesting(db, addr1, big.NewInt(1000000)) 188 chain, receipts := blockchain.GenerateChain(params.TestChainConfig, genesis, gxhash.NewFaker(), db, 100010, func(i int, gen *blockchain.BlockGen) { 189 switch i { 190 case 2403: 191 receipt := makeReceipt(addr1) 192 gen.AddUncheckedReceipt(receipt) 193 case 1034: 194 receipt := makeReceipt(addr2) 195 gen.AddUncheckedReceipt(receipt) 196 case 34: 197 receipt := makeReceipt(addr3) 198 gen.AddUncheckedReceipt(receipt) 199 case 99999: 200 receipt := makeReceipt(addr4) 201 gen.AddUncheckedReceipt(receipt) 202 203 } 204 }) 205 for i, block := range chain { 206 db.WriteBlock(block) 207 db.WriteCanonicalHash(block.Hash(), block.NumberU64()) 208 db.WriteHeadBlockHash(block.Hash()) 209 db.WriteReceipts(block.Hash(), block.NumberU64(), receipts[i]) 210 } 211 b.ResetTimer() 212 213 filter := NewRangeFilter(backend, 0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil) 214 215 for i := 0; i < b.N; i++ { 216 logs, _ := filter.Logs(context.Background()) 217 if len(logs) != 4 { 218 b.Fatal("expected 4 logs, got", len(logs)) 219 } 220 } 221 } 222 223 func genReceipt(failed bool, cumulativeGasUsed uint64) *types.Receipt { 224 r := &types.Receipt{GasUsed: cumulativeGasUsed} 225 if failed { 226 r.Status = types.ReceiptStatusFailed 227 } else { 228 r.Status = types.ReceiptStatusSuccessful 229 } 230 return r 231 } 232 233 func TestFilters(t *testing.T) { 234 var ( 235 db = database.NewMemoryDBManager() 236 mux = new(event.TypeMux) 237 txFeed = new(event.Feed) 238 rmLogsFeed = new(event.Feed) 239 logsFeed = new(event.Feed) 240 chainFeed = new(event.Feed) 241 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed, params.TestChainConfig} 242 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 243 addr = crypto.PubkeyToAddress(key1.PublicKey) 244 245 hash1 = common.BytesToHash([]byte("topic1")) 246 hash2 = common.BytesToHash([]byte("topic2")) 247 hash3 = common.BytesToHash([]byte("topic3")) 248 hash4 = common.BytesToHash([]byte("topic4")) 249 ) 250 defer db.Close() 251 252 genesis := blockchain.GenesisBlockForTesting(db, addr, big.NewInt(1000000)) 253 chain, receipts := blockchain.GenerateChain(params.TestChainConfig, genesis, gxhash.NewFaker(), db, 1000, func(i int, gen *blockchain.BlockGen) { 254 switch i { 255 case 1: 256 receipt := genReceipt(false, 0) 257 receipt.Logs = []*types.Log{ 258 { 259 Address: addr, 260 Topics: []common.Hash{hash1}, 261 }, 262 } 263 gen.AddUncheckedReceipt(receipt) 264 gen.AddUncheckedTx(types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)) 265 case 2: 266 receipt := genReceipt(false, 0) 267 receipt.Logs = []*types.Log{ 268 { 269 Address: addr, 270 Topics: []common.Hash{hash2}, 271 }, 272 } 273 gen.AddUncheckedReceipt(receipt) 274 gen.AddUncheckedTx(types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil)) 275 276 case 998: 277 receipt := genReceipt(false, 0) 278 receipt.Logs = []*types.Log{ 279 { 280 Address: addr, 281 Topics: []common.Hash{hash3}, 282 }, 283 } 284 gen.AddUncheckedReceipt(receipt) 285 gen.AddUncheckedTx(types.NewTransaction(998, common.HexToAddress("0x998"), big.NewInt(998), 998, big.NewInt(998), nil)) 286 case 999: 287 receipt := genReceipt(false, 0) 288 receipt.Logs = []*types.Log{ 289 { 290 Address: addr, 291 Topics: []common.Hash{hash4}, 292 }, 293 } 294 gen.AddUncheckedReceipt(receipt) 295 gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, big.NewInt(999), nil)) 296 } 297 }) 298 for i, block := range chain { 299 db.WriteBlock(block) 300 db.WriteCanonicalHash(block.Hash(), block.NumberU64()) 301 db.WriteHeadBlockHash(block.Hash()) 302 db.WriteReceipts(block.Hash(), block.NumberU64(), receipts[i]) 303 } 304 305 filter := NewRangeFilter(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) 306 307 logs, _ := filter.Logs(context.Background()) 308 if len(logs) != 4 { 309 t.Error("expected 4 log, got", len(logs)) 310 } 311 312 filter = NewRangeFilter(backend, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}) 313 logs, _ = filter.Logs(context.Background()) 314 if len(logs) != 1 { 315 t.Error("expected 1 log, got", len(logs)) 316 } 317 if len(logs) > 0 && logs[0].Topics[0] != hash3 { 318 t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) 319 } 320 321 filter = NewRangeFilter(backend, 990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}) 322 logs, _ = filter.Logs(context.Background()) 323 if len(logs) != 1 { 324 t.Error("expected 1 log, got", len(logs)) 325 } 326 if len(logs) > 0 && logs[0].Topics[0] != hash3 { 327 t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) 328 } 329 330 filter = NewRangeFilter(backend, 1, 10, nil, [][]common.Hash{{hash1, hash2}}) 331 332 logs, _ = filter.Logs(context.Background()) 333 if len(logs) != 2 { 334 t.Error("expected 2 log, got", len(logs)) 335 } 336 337 failHash := common.BytesToHash([]byte("fail")) 338 filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}}) 339 340 logs, _ = filter.Logs(context.Background()) 341 if len(logs) != 0 { 342 t.Error("expected 0 log, got", len(logs)) 343 } 344 345 failAddr := common.BytesToAddress([]byte("failmenow")) 346 filter = NewRangeFilter(backend, 0, -1, []common.Address{failAddr}, nil) 347 348 logs, _ = filter.Logs(context.Background()) 349 if len(logs) != 0 { 350 t.Error("expected 0 log, got", len(logs)) 351 } 352 353 filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}}) 354 355 logs, _ = filter.Logs(context.Background()) 356 if len(logs) != 0 { 357 t.Error("expected 0 log, got", len(logs)) 358 } 359 }