Skip to content
Draft
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
173 changes: 77 additions & 96 deletions proxyd/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"time"

sw "github.com/ethereum-optimism/infra/proxyd/pkg/avg-sliding-window"
supervisorBackend "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend"
supervisorTypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
Expand All @@ -30,9 +29,11 @@ import (
)

const (
JSONRPCVersion = "2.0"
JSONRPCErrorInternal = -32000
notFoundRpcError = -32601
JSONRPCVersion = "2.0"
JSONRPCErrorInternal = -32000
JSONRPCErrorInvalidRequest = -32600
notFoundRpcError = -32601
JSONRPCErrorInvalidParams = -32602
)

var (
Expand Down Expand Up @@ -165,123 +166,103 @@ Summary:
-321500 MISSED_DATA
-321501 DATA_CORRUPTION
*/
var interopRPCErrorMap = map[error]*RPCErr{
supervisorTypes.ErrUninitialized: {
Code: -320400,
HTTPErrorCode: 400,
},
supervisorTypes.ErrSkipped: {
Code: -320500,
HTTPErrorCode: 422,
},
supervisorTypes.ErrUnknownChain: {
Code: -320501,
HTTPErrorCode: 404,
},
supervisorTypes.ErrConflict: {
Code: -320600,
HTTPErrorCode: 409,
},
supervisorTypes.ErrIneffective: {
Code: -320601,
HTTPErrorCode: 422,
},
supervisorTypes.ErrOutOfOrder: {
Code: -320900,
HTTPErrorCode: 409,
},
supervisorTypes.ErrAwaitReplacementBlock: {
Code: -320901,
HTTPErrorCode: 409,
},
supervisorTypes.ErrStop: {
Code: -321000,
HTTPErrorCode: 400,
},
supervisorTypes.ErrOutOfScope: {
Code: -321100,
HTTPErrorCode: 400,
},
supervisorTypes.ErrPreviousToFirst: {
Code: -321200,
HTTPErrorCode: 404,
},
supervisorTypes.ErrFuture: {
Code: -321401,
HTTPErrorCode: 422,
},
supervisorTypes.ErrNotExact: {
Code: -321500,
HTTPErrorCode: 404,
},
supervisorTypes.ErrDataCorruption: {
Code: -321501,
HTTPErrorCode: 422,
},
supervisorBackend.ErrUnexpectedMinSafetyLevel: {
Code: -32602, // invalid params
HTTPErrorCode: 400,
},
errors.New("stopped acces-list check early"): {
Code: -32602, // invalid params
HTTPErrorCode: 400,
},
errors.New("failed to read data"): {
Code: -32602, // invalid params
HTTPErrorCode: 400,
},
func getInteropRPCErrorHttpCode(err error) (httpCode int, knownErr bool) {
knownErr = true
switch err.Error() {
case supervisorTypes.ErrUninitialized.Error():
httpCode = 400
case supervisorTypes.ErrSkipped.Error():
httpCode = 422
case supervisorTypes.ErrUnknownChain.Error():
httpCode = 404
case supervisorTypes.ErrConflict.Error():
httpCode = 409
case supervisorTypes.ErrIneffective.Error():
httpCode = 422
case supervisorTypes.ErrOutOfOrder.Error():
httpCode = 409
case supervisorTypes.ErrAwaitReplacementBlock.Error():
httpCode = 409
case supervisorTypes.ErrStop.Error():
httpCode = 400
case supervisorTypes.ErrOutOfScope.Error():
httpCode = 400
case supervisorTypes.ErrPreviousToFirst.Error():
httpCode = 404
case supervisorTypes.ErrFuture.Error():
httpCode = 422
case supervisorTypes.ErrNotExact.Error():
httpCode = 404
case supervisorTypes.ErrDataCorruption.Error():
httpCode = 422
default:
httpCode = 400
knownErr = false
}
return
}

func ParseInteropError(err error) *RPCErr {
var fallbackErr *RPCErr
if rpcErr, ok := err.(*RPCErr); ok {
return rpcErr
}

httpErr, isHTTPError := err.(rpc.HTTPError)
if !isHTTPError {
fallbackErr = &RPCErr{
return &RPCErr{
Code: JSONRPCErrorInternal,
Message: err.Error(),
HTTPErrorCode: 500,
}
} else {
// if the underlying error is a JSON-RPC error, overwrite it with the inherent error message body
var rpcErrJson rpcResJSON
unmarshalErr := json.Unmarshal(httpErr.Body, &rpcErrJson)
if unmarshalErr != nil {
fallbackErr = ErrInvalidParams(string(httpErr.Body))
fallbackErr.HTTPErrorCode = httpErr.StatusCode
} else {
fallbackErr = &RPCErr{
Code: rpcErrJson.Error.Code,
Message: rpcErrJson.Error.Message,
Data: rpcErrJson.Error.Data,
HTTPErrorCode: httpErr.StatusCode,
}

err = fmt.Errorf(rpcErrJson.Error.Message)
}
}

errStr := err.Error()
for errSubStr, errCodes := range interopRPCErrorMap {
if strings.Contains(errStr, errSubStr.Error()) {
interopParsedErr := errCodes.Clone()
interopParsedErr.Message = errStr
return interopParsedErr
// if the underlying error is a JSON-RPC error, overwrite it with the inherent error message body
var rpcResponse rpcResJSON
if unmarshalErr := json.Unmarshal(httpErr.Body, &rpcResponse); unmarshalErr == nil {
httpCode, knownErr := getInteropRPCErrorHttpCode(rpcResponse.Error)
if !knownErr {
httpCode = httpErr.StatusCode // fallback to the HTTP status code of the original error
}
rpcResponse.Error.HTTPErrorCode = httpCode
return rpcResponse.Error
}
var rpcErrResponse rpc.JsonError
if unmarshalErr := json.Unmarshal(httpErr.Body, &rpcErrResponse); unmarshalErr == nil {
var data json.RawMessage
if rpcErrResponse.Data != nil {
dataBytes, err := json.Marshal(rpcErrResponse.Data)
if err == nil {
data = json.RawMessage(dataBytes)
} else {
data = json.RawMessage([]byte(fmt.Sprintf("%+v", rpcErrResponse.Data)))
}
}
httpCode, _ := getInteropRPCErrorHttpCode(err) // no knownErr check as we're already want to fallback to 400
return &RPCErr{
Code: rpcErrResponse.Code,
Message: rpcErrResponse.Message,
Data: data,
HTTPErrorCode: httpCode,
}
}

fallbackErr := ErrInvalidParams(string(httpErr.Body))
fallbackErr.HTTPErrorCode = httpErr.StatusCode

return fallbackErr
}

func ErrInvalidRequest(msg string) *RPCErr {
return &RPCErr{
Code: -32600,
Code: JSONRPCErrorInvalidRequest,
Message: msg,
HTTPErrorCode: 400,
}
}

func ErrInvalidParams(msg string) *RPCErr {
return &RPCErr{
Code: -32602,
Code: JSONRPCErrorInvalidParams,
Message: msg,
HTTPErrorCode: 400,
}
Expand Down
76 changes: 76 additions & 0 deletions proxyd/backoff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package proxyd

import "time"

type BackoffStrategy interface {
Backoff()
WithinBackoff() bool
LastBackoffTime() time.Time
Reset()
BackoffWait() time.Duration
}

type StaticBackoff struct {
lastBackoffTime time.Time
interval time.Duration
}

func (b *StaticBackoff) WithinBackoff() bool {
if b.lastBackoffTime.IsZero() {
return false
}
return time.Since(b.lastBackoffTime) < b.interval
}

func (b *StaticBackoff) LastBackoffTime() time.Time {
return b.lastBackoffTime
}

func (b *StaticBackoff) Reset() {
b.lastBackoffTime = time.Time{}
}

func (b *StaticBackoff) BackoffWait() time.Duration {
if b.WithinBackoff() {
return b.interval - time.Since(b.lastBackoffTime)
}
return 0
}

type IncrementalBackoff struct {
lastBackoffTime time.Time
maxDuration time.Duration
stepInterval time.Duration
stepCount int
}

func (b *IncrementalBackoff) nextWhen() {
dur := b.stepInterval * time.Duration(b.stepCount)
if dur > b.maxDuration {
return b.maxDuration
}
return dur
}

func (b *IncrementalBackoff) WithinBackoff() bool {
if b.lastBackoffTime.IsZero() {
return false
}
return time.Since(b.lastBackoffTime) < b.maxDuration
}

func (b *IncrementalBackoff) LastBackoffTime() time.Time {
return b.lastBackoffTime
}

func (b *IncrementalBackoff) Reset() {
b.lastBackoffTime = time.Time{}
b.stepCount = 0
}

func (b *IncrementalBackoff) BackoffWait() time.Duration {
if b.WithinBackoff() {
return b.maxDuration - time.Since(b.lastBackoffTime)
}
return 0
}
1 change: 1 addition & 0 deletions proxyd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ type InteropValidationConfig struct {
ReqSizeLimit int `toml:"req_size_limit"`
AccessListSizeLimit int `toml:"access_list_size_limit"`
RateLimit SenderRateLimitConfig `toml:"sender_rate_limit"`
ForceDisableInteropValidation bool `toml:"force_disable_interop_validation"`
}

type InteropValidationStrategy string
Expand Down
26 changes: 13 additions & 13 deletions proxyd/go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
module github.com/ethereum-optimism/infra/proxyd

go 1.22.0
go 1.23.0

toolchain go1.23.6
toolchain go1.24.0

require (
github.com/BurntSushi/toml v1.5.0
github.com/alicebob/miniredis v2.5.0+incompatible
github.com/emirpasic/gods v1.18.1
github.com/ethereum-optimism/optimism v1.13.3-0.20250506125223-182c0424f6dc
github.com/ethereum/go-ethereum v1.15.3
github.com/ethereum-optimism/optimism v1.13.5-0.20250709133933-ab50df748916
github.com/ethereum/go-ethereum v1.15.11
github.com/go-redsync/redsync/v4 v4.10.0
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/gorilla/mux v1.8.0
Expand All @@ -22,7 +22,7 @@ require (
github.com/stretchr/testify v1.10.0
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a
github.com/xaionaro-go/weightedshuffle v0.0.0-20211213010739-6a74fbc7d24a
golang.org/x/sync v0.10.0
golang.org/x/sync v0.14.0
gopkg.in/yaml.v3 v3.0.1
)

Expand Down Expand Up @@ -121,21 +121,21 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/supranational/blst v0.3.14 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/urfave/cli/v2 v2.27.6 // indirect
github.com/wlynxg/anet v0.0.4 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yuin/gopher-lua v1.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/crypto v0.32.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/net v0.36.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.10.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.11.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
Expand Down
Loading