rpc: add configurable http and `eth_call` timeout

pull/4374/head
MaxMustermann2 2 years ago committed by Casey Gardiner
parent 2b9b2f580b
commit a6b3f890e4
  1. 17
      cmd/harmony/config_migrations.go
  2. 6
      cmd/harmony/default.go
  3. 39
      cmd/harmony/flags.go
  4. 58
      cmd/harmony/flags_test.go
  5. 64
      internal/configs/harmony/harmony.go
  6. 81
      internal/configs/harmony/harmony_test.go
  7. 7
      internal/configs/node/config.go
  8. 6
      internal/configs/node/network.go
  9. 5
      rosetta/rosetta.go
  10. 10
      rosetta/services/call_service.go
  11. 22
      rpc/contract.go
  12. 25
      rpc/rpc.go

@ -340,6 +340,23 @@ func init() {
return confTree return confTree
} }
migrations["2.5.12"] = func(confTree *toml.Tree) *toml.Tree {
if confTree.Get("HTTP.ReadTimeout") == nil {
confTree.Set("HTTP.ReadTimeout", defaultConfig.HTTP.ReadTimeout)
}
if confTree.Get("HTTP.WriteTimeout") == nil {
confTree.Set("HTTP.WriteTimeout", defaultConfig.HTTP.WriteTimeout)
}
if confTree.Get("HTTP.IdleTimeout") == nil {
confTree.Set("HTTP.IdleTimeout", defaultConfig.HTTP.IdleTimeout)
}
if confTree.Get("RPCOpt.EvmCallTimeout") == nil {
confTree.Set("RPCOpt.EvmCallTimeout", defaultConfig.RPCOpt.EvmCallTimeout)
}
confTree.Set("Version", "2.5.13")
return confTree
}
// check that the latest version here is the same as in default.go // check that the latest version here is the same as in default.go
largestKey := getNextVersion(migrations) largestKey := getNextVersion(migrations)
if largestKey != tomlConfigVersion { if largestKey != tomlConfigVersion {

@ -5,7 +5,7 @@ import (
nodeconfig "github.com/harmony-one/harmony/internal/configs/node" nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
) )
const tomlConfigVersion = "2.5.12" const tomlConfigVersion = "2.5.13"
const ( const (
defNetworkType = nodeconfig.Mainnet defNetworkType = nodeconfig.Mainnet
@ -44,6 +44,9 @@ var defaultConfig = harmonyconfig.HarmonyConfig{
Port: nodeconfig.DefaultRPCPort, Port: nodeconfig.DefaultRPCPort,
AuthPort: nodeconfig.DefaultAuthRPCPort, AuthPort: nodeconfig.DefaultAuthRPCPort,
RosettaPort: nodeconfig.DefaultRosettaPort, RosettaPort: nodeconfig.DefaultRosettaPort,
ReadTimeout: nodeconfig.DefaultHTTPTimeoutRead,
WriteTimeout: nodeconfig.DefaultHTTPTimeoutWrite,
IdleTimeout: nodeconfig.DefaultHTTPTimeoutIdle,
}, },
WS: harmonyconfig.WsConfig{ WS: harmonyconfig.WsConfig{
Enabled: true, Enabled: true,
@ -59,6 +62,7 @@ var defaultConfig = harmonyconfig.HarmonyConfig{
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: nodeconfig.DefaultRPCRateLimit, RequestsPerSecond: nodeconfig.DefaultRPCRateLimit,
EvmCallTimeout: nodeconfig.DefaultEvmCallTimeout,
}, },
BLSKeys: harmonyconfig.BlsConfig{ BLSKeys: harmonyconfig.BlsConfig{
KeyDir: "./.hmy/blskeys", KeyDir: "./.hmy/blskeys",

@ -75,6 +75,9 @@ var (
httpPortFlag, httpPortFlag,
httpAuthPortFlag, httpAuthPortFlag,
httpRosettaPortFlag, httpRosettaPortFlag,
httpReadTimeoutFlag,
httpWriteTimeoutFlag,
httpIdleTimeoutFlag,
} }
wsFlags = []cli.Flag{ wsFlags = []cli.Flag{
@ -92,6 +95,7 @@ var (
rpcFilterFileFlag, rpcFilterFileFlag,
rpcRateLimiterEnabledFlag, rpcRateLimiterEnabledFlag,
rpcRateLimitFlag, rpcRateLimitFlag,
rpcEvmCallTimeoutFlag,
} }
blsFlags = append(newBLSFlags, legacyBLSFlags...) blsFlags = append(newBLSFlags, legacyBLSFlags...)
@ -695,6 +699,21 @@ var (
Usage: "rosetta port to listen for HTTP requests", Usage: "rosetta port to listen for HTTP requests",
DefValue: defaultConfig.HTTP.RosettaPort, DefValue: defaultConfig.HTTP.RosettaPort,
} }
httpReadTimeoutFlag = cli.StringFlag{
Name: "http.timeout.read",
Usage: "maximum duration to read the entire request, including the body",
DefValue: defaultConfig.HTTP.ReadTimeout,
}
httpWriteTimeoutFlag = cli.StringFlag{
Name: "http.timeout.write",
Usage: "maximum duration before timing out writes of the response",
DefValue: defaultConfig.HTTP.WriteTimeout,
}
httpIdleTimeoutFlag = cli.StringFlag{
Name: "http.timeout.idle",
Usage: "maximum amount of time to wait for the next request when keep-alives are enabled",
DefValue: defaultConfig.HTTP.IdleTimeout,
}
) )
func applyHTTPFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) { func applyHTTPFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) {
@ -732,6 +751,16 @@ func applyHTTPFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) {
config.HTTP.Enabled = true config.HTTP.Enabled = true
} }
if cli.IsFlagChanged(cmd, httpReadTimeoutFlag) {
config.HTTP.ReadTimeout = cli.GetStringFlagValue(cmd, httpReadTimeoutFlag)
}
if cli.IsFlagChanged(cmd, httpWriteTimeoutFlag) {
config.HTTP.WriteTimeout = cli.GetStringFlagValue(cmd, httpWriteTimeoutFlag)
}
if cli.IsFlagChanged(cmd, httpIdleTimeoutFlag) {
config.HTTP.IdleTimeout = cli.GetStringFlagValue(cmd, httpIdleTimeoutFlag)
}
} }
// ws flags // ws flags
@ -821,6 +850,12 @@ var (
Usage: "the number of requests per second for RPCs", Usage: "the number of requests per second for RPCs",
DefValue: defaultConfig.RPCOpt.RequestsPerSecond, DefValue: defaultConfig.RPCOpt.RequestsPerSecond,
} }
rpcEvmCallTimeoutFlag = cli.StringFlag{
Name: "rpc.evm-call-timeout",
Usage: "timeout for evm execution (eth_call); 0 means infinite timeout",
DefValue: defaultConfig.RPCOpt.EvmCallTimeout,
}
) )
func applyRPCOptFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) { func applyRPCOptFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) {
@ -845,7 +880,9 @@ func applyRPCOptFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) {
if cli.IsFlagChanged(cmd, rpcRateLimitFlag) { if cli.IsFlagChanged(cmd, rpcRateLimitFlag) {
config.RPCOpt.RequestsPerSecond = cli.GetIntFlagValue(cmd, rpcRateLimitFlag) config.RPCOpt.RequestsPerSecond = cli.GetIntFlagValue(cmd, rpcRateLimitFlag)
} }
if cli.IsFlagChanged(cmd, rpcEvmCallTimeoutFlag) {
config.RPCOpt.EvmCallTimeout = cli.GetStringFlagValue(cmd, rpcEvmCallTimeoutFlag)
}
} }
// bls flags // bls flags

