github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/eth/filters/filter_system_test.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package filters 13 14 import ( 15 "context" 16 "fmt" 17 "math/big" 18 "math/rand" 19 "reflect" 20 "testing" 21 "time" 22 23 sberex "github.com/Sberex/go-sberex" 24 "github.com/Sberex/go-sberex/common" 25 "github.com/Sberex/go-sberex/consensus/ethash" 26 "github.com/Sberex/go-sberex/core" 27 "github.com/Sberex/go-sberex/core/bloombits" 28 "github.com/Sberex/go-sberex/core/types" 29 "github.com/Sberex/go-sberex/ethdb" 30 "github.com/Sberex/go-sberex/event" 31 "github.com/Sberex/go-sberex/params" 32 "github.com/Sberex/go-sberex/rpc" 33 ) 34 35 type testBackend struct { 36 mux *event.TypeMux 37 db ethdb.Database 38 sections uint64 39 txFeed *event.Feed 40 rmLogsFeed *event.Feed 41 logsFeed *event.Feed 42 chainFeed *event.Feed 43 } 44 45 func (b *testBackend) ChainDb() ethdb.Database { 46 return b.db 47 } 48 49 func (b *testBackend) EventMux() *event.TypeMux { 50 return b.mux 51 } 52 53 func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { 54 var hash common.Hash 55 var num uint64 56 if blockNr == rpc.LatestBlockNumber { 57 hash = core.GetHeadBlockHash(b.db) 58 num = core.GetBlockNumber(b.db, hash) 59 } else { 60 num = uint64(blockNr) 61 hash = core.GetCanonicalHash(b.db, num) 62 } 63 return core.GetHeader(b.db, hash, num), nil 64 } 65 66 func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { 67 number := core.GetBlockNumber(b.db, blockHash) 68 return core.GetBlockReceipts(b.db, blockHash, number), nil 69 } 70 71 func (b *testBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { 72 number := core.GetBlockNumber(b.db, blockHash) 73 receipts := core.GetBlockReceipts(b.db, blockHash, number) 74 75 logs := make([][]*types.Log, len(receipts)) 76 for i, receipt := range receipts { 77 logs[i] = receipt.Logs 78 } 79 return logs, nil 80 } 81 82 func (b *testBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { 83 return b.txFeed.Subscribe(ch) 84 } 85 86 func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 87 return b.rmLogsFeed.Subscribe(ch) 88 } 89 90 func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 91 return b.logsFeed.Subscribe(ch) 92 } 93 94 func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 95 return b.chainFeed.Subscribe(ch) 96 } 97 98 func (b *testBackend) BloomStatus() (uint64, uint64) { 99 return params.BloomBitsBlocks, b.sections 100 } 101 102 func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { 103 requests := make(chan chan *bloombits.Retrieval) 104 105 go session.Multiplex(16, 0, requests) 106 go func() { 107 for { 108 // Wait for a service request or a shutdown 109 select { 110 case <-ctx.Done(): 111 return 112 113 case request := <-requests: 114 task := <-request 115 116 task.Bitsets = make([][]byte, len(task.Sections)) 117 for i, section := range task.Sections { 118 if rand.Int()%4 != 0 { // Handle occasional missing deliveries 119 head := core.GetCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1) 120 task.Bitsets[i], _ = core.GetBloomBits(b.db, task.Bit, section, head) 121 } 122 } 123 request <- task 124 } 125 } 126 }() 127 } 128 129 // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. 130 // It creates multiple subscriptions: 131 // - one at the start and should receive all posted chain events and a second (blockHashes) 132 // - one that is created after a cutoff moment and uninstalled after a second cutoff moment (blockHashes[cutoff1:cutoff2]) 133 // - one that is created after the second cutoff moment (blockHashes[cutoff2:]) 134 func TestBlockSubscription(t *testing.T) { 135 t.Parallel() 136 137 var ( 138 mux = new(event.TypeMux) 139 db, _ = ethdb.NewMemDatabase() 140 txFeed = new(event.Feed) 141 rmLogsFeed = new(event.Feed) 142 logsFeed = new(event.Feed) 143 chainFeed = new(event.Feed) 144 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 145 api = NewPublicFilterAPI(backend, false) 146 genesis = new(core.Genesis).MustCommit(db) 147 chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) 148 chainEvents = []core.ChainEvent{} 149 ) 150 151 for _, blk := range chain { 152 chainEvents = append(chainEvents, core.ChainEvent{Hash: blk.Hash(), Block: blk}) 153 } 154 155 chan0 := make(chan *types.Header) 156 sub0 := api.events.SubscribeNewHeads(chan0) 157 chan1 := make(chan *types.Header) 158 sub1 := api.events.SubscribeNewHeads(chan1) 159 160 go func() { // simulate client 161 i1, i2 := 0, 0 162 for i1 != len(chainEvents) || i2 != len(chainEvents) { 163 select { 164 case header := <-chan0: 165 if chainEvents[i1].Hash != header.Hash() { 166 t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Hash, header.Hash()) 167 } 168 i1++ 169 case header := <-chan1: 170 if chainEvents[i2].Hash != header.Hash() { 171 t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Hash, header.Hash()) 172 } 173 i2++ 174 } 175 } 176 177 sub0.Unsubscribe() 178 sub1.Unsubscribe() 179 }() 180 181 time.Sleep(1 * time.Second) 182 for _, e := range chainEvents { 183 chainFeed.Send(e) 184 } 185 186 <-sub0.Err() 187 <-sub1.Err() 188 } 189 190 // TestPendingTxFilter tests whether pending tx filters retrieve all pending transactions that are posted to the event mux. 191 func TestPendingTxFilter(t *testing.T) { 192 t.Parallel() 193 194 var ( 195 mux = new(event.TypeMux) 196 db, _ = ethdb.NewMemDatabase() 197 txFeed = new(event.Feed) 198 rmLogsFeed = new(event.Feed) 199 logsFeed = new(event.Feed) 200 chainFeed = new(event.Feed) 201 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 202 api = NewPublicFilterAPI(backend, false) 203 204 transactions = []*types.Transaction{ 205 types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 206 types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 207 types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 208 types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 209 types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 210 } 211 212 hashes []common.Hash 213 ) 214 215 fid0 := api.NewPendingTransactionFilter() 216 217 time.Sleep(1 * time.Second) 218 for _, tx := range transactions { 219 ev := core.TxPreEvent{Tx: tx} 220 txFeed.Send(ev) 221 } 222 223 timeout := time.Now().Add(1 * time.Second) 224 for { 225 results, err := api.GetFilterChanges(fid0) 226 if err != nil { 227 t.Fatalf("Unable to retrieve logs: %v", err) 228 } 229 230 h := results.([]common.Hash) 231 hashes = append(hashes, h...) 232 if len(hashes) >= len(transactions) { 233 break 234 } 235 // check timeout 236 if time.Now().After(timeout) { 237 break 238 } 239 240 time.Sleep(100 * time.Millisecond) 241 } 242 243 if len(hashes) != len(transactions) { 244 t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes)) 245 return 246 } 247 for i := range hashes { 248 if hashes[i] != transactions[i].Hash() { 249 t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) 250 } 251 } 252 } 253 254 // TestLogFilterCreation test whether a given filter criteria makes sense. 255 // If not it must return an error. 256 func TestLogFilterCreation(t *testing.T) { 257 var ( 258 mux = new(event.TypeMux) 259 db, _ = ethdb.NewMemDatabase() 260 txFeed = new(event.Feed) 261 rmLogsFeed = new(event.Feed) 262 logsFeed = new(event.Feed) 263 chainFeed = new(event.Feed) 264 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 265 api = NewPublicFilterAPI(backend, false) 266 267 testCases = []struct { 268 crit FilterCriteria 269 success bool 270 }{ 271 // defaults 272 {FilterCriteria{}, true}, 273 // valid block number range 274 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, 275 // "mined" block range to pending 276 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true}, 277 // new mined and pending blocks 278 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, true}, 279 // from block "higher" than to block 280 {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, 281 // from block "higher" than to block 282 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 283 // from block "higher" than to block 284 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 285 // from block "higher" than to block 286 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, 287 } 288 ) 289 290 for i, test := range testCases { 291 _, err := api.NewFilter(test.crit) 292 if test.success && err != nil { 293 t.Errorf("expected filter creation for case %d to success, got %v", i, err) 294 } 295 if !test.success && err == nil { 296 t.Errorf("expected testcase %d to fail with an error", i) 297 } 298 } 299 } 300 301 // TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error 302 // when the filter is created. 303 func TestInvalidLogFilterCreation(t *testing.T) { 304 t.Parallel() 305 306 var ( 307 mux = new(event.TypeMux) 308 db, _ = ethdb.NewMemDatabase() 309 txFeed = new(event.Feed) 310 rmLogsFeed = new(event.Feed) 311 logsFeed = new(event.Feed) 312 chainFeed = new(event.Feed) 313 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 314 api = NewPublicFilterAPI(backend, false) 315 ) 316 317 // different situations where log filter creation should fail. 318 // Reason: fromBlock > toBlock 319 testCases := []FilterCriteria{ 320 0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 321 1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 322 2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 323 } 324 325 for i, test := range testCases { 326 if _, err := api.NewFilter(test); err == nil { 327 t.Errorf("Expected NewFilter for case #%d to fail", i) 328 } 329 } 330 } 331 332 // TestLogFilter tests whether log filters match the correct logs that are posted to the event feed. 333 func TestLogFilter(t *testing.T) { 334 t.Parallel() 335 336 var ( 337 mux = new(event.TypeMux) 338 db, _ = ethdb.NewMemDatabase() 339 txFeed = new(event.Feed) 340 rmLogsFeed = new(event.Feed) 341 logsFeed = new(event.Feed) 342 chainFeed = new(event.Feed) 343 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 344 api = NewPublicFilterAPI(backend, false) 345 346 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 347 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 348 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 349 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 350 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 351 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 352 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 353 354 // posted twice, once as vm.Logs and once as core.PendingLogsEvent 355 allLogs = []*types.Log{ 356 {Address: firstAddr}, 357 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 358 {Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 359 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2}, 360 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, 361 } 362 363 expectedCase7 = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} 364 expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} 365 366 testCases = []struct { 367 crit FilterCriteria 368 expected []*types.Log 369 id rpc.ID 370 }{ 371 // match all 372 0: {FilterCriteria{}, allLogs, ""}, 373 // match none due to no matching addresses 374 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""}, 375 // match logs based on addresses, ignore topics 376 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, 377 // match none due to no matching topics (match with address) 378 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""}, 379 // match logs based on addresses and topics 380 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, 381 // match logs based on multiple addresses and "or" topics 382 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, 383 // logs in the pending block 384 6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""}, 385 // mined logs with block num >= 2 or pending logs 386 7: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, expectedCase7, ""}, 387 // all "mined" logs with block num >= 2 388 8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, 389 // all "mined" logs 390 9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, 391 // all "mined" logs with 1>= block num <=2 and topic secondTopic 392 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, 393 // all "mined" and pending logs with topic firstTopic 394 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""}, 395 // match all logs due to wildcard topic 396 12: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""}, 397 } 398 ) 399 400 // create all filters 401 for i := range testCases { 402 testCases[i].id, _ = api.NewFilter(testCases[i].crit) 403 } 404 405 // raise events 406 time.Sleep(1 * time.Second) 407 if nsend := logsFeed.Send(allLogs); nsend == 0 { 408 t.Fatal("Shoud have at least one subscription") 409 } 410 if err := mux.Post(core.PendingLogsEvent{Logs: allLogs}); err != nil { 411 t.Fatal(err) 412 } 413 414 for i, tt := range testCases { 415 var fetched []*types.Log 416 timeout := time.Now().Add(1 * time.Second) 417 for { // fetch all expected logs 418 results, err := api.GetFilterChanges(tt.id) 419 if err != nil { 420 t.Fatalf("Unable to fetch logs: %v", err) 421 } 422 423 fetched = append(fetched, results.([]*types.Log)...) 424 if len(fetched) >= len(tt.expected) { 425 break 426 } 427 // check timeout 428 if time.Now().After(timeout) { 429 break 430 } 431 432 time.Sleep(100 * time.Millisecond) 433 } 434 435 if len(fetched) != len(tt.expected) { 436 t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 437 return 438 } 439 440 for l := range fetched { 441 if fetched[l].Removed { 442 t.Errorf("expected log not to be removed for log %d in case %d", l, i) 443 } 444 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 445 t.Errorf("invalid log on index %d for case %d", l, i) 446 } 447 } 448 } 449 } 450 451 // TestPendingLogsSubscription tests if a subscription receives the correct pending logs that are posted to the event feed. 452 func TestPendingLogsSubscription(t *testing.T) { 453 t.Parallel() 454 455 var ( 456 mux = new(event.TypeMux) 457 db, _ = ethdb.NewMemDatabase() 458 txFeed = new(event.Feed) 459 rmLogsFeed = new(event.Feed) 460 logsFeed = new(event.Feed) 461 chainFeed = new(event.Feed) 462 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 463 api = NewPublicFilterAPI(backend, false) 464 465 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 466 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 467 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 468 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 469 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 470 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 471 thirdTopic = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333") 472 fourthTopic = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444") 473 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 474 475 allLogs = []core.PendingLogsEvent{ 476 {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}}}, 477 {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}}}, 478 {Logs: []*types.Log{{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}}}, 479 {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}}}, 480 {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}}}, 481 {Logs: []*types.Log{ 482 {Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 483 {Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5}, 484 {Address: thirdAddress, Topics: []common.Hash{fourthTopic}, BlockNumber: 5}, 485 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 486 }}, 487 } 488 489 convertLogs = func(pl []core.PendingLogsEvent) []*types.Log { 490 var logs []*types.Log 491 for _, l := range pl { 492 logs = append(logs, l.Logs...) 493 } 494 return logs 495 } 496 497 testCases = []struct { 498 crit sberex.FilterQuery 499 expected []*types.Log 500 c chan []*types.Log 501 sub *Subscription 502 }{ 503 // match all 504 {sberex.FilterQuery{}, convertLogs(allLogs), nil, nil}, 505 // match none due to no matching addresses 506 {sberex.FilterQuery{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, nil, nil}, 507 // match logs based on addresses, ignore topics 508 {sberex.FilterQuery{Addresses: []common.Address{firstAddr}}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, 509 // match none due to no matching topics (match with address) 510 {sberex.FilterQuery{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, nil, nil}, 511 // match logs based on addresses and topics 512 {sberex.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[3:5]), allLogs[5].Logs[0]), nil, nil}, 513 // match logs based on multiple addresses and "or" topics 514 {sberex.FilterQuery{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[2:5]), allLogs[5].Logs[0]), nil, nil}, 515 // block numbers are ignored for filters created with New***Filter, these return all logs that match the given criteria when the state changes 516 {sberex.FilterQuery{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(2), ToBlock: big.NewInt(3)}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, 517 // multiple pending logs, should match only 2 topics from the logs in block 5 518 {sberex.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, fourthTopic}}}, []*types.Log{allLogs[5].Logs[0], allLogs[5].Logs[2]}, nil, nil}, 519 } 520 ) 521 522 // create all subscriptions, this ensures all subscriptions are created before the events are posted. 523 // on slow machines this could otherwise lead to missing events when the subscription is created after 524 // (some) events are posted. 525 for i := range testCases { 526 testCases[i].c = make(chan []*types.Log) 527 testCases[i].sub, _ = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) 528 } 529 530 for n, test := range testCases { 531 i := n 532 tt := test 533 go func() { 534 var fetched []*types.Log 535 fetchLoop: 536 for { 537 logs := <-tt.c 538 fetched = append(fetched, logs...) 539 if len(fetched) >= len(tt.expected) { 540 break fetchLoop 541 } 542 } 543 544 if len(fetched) != len(tt.expected) { 545 panic(fmt.Sprintf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched))) 546 } 547 548 for l := range fetched { 549 if fetched[l].Removed { 550 panic(fmt.Sprintf("expected log not to be removed for log %d in case %d", l, i)) 551 } 552 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 553 panic(fmt.Sprintf("invalid log on index %d for case %d", l, i)) 554 } 555 } 556 }() 557 } 558 559 // raise events 560 time.Sleep(1 * time.Second) 561 // allLogs are type of core.PendingLogsEvent 562 for _, l := range allLogs { 563 if err := mux.Post(l); err != nil { 564 t.Fatal(err) 565 } 566 } 567 }