Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/forty-walls-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/proxyd': patch
---

Add customizable whitelist error
25 changes: 13 additions & 12 deletions proxyd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions proxyd/integration_tests/testdata/whitelist.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
whitelist_error_message = "rpc method is not whitelisted custom message"

[server]
rpc_port = 8545

Expand Down
2 changes: 2 additions & 0 deletions proxyd/integration_tests/testdata/ws.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
whitelist_error_message = "rpc method is not whitelisted"

ws_backend_group = "main"

ws_method_whitelist = [
Expand Down
2 changes: 1 addition & 1 deletion proxyd/integration_tests/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}`
Expand Down
9 changes: 9 additions & 0 deletions proxyd/integration_tests/ws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions proxyd/proxyd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 4 additions & 14 deletions proxyd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down