@@ -22,6 +22,7 @@ import (
2222 "math/big"
2323 "math/rand"
2424 "reflect"
25+ "runtime"
2526 "testing"
2627 "time"
2728
@@ -38,6 +39,10 @@ import (
3839 "github.com/XinFinOrg/XDPoSChain/rpc"
3940)
4041
42+ var (
43+ deadline = 5 * time .Minute
44+ )
45+
4146type testBackend struct {
4247 mux * event.TypeMux
4348 db ethdb.Database
@@ -149,7 +154,7 @@ func TestBlockSubscription(t *testing.T) {
149154 var (
150155 db = rawdb .NewMemoryDatabase ()
151156 backend = & testBackend {db : db }
152- api = NewPublicFilterAPI (backend , false )
157+ api = NewPublicFilterAPI (backend , false , deadline )
153158 genesis = new (core.Genesis ).MustCommit (db )
154159 chain , _ = core .GenerateChain (params .TestChainConfig , genesis , ethash .NewFaker (), db , 10 , func (i int , gen * core.BlockGen ) {})
155160 chainEvents = []core.ChainEvent {}
@@ -201,7 +206,7 @@ func TestPendingTxFilter(t *testing.T) {
201206 var (
202207 db = rawdb .NewMemoryDatabase ()
203208 backend = & testBackend {db : db }
204- api = NewPublicFilterAPI (backend , false )
209+ api = NewPublicFilterAPI (backend , false , deadline )
205210
206211 transactions = []* types.Transaction {
207212 types .NewTransaction (0 , common .HexToAddress ("0xb794f5ea0ba39494ce83a213fffba74279579268" ), new (big.Int ), 0 , new (big.Int ), nil ),
@@ -256,7 +261,7 @@ func TestLogFilterCreation(t *testing.T) {
256261 var (
257262 db = rawdb .NewMemoryDatabase ()
258263 backend = & testBackend {db : db }
259- api = NewPublicFilterAPI (backend , false )
264+ api = NewPublicFilterAPI (backend , false , deadline )
260265
261266 testCases = []struct {
262267 crit FilterCriteria
@@ -300,7 +305,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
300305 var (
301306 db = rawdb .NewMemoryDatabase ()
302307 backend = & testBackend {db : db }
303- api = NewPublicFilterAPI (backend , false )
308+ api = NewPublicFilterAPI (backend , false , deadline )
304309 )
305310
306311 // different situations where log filter creation should fail.
@@ -322,7 +327,7 @@ func TestInvalidGetLogsRequest(t *testing.T) {
322327 var (
323328 db = rawdb .NewMemoryDatabase ()
324329 backend = & testBackend {db : db }
325- api = NewPublicFilterAPI (backend , false )
330+ api = NewPublicFilterAPI (backend , false , deadline )
326331 blockHash = common .HexToHash ("0x1111111111111111111111111111111111111111111111111111111111111111" )
327332 )
328333
@@ -347,7 +352,7 @@ func TestLogFilter(t *testing.T) {
347352 var (
348353 db = rawdb .NewMemoryDatabase ()
349354 backend = & testBackend {db : db }
350- api = NewPublicFilterAPI (backend , false )
355+ api = NewPublicFilterAPI (backend , false , deadline )
351356
352357 firstAddr = common .HexToAddress ("0x1111111111111111111111111111111111111111" )
353358 secondAddr = common .HexToAddress ("0x2222222222222222222222222222222222222222" )
@@ -461,7 +466,7 @@ func TestPendingLogsSubscription(t *testing.T) {
461466 var (
462467 db = rawdb .NewMemoryDatabase ()
463468 backend = & testBackend {db : db }
464- api = NewPublicFilterAPI (backend , false )
469+ api = NewPublicFilterAPI (backend , false , deadline )
465470
466471 firstAddr = common .HexToAddress ("0x1111111111111111111111111111111111111111" )
467472 secondAddr = common .HexToAddress ("0x2222222222222222222222222222222222222222" )
@@ -587,6 +592,73 @@ func TestPendingLogsSubscription(t *testing.T) {
587592 }
588593}
589594
595+ // TestPendingTxFilterDeadlock tests if the event loop hangs when pending
596+ // txes arrive at the same time that one of multiple filters is timing out.
597+ // Please refer to #22131 for more details.
598+ func TestPendingTxFilterDeadlock (t * testing.T ) {
599+ t .Parallel ()
600+ timeout := 100 * time .Millisecond
601+
602+ var (
603+ db = rawdb .NewMemoryDatabase ()
604+ backend = & testBackend {db : db }
605+ api = NewFilterAPI (backend , false , timeout )
606+ done = make (chan struct {})
607+ )
608+
609+ go func () {
610+ // Bombard feed with txes until signal was received to stop
611+ i := uint64 (0 )
612+ for {
613+ select {
614+ case <- done :
615+ return
616+ default :
617+ }
618+
619+ tx := types .NewTransaction (i , common .HexToAddress ("0xb794f5ea0ba39494ce83a213fffba74279579268" ), new (big.Int ), 0 , new (big.Int ), nil )
620+ backend .txFeed .Send (core.NewTxsEvent {Txs : []* types.Transaction {tx }})
621+ i ++
622+ }
623+ }()
624+
625+ // Create a bunch of filters that will
626+ // timeout either in 100ms or 200ms
627+ fids := make ([]rpc.ID , 20 )
628+ for i := 0 ; i < len (fids ); i ++ {
629+ fid := api .NewPendingTransactionFilter ()
630+ fids [i ] = fid
631+ // Wait for at least one tx to arrive in filter
632+ for {
633+ hashes , err := api .GetFilterChanges (fid )
634+ if err != nil {
635+ t .Fatalf ("Filter should exist: %v\n " , err )
636+ }
637+ if len (hashes .([]common.Hash )) > 0 {
638+ break
639+ }
640+ runtime .Gosched ()
641+ }
642+ }
643+
644+ // Wait until filters have timed out
645+ time .Sleep (3 * timeout )
646+
647+ // If tx loop doesn't consume `done` after a second
648+ // it's hanging.
649+ select {
650+ case done <- struct {}{}:
651+ // Check that all filters have been uninstalled
652+ for _ , fid := range fids {
653+ if _ , err := api .GetFilterChanges (fid ); err == nil {
654+ t .Errorf ("Filter %s should have been uninstalled\n " , fid )
655+ }
656+ }
657+ case <- time .After (1 * time .Second ):
658+ t .Error ("Tx sending loop hangs" )
659+ }
660+ }
661+
590662func flattenLogs (pl [][]* types.Log ) []* types.Log {
591663 var logs []* types.Log
592664 for _ , l := range pl {
0 commit comments