fix: limit total number of filters that can be created (#661)

* Problem: No way to limit total number of filters that can be created

Solution: Add a config parameter to set the total number of filters that can be created

* Add defer statement for releasing locks

* Change default value for filter cap to 200

* Changed data type of filter cap to int32

* Add changelog entry

* Update CHANGELOG.md

* Fix struct alignment

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
Devashish Dixit
2021-10-13 11:03:49 +00:00
committed by GitHub
co-authored by Federico Kunze Küllmer
parent 8e12d94359
commit c7a2fb97c7
7 changed files with 54 additions and 16 deletions
+5
View File
@@ -765,6 +765,11 @@ func (e *EVMBackend) RPCGasCap() uint64 {
return e.cfg.JSONRPC.GasCap
}
// RPCFilterCap is the limit for total number of filters that can be created
func (e *EVMBackend) RPCFilterCap() int32 {
return e.cfg.JSONRPC.FilterCap
}
// RPCMinGasPrice returns the minimum gas price for a transaction obtained from
// the node config. If set value is 0, it will default to 20.
+23 -6
View File
@@ -36,6 +36,8 @@ type Backend interface {
BloomStatus() (uint64, uint64)
GetFilteredBlocks(from int64, to int64, bloomIndexes [][]BloomIV, filterAddresses bool) ([]int64, error)
RPCFilterCap() int32
}
// consider a filter inactive if it has not been polled for within deadline
@@ -107,15 +109,20 @@ func (api *PublicFilterAPI) timeoutLoop() {
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newPendingTransactionFilter
func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
api.filtersMu.Lock()
defer api.filtersMu.Unlock()
if len(api.filters) >= int(api.backend.RPCFilterCap()) {
return rpc.ID("error creating pending tx filter: max limit reached")
}
pendingTxSub, cancelSubs, err := api.events.SubscribePendingTxs()
if err != nil {
// wrap error on the ID
return rpc.ID(fmt.Sprintf("error creating pending tx filter: %s", err.Error()))
}
api.filtersMu.Lock()
api.filters[pendingTxSub.ID()] = &filter{typ: filters.PendingTransactionsSubscription, deadline: time.NewTimer(deadline), hashes: make([]common.Hash, 0), s: pendingTxSub}
api.filtersMu.Unlock()
go func(txsCh <-chan coretypes.ResultEvent, errCh <-chan error) {
defer cancelSubs()
@@ -219,6 +226,13 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter
func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
api.filtersMu.Lock()
defer api.filtersMu.Unlock()
if len(api.filters) >= int(api.backend.RPCFilterCap()) {
return rpc.ID("error creating block filter: max limit reached")
}
headerSub, cancelSubs, err := api.events.SubscribeNewHeads()
if err != nil {
// wrap error on the ID
@@ -228,9 +242,7 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
// TODO: use events to get the base fee amount
baseFee := big.NewInt(params.InitialBaseFee)
api.filtersMu.Lock()
api.filters[headerSub.ID()] = &filter{typ: filters.BlocksSubscription, deadline: time.NewTimer(deadline), hashes: []common.Hash{}, s: headerSub}
api.filtersMu.Unlock()
go func(headersCh <-chan coretypes.ResultEvent, errCh <-chan error) {
defer cancelSubs()
@@ -404,6 +416,13 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit filters.FilterCriteri
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter
func (api *PublicFilterAPI) NewFilter(criteria filters.FilterCriteria) (rpc.ID, error) {
api.filtersMu.Lock()
defer api.filtersMu.Unlock()
if len(api.filters) >= int(api.backend.RPCFilterCap()) {
return rpc.ID(""), fmt.Errorf("error creating filter: max limit reached")
}
var (
filterID = rpc.ID("")
err error
@@ -416,9 +435,7 @@ func (api *PublicFilterAPI) NewFilter(criteria filters.FilterCriteria) (rpc.ID,
filterID = logsSub.ID()
api.filtersMu.Lock()
api.filters[filterID] = &filter{typ: filters.LogsSubscription, deadline: time.NewTimer(deadline), hashes: []common.Hash{}, s: logsSub}
api.filtersMu.Unlock()
go func(eventCh <-chan coretypes.ResultEvent) {
defer cancelSubs()