Skip to content

Commit

Permalink
Merge pull request #2903 from dessaya/jsonrpc-params
Browse files Browse the repository at this point in the history
feat(jsonrpc): configurable eth_getLogs limits
  • Loading branch information
dessaya authored Oct 6, 2023
2 parents e91e0a6 + 30736ff commit 70ce533
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 36 deletions.
5 changes: 5 additions & 0 deletions components/webapi/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/iotaledger/wasp/packages/chains"
"github.com/iotaledger/wasp/packages/daemon"
"github.com/iotaledger/wasp/packages/dkg"
"github.com/iotaledger/wasp/packages/evm/jsonrpc"
"github.com/iotaledger/wasp/packages/isc"
"github.com/iotaledger/wasp/packages/metrics"
"github.com/iotaledger/wasp/packages/peering"
Expand Down Expand Up @@ -291,6 +292,10 @@ func provide(c *dig.Container) error {
websocketService,
ParamsWebAPI.IndexDbPath,
deps.Publisher,
jsonrpc.NewParameters(
ParamsWebAPI.Limits.Jsonrpc.MaxBlocksInLogsFilterRange,
ParamsWebAPI.Limits.Jsonrpc.MaxLogsInResult,
),
)

return webapiServerResult{
Expand Down
33 changes: 20 additions & 13 deletions components/webapi/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,29 @@ import (
)

type ParametersWebAPI struct {
Enabled bool `default:"true" usage:"whether the web api plugin is enabled"`
BindAddress string `default:"0.0.0.0:9090" usage:"the bind address for the node web api"`
Auth authentication.AuthConfiguration `usage:"configures the authentication for the API service"`
IndexDbPath string `default:"waspdb/chains/index" usage:"directory for storing indexes of historical data (only archive nodes will create/use them)"`
Limits struct {
Timeout time.Duration `default:"30s" usage:"the timeout after which a long running operation will be canceled"`
ReadTimeout time.Duration `default:"10s" usage:"the read timeout for the HTTP request body"`
WriteTimeout time.Duration `default:"60s" usage:"the write timeout for the HTTP response body"`
MaxBodyLength string `default:"2M" usage:"the maximum number of characters that the body of an API call may contain"`
MaxTopicSubscriptionsPerClient int `default:"0" usage:"defines the max amount of subscriptions per client. 0 = deactivated (default)"`
ConfirmedStateLagThreshold uint32 `default:"2" usage:"the threshold that define a chain is unsynchronized"`
}

Enabled bool `default:"true" usage:"whether the web api plugin is enabled"`
BindAddress string `default:"0.0.0.0:9090" usage:"the bind address for the node web api"`
Auth authentication.AuthConfiguration `usage:"configures the authentication for the API service"`
IndexDbPath string `default:"waspdb/chains/index" usage:"directory for storing indexes of historical data (only archive nodes will create/use them)"`
Limits ParametersWebAPILimits
DebugRequestLoggerEnabled bool `default:"false" usage:"whether the debug logging for requests should be enabled"`
}

type ParametersWebAPILimits struct {
Timeout time.Duration `default:"30s" usage:"the timeout after which a long running operation will be canceled"`
ReadTimeout time.Duration `default:"10s" usage:"the read timeout for the HTTP request body"`
WriteTimeout time.Duration `default:"60s" usage:"the write timeout for the HTTP response body"`
MaxBodyLength string `default:"2M" usage:"the maximum number of characters that the body of an API call may contain"`
MaxTopicSubscriptionsPerClient int `default:"0" usage:"defines the max amount of subscriptions per client. 0 = deactivated (default)"`
ConfirmedStateLagThreshold uint32 `default:"2" usage:"the threshold that define a chain is unsynchronized"`
Jsonrpc ParametersJSONRPC
}

type ParametersJSONRPC struct {
MaxBlocksInLogsFilterRange int `default:"1000" usage:"maximum amount of blocks in eth_getLogs filter range"`
MaxLogsInResult int `default:"10000" usage:"maximum amount of logs in eth_getLogs result"`
}

var ParamsWebAPI = &ParametersWebAPI{
Auth: authentication.AuthConfiguration{
Scheme: "jwt",
Expand Down
10 changes: 2 additions & 8 deletions components/webapi/webapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,14 @@ func TestInternalServerErrors(t *testing.T) {
Enabled: true,
BindAddress: ":9999",
Auth: authentication.AuthConfiguration{},
Limits: struct {
Timeout time.Duration "default:\"30s\" usage:\"the timeout after which a long running operation will be canceled\""
ReadTimeout time.Duration "default:\"10s\" usage:\"the read timeout for the HTTP request body\""
WriteTimeout time.Duration "default:\"60s\" usage:\"the write timeout for the HTTP response body\""
MaxBodyLength string "default:\"2M\" usage:\"the maximum number of characters that the body of an API call may contain\""
MaxTopicSubscriptionsPerClient int "default:\"0\" usage:\"defines the max amount of subscriptions per client. 0 = deactivated (default)\""
ConfirmedStateLagThreshold uint32 "default:\"2\" usage:\"the threshold that define a chain is unsynchronized\""
}{
Limits: webapi.ParametersWebAPILimits{
Timeout: time.Minute,
ReadTimeout: time.Minute,
WriteTimeout: time.Minute,
MaxBodyLength: "1M",
MaxTopicSubscriptionsPerClient: 0,
ConfirmedStateLagThreshold: 2,
Jsonrpc: webapi.ParametersJSONRPC{},
},
DebugRequestLoggerEnabled: true,
},
Expand Down
19 changes: 10 additions & 9 deletions packages/evm/jsonrpc/evmchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ type NewBlockEvent struct {
logs []*types.Log
}

type LogsLimits struct {
MaxBlocksInLogsFilterRange int
MaxLogsInResult int
}

func NewEVMChain(
backend ChainBackend,
pub *publisher.Publisher,
Expand Down Expand Up @@ -476,16 +481,11 @@ func (e *EVMChain) BlockTransactionCountByNumber(blockNumber *big.Int) (uint64,
return uint64(len(block.Transactions())), nil
}

const (
maxBlocksInFilterRange = 1_000
maxLogsInResult = 10_000
)

// Logs executes a log filter operation, blocking during execution and
// returning all the results in one batch.
//
//nolint:gocyclo
func (e *EVMChain) Logs(query *ethereum.FilterQuery) ([]*types.Log, error) {
func (e *EVMChain) Logs(query *ethereum.FilterQuery, params *LogsLimits) ([]*types.Log, error) {
e.log.Debugf("Logs(q=%v)", query)
logs := make([]*types.Log, 0)

Expand All @@ -499,7 +499,7 @@ func (e *EVMChain) Logs(query *ethereum.FilterQuery) ([]*types.Log, error) {
}
db := blockchainDB(state)
receipts := db.GetReceiptsByBlockNumber(uint64(state.BlockIndex()))
err = filterAndAppendToLogs(query, receipts, &logs)
err = filterAndAppendToLogs(query, receipts, &logs, params.MaxLogsInResult)
if err != nil {
return nil, err
}
Expand All @@ -526,7 +526,7 @@ func (e *EVMChain) Logs(query *ethereum.FilterQuery) ([]*types.Log, error) {
{
from := from.Uint64()
to := to.Uint64()
if to > from && to-from > maxBlocksInFilterRange {
if to > from && to-from > uint64(params.MaxBlocksInLogsFilterRange) {
return nil, errors.New("too many blocks in filter range")
}
for i := from; i <= to; i++ {
Expand All @@ -538,6 +538,7 @@ func (e *EVMChain) Logs(query *ethereum.FilterQuery) ([]*types.Log, error) {
query,
blockchainDB(state).GetReceiptsByBlockNumber(i),
&logs,
params.MaxLogsInResult,
)
if err != nil {
return nil, err
Expand All @@ -547,7 +548,7 @@ func (e *EVMChain) Logs(query *ethereum.FilterQuery) ([]*types.Log, error) {
return logs, nil
}

func filterAndAppendToLogs(query *ethereum.FilterQuery, receipts []*types.Receipt, logs *[]*types.Log) error {
func filterAndAppendToLogs(query *ethereum.FilterQuery, receipts []*types.Receipt, logs *[]*types.Log, maxLogsInResult int) error {
for _, r := range receipts {
if r.Status == types.ReceiptStatusFailed {
continue
Expand Down
7 changes: 6 additions & 1 deletion packages/evm/jsonrpc/jsonrpctest/jsonrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ func newSoloTestEnv(t testing.TB) *soloTestEnv {
chain, _ := s.NewChainExt(chainOwner, 0, "chain1")

accounts := jsonrpc.NewAccountManager(nil)
rpcsrv, err := jsonrpc.NewServer(chain.EVM(), accounts, chain.GetChainMetrics().WebAPI)
rpcsrv, err := jsonrpc.NewServer(
chain.EVM(),
accounts,
chain.GetChainMetrics().WebAPI,
jsonrpc.ParametersDefault(),
)
require.NoError(t, err)
t.Cleanup(rpcsrv.Stop)

Expand Down
28 changes: 27 additions & 1 deletion packages/evm/jsonrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,36 @@ import (
"github.com/iotaledger/wasp/packages/metrics"
)

type Parameters struct {
Logs LogsLimits
}

func NewParameters(
maxBlocksInLogsFilterRange int,
maxLogsInResult int,
) *Parameters {
return &Parameters{
Logs: LogsLimits{
MaxBlocksInLogsFilterRange: maxBlocksInLogsFilterRange,
MaxLogsInResult: maxLogsInResult,
},
}
}

func ParametersDefault() *Parameters {
return &Parameters{
Logs: LogsLimits{
MaxBlocksInLogsFilterRange: 1000,
MaxLogsInResult: 10000,
},
}
}

func NewServer(
evmChain *EVMChain,
accountManager *AccountManager,
metrics *metrics.ChainWebAPIMetrics,
params *Parameters,
) (*rpc.Server, error) {
chainID := evmChain.ChainID()
rpcsrv := rpc.NewServer()
Expand All @@ -22,7 +48,7 @@ func NewServer(
}{
{"web3", NewWeb3Service()},
{"net", NewNetService(int(chainID))},
{"eth", NewEthService(evmChain, accountManager, metrics)},
{"eth", NewEthService(evmChain, accountManager, metrics, params)},
{"debug", NewDebugService(evmChain, metrics)},
{"txpool", NewTxPoolService()},
{"evm", NewEVMService(evmChain)},
Expand Down
14 changes: 12 additions & 2 deletions packages/evm/jsonrpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,20 @@ type EthService struct {
evmChain *EVMChain
accounts *AccountManager
metrics *metrics.ChainWebAPIMetrics
params *Parameters
}

func NewEthService(evmChain *EVMChain, accounts *AccountManager, metrics *metrics.ChainWebAPIMetrics) *EthService {
func NewEthService(
evmChain *EVMChain,
accounts *AccountManager,
metrics *metrics.ChainWebAPIMetrics,
params *Parameters,
) *EthService {
return &EthService{
evmChain: evmChain,
accounts: accounts,
metrics: metrics,
params: params,
}
}

Expand Down Expand Up @@ -496,7 +503,10 @@ func (e *EthService) parseTxArgs(args *SendTxArgs) (*types.Transaction, error) {
}

func (e *EthService) getLogs(q *RPCFilterQuery) ([]*types.Log, error) {
logs, err := e.evmChain.Logs((*ethereum.FilterQuery)(q))
logs, err := e.evmChain.Logs(
(*ethereum.FilterQuery)(q),
&e.params.Logs,
)
if err != nil {
return nil, e.resolveError(err)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/webapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/iotaledger/wasp/packages/authentication"
"github.com/iotaledger/wasp/packages/chains"
"github.com/iotaledger/wasp/packages/dkg"
"github.com/iotaledger/wasp/packages/evm/jsonrpc"
"github.com/iotaledger/wasp/packages/metrics"
"github.com/iotaledger/wasp/packages/peering"
"github.com/iotaledger/wasp/packages/publisher"
Expand Down Expand Up @@ -93,6 +94,7 @@ func Init(
websocketService *websocket.Service,
indexDbPath string,
pub *publisher.Publisher,
jsonrpcParams *jsonrpc.Parameters,
) {
// load mock files to generate correct echo swagger documentation
mocker := NewMocker()
Expand All @@ -104,7 +106,7 @@ func Init(
offLedgerService := services.NewOffLedgerService(chainService, networkProvider, requestCacheTTL)
metricsService := services.NewMetricsService(chainsProvider, chainMetricsProvider)
peeringService := services.NewPeeringService(chainsProvider, networkProvider, trustedNetworkManager)
evmService := services.NewEVMService(chainsProvider, chainService, networkProvider, pub, indexDbPath, chainMetricsProvider, logger.Named("EVMService"))
evmService := services.NewEVMService(chainsProvider, chainService, networkProvider, pub, indexDbPath, chainMetricsProvider, jsonrpcParams, logger.Named("EVMService"))
nodeService := services.NewNodeService(chainRecordRegistryProvider, nodeIdentityProvider, chainsProvider, shutdownHandler, trustedNetworkManager)
dkgService := services.NewDKGService(dkShareRegistryProvider, dkgNodeProvider, trustedNetworkManager)
userService := services.NewUserService(userManager)
Expand Down
4 changes: 4 additions & 0 deletions packages/webapi/services/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type EVMService struct {
publisher *publisher.Publisher
indexDbPath string
metrics *metrics.ChainMetricsProvider
jsonrpcParams *jsonrpc.Parameters
log *logger.Logger
}

Expand All @@ -44,6 +45,7 @@ func NewEVMService(
pub *publisher.Publisher,
indexDbPath string,
metrics *metrics.ChainMetricsProvider,
jsonrpcParams *jsonrpc.Parameters,
log *logger.Logger,
) interfaces.EVMService {
return &EVMService{
Expand All @@ -55,6 +57,7 @@ func NewEVMService(
publisher: pub,
indexDbPath: indexDbPath,
metrics: metrics,
jsonrpcParams: jsonrpcParams,
log: log,
}
}
Expand All @@ -79,6 +82,7 @@ func (e *EVMService) getEVMBackend(chainID isc.ChainID) (*chainServer, error) {
jsonrpc.NewEVMChain(backend, e.publisher, e.chainsProvider().IsArchiveNode(), hivedb.EngineRocksDB, e.indexDbPath, e.log.Named("EVMChain")),
jsonrpc.NewAccountManager(nil),
e.metrics.GetChainMetrics(chainID).WebAPI,
e.jsonrpcParams,
)
if err != nil {
return nil, err
Expand Down
3 changes: 2 additions & 1 deletion tools/api-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/iotaledger/wasp/components/webapi"
"github.com/iotaledger/wasp/packages/authentication"
"github.com/iotaledger/wasp/packages/cryptolib"
"github.com/iotaledger/wasp/packages/evm/jsonrpc"
v2 "github.com/iotaledger/wasp/packages/webapi"
)

Expand All @@ -35,7 +36,7 @@ func main() {
}

swagger := webapi.CreateEchoSwagger(e, app.Version)
v2.Init(mockLog, swagger, app.Version, nil, nil, nil, nil, nil, nil, &NodeIdentityProviderMock{}, nil, nil, nil, nil, authentication.AuthConfiguration{Scheme: authentication.AuthJWT}, time.Second, nil, "", nil)
v2.Init(mockLog, swagger, app.Version, nil, nil, nil, nil, nil, nil, &NodeIdentityProviderMock{}, nil, nil, nil, nil, authentication.AuthConfiguration{Scheme: authentication.AuthJWT}, time.Second, nil, "", nil, jsonrpc.ParametersDefault())

root, ok := swagger.(*echoswagger.Root)
if !ok {
Expand Down

0 comments on commit 70ce533

Please sign in to comment.