github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/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 "runtime" 26 "testing" 27 "time" 28 29 "github.com/scroll-tech/go-ethereum" 30 "github.com/scroll-tech/go-ethereum/common" 31 "github.com/scroll-tech/go-ethereum/consensus/ethash" 32 "github.com/scroll-tech/go-ethereum/core" 33 "github.com/scroll-tech/go-ethereum/core/bloombits" 34 "github.com/scroll-tech/go-ethereum/core/rawdb" 35 "github.com/scroll-tech/go-ethereum/core/types" 36 "github.com/scroll-tech/go-ethereum/core/vm" 37 "github.com/scroll-tech/go-ethereum/eth/ethconfig" 38 "github.com/scroll-tech/go-ethereum/ethdb" 39 "github.com/scroll-tech/go-ethereum/event" 40 "github.com/scroll-tech/go-ethereum/params" 41 "github.com/scroll-tech/go-ethereum/rpc" 42 ) 43 44 var ( 45 deadline = 5 * time.Minute 46 ) 47 48 type testBackend struct { 49 mux *event.TypeMux 50 db ethdb.Database 51 sections uint64 52 txFeed event.Feed 53 logsFeed event.Feed 54 rmLogsFeed event.Feed 55 pendingLogsFeed event.Feed 56 chainFeed event.Feed 57 } 58 59 func (b *testBackend) ChainDb() ethdb.Database { 60 return b.db 61 } 62 63 func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { 64 var ( 65 hash common.Hash 66 num uint64 67 ) 68 if blockNr == rpc.LatestBlockNumber { 69 hash = rawdb.ReadHeadBlockHash(b.db) 70 number := rawdb.ReadHeaderNumber(b.db, hash) 71 if number == nil { 72 return nil, nil 73 } 74 num = *number 75 } else { 76 num = uint64(blockNr) 77 hash = rawdb.ReadCanonicalHash(b.db, num) 78 } 79 return rawdb.ReadHeader(b.db, hash, num), nil 80 } 81 82 func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 83 number := rawdb.ReadHeaderNumber(b.db, hash) 84 if number == nil { 85 return nil, nil 86 } 87 return rawdb.ReadHeader(b.db, hash, *number), nil 88 } 89 90 func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 91 if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { 92 return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil 93 } 94 return nil, nil 95 } 96 97 func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { 98 number := rawdb.ReadHeaderNumber(b.db, hash) 99 if number == nil { 100 return nil, nil 101 } 102 receipts := rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig) 103 104 logs := make([][]*types.Log, len(receipts)) 105 for i, receipt := range receipts { 106 logs[i] = receipt.Logs 107 } 108 return logs, nil 109 } 110 111 func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 112 return b.txFeed.Subscribe(ch) 113 } 114 115 func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 116 return b.rmLogsFeed.Subscribe(ch) 117 } 118 119 func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 120 return b.logsFeed.Subscribe(ch) 121 } 122 123 func (b *testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { 124 return b.pendingLogsFeed.Subscribe(ch) 125 } 126 127 func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 128 return b.chainFeed.Subscribe(ch) 129 } 130 131 func (b *testBackend) BloomStatus() (uint64, uint64) { 132 return params.BloomBitsBlocks, b.sections 133 } 134 135 func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { 136 requests := make(chan chan *bloombits.Retrieval) 137 138 go session.Multiplex(16, 0, requests) 139 go func() { 140 for { 141 // Wait for a service request or a shutdown 142 select { 143 case <-ctx.Done(): 144 return 145 146 case request := <-requests: 147 task := <-request 148 149 task.Bitsets = make([][]byte, len(task.Sections)) 150 for i, section := range task.Sections { 151 if rand.Int()%4 != 0 { // Handle occasional missing deliveries 152 head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1) 153 task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head) 154 } 155 } 156 request <- task 157 } 158 } 159 }() 160 } 161 162 // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. 163 // It creates multiple subscriptions: 164 // - one at the start and should receive all posted chain events and a second (blockHashes) 165 // - one that is created after a cutoff moment and uninstalled after a second cutoff moment (blockHashes[cutoff1:cutoff2]) 166 // - one that is created after the second cutoff moment (blockHashes[cutoff2:]) 167 func TestBlockSubscription(t *testing.T) { 168 t.Parallel() 169 170 var ( 171 db = rawdb.NewMemoryDatabase() 172 backend = &testBackend{db: db} 173 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 174 genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) 175 chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) 176 chainEvents = []core.ChainEvent{} 177 ) 178 179 for _, blk := range chain { 180 chainEvents = append(chainEvents, core.ChainEvent{Hash: blk.Hash(), Block: blk}) 181 } 182 183 chan0 := make(chan *types.Header) 184 sub0 := api.events.SubscribeNewHeads(chan0) 185 chan1 := make(chan *types.Header) 186 sub1 := api.events.SubscribeNewHeads(chan1) 187 188 go func() { // simulate client 189 i1, i2 := 0, 0 190 for i1 != len(chainEvents) || i2 != len(chainEvents) { 191 select { 192 case header := <-chan0: 193 if chainEvents[i1].Hash != header.Hash() { 194 t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Hash, header.Hash()) 195 } 196 i1++ 197 case header := <-chan1: 198 if chainEvents[i2].Hash != header.Hash() { 199 t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Hash, header.Hash()) 200 } 201 i2++ 202 } 203 } 204 205 sub0.Unsubscribe() 206 sub1.Unsubscribe() 207 }() 208 209 time.Sleep(1 * time.Second) 210 for _, e := range chainEvents { 211 backend.chainFeed.Send(e) 212 } 213 214 <-sub0.Err() 215 <-sub1.Err() 216 } 217 218 // TestPendingTxFilter tests whether pending tx filters retrieve all pending transactions that are posted to the event mux. 219 func TestPendingTxFilter(t *testing.T) { 220 t.Parallel() 221 222 var ( 223 db = rawdb.NewMemoryDatabase() 224 backend = &testBackend{db: db} 225 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 226 227 transactions = []*types.Transaction{ 228 types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 229 types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 230 types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 231 types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 232 types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 233 } 234 235 hashes []common.Hash 236 ) 237 238 fid0 := api.NewPendingTransactionFilter() 239 240 time.Sleep(1 * time.Second) 241 backend.txFeed.Send(core.NewTxsEvent{Txs: transactions}) 242 243 timeout := time.Now().Add(1 * time.Second) 244 for { 245 results, err := api.GetFilterChanges(fid0) 246 if err != nil { 247 t.Fatalf("Unable to retrieve logs: %v", err) 248 } 249 250 h := results.([]common.Hash) 251 hashes = append(hashes, h...) 252 if len(hashes) >= len(transactions) { 253 break 254 } 255 // check timeout 256 if time.Now().After(timeout) { 257 break 258 } 259 260 time.Sleep(100 * time.Millisecond) 261 } 262 263 if len(hashes) != len(transactions) { 264 t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes)) 265 return 266 } 267 for i := range hashes { 268 if hashes[i] != transactions[i].Hash() { 269 t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) 270 } 271 } 272 } 273 274 // TestLogFilterCreation test whether a given filter criteria makes sense. 275 // If not it must return an error. 276 func TestLogFilterCreation(t *testing.T) { 277 var ( 278 db = rawdb.NewMemoryDatabase() 279 backend = &testBackend{db: db} 280 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 281 282 testCases = []struct { 283 crit FilterCriteria 284 success bool 285 }{ 286 // defaults 287 {FilterCriteria{}, true}, 288 // valid block number range 289 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, 290 // "mined" block range to pending 291 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true}, 292 // new mined and pending blocks 293 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, true}, 294 // from block "higher" than to block 295 {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, 296 // from block "higher" than to block 297 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 298 // from block "higher" than to block 299 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 300 // from block "higher" than to block 301 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, 302 } 303 ) 304 305 for i, test := range testCases { 306 _, err := api.NewFilter(test.crit) 307 if test.success && err != nil { 308 t.Errorf("expected filter creation for case %d to success, got %v", i, err) 309 } 310 if !test.success && err == nil { 311 t.Errorf("expected testcase %d to fail with an error", i) 312 } 313 } 314 } 315 316 // TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error 317 // when the filter is created. 318 func TestInvalidLogFilterCreation(t *testing.T) { 319 t.Parallel() 320 321 var ( 322 db = rawdb.NewMemoryDatabase() 323 backend = &testBackend{db: db} 324 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 325 ) 326 327 // different situations where log filter creation should fail. 328 // Reason: fromBlock > toBlock 329 testCases := []FilterCriteria{ 330 0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 331 1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 332 2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 333 } 334 335 for i, test := range testCases { 336 if _, err := api.NewFilter(test); err == nil { 337 t.Errorf("Expected NewFilter for case #%d to fail", i) 338 } 339 } 340 } 341 342 func TestInvalidGetLogsRequest(t *testing.T) { 343 var ( 344 db = rawdb.NewMemoryDatabase() 345 backend = &testBackend{db: db} 346 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 347 blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 348 ) 349 350 // Reason: Cannot specify both BlockHash and FromBlock/ToBlock) 351 testCases := []FilterCriteria{ 352 0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)}, 353 1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)}, 354 2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 355 } 356 357 for i, test := range testCases { 358 if _, err := api.GetLogs(context.Background(), test); err == nil { 359 t.Errorf("Expected Logs for case #%d to fail", i) 360 } 361 } 362 } 363 364 func TestGetLogsRange(t *testing.T) { 365 var ( 366 db = rawdb.NewMemoryDatabase() 367 backend = &testBackend{db: db} 368 api = NewPublicFilterAPI(backend, false, deadline, 2) 369 ) 370 (&core.Genesis{ 371 Config: params.TestChainConfig, 372 }).MustCommit(db) 373 chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false) 374 bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, 10, nil) 375 if _, err := chain.InsertChain(bs); err != nil { 376 panic(err) 377 } 378 // those test cases should fail because block range is greater then limit 379 failTestCases := []FilterCriteria{ 380 // from 0 to 2 block 381 0: {FromBlock: big.NewInt(0), ToBlock: big.NewInt(2)}, 382 // from 8 to latest block (10) 383 1: {FromBlock: big.NewInt(8)}, 384 // from 0 to latest block (10) 385 2: {FromBlock: big.NewInt(0)}, 386 } 387 for i, test := range failTestCases { 388 if _, err := api.GetLogs(context.Background(), test); err == nil { 389 t.Errorf("Expected Logs for failing case #%d to fail", i) 390 } 391 } 392 393 okTestCases := []FilterCriteria{ 394 // from latest to latest block 395 0: {}, 396 // from 9 to last block (10) 397 1: {FromBlock: big.NewInt(9)}, 398 // from 3 to 4 block 399 2: {FromBlock: big.NewInt(3), ToBlock: big.NewInt(4)}, 400 } 401 for i, test := range okTestCases { 402 if _, err := api.GetLogs(context.Background(), test); err != nil { 403 t.Errorf("Expected Logs for ok case #%d not to fail", i) 404 } 405 } 406 } 407 408 // TestLogFilter tests whether log filters match the correct logs that are posted to the event feed. 409 func TestLogFilter(t *testing.T) { 410 t.Parallel() 411 412 var ( 413 db = rawdb.NewMemoryDatabase() 414 backend = &testBackend{db: db} 415 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 416 417 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 418 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 419 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 420 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 421 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 422 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 423 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 424 425 // posted twice, once as regular logs and once as pending logs. 426 allLogs = []*types.Log{ 427 {Address: firstAddr}, 428 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 429 {Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 430 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2}, 431 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, 432 } 433 434 expectedCase7 = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} 435 expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} 436 437 testCases = []struct { 438 crit FilterCriteria 439 expected []*types.Log 440 id rpc.ID 441 }{ 442 // match all 443 0: {FilterCriteria{}, allLogs, ""}, 444 // match none due to no matching addresses 445 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""}, 446 // match logs based on addresses, ignore topics 447 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, 448 // match none due to no matching topics (match with address) 449 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""}, 450 // match logs based on addresses and topics 451 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, 452 // match logs based on multiple addresses and "or" topics 453 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, 454 // logs in the pending block 455 6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""}, 456 // mined logs with block num >= 2 or pending logs 457 7: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, expectedCase7, ""}, 458 // all "mined" logs with block num >= 2 459 8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, 460 // all "mined" logs 461 9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, 462 // all "mined" logs with 1>= block num <=2 and topic secondTopic 463 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, 464 // all "mined" and pending logs with topic firstTopic 465 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""}, 466 // match all logs due to wildcard topic 467 12: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""}, 468 } 469 ) 470 471 // create all filters 472 for i := range testCases { 473 testCases[i].id, _ = api.NewFilter(testCases[i].crit) 474 } 475 476 // raise events 477 time.Sleep(1 * time.Second) 478 if nsend := backend.logsFeed.Send(allLogs); nsend == 0 { 479 t.Fatal("Logs event not delivered") 480 } 481 if nsend := backend.pendingLogsFeed.Send(allLogs); nsend == 0 { 482 t.Fatal("Pending logs event not delivered") 483 } 484 485 for i, tt := range testCases { 486 var fetched []*types.Log 487 timeout := time.Now().Add(1 * time.Second) 488 for { // fetch all expected logs 489 results, err := api.GetFilterChanges(tt.id) 490 if err != nil { 491 t.Fatalf("Unable to fetch logs: %v", err) 492 } 493 494 fetched = append(fetched, results.([]*types.Log)...) 495 if len(fetched) >= len(tt.expected) { 496 break 497 } 498 // check timeout 499 if time.Now().After(timeout) { 500 break 501 } 502 503 time.Sleep(100 * time.Millisecond) 504 } 505 506 if len(fetched) != len(tt.expected) { 507 t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 508 return 509 } 510 511 for l := range fetched { 512 if fetched[l].Removed { 513 t.Errorf("expected log not to be removed for log %d in case %d", l, i) 514 } 515 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 516 t.Errorf("invalid log on index %d for case %d", l, i) 517 } 518 } 519 } 520 } 521 522 // TestPendingLogsSubscription tests if a subscription receives the correct pending logs that are posted to the event feed. 523 func TestPendingLogsSubscription(t *testing.T) { 524 t.Parallel() 525 526 var ( 527 db = rawdb.NewMemoryDatabase() 528 backend = &testBackend{db: db} 529 api = NewPublicFilterAPI(backend, false, deadline, ethconfig.Defaults.MaxBlockRange) 530 531 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 532 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 533 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 534 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 535 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 536 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 537 thirdTopic = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333") 538 fourthTopic = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444") 539 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 540 541 allLogs = [][]*types.Log{ 542 {{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}}, 543 {{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}}, 544 {{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}}, 545 {{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}}, 546 {{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}}, 547 { 548 {Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 549 {Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5}, 550 {Address: thirdAddress, Topics: []common.Hash{fourthTopic}, BlockNumber: 5}, 551 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 552 }, 553 } 554 555 pendingBlockNumber = big.NewInt(rpc.PendingBlockNumber.Int64()) 556 557 testCases = []struct { 558 crit ethereum.FilterQuery 559 expected []*types.Log 560 c chan []*types.Log 561 sub *Subscription 562 err chan error 563 }{ 564 // match all 565 { 566 ethereum.FilterQuery{FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 567 flattenLogs(allLogs), 568 nil, nil, nil, 569 }, 570 // match none due to no matching addresses 571 { 572 ethereum.FilterQuery{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 573 nil, 574 nil, nil, nil, 575 }, 576 // match logs based on addresses, ignore topics 577 { 578 ethereum.FilterQuery{Addresses: []common.Address{firstAddr}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 579 append(flattenLogs(allLogs[:2]), allLogs[5][3]), 580 nil, nil, nil, 581 }, 582 // match none due to no matching topics (match with address) 583 { 584 ethereum.FilterQuery{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 585 nil, 586 nil, nil, nil, 587 }, 588 // match logs based on addresses and topics 589 { 590 ethereum.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 591 append(flattenLogs(allLogs[3:5]), allLogs[5][0]), 592 nil, nil, nil, 593 }, 594 // match logs based on multiple addresses and "or" topics 595 { 596 ethereum.FilterQuery{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 597 append(flattenLogs(allLogs[2:5]), allLogs[5][0]), 598 nil, nil, nil, 599 }, 600 // multiple pending logs, should match only 2 topics from the logs in block 5 601 { 602 ethereum.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, fourthTopic}}, FromBlock: pendingBlockNumber, ToBlock: pendingBlockNumber}, 603 []*types.Log{allLogs[5][0], allLogs[5][2]}, 604 nil, nil, nil, 605 }, 606 // match none due to only matching new mined logs 607 { 608 ethereum.FilterQuery{}, 609 nil, 610 nil, nil, nil, 611 }, 612 // match none due to only matching mined logs within a specific block range 613 { 614 ethereum.FilterQuery{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, 615 nil, 616 nil, nil, nil, 617 }, 618 // match all due to matching mined and pending logs 619 { 620 ethereum.FilterQuery{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, 621 flattenLogs(allLogs), 622 nil, nil, nil, 623 }, 624 // match none due to matching logs from a specific block number to new mined blocks 625 { 626 ethereum.FilterQuery{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 627 nil, 628 nil, nil, nil, 629 }, 630 } 631 ) 632 633 // create all subscriptions, this ensures all subscriptions are created before the events are posted. 634 // on slow machines this could otherwise lead to missing events when the subscription is created after 635 // (some) events are posted. 636 for i := range testCases { 637 testCases[i].c = make(chan []*types.Log) 638 testCases[i].err = make(chan error) 639 640 var err error 641 testCases[i].sub, err = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) 642 if err != nil { 643 t.Fatalf("SubscribeLogs %d failed: %v\n", i, err) 644 } 645 } 646 647 for n, test := range testCases { 648 i := n 649 tt := test 650 go func() { 651 defer tt.sub.Unsubscribe() 652 653 var fetched []*types.Log 654 655 timeout := time.After(1 * time.Second) 656 fetchLoop: 657 for { 658 select { 659 case logs := <-tt.c: 660 // Do not break early if we've fetched greater, or equal, 661 // to the number of logs expected. This ensures we do not 662 // deadlock the filter system because it will do a blocking 663 // send on this channel if another log arrives. 664 fetched = append(fetched, logs...) 665 case <-timeout: 666 break fetchLoop 667 } 668 } 669 670 if len(fetched) != len(tt.expected) { 671 tt.err <- fmt.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 672 return 673 } 674 675 for l := range fetched { 676 if fetched[l].Removed { 677 tt.err <- fmt.Errorf("expected log not to be removed for log %d in case %d", l, i) 678 return 679 } 680 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 681 tt.err <- fmt.Errorf("invalid log on index %d for case %d\n", l, i) 682 return 683 } 684 } 685 tt.err <- nil 686 }() 687 } 688 689 // raise events 690 for _, ev := range allLogs { 691 backend.pendingLogsFeed.Send(ev) 692 } 693 694 for i := range testCases { 695 err := <-testCases[i].err 696 if err != nil { 697 t.Fatalf("test %d failed: %v", i, err) 698 } 699 <-testCases[i].sub.Err() 700 } 701 } 702 703 // TestPendingTxFilterDeadlock tests if the event loop hangs when pending 704 // txes arrive at the same time that one of multiple filters is timing out. 705 // Please refer to #22131 for more details. 706 func TestPendingTxFilterDeadlock(t *testing.T) { 707 t.Parallel() 708 timeout := 100 * time.Millisecond 709 710 var ( 711 db = rawdb.NewMemoryDatabase() 712 backend = &testBackend{db: db} 713 api = NewPublicFilterAPI(backend, false, timeout, ethconfig.Defaults.MaxBlockRange) 714 done = make(chan struct{}) 715 ) 716 717 go func() { 718 // Bombard feed with txes until signal was received to stop 719 i := uint64(0) 720 for { 721 select { 722 case <-done: 723 return 724 default: 725 } 726 727 tx := types.NewTransaction(i, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil) 728 backend.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}}) 729 i++ 730 } 731 }() 732 733 // Create a bunch of filters that will 734 // timeout either in 100ms or 200ms 735 fids := make([]rpc.ID, 20) 736 for i := 0; i < len(fids); i++ { 737 fid := api.NewPendingTransactionFilter() 738 fids[i] = fid 739 // Wait for at least one tx to arrive in filter 740 for { 741 hashes, err := api.GetFilterChanges(fid) 742 if err != nil { 743 t.Fatalf("Filter should exist: %v\n", err) 744 } 745 if len(hashes.([]common.Hash)) > 0 { 746 break 747 } 748 runtime.Gosched() 749 } 750 } 751 752 // Wait until filters have timed out 753 time.Sleep(3 * timeout) 754 755 // If tx loop doesn't consume `done` after a second 756 // it's hanging. 757 select { 758 case done <- struct{}{}: 759 // Check that all filters have been uninstalled 760 for _, fid := range fids { 761 if _, err := api.GetFilterChanges(fid); err == nil { 762 t.Errorf("Filter %s should have been uninstalled\n", fid) 763 } 764 } 765 case <-time.After(1 * time.Second): 766 t.Error("Tx sending loop hangs") 767 } 768 } 769 770 func flattenLogs(pl [][]*types.Log) []*types.Log { 771 var logs []*types.Log 772 for _, l := range pl { 773 logs = append(logs, l...) 774 } 775 return logs 776 }