github.com/ethereum/go-ethereum@v1.16.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 "errors" 22 "math/big" 23 "reflect" 24 "runtime" 25 "testing" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/consensus/ethash" 30 "github.com/ethereum/go-ethereum/core" 31 "github.com/ethereum/go-ethereum/core/filtermaps" 32 "github.com/ethereum/go-ethereum/core/rawdb" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/ethdb" 35 "github.com/ethereum/go-ethereum/event" 36 "github.com/ethereum/go-ethereum/internal/ethapi" 37 "github.com/ethereum/go-ethereum/params" 38 "github.com/ethereum/go-ethereum/rpc" 39 ) 40 41 type testBackend struct { 42 db ethdb.Database 43 fm *filtermaps.FilterMaps 44 txFeed event.Feed 45 logsFeed event.Feed 46 rmLogsFeed event.Feed 47 chainFeed event.Feed 48 pendingBlock *types.Block 49 pendingReceipts types.Receipts 50 } 51 52 func (b *testBackend) ChainConfig() *params.ChainConfig { 53 return params.TestChainConfig 54 } 55 56 func (b *testBackend) CurrentHeader() *types.Header { 57 hdr, _ := b.HeaderByNumber(context.TODO(), rpc.LatestBlockNumber) 58 return hdr 59 } 60 61 func (b *testBackend) CurrentBlock() *types.Header { 62 return b.CurrentHeader() 63 } 64 65 func (b *testBackend) ChainDb() ethdb.Database { 66 return b.db 67 } 68 69 func (b *testBackend) GetCanonicalHash(number uint64) common.Hash { 70 return rawdb.ReadCanonicalHash(b.db, number) 71 } 72 73 func (b *testBackend) GetHeader(hash common.Hash, number uint64) *types.Header { 74 hdr, _ := b.HeaderByHash(context.Background(), hash) 75 return hdr 76 } 77 78 func (b *testBackend) GetReceiptsByHash(hash common.Hash) types.Receipts { 79 r, _ := b.GetReceipts(context.Background(), hash) 80 return r 81 } 82 83 func (b *testBackend) GetRawReceipts(hash common.Hash, number uint64) types.Receipts { 84 return rawdb.ReadRawReceipts(b.db, hash, number) 85 } 86 87 func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { 88 var ( 89 hash common.Hash 90 num uint64 91 ) 92 switch blockNr { 93 case rpc.LatestBlockNumber: 94 hash = rawdb.ReadHeadBlockHash(b.db) 95 number := rawdb.ReadHeaderNumber(b.db, hash) 96 if number == nil { 97 return nil, nil 98 } 99 num = *number 100 case rpc.FinalizedBlockNumber: 101 hash = rawdb.ReadFinalizedBlockHash(b.db) 102 number := rawdb.ReadHeaderNumber(b.db, hash) 103 if number == nil { 104 return nil, nil 105 } 106 num = *number 107 case rpc.SafeBlockNumber: 108 return nil, errors.New("safe block not found") 109 default: 110 num = uint64(blockNr) 111 hash = rawdb.ReadCanonicalHash(b.db, num) 112 } 113 return rawdb.ReadHeader(b.db, hash, num), nil 114 } 115 116 func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 117 number := rawdb.ReadHeaderNumber(b.db, hash) 118 if number == nil { 119 return nil, nil 120 } 121 return rawdb.ReadHeader(b.db, hash, *number), nil 122 } 123 124 func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { 125 if body := rawdb.ReadBody(b.db, hash, uint64(number)); body != nil { 126 return body, nil 127 } 128 return nil, errors.New("block body not found") 129 } 130 131 func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 132 if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { 133 if header := rawdb.ReadHeader(b.db, hash, *number); header != nil { 134 return rawdb.ReadReceipts(b.db, hash, *number, header.Time, params.TestChainConfig), nil 135 } 136 } 137 return nil, nil 138 } 139 140 func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { 141 logs := rawdb.ReadLogs(b.db, hash, number) 142 return logs, nil 143 } 144 145 func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 146 return b.txFeed.Subscribe(ch) 147 } 148 149 func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 150 return b.rmLogsFeed.Subscribe(ch) 151 } 152 153 func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 154 return b.logsFeed.Subscribe(ch) 155 } 156 157 func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 158 return b.chainFeed.Subscribe(ch) 159 } 160 161 func (b *testBackend) CurrentView() *filtermaps.ChainView { 162 head := b.CurrentBlock() 163 return filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash()) 164 } 165 166 func (b *testBackend) NewMatcherBackend() filtermaps.MatcherBackend { 167 return b.fm.NewMatcherBackend() 168 } 169 170 func (b *testBackend) startFilterMaps(history uint64, disabled bool, params filtermaps.Params) { 171 head := b.CurrentBlock() 172 chainView := filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash()) 173 config := filtermaps.Config{ 174 History: history, 175 Disabled: disabled, 176 ExportFileName: "", 177 } 178 b.fm, _ = filtermaps.NewFilterMaps(b.db, chainView, 0, 0, params, config) 179 b.fm.Start() 180 b.fm.WaitIdle() 181 } 182 183 func (b *testBackend) stopFilterMaps() { 184 b.fm.Stop() 185 b.fm = nil 186 } 187 188 func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) { 189 b.pendingBlock = block 190 b.pendingReceipts = receipts 191 } 192 193 func (b *testBackend) HistoryPruningCutoff() uint64 { 194 return 0 195 } 196 197 func newTestFilterSystem(db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { 198 backend := &testBackend{db: db} 199 sys := NewFilterSystem(backend, cfg) 200 return backend, sys 201 } 202 203 // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. 204 // It creates multiple subscriptions: 205 // - one at the start and should receive all posted chain events and a second (blockHashes) 206 // - one that is created after a cutoff moment and uninstalled after a second cutoff moment (blockHashes[cutoff1:cutoff2]) 207 // - one that is created after the second cutoff moment (blockHashes[cutoff2:]) 208 func TestBlockSubscription(t *testing.T) { 209 t.Parallel() 210 211 var ( 212 db = rawdb.NewMemoryDatabase() 213 backend, sys = newTestFilterSystem(db, Config{}) 214 api = NewFilterAPI(sys) 215 genesis = &core.Genesis{ 216 Config: params.TestChainConfig, 217 BaseFee: big.NewInt(params.InitialBaseFee), 218 } 219 _, chain, _ = core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 10, func(i int, gen *core.BlockGen) {}) 220 chainEvents []core.ChainEvent 221 ) 222 223 for _, blk := range chain { 224 chainEvents = append(chainEvents, core.ChainEvent{Header: blk.Header()}) 225 } 226 227 chan0 := make(chan *types.Header) 228 sub0 := api.events.SubscribeNewHeads(chan0) 229 chan1 := make(chan *types.Header) 230 sub1 := api.events.SubscribeNewHeads(chan1) 231 232 go func() { // simulate client 233 i1, i2 := 0, 0 234 for i1 != len(chainEvents) || i2 != len(chainEvents) { 235 select { 236 case header := <-chan0: 237 if chainEvents[i1].Header.Hash() != header.Hash() { 238 t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Header.Hash(), header.Hash()) 239 } 240 i1++ 241 case header := <-chan1: 242 if chainEvents[i2].Header.Hash() != header.Hash() { 243 t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Header.Hash(), header.Hash()) 244 } 245 i2++ 246 } 247 } 248 249 sub0.Unsubscribe() 250 sub1.Unsubscribe() 251 }() 252 253 time.Sleep(1 * time.Second) 254 for _, e := range chainEvents { 255 backend.chainFeed.Send(e) 256 } 257 258 <-sub0.Err() 259 <-sub1.Err() 260 } 261 262 // TestPendingTxFilter tests whether pending tx filters retrieve all pending transactions that are posted to the event mux. 263 func TestPendingTxFilter(t *testing.T) { 264 t.Parallel() 265 266 var ( 267 db = rawdb.NewMemoryDatabase() 268 backend, sys = newTestFilterSystem(db, Config{}) 269 api = NewFilterAPI(sys) 270 271 transactions = []*types.Transaction{ 272 types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 273 types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 274 types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 275 types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 276 types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 277 } 278 279 hashes []common.Hash 280 ) 281 282 fid0 := api.NewPendingTransactionFilter(nil) 283 284 time.Sleep(1 * time.Second) 285 backend.txFeed.Send(core.NewTxsEvent{Txs: transactions}) 286 287 timeout := time.Now().Add(1 * time.Second) 288 for { 289 results, err := api.GetFilterChanges(fid0) 290 if err != nil { 291 t.Fatalf("Unable to retrieve logs: %v", err) 292 } 293 294 h := results.([]common.Hash) 295 hashes = append(hashes, h...) 296 if len(hashes) >= len(transactions) { 297 break 298 } 299 // check timeout 300 if time.Now().After(timeout) { 301 break 302 } 303 304 time.Sleep(100 * time.Millisecond) 305 } 306 307 if len(hashes) != len(transactions) { 308 t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes)) 309 return 310 } 311 for i := range hashes { 312 if hashes[i] != transactions[i].Hash() { 313 t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) 314 } 315 } 316 } 317 318 // TestPendingTxFilterFullTx tests whether pending tx filters retrieve all pending transactions that are posted to the event mux. 319 func TestPendingTxFilterFullTx(t *testing.T) { 320 t.Parallel() 321 322 var ( 323 db = rawdb.NewMemoryDatabase() 324 backend, sys = newTestFilterSystem(db, Config{}) 325 api = NewFilterAPI(sys) 326 327 transactions = []*types.Transaction{ 328 types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 329 types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 330 types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 331 types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 332 types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 333 } 334 335 txs []*ethapi.RPCTransaction 336 ) 337 338 fullTx := true 339 fid0 := api.NewPendingTransactionFilter(&fullTx) 340 341 time.Sleep(1 * time.Second) 342 backend.txFeed.Send(core.NewTxsEvent{Txs: transactions}) 343 344 timeout := time.Now().Add(1 * time.Second) 345 for { 346 results, err := api.GetFilterChanges(fid0) 347 if err != nil { 348 t.Fatalf("Unable to retrieve logs: %v", err) 349 } 350 351 tx := results.([]*ethapi.RPCTransaction) 352 txs = append(txs, tx...) 353 if len(txs) >= len(transactions) { 354 break 355 } 356 // check timeout 357 if time.Now().After(timeout) { 358 break 359 } 360 361 time.Sleep(100 * time.Millisecond) 362 } 363 364 if len(txs) != len(transactions) { 365 t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(txs)) 366 return 367 } 368 for i := range txs { 369 if txs[i].Hash != transactions[i].Hash() { 370 t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash) 371 } 372 } 373 } 374 375 // TestLogFilterCreation test whether a given filter criteria makes sense. 376 // If not it must return an error. 377 func TestLogFilterCreation(t *testing.T) { 378 var ( 379 db = rawdb.NewMemoryDatabase() 380 _, sys = newTestFilterSystem(db, Config{}) 381 api = NewFilterAPI(sys) 382 383 testCases = []struct { 384 crit FilterCriteria 385 success bool 386 }{ 387 // defaults 388 {FilterCriteria{}, true}, 389 // valid block number range 390 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, 391 // "mined" block range to pending 392 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true}, 393 // from block "higher" than to block 394 {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, 395 // from block "higher" than to block 396 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 397 // from block "higher" than to block 398 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 399 // from block "higher" than to block 400 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, 401 // topics more than 4 402 {FilterCriteria{Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, false}, 403 } 404 ) 405 406 for i, test := range testCases { 407 id, err := api.NewFilter(test.crit) 408 if err != nil && test.success { 409 t.Errorf("expected filter creation for case %d to success, got %v", i, err) 410 } 411 if err == nil { 412 api.UninstallFilter(id) 413 if !test.success { 414 t.Errorf("expected testcase %d to fail with an error", i) 415 } 416 } 417 } 418 } 419 420 // TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error 421 // when the filter is created. 422 func TestInvalidLogFilterCreation(t *testing.T) { 423 t.Parallel() 424 425 var ( 426 db = rawdb.NewMemoryDatabase() 427 _, sys = newTestFilterSystem(db, Config{}) 428 api = NewFilterAPI(sys) 429 ) 430 431 // different situations where log filter creation should fail. 432 // Reason: fromBlock > toBlock 433 testCases := []FilterCriteria{ 434 0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 435 1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 436 2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 437 3: {Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, 438 4: {Addresses: make([]common.Address, maxAddresses+1)}, 439 } 440 441 for i, test := range testCases { 442 if _, err := api.NewFilter(test); err == nil { 443 t.Errorf("Expected NewFilter for case #%d to fail", i) 444 } 445 } 446 } 447 448 // TestInvalidGetLogsRequest tests invalid getLogs requests 449 func TestInvalidGetLogsRequest(t *testing.T) { 450 t.Parallel() 451 452 var ( 453 db = rawdb.NewMemoryDatabase() 454 _, sys = newTestFilterSystem(db, Config{}) 455 api = NewFilterAPI(sys) 456 blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 457 ) 458 459 // Reason: Cannot specify both BlockHash and FromBlock/ToBlock) 460 testCases := []FilterCriteria{ 461 0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)}, 462 1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)}, 463 2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 464 3: {BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, 465 4: {BlockHash: &blockHash, Addresses: make([]common.Address, maxAddresses+1)}, 466 } 467 468 for i, test := range testCases { 469 if _, err := api.GetLogs(context.Background(), test); err == nil { 470 t.Errorf("Expected Logs for case #%d to fail", i) 471 } 472 } 473 } 474 475 // TestInvalidGetRangeLogsRequest tests getLogs with invalid block range 476 func TestInvalidGetRangeLogsRequest(t *testing.T) { 477 t.Parallel() 478 479 var ( 480 db = rawdb.NewMemoryDatabase() 481 _, sys = newTestFilterSystem(db, Config{}) 482 api = NewFilterAPI(sys) 483 ) 484 485 if _, err := api.GetLogs(context.Background(), FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}); err != errInvalidBlockRange { 486 t.Errorf("Expected Logs for invalid range return error, but got: %v", err) 487 } 488 } 489 490 // TestLogFilter tests whether log filters match the correct logs that are posted to the event feed. 491 func TestLogFilter(t *testing.T) { 492 t.Parallel() 493 494 var ( 495 db = rawdb.NewMemoryDatabase() 496 backend, sys = newTestFilterSystem(db, Config{}) 497 api = NewFilterAPI(sys) 498 499 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 500 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 501 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 502 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 503 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 504 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 505 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 506 507 // posted twice, once as regular logs and once as pending logs. 508 allLogs = []*types.Log{ 509 {Address: firstAddr}, 510 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 511 {Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 512 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2}, 513 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, 514 } 515 516 testCases = []struct { 517 crit FilterCriteria 518 expected []*types.Log 519 id rpc.ID 520 }{ 521 // match all 522 0: {FilterCriteria{}, allLogs, ""}, 523 // match none due to no matching addresses 524 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""}, 525 // match logs based on addresses, ignore topics 526 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, 527 // match none due to no matching topics (match with address) 528 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""}, 529 // match logs based on addresses and topics 530 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, 531 // match logs based on multiple addresses and "or" topics 532 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, 533 // all "mined" logs with block num >= 2 534 6: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, 535 // all "mined" logs 536 7: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, 537 // all "mined" logs with 1>= block num <=2 and topic secondTopic 538 8: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, 539 // match all logs due to wildcard topic 540 9: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""}, 541 } 542 ) 543 544 // create all filters 545 for i := range testCases { 546 testCases[i].id, _ = api.NewFilter(testCases[i].crit) 547 } 548 549 // raise events 550 time.Sleep(1 * time.Second) 551 if nsend := backend.logsFeed.Send(allLogs); nsend == 0 { 552 t.Fatal("Logs event not delivered") 553 } 554 555 for i, tt := range testCases { 556 var fetched []*types.Log 557 timeout := time.Now().Add(1 * time.Second) 558 for { // fetch all expected logs 559 results, err := api.GetFilterChanges(tt.id) 560 if err != nil { 561 t.Fatalf("test %d: unable to fetch logs: %v", i, err) 562 } 563 564 fetched = append(fetched, results.([]*types.Log)...) 565 if len(fetched) >= len(tt.expected) { 566 break 567 } 568 // check timeout 569 if time.Now().After(timeout) { 570 break 571 } 572 573 time.Sleep(100 * time.Millisecond) 574 } 575 576 if len(fetched) != len(tt.expected) { 577 t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 578 return 579 } 580 581 for l := range fetched { 582 if fetched[l].Removed { 583 t.Errorf("expected log not to be removed for log %d in case %d", l, i) 584 } 585 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 586 t.Errorf("invalid log on index %d for case %d", l, i) 587 } 588 } 589 } 590 } 591 592 // TestPendingTxFilterDeadlock tests if the event loop hangs when pending 593 // txes arrive at the same time that one of multiple filters is timing out. 594 // Please refer to #22131 for more details. 595 func TestPendingTxFilterDeadlock(t *testing.T) { 596 t.Parallel() 597 timeout := 100 * time.Millisecond 598 599 var ( 600 db = rawdb.NewMemoryDatabase() 601 backend, sys = newTestFilterSystem(db, Config{Timeout: timeout}) 602 api = NewFilterAPI(sys) 603 done = make(chan struct{}) 604 ) 605 606 go func() { 607 // Bombard feed with txes until signal was received to stop 608 i := uint64(0) 609 for { 610 select { 611 case <-done: 612 return 613 default: 614 } 615 616 tx := types.NewTransaction(i, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil) 617 backend.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}}) 618 i++ 619 } 620 }() 621 622 // Create a bunch of filters that will 623 // timeout either in 100ms or 200ms 624 subs := make([]*Subscription, 20) 625 for i := range subs { 626 fid := api.NewPendingTransactionFilter(nil) 627 api.filtersMu.Lock() 628 f, ok := api.filters[fid] 629 api.filtersMu.Unlock() 630 if !ok { 631 t.Fatalf("Filter %s should exist", fid) 632 } 633 subs[i] = f.s 634 // Wait for at least one tx to arrive in filter 635 for { 636 hashes, err := api.GetFilterChanges(fid) 637 if err != nil { 638 t.Fatalf("Filter should exist: %v\n", err) 639 } 640 if len(hashes.([]common.Hash)) > 0 { 641 break 642 } 643 runtime.Gosched() 644 } 645 } 646 647 // Wait until filters have timed out and have been uninstalled. 648 for _, sub := range subs { 649 select { 650 case <-sub.Err(): 651 case <-time.After(1 * time.Second): 652 t.Fatalf("Filter timeout is hanging") 653 } 654 } 655 }