proxyd: Add customizable whitelist error message (#3544)
* proxyd: Add customizable whitelist error message Alchemy is asking for this so that we can include their affiliate link. * add missing test case * fix error message * goimports
This commit is contained in:
parent
7f2456f217
commit
485258d3c2
@ -96,18 +96,19 @@ type BackendGroupsConfig map[string]*BackendGroupConfig
|
||||
type MethodMappingsConfig map[string]string
|
||||
|
||||
type Config struct {
|
||||
WSBackendGroup string `toml:"ws_backend_group"`
|
||||
Server ServerConfig `toml:"server"`
|
||||
Cache CacheConfig `toml:"cache"`
|
||||
Redis RedisConfig `toml:"redis"`
|
||||
Metrics MetricsConfig `toml:"metrics"`
|
||||
RateLimit RateLimitConfig `toml:"rate_limit"`
|
||||
BackendOptions BackendOptions `toml:"backend"`
|
||||
Backends BackendsConfig `toml:"backends"`
|
||||
Authentication map[string]string `toml:"authentication"`
|
||||
BackendGroups BackendGroupsConfig `toml:"backend_groups"`
|
||||
RPCMethodMappings map[string]string `toml:"rpc_method_mappings"`
|
||||
WSMethodWhitelist []string `toml:"ws_method_whitelist"`
|
||||
WSBackendGroup string `toml:"ws_backend_group"`
|
||||
Server ServerConfig `toml:"server"`
|
||||
Cache CacheConfig `toml:"cache"`
|
||||
Redis RedisConfig `toml:"redis"`
|
||||
Metrics MetricsConfig `toml:"metrics"`
|
||||
RateLimit RateLimitConfig `toml:"rate_limit"`
|
||||
BackendOptions BackendOptions `toml:"backend"`
|
||||
Backends BackendsConfig `toml:"backends"`
|
||||
Authentication map[string]string `toml:"authentication"`
|
||||
BackendGroups BackendGroupsConfig `toml:"backend_groups"`
|
||||
RPCMethodMappings map[string]string `toml:"rpc_method_mappings"`
|
||||
WSMethodWhitelist []string `toml:"ws_method_whitelist"`
|
||||
WhitelistErrorMessage string `toml:"whitelist_error_message"`
|
||||
}
|
||||
|
||||
func ReadFromEnvOrConfig(value string) (string, error) {
|
||||
|
@ -1,3 +1,5 @@
|
||||
whitelist_error_message = "rpc method is not whitelisted custom message"
|
||||
|
||||
[server]
|
||||
rpc_port = 8545
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
whitelist_error_message = "rpc method is not whitelisted"
|
||||
|
||||
ws_backend_group = "main"
|
||||
|
||||
ws_method_whitelist = [
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
notWhitelistedResponse = `{"jsonrpc":"2.0","error":{"code":-32001,"message":"rpc method is not whitelisted"},"id":999}`
|
||||
notWhitelistedResponse = `{"jsonrpc":"2.0","error":{"code":-32001,"message":"rpc method is not whitelisted custom message"},"id":999}`
|
||||
parseErrResponse = `{"jsonrpc":"2.0","error":{"code":-32700,"message":"parse error"},"id":null}`
|
||||
invalidJSONRPCVersionResponse = `{"error":{"code":-32601,"message":"invalid JSON-RPC version"},"id":null,"jsonrpc":"2.0"}`
|
||||
invalidIDResponse = `{"error":{"code":-32601,"message":"invalid ID"},"id":null,"jsonrpc":"2.0"}`
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
"github.com/ethereum-optimism/optimism/proxyd"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -42,6 +44,13 @@ func TestConcurrentWSPanic(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer shutdown()
|
||||
|
||||
// suppress tons of log messages
|
||||
oldHandler := log.Root().GetHandler()
|
||||
log.Root().SetHandler(log.DiscardHandler())
|
||||
defer func() {
|
||||
log.Root().SetHandler(oldHandler)
|
||||
}()
|
||||
|
||||
<-readyCh
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
@ -55,6 +55,17 @@ func Start(config *Config) (func(), error) {
|
||||
}
|
||||
}
|
||||
|
||||
// While modifying shared globals is a bad practice, the alternative
|
||||
// is to clone these errors on every invocation. This is inefficient.
|
||||
// We'd also have to make sure that errors.Is and errors.As continue
|
||||
// to function properly on the cloned errors.
|
||||
if config.RateLimit.ErrorMessage != "" {
|
||||
ErrOverRateLimit.Message = config.RateLimit.ErrorMessage
|
||||
}
|
||||
if config.WhitelistErrorMessage != "" {
|
||||
ErrMethodNotWhitelisted.Message = config.WhitelistErrorMessage
|
||||
}
|
||||
|
||||
maxConcurrentRPCs := config.Server.MaxConcurrentRPCs
|
||||
if maxConcurrentRPCs == 0 {
|
||||
maxConcurrentRPCs = math.MaxInt64
|
||||
|
@ -244,12 +244,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if isLimited("") {
|
||||
rpcErr := ErrOverRateLimit
|
||||
if s.limConfig.ErrorMessage != "" {
|
||||
rpcErr = ErrOverRateLimit.Clone()
|
||||
rpcErr.Message = s.limConfig.ErrorMessage
|
||||
}
|
||||
RecordRPCError(ctx, BackendProxyd, "unknown", rpcErr)
|
||||
RecordRPCError(ctx, BackendProxyd, "unknown", ErrOverRateLimit)
|
||||
log.Warn(
|
||||
"rate limited request",
|
||||
"req_id", GetReqID(ctx),
|
||||
@ -258,7 +253,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
|
||||
"origin", origin,
|
||||
"remote_ip", xff,
|
||||
)
|
||||
writeRPCError(ctx, w, nil, rpcErr)
|
||||
writeRPCError(ctx, w, nil, ErrOverRateLimit)
|
||||
return
|
||||
}
|
||||
|
||||
@ -394,13 +389,8 @@ func (s *Server) handleBatchRPC(ctx context.Context, reqs []json.RawMessage, isL
|
||||
"req_id", GetReqID(ctx),
|
||||
"method", parsedReq.Method,
|
||||
)
|
||||
rpcErr := ErrOverRateLimit
|
||||
if s.limConfig.ErrorMessage != "" {
|
||||
rpcErr = rpcErr.Clone()
|
||||
rpcErr.Message = s.limConfig.ErrorMessage
|
||||
}
|
||||
RecordRPCError(ctx, BackendProxyd, parsedReq.Method, rpcErr)
|
||||
responses[i] = NewRPCErrorRes(parsedReq.ID, rpcErr)
|
||||
RecordRPCError(ctx, BackendProxyd, parsedReq.Method, ErrOverRateLimit)
|
||||
responses[i] = NewRPCErrorRes(parsedReq.ID, ErrOverRateLimit)
|
||||
continue
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user