Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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