Skip to content

Commit a2919c3

Browse files
committed
local rate limiting
1 parent 03526b7 commit a2919c3

File tree

6 files changed

+29
-0
lines changed

6 files changed

+29
-0
lines changed

cmd/receiver-proxy/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ var flags []cli.Flag = []cli.Flag{
8080
Usage: "Number of parallel connections for each peer and archival RPC",
8181
EnvVars: []string{"CONN_PER_PEER"},
8282
},
83+
&cli.IntFlag{
84+
Name: "max-local-requests-per-second",
85+
Value: 100,
86+
Usage: "Maximum number of unique local requests per second",
87+
EnvVars: []string{"MAX_LOCAL_RPS"},
88+
},
8389

8490
// certificate config
8591
&cli.DurationFlag{
@@ -198,6 +204,7 @@ func main() {
198204
flashbotsSignerAddress := eth.HexToAddress(flashbotsSignerStr)
199205
maxRequestBodySizeBytes := cCtx.Int64("max-request-body-size-bytes")
200206
connectionsPerPeer := cCtx.Int("connections-per-peer")
207+
maxLocalRPS := cCtx.Int("max-local-requests-per-second")
201208

202209
proxyConfig := &proxy.ReceiverProxyConfig{
203210
ReceiverProxyConstantConfig: proxy.ReceiverProxyConstantConfig{Log: log, FlashbotsSignerAddress: flashbotsSignerAddress},
@@ -210,6 +217,7 @@ func main() {
210217
EthRPC: rpcEndpoint,
211218
MaxRequestBodySizeBytes: maxRequestBodySizeBytes,
212219
ConnectionsPerPeer: connectionsPerPeer,
220+
MaxLocalRPS: maxLocalRPS,
213221
}
214222

215223
instance, err := proxy.NewReceiverProxy(*proxyConfig)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/hashicorp/golang-lru/v2 v2.0.7
1212
github.com/stretchr/testify v1.9.0
1313
github.com/urfave/cli/v2 v2.27.2
14+
golang.org/x/time v0.5.0
1415
)
1516

1617
require (

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
151151
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
152152
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
153153
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
154+
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
155+
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
154156
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
155157
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
156158
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

proxy/api.go renamed to proxy/receiver_api.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
errUnknownPeer = errors.New("unknown peers can't send to the public address")
2929
errSubsidyWrongEndpoint = errors.New("subsidy can only be called on public method")
3030
errSubsidyWrongCaller = errors.New("subsidy can only be called by Flashbots")
31+
errRateLimiting = errors.New("requests to local API are rate limited")
3132

3233
errUUIDParse = errors.New("failed to parse UUID")
3334

@@ -315,6 +316,12 @@ func (prx *ReceiverProxy) HandleParsedRequest(ctx context.Context, parsedRequest
315316
}
316317
prx.requestUniqueKeysRLU.Add(*parsedRequest.requestArgUniqueKey, struct{}{})
317318
}
319+
if !parsedRequest.publicEndpoint {
320+
err := prx.localAPIRateLimiter.Wait(ctx)
321+
if err != nil {
322+
return errors.Join(errRateLimiting, err)
323+
}
324+
}
318325
select {
319326
case <-ctx.Done():
320327
case prx.shareQueue <- &parsedRequest:

proxy/receiver_proxy.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/flashbots/go-utils/signature"
1414
"github.com/google/uuid"
1515
"github.com/hashicorp/golang-lru/v2/expirable"
16+
"golang.org/x/time/rate"
1617
)
1718

1819
var (
@@ -61,6 +62,8 @@ type ReceiverProxy struct {
6162
replacementNonceRLU *expirable.LRU[replacementNonceKey, int]
6263

6364
peerUpdaterClose chan struct{}
65+
66+
localAPIRateLimiter *rate.Limiter
6467
}
6568

6669
type ReceiverProxyConstantConfig struct {
@@ -86,6 +89,7 @@ type ReceiverProxyConfig struct {
8689
MaxRequestBodySizeBytes int64
8790

8891
ConnectionsPerPeer int
92+
MaxLocalRPS int
8993
}
9094

9195
func NewReceiverProxy(config ReceiverProxyConfig) (*ReceiverProxy, error) {
@@ -105,6 +109,11 @@ func NewReceiverProxy(config ReceiverProxyConfig) (*ReceiverProxy, error) {
105109

106110
localBuilder := rpcclient.NewClient(config.LocalBuilderEndpoint)
107111

112+
limit := rate.Limit(config.MaxLocalRPS)
113+
if config.MaxLocalRPS == 0 {
114+
limit = rate.Inf
115+
}
116+
localAPIRateLimiter := rate.NewLimiter(limit, config.MaxLocalRPS)
108117
prx := &ReceiverProxy{
109118
ReceiverProxyConstantConfig: config.ReceiverProxyConstantConfig,
110119
ConfigHub: NewBuilderConfigHub(config.Log, config.BuilderConfigHubEndpoint),
@@ -114,6 +123,7 @@ func NewReceiverProxy(config ReceiverProxyConfig) (*ReceiverProxy, error) {
114123
localBuilder: localBuilder,
115124
requestUniqueKeysRLU: expirable.NewLRU[uuid.UUID, struct{}](requestsRLUSize, nil, requestsRLUTTL),
116125
replacementNonceRLU: expirable.NewLRU[replacementNonceKey, int](replacementNonceSize, nil, replacementNonceTTL),
126+
localAPIRateLimiter: localAPIRateLimiter,
117127
}
118128
maxRequestBodySizeBytes := DefaultMaxRequestBodySizeBytes
119129
if config.MaxRequestBodySizeBytes != 0 {

proxy/receiver_proxy_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ func createProxy(localBuilder, name string) *ReceiverProxy {
189189
ArchiveEndpoint: archiveServer.URL,
190190
LocalBuilderEndpoint: localBuilder,
191191
EthRPC: "eth-rpc-not-set",
192+
MaxLocalRPS: 10,
192193
})
193194
if err != nil {
194195
panic(err)

0 commit comments

Comments
 (0)