@ -77,6 +77,9 @@ func TestHarmonyFlags(t *testing.T) {
AuthPort: 9501, AuthPort: 9501,
RosettaEnabled: false, RosettaEnabled: false,
RosettaPort: 9700, RosettaPort: 9700,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
}, },
RPCOpt: harmonyconfig.RpcOptConfig{ RPCOpt: harmonyconfig.RpcOptConfig{
DebugEnabled: false, DebugEnabled: false,
@ -86,6 +89,7 @@ func TestHarmonyFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
WS: harmonyconfig.WsConfig{ WS: harmonyconfig.WsConfig{
Enabled: true, Enabled: true,
@ -531,6 +535,9 @@ func TestRPCFlags(t *testing.T) {
Port: defaultConfig.HTTP.Port, Port: defaultConfig.HTTP.Port,
AuthPort: defaultConfig.HTTP.AuthPort, AuthPort: defaultConfig.HTTP.AuthPort,
RosettaPort: defaultConfig.HTTP.RosettaPort, RosettaPort: defaultConfig.HTTP.RosettaPort,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
}, },
}, },
{ {
@ -542,6 +549,9 @@ func TestRPCFlags(t *testing.T) {
Port: 9001, Port: 9001,
AuthPort: defaultConfig.HTTP.AuthPort, AuthPort: defaultConfig.HTTP.AuthPort,
RosettaPort: defaultConfig.HTTP.RosettaPort, RosettaPort: defaultConfig.HTTP.RosettaPort,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
}, },
}, },
{ {
@ -553,6 +563,9 @@ func TestRPCFlags(t *testing.T) {
Port: defaultConfig.HTTP.Port, Port: defaultConfig.HTTP.Port,
AuthPort: 9001, AuthPort: 9001,
RosettaPort: defaultConfig.HTTP.RosettaPort, RosettaPort: defaultConfig.HTTP.RosettaPort,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
}, },
}, },
{ {
@ -564,6 +577,9 @@ func TestRPCFlags(t *testing.T) {
Port: 9001, Port: 9001,
AuthPort: defaultConfig.HTTP.AuthPort, AuthPort: defaultConfig.HTTP.AuthPort,
RosettaPort: 10001, RosettaPort: 10001,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
}, },
}, },
{ {
@ -575,6 +591,9 @@ func TestRPCFlags(t *testing.T) {
Port: defaultConfig.HTTP.Port, Port: defaultConfig.HTTP.Port,
AuthPort: defaultConfig.HTTP.AuthPort, AuthPort: defaultConfig.HTTP.AuthPort,
RosettaPort: 10001, RosettaPort: 10001,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
}, },
}, },
{ {
@ -586,6 +605,23 @@ func TestRPCFlags(t *testing.T) {
Port: 9501, Port: 9501,
AuthPort: 9502, AuthPort: 9502,
RosettaPort: 9701, RosettaPort: 9701,
ReadTimeout: defaultConfig.HTTP.ReadTimeout,
WriteTimeout: defaultConfig.HTTP.WriteTimeout,
IdleTimeout: defaultConfig.HTTP.IdleTimeout,
},
},
{
args: []string{"--http.timeout.read", "10s", "--http.timeout.write", "20s", "--http.timeout.idle", "30s"},
expConfig: harmonyconfig.HttpConfig{
Enabled: true,
RosettaEnabled: false,
IP: defaultConfig.HTTP.IP,
Port: defaultConfig.HTTP.Port,
AuthPort: defaultConfig.HTTP.AuthPort,
RosettaPort: defaultConfig.HTTP.RosettaPort,
ReadTimeout: "10s",
WriteTimeout: "20s",
IdleTimeout: "30s",
}, },
}, },
} }
@ -699,6 +735,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -712,6 +749,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -725,6 +763,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -738,6 +777,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -751,6 +791,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./rmf.toml", RpcFilterFile: "./rmf.toml",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -764,6 +805,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 1000, RequestsPerSecond: 1000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -777,6 +819,7 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true, RateLimterEnabled: true,
RequestsPerSecond: 2000, RequestsPerSecond: 2000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
}, },
}, },
@ -790,6 +833,21 @@ func TestRPCOptFlags(t *testing.T) {
RpcFilterFile: "./.hmy/rpc_filter.txt", RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: false, RateLimterEnabled: false,
RequestsPerSecond: 2000, RequestsPerSecond: 2000,
EvmCallTimeout: defaultConfig.RPCOpt.EvmCallTimeout,
},
},
{
args: []string{"--rpc.evm-call-timeout", "10s"},
expConfig: harmonyconfig.RpcOptConfig{
DebugEnabled: false,
EthRPCsEnabled: true,
StakingRPCsEnabled: true,
LegacyRPCsEnabled: true,
RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true,
RequestsPerSecond: 1000,
EvmCallTimeout: "10s",
}, },
}, },
} }

@ -3,6 +3,10 @@ package harmony
import ( import (
"reflect" "reflect"
"strings" "strings"
"time"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
) )
// HarmonyConfig contains all the configs user can set for running harmony binary. Served as the bridge // HarmonyConfig contains all the configs user can set for running harmony binary. Served as the bridge
@ -32,6 +36,62 @@ type HarmonyConfig struct {
ShardData ShardDataConfig ShardData ShardDataConfig
} }
func (hc HarmonyConfig) ToRPCServerConfig() nodeconfig.RPCServerConfig {
readTimeout, err := time.ParseDuration(hc.HTTP.ReadTimeout)
if err != nil {
readTimeout, _ = time.ParseDuration(nodeconfig.DefaultHTTPTimeoutRead)
utils.Logger().Warn().
Str("provided", hc.HTTP.ReadTimeout).
Dur("updated", readTimeout).
Msg("Sanitizing invalid http read timeout")
}
writeTimeout, err := time.ParseDuration(hc.HTTP.WriteTimeout)
if err != nil {
writeTimeout, _ = time.ParseDuration(nodeconfig.DefaultHTTPTimeoutWrite)
utils.Logger().Warn().
Str("provided", hc.HTTP.WriteTimeout).
Dur("updated", writeTimeout).
Msg("Sanitizing invalid http write timeout")
}
idleTimeout, err := time.ParseDuration(hc.HTTP.IdleTimeout)
if err != nil {
idleTimeout, _ = time.ParseDuration(nodeconfig.DefaultHTTPTimeoutIdle)
utils.Logger().Warn().
Str("provided", hc.HTTP.IdleTimeout).
Dur("updated", idleTimeout).
Msg("Sanitizing invalid http idle timeout")
}
evmCallTimeout, err := time.ParseDuration(hc.RPCOpt.EvmCallTimeout)
if err != nil {
evmCallTimeout, _ = time.ParseDuration(nodeconfig.DefaultEvmCallTimeout)
utils.Logger().Warn().
Str("provided", hc.RPCOpt.EvmCallTimeout).
Dur("updated", evmCallTimeout).
Msg("Sanitizing invalid evm_call timeout")
}
return nodeconfig.RPCServerConfig{
HTTPEnabled: hc.HTTP.Enabled,
HTTPIp: hc.HTTP.IP,
HTTPPort: hc.HTTP.Port,
HTTPAuthPort: hc.HTTP.AuthPort,
HTTPTimeoutRead: readTimeout,
HTTPTimeoutWrite: writeTimeout,
HTTPTimeoutIdle: idleTimeout,
WSEnabled: hc.WS.Enabled,
WSIp: hc.WS.IP,
WSPort: hc.WS.Port,
WSAuthPort: hc.WS.AuthPort,
DebugEnabled: hc.RPCOpt.DebugEnabled,
EthRPCsEnabled: hc.RPCOpt.EthRPCsEnabled,
StakingRPCsEnabled: hc.RPCOpt.StakingRPCsEnabled,
LegacyRPCsEnabled: hc.RPCOpt.LegacyRPCsEnabled,
RpcFilterFile: hc.RPCOpt.RpcFilterFile,
RateLimiterEnabled: hc.RPCOpt.RateLimterEnabled,
RequestsPerSecond: hc.RPCOpt.RequestsPerSecond,
EvmCallTimeout: evmCallTimeout,
}
}
type DnsSync struct { type DnsSync struct {
Port int // replaces: Network.DNSSyncPort Port int // replaces: Network.DNSSyncPort
Zone string // replaces: Network.DNSZone Zone string // replaces: Network.DNSZone
@ -180,6 +240,9 @@ type HttpConfig struct {
AuthPort int AuthPort int
RosettaEnabled bool RosettaEnabled bool
RosettaPort int RosettaPort int
ReadTimeout string
WriteTimeout string
IdleTimeout string
} }
type WsConfig struct { type WsConfig struct {
@ -197,6 +260,7 @@ type RpcOptConfig struct {
RpcFilterFile string // Define filters to enable/disable RPC exposure RpcFilterFile string // Define filters to enable/disable RPC exposure
RateLimterEnabled bool // Enable Rate limiter for RPC RateLimterEnabled bool // Enable Rate limiter for RPC
RequestsPerSecond int // for RPC rate limiter RequestsPerSecond int // for RPC rate limiter
EvmCallTimeout string // Timeout for eth_call
} }
type DevnetConfig struct { type DevnetConfig struct {

@ -0,0 +1,81 @@
package harmony
import (
"fmt"
"testing"
"time"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/stretchr/testify/assert"
)
func TestToRPCServerConfig(t *testing.T) {
tests := []struct {
input HarmonyConfig
output nodeconfig.RPCServerConfig
}{
{
input: HarmonyConfig{
HTTP: HttpConfig{
Enabled: true,
RosettaEnabled: false,
IP: "127.0.0.1",
Port: nodeconfig.DefaultRPCPort,
AuthPort: nodeconfig.DefaultAuthRPCPort,
RosettaPort: nodeconfig.DefaultRosettaPort,
ReadTimeout: "-1",
WriteTimeout: "-2",
IdleTimeout: "-3",
},
WS: WsConfig{
Enabled: true,
IP: "127.0.0.1",
Port: nodeconfig.DefaultWSPort,
AuthPort: nodeconfig.DefaultAuthWSPort,
},
RPCOpt: RpcOptConfig{
DebugEnabled: false,
EthRPCsEnabled: true,
StakingRPCsEnabled: true,
LegacyRPCsEnabled: true,
RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimterEnabled: true,
RequestsPerSecond: nodeconfig.DefaultRPCRateLimit,
EvmCallTimeout: "-4",
},
},
output: nodeconfig.RPCServerConfig{
HTTPEnabled: true,
HTTPIp: "127.0.0.1",
HTTPPort: nodeconfig.DefaultRPCPort,
HTTPAuthPort: nodeconfig.DefaultAuthRPCPort,
HTTPTimeoutRead: 30 * time.Second,
HTTPTimeoutWrite: 30 * time.Second,
HTTPTimeoutIdle: 120 * time.Second,
WSEnabled: true,
WSIp: "127.0.0.1",
WSPort: nodeconfig.DefaultWSPort,
WSAuthPort: nodeconfig.DefaultAuthWSPort,
DebugEnabled: false,
EthRPCsEnabled: true,
StakingRPCsEnabled: true,
LegacyRPCsEnabled: true,
RpcFilterFile: "./.hmy/rpc_filter.txt",
RateLimiterEnabled: true,
RequestsPerSecond: nodeconfig.DefaultRPCRateLimit,
EvmCallTimeout: 5 * time.Second,
},
},
}
for i, tt := range tests {
assertObject := assert.New(t)
name := fmt.Sprintf("TestToRPCServerConfig: #%d", i)
t.Run(name, func(t *testing.T) {
assertObject.Equal(
tt.input.ToRPCServerConfig(),
tt.output,
name,
)
})
}
}

@ -8,6 +8,7 @@ import (
"math/big" "math/big"
"strings" "strings"
"sync" "sync"
"time"
bls_core "github.com/harmony-one/bls/ffi/go/bls" bls_core "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/crypto/bls"
@ -115,6 +116,10 @@ type RPCServerConfig struct {
HTTPPort int HTTPPort int
HTTPAuthPort int HTTPAuthPort int
HTTPTimeoutRead time.Duration
HTTPTimeoutWrite time.Duration
HTTPTimeoutIdle time.Duration
WSEnabled bool WSEnabled bool
WSIp string WSIp string
WSPort int WSPort int
@ -130,6 +135,8 @@ type RPCServerConfig struct {
RateLimiterEnabled bool RateLimiterEnabled bool
RequestsPerSecond int RequestsPerSecond int
EvmCallTimeout time.Duration
} }
// RosettaServerConfig is the config for the rosetta server // RosettaServerConfig is the config for the rosetta server

@ -51,6 +51,12 @@ const (
DefaultAuthRPCPort = 9501 DefaultAuthRPCPort = 9501
// DefaultRosettaPort is the default rosetta port. The actual port used is 9000+700 // DefaultRosettaPort is the default rosetta port. The actual port used is 9000+700
DefaultRosettaPort = 9700 DefaultRosettaPort = 9700
// DefaultHTTP timeouts - read, write, and idle
DefaultHTTPTimeoutRead = "30s"
DefaultHTTPTimeoutWrite = "30s"
DefaultHTTPTimeoutIdle = "120s"
// DefaultEvmCallTimeout is the default timeout for evm call
DefaultEvmCallTimeout = "5s"
// DefaultWSPort is the default port for web socket endpoint. The actual port used is // DefaultWSPort is the default port for web socket endpoint. The actual port used is
DefaultWSPort = 9800 DefaultWSPort = 9800
// DefaultAuthWSPort is the default port for web socket auth endpoint. The actual port used is // DefaultAuthWSPort is the default port for web socket auth endpoint. The actual port used is

@ -84,7 +84,10 @@ func getRouter(asserter *asserter.Asserter, hmy *hmy.Harmony, limiterEnable bool
server.NewMempoolAPIController(services.NewMempoolAPI(hmy), asserter), server.NewMempoolAPIController(services.NewMempoolAPI(hmy), asserter),
server.NewNetworkAPIController(services.NewNetworkAPI(hmy), asserter), server.NewNetworkAPIController(services.NewNetworkAPI(hmy), asserter),
server.NewConstructionAPIController(services.NewConstructionAPI(hmy), asserter), server.NewConstructionAPIController(services.NewConstructionAPI(hmy), asserter),
server.NewCallAPIController(services.NewCallAPIService(hmy, limiterEnable, rateLimit), asserter), server.NewCallAPIController(
services.NewCallAPIService(hmy, limiterEnable, rateLimit, hmy.NodeAPI.GetConfig().NodeConfig.RPCServer.EvmCallTimeout),
asserter,
),
server.NewEventsAPIController(services.NewEventAPI(hmy), asserter), server.NewEventsAPIController(services.NewEventAPI(hmy), asserter),
server.NewSearchAPIController(services.NewSearchAPI(hmy), asserter), server.NewSearchAPIController(services.NewSearchAPI(hmy), asserter),
) )

@ -3,6 +3,7 @@ package services
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"time"
"github.com/coinbase/rosetta-sdk-go/server" "github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types" "github.com/coinbase/rosetta-sdk-go/types"
@ -82,10 +83,15 @@ func (c *CallAPIService) Call(
} }
func NewCallAPIService(hmy *hmy.Harmony, limiterEnable bool, rateLimit int) server.CallAPIServicer { func NewCallAPIService(
hmy *hmy.Harmony,
limiterEnable bool,
rateLimit int,
evmCallTimeout time.Duration,
) server.CallAPIServicer {
return &CallAPIService{ return &CallAPIService{
hmy: hmy, hmy: hmy,
publicContractAPI: rpc2.NewPublicContractAPI(hmy, rpc2.V2, limiterEnable, rateLimit), publicContractAPI: rpc2.NewPublicContractAPI(hmy, rpc2.V2, limiterEnable, rateLimit, evmCallTimeout),
publicStakingAPI: rpc2.NewPublicStakingAPI(hmy, rpc2.V2), publicStakingAPI: rpc2.NewPublicStakingAPI(hmy, rpc2.V2),
publicBlockChainAPI: rpc2.NewPublicBlockchainAPI(hmy, rpc2.V2, limiterEnable, rateLimit), publicBlockChainAPI: rpc2.NewPublicBlockchainAPI(hmy, rpc2.V2, limiterEnable, rateLimit),
} }

@ -31,11 +31,18 @@ type PublicContractService struct {
hmy *hmy.Harmony hmy *hmy.Harmony
version Version version Version
// TEMP SOLUTION to rpc node spamming issue // TEMP SOLUTION to rpc node spamming issue
limiterCall *rate.Limiter limiterCall *rate.Limiter
evmCallTimeout time.Duration
} }
// NewPublicContractAPI creates a new API for the RPC interface // NewPublicContractAPI creates a new API for the RPC interface
func NewPublicContractAPI(hmy *hmy.Harmony, version Version, limiterEnable bool, limit int) rpc.API { func NewPublicContractAPI(
hmy *hmy.Harmony,
version Version,
limiterEnable bool,
limit int,
evmCallTimeout time.Duration,
) rpc.API {
var limiter *rate.Limiter var limiter *rate.Limiter
if limiterEnable { if limiterEnable {
limiter = rate.NewLimiter(rate.Limit(limit), limit) limiter = rate.NewLimiter(rate.Limit(limit), limit)
@ -44,8 +51,13 @@ func NewPublicContractAPI(hmy *hmy.Harmony, version Version, limiterEnable bool,
return rpc.API{ return rpc.API{
Namespace: version.Namespace(), Namespace: version.Namespace(),
Version: APIVersion, Version: APIVersion,
Service: &PublicContractService{hmy, version, limiter}, Service: &PublicContractService{
Public: true, hmy: hmy,
version: version,
limiterCall: limiter,
evmCallTimeout: evmCallTimeout,
},
Public: true,
} }
} }
@ -80,7 +92,7 @@ func (s *PublicContractService) Call(
} }
// Execute call // Execute call
result, err := DoEVMCall(ctx, s.hmy, args, blockNrOrHash, CallTimeout) result, err := DoEVMCall(ctx, s.hmy, args, blockNrOrHash, s.evmCallTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -58,9 +58,9 @@ var (
wsEndpoint = "" wsEndpoint = ""
wsAuthEndpoint = "" wsAuthEndpoint = ""
httpVirtualHosts = []string{"*"} httpVirtualHosts = []string{"*"}
httpTimeouts = rpc.DefaultHTTPTimeouts // httpTimeouts = rpc.DefaultHTTPTimeouts
httpOrigins = []string{"*"} httpOrigins = []string{"*"}
wsOrigins = []string{"*"} wsOrigins = []string{"*"}
) )
// Version of the RPC // Version of the RPC
@ -86,13 +86,18 @@ func StartServers(hmy *hmy.Harmony, apis []rpc.API, config nodeconfig.RPCServerC
rmf.ExposeAll() rmf.ExposeAll()
} }
if config.HTTPEnabled { if config.HTTPEnabled {
timeouts := rpc.HTTPTimeouts{
ReadTimeout: config.HTTPTimeoutRead,
WriteTimeout: config.HTTPTimeoutWrite,
IdleTimeout: config.HTTPTimeoutIdle,
}
httpEndpoint = fmt.Sprintf("%v:%v", config.HTTPIp, config.HTTPPort) httpEndpoint = fmt.Sprintf("%v:%v", config.HTTPIp, config.HTTPPort)
if err := startHTTP(apis, &rmf); err != nil { if err := startHTTP(apis, &rmf, timeouts); err != nil {
return err return err
} }
httpAuthEndpoint = fmt.Sprintf("%v:%v", config.HTTPIp, config.HTTPAuthPort) httpAuthEndpoint = fmt.Sprintf("%v:%v", config.HTTPIp, config.HTTPAuthPort)
if err := startAuthHTTP(authApis, &rmf); err != nil { if err := startAuthHTTP(authApis, &rmf, timeouts); err != nil {
return err return err
} }
} }
@ -158,8 +163,8 @@ func getAPIs(hmy *hmy.Harmony, config nodeconfig.RPCServerConfig) []rpc.API {
NewPublicHarmonyAPI(hmy, V2), NewPublicHarmonyAPI(hmy, V2),
NewPublicBlockchainAPI(hmy, V1, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicBlockchainAPI(hmy, V1, config.RateLimiterEnabled, config.RequestsPerSecond),
NewPublicBlockchainAPI(hmy, V2, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicBlockchainAPI(hmy, V2, config.RateLimiterEnabled, config.RequestsPerSecond),
NewPublicContractAPI(hmy, V1, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicContractAPI(hmy, V1, config.RateLimiterEnabled, config.RequestsPerSecond, config.EvmCallTimeout),
NewPublicContractAPI(hmy, V2, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicContractAPI(hmy, V2, config.RateLimiterEnabled, config.RequestsPerSecond, config.EvmCallTimeout),
NewPublicTransactionAPI(hmy, V1), NewPublicTransactionAPI(hmy, V1),
NewPublicTransactionAPI(hmy, V2), NewPublicTransactionAPI(hmy, V2),
NewPublicPoolAPI(hmy, V1, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicPoolAPI(hmy, V1, config.RateLimiterEnabled, config.RequestsPerSecond),
@ -185,7 +190,7 @@ func getAPIs(hmy *hmy.Harmony, config nodeconfig.RPCServerConfig) []rpc.API {
publicAPIs = append(publicAPIs, publicAPIs = append(publicAPIs,
NewPublicHarmonyAPI(hmy, Eth), NewPublicHarmonyAPI(hmy, Eth),
NewPublicBlockchainAPI(hmy, Eth, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicBlockchainAPI(hmy, Eth, config.RateLimiterEnabled, config.RequestsPerSecond),
NewPublicContractAPI(hmy, Eth, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicContractAPI(hmy, Eth, config.RateLimiterEnabled, config.RequestsPerSecond, config.EvmCallTimeout),
NewPublicTransactionAPI(hmy, Eth), NewPublicTransactionAPI(hmy, Eth),
NewPublicPoolAPI(hmy, Eth, config.RateLimiterEnabled, config.RequestsPerSecond), NewPublicPoolAPI(hmy, Eth, config.RateLimiterEnabled, config.RequestsPerSecond),
eth.NewPublicEthService(hmy, "eth"), eth.NewPublicEthService(hmy, "eth"),
@ -210,7 +215,7 @@ func getAPIs(hmy *hmy.Harmony, config nodeconfig.RPCServerConfig) []rpc.API {
return publicAPIs return publicAPIs
} }
func startHTTP(apis []rpc.API, rmf *rpc.RpcMethodFilter) (err error) { func startHTTP(apis []rpc.API, rmf *rpc.RpcMethodFilter, httpTimeouts rpc.HTTPTimeouts) (err error) {
httpListener, httpHandler, err = rpc.StartHTTPEndpoint( httpListener, httpHandler, err = rpc.StartHTTPEndpoint(
httpEndpoint, apis, HTTPModules, rmf, httpOrigins, httpVirtualHosts, httpTimeouts, httpEndpoint, apis, HTTPModules, rmf, httpOrigins, httpVirtualHosts, httpTimeouts,
) )
@ -227,7 +232,7 @@ func startHTTP(apis []rpc.API, rmf *rpc.RpcMethodFilter) (err error) {
return nil return nil
} }
func startAuthHTTP(apis []rpc.API, rmf *rpc.RpcMethodFilter) (err error) { func startAuthHTTP(apis []rpc.API, rmf *rpc.RpcMethodFilter, httpTimeouts rpc.HTTPTimeouts) (err error) {
httpListener, httpHandler, err = rpc.StartHTTPEndpoint( httpListener, httpHandler, err = rpc.StartHTTPEndpoint(
httpAuthEndpoint, apis, HTTPModules, rmf, httpOrigins, httpVirtualHosts, httpTimeouts, httpAuthEndpoint, apis, HTTPModules, rmf, httpOrigins, httpVirtualHosts, httpTimeouts,
) )

Loading…
Cancel
Save