4141// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
4242const maxTopics = 4
4343
44- var (
45- deadline = 5 * time .Minute // consider a filter inactive if it has not been polled for within deadline
46- )
47-
4844// filter is a helper struct that holds meta information over the filter type
4945// and associated subscription in the event system.
5046type filter struct {
@@ -66,38 +62,49 @@ type PublicFilterAPI struct {
6662 events * EventSystem
6763 filtersMu sync.Mutex
6864 filters map [rpc.ID ]* filter
65+ timeout time.Duration
6966}
7067
7168// NewPublicFilterAPI returns a new PublicFilterAPI instance.
72- func NewPublicFilterAPI (backend Backend , lightMode bool ) * PublicFilterAPI {
69+ func NewPublicFilterAPI (backend Backend , lightMode bool , timeout time. Duration ) * PublicFilterAPI {
7370 api := & PublicFilterAPI {
7471 backend : backend ,
7572 chainDb : backend .ChainDb (),
7673 events : NewEventSystem (backend , lightMode ),
7774 filters : make (map [rpc.ID ]* filter ),
75+ timeout : timeout ,
7876 }
79- go api .timeoutLoop ()
77+ go api .timeoutLoop (timeout )
8078
8179 return api
8280}
8381
8482// timeoutLoop runs every 5 minutes and deletes filters that have not been recently used.
8583// Tt is started when the api is created.
86- func (api * PublicFilterAPI ) timeoutLoop () {
87- ticker := time .NewTicker (5 * time .Minute )
84+ func (api * PublicFilterAPI ) timeoutLoop (timeout time.Duration ) {
85+ var toUninstall []* Subscription
86+ ticker := time .NewTicker (timeout )
8887 for {
8988 <- ticker .C
9089 api .filtersMu .Lock ()
9190 for id , f := range api .filters {
9291 select {
9392 case <- f .deadline .C :
94- f .s . Unsubscribe ( )
93+ toUninstall = append ( toUninstall , f .s )
9594 delete (api .filters , id )
9695 default :
9796 continue
9897 }
9998 }
10099 api .filtersMu .Unlock ()
100+
101+ // Unsubscribes are processed outside the lock to avoid the following scenario:
102+ // event loop attempts broadcasting events to still active filters while
103+ // Unsubscribe is waiting for it to process the uninstall request.
104+ for _ , s := range toUninstall {
105+ s .Unsubscribe ()
106+ }
107+ toUninstall = nil
101108 }
102109}
103110
@@ -115,7 +122,7 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
115122 )
116123
117124 api .filtersMu .Lock ()
118- api .filters [pendingTxSub .ID ] = & filter {typ : PendingTransactionsSubscription , deadline : time .NewTimer (deadline ), hashes : make ([]common.Hash , 0 ), s : pendingTxSub }
125+ api .filters [pendingTxSub .ID ] = & filter {typ : PendingTransactionsSubscription , deadline : time .NewTimer (api . timeout ), hashes : make ([]common.Hash , 0 ), s : pendingTxSub }
119126 api .filtersMu .Unlock ()
120127
121128 go func () {
@@ -185,7 +192,7 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
185192 )
186193
187194 api .filtersMu .Lock ()
188- api .filters [headerSub .ID ] = & filter {typ : BlocksSubscription , deadline : time .NewTimer (deadline ), hashes : make ([]common.Hash , 0 ), s : headerSub }
195+ api .filters [headerSub .ID ] = & filter {typ : BlocksSubscription , deadline : time .NewTimer (api . timeout ), hashes : make ([]common.Hash , 0 ), s : headerSub }
189196 api .filtersMu .Unlock ()
190197
191198 go func () {
@@ -302,7 +309,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
302309 }
303310
304311 api .filtersMu .Lock ()
305- api .filters [logsSub .ID ] = & filter {typ : LogsSubscription , crit : crit , deadline : time .NewTimer (deadline ), logs : make ([]* types.Log , 0 ), s : logsSub }
312+ api .filters [logsSub .ID ] = & filter {typ : LogsSubscription , crit : crit , deadline : time .NewTimer (api . timeout ), logs : make ([]* types.Log , 0 ), s : logsSub }
306313 api .filtersMu .Unlock ()
307314
308315 go func () {
@@ -431,7 +438,7 @@ func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
431438 // receive timer value and reset timer
432439 <- f .deadline .C
433440 }
434- f .deadline .Reset (deadline )
441+ f .deadline .Reset (api . timeout )
435442
436443 switch f .typ {
437444 case PendingTransactionsSubscription , BlocksSubscription :
0 commit comments