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