From 69976a8f024d6bcc677a673b42a634d2f896b51d Mon Sep 17 00:00:00 2001 From: Solar Mithril Date: Wed, 30 Jul 2025 20:50:40 +0500 Subject: [PATCH 1/3] Add bproxy and websocket proxy Make flashblocks overlay work --- playground/catalog.go | 2 + playground/components.go | 96 +++++++++++++++++++++++++++++++++--- playground/recipe_opstack.go | 25 ++++++++-- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/playground/catalog.go b/playground/catalog.go index 2b6b540..361a90f 100644 --- a/playground/catalog.go +++ b/playground/catalog.go @@ -25,6 +25,8 @@ func init() { register(&OpRbuilder{}) register(&FlashblocksRPC{}) register(&Contender{}) + register(&BProxy{}) + register(&WebsocketProxy{}) } func FindComponent(name string) ServiceGen { diff --git a/playground/components.go b/playground/components.go index 7abcf27..703768c 100644 --- a/playground/components.go +++ b/playground/components.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "strconv" + "strings" "time" "github.com/ethereum/go-ethereum/common/hexutil" @@ -100,13 +101,31 @@ func (o *OpRbuilder) Name() string { type FlashblocksRPC struct { FlashblocksWSService string + BaseOverlay bool } func (f *FlashblocksRPC) Run(service *Service, ctx *ExContext) { - service.WithImage("flashbots/flashblocks-rpc"). - WithTag("sha-7caffb9"). - WithArgs( - "node", + if f.BaseOverlay { + // Base doesn't have built image, so we use mikawamp/base-reth-node + service.WithImage("docker.io/mikawamp/base-reth-node"). + WithTag("latest"). + WithEntrypoint("/app/base-reth-node"). + WithArgs( + "node", + // We use websocket proxy to connect to rollup-boost, so we need to add /ws to the url + "--websocket-url", ConnectWs(f.FlashblocksWSService, "flashblocks") + "/ws", + ) + } else { + service.WithImage("flashbots/flashblocks-rpc"). + WithTag("sha-7caffb9"). + WithArgs( + "node", + "--flashblocks.enabled", + // We use websocket proxy to connect to rollup-boost, so we need to add /ws to the url + "--flashblocks.websocket-url", ConnectWs(f.FlashblocksWSService, "flashblocks") + "/ws", + ) + } + service.WithArgs( "--authrpc.port", `{{Port "authrpc" 8551}}`, "--authrpc.addr", "0.0.0.0", "--authrpc.jwtsecret", "/data/jwtsecret", @@ -119,8 +138,6 @@ func (f *FlashblocksRPC) Run(service *Service, ctx *ExContext) { "--color", "never", "--metrics", `0.0.0.0:{{Port "metrics" 9090}}`, "--port", `{{Port "rpc" 30303}}`, - "--flashblocks.enabled", - "--flashblocks.websocket-url", ConnectWs(f.FlashblocksWSService, "flashblocks"), ). WithArtifact("/data/jwtsecret", "jwtsecret"). WithArtifact("/data/l2-genesis.json", "l2-genesis.json"). @@ -137,6 +154,73 @@ func (f *FlashblocksRPC) Name() string { return "flashblocks-rpc" } +type BProxy struct { + TargetAuthrpc string + Peers []string + Flashblocks bool + FlashblocksBuilderURL string +} + +func (f* BProxy) Run(service *Service, ctx *ExContext) { + peers := []string{} + for _, peer := range f.Peers { + peers = append(peers, Connect(peer, "authrpc")) + } + service.WithImage("ghcr.io/flashbots/bproxy"). + WithTag("v0.0.91"). + WithArgs( + "serve", + "--authrpc-backend", f.TargetAuthrpc, + "--authrpc-backend-timeout", "5s", + "--authrpc-client-idle-connection-timeout", "15m", + "--authrpc-deduplicate-fcus", + "--authrpc-enabled", + "--authrpc-listen-address", `0.0.0.0:{{Port "authrpc" 8651}}`, + "--authrpc-log-requests", + "--authrpc-log-responses", + "--authrpc-max-backend-connections-per-host", "1", + "--authrpc-max-request-size", "150", + "--authrpc-max-response-size", "1150", + "--authrpc-peers", strings.Join(peers, ","), + "--authrpc-remove-backend-from-peers", + "--authrpc-use-priority-queue", + ). + WithArtifact("/data/jwtsecret", "jwtsecret") + + if f.Flashblocks { + service.WithArgs( + "--flashblocks-backend", f.FlashblocksBuilderURL, + "--flashblocks-enabled", + "--flashblocks-listen-address", `0.0.0.0:{{Port "flashblocks" 1114}}`, + "--flashblocks-log-messages", + ) + } + +} + +func (f *BProxy) Name() string { + return "bproxy" +} + +type WebsocketProxy struct { + Upstream string +} + +func (w *WebsocketProxy) Run(service *Service, ctx *ExContext) { + service.WithImage("docker.io/mikawamp/websocket-rpc"). + WithTag("latest"). + WithArgs( + "--listen-addr", `0.0.0.0:{{Port "flashblocks" 1115}}`, + "--upstream-ws", ConnectWs(w.Upstream, "flashblocks"), + "--enable-compression", + "--client-ping-enabled", + ) +} + +func (w *WebsocketProxy) Name() string { + return "websocket-proxy" +} + type OpBatcher struct { L1Node string L2Node string diff --git a/playground/recipe_opstack.go b/playground/recipe_opstack.go index edc51b6..e7bb9b5 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -30,6 +30,9 @@ type OpRecipe struct { // flashblocksBuilderURL is the URL of the builder that returns the flashblocks. This is meant to be used // for external builders. flashblocksBuilderURL string + + // Indicates that flashblocks-rpc should use base image + baseOverlay bool } func (o *OpRecipe) Name() string { @@ -47,6 +50,7 @@ func (o *OpRecipe) Flags() *flag.FlagSet { flags.Uint64Var(&o.blockTime, "block-time", defaultOpBlockTimeSeconds, "Block time to use for the rollup") flags.Uint64Var(&o.batcherMaxChannelDuration, "batcher-max-channel-duration", 2, "Maximum channel duration to use for the batcher") flags.BoolVar(&o.flashblocks, "flashblocks", false, "Whether to enable flashblocks") + flags.BoolVar(&o.baseOverlay, "base-overlay", false, "Whether to use base implementation for flashblocks-rpc") flags.StringVar(&o.flashblocksBuilderURL, "flashblocks-builder", "", "External URL of builder flashblocks stream") return flags } @@ -96,21 +100,36 @@ func (o *OpRecipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { flashblocksBuilderURLRef = ConnectWs("op-rbuilder", "flashblocks") } + svcManager.AddService("bproxy", &BProxy{ + TargetAuthrpc: externalBuilderRef, + Peers: []string{ + "flashblocks-rpc", + }, + Flashblocks: o.flashblocks, + FlashblocksBuilderURL: flashblocksBuilderURLRef, + }) + + svcManager.AddService("websocket-proxy", &WebsocketProxy{ + Upstream: "rollup-boost", + }) + elNode := "op-geth" if o.externalBuilder != "" { elNode = "rollup-boost" svcManager.AddService("rollup-boost", &RollupBoost{ ELNode: "op-geth", - Builder: externalBuilderRef, + Builder: Connect("bproxy", "authrpc"), Flashblocks: o.flashblocks, - FlashblocksBuilderURL: flashblocksBuilderURLRef, + FlashblocksBuilderURL: ConnectWs("bproxy", "flashblocks"), }) } + if o.flashblocks { svcManager.AddService("flashblocks-rpc", &FlashblocksRPC{ - FlashblocksWSService: "rollup-boost", // rollup-boost provides the websocket stream + FlashblocksWSService: "websocket-proxy", // rollup-boost provides the websocket stream + BaseOverlay: o.baseOverlay, }) } From 3a7797ce8446b111140654fcf1cd88ae29818774 Mon Sep 17 00:00:00 2001 From: Solar Mithril Date: Wed, 30 Jul 2025 21:22:50 +0500 Subject: [PATCH 2/3] Make it so flashblock-rpc peer added only if flashblock enabled --- playground/recipe_opstack.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/playground/recipe_opstack.go b/playground/recipe_opstack.go index e7bb9b5..abb6ef4 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -74,6 +74,7 @@ func (o *OpRecipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { flashblocksBuilderURLRef := o.flashblocksBuilderURL externalBuilderRef := o.externalBuilder + peers := []string{} opGeth := &OpGeth{} svcManager.AddService("op-geth", opGeth) @@ -100,11 +101,13 @@ func (o *OpRecipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { flashblocksBuilderURLRef = ConnectWs("op-rbuilder", "flashblocks") } + if o.flashblocks { + peers = append(peers, "flashblocks-rpc") + } + svcManager.AddService("bproxy", &BProxy{ TargetAuthrpc: externalBuilderRef, - Peers: []string{ - "flashblocks-rpc", - }, + Peers: peers, Flashblocks: o.flashblocks, FlashblocksBuilderURL: flashblocksBuilderURLRef, }) From 43cbbedeea04fa66f1a4667684dc3704f825e16d Mon Sep 17 00:00:00 2001 From: Solar Mithril Date: Thu, 31 Jul 2025 15:43:34 +0500 Subject: [PATCH 3/3] Make websocket proxy configurable and bproxy enabled only if flashblocks enabled --- playground/components.go | 12 ++++++--- playground/recipe_opstack.go | 51 +++++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/playground/components.go b/playground/components.go index 703768c..38a0c61 100644 --- a/playground/components.go +++ b/playground/components.go @@ -102,9 +102,15 @@ func (o *OpRbuilder) Name() string { type FlashblocksRPC struct { FlashblocksWSService string BaseOverlay bool + UseWebsocketProxy bool // Whether to add /ws path for websocket proxy } func (f *FlashblocksRPC) Run(service *Service, ctx *ExContext) { + websocketURL := ConnectWs(f.FlashblocksWSService, "flashblocks") + if f.UseWebsocketProxy { + websocketURL += "/ws" + } + if f.BaseOverlay { // Base doesn't have built image, so we use mikawamp/base-reth-node service.WithImage("docker.io/mikawamp/base-reth-node"). @@ -112,8 +118,7 @@ func (f *FlashblocksRPC) Run(service *Service, ctx *ExContext) { WithEntrypoint("/app/base-reth-node"). WithArgs( "node", - // We use websocket proxy to connect to rollup-boost, so we need to add /ws to the url - "--websocket-url", ConnectWs(f.FlashblocksWSService, "flashblocks") + "/ws", + "--websocket-url", websocketURL, ) } else { service.WithImage("flashbots/flashblocks-rpc"). @@ -121,8 +126,7 @@ func (f *FlashblocksRPC) Run(service *Service, ctx *ExContext) { WithArgs( "node", "--flashblocks.enabled", - // We use websocket proxy to connect to rollup-boost, so we need to add /ws to the url - "--flashblocks.websocket-url", ConnectWs(f.FlashblocksWSService, "flashblocks") + "/ws", + "--flashblocks.websocket-url", websocketURL, ) } service.WithArgs( diff --git a/playground/recipe_opstack.go b/playground/recipe_opstack.go index abb6ef4..9da5652 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -33,6 +33,9 @@ type OpRecipe struct { // Indicates that flashblocks-rpc should use base image baseOverlay bool + + // whether to enable websocket proxy + enableWebsocketProxy bool } func (o *OpRecipe) Name() string { @@ -52,6 +55,7 @@ func (o *OpRecipe) Flags() *flag.FlagSet { flags.BoolVar(&o.flashblocks, "flashblocks", false, "Whether to enable flashblocks") flags.BoolVar(&o.baseOverlay, "base-overlay", false, "Whether to use base implementation for flashblocks-rpc") flags.StringVar(&o.flashblocksBuilderURL, "flashblocks-builder", "", "External URL of builder flashblocks stream") + flags.BoolVar(&o.enableWebsocketProxy, "enable-websocket-proxy", false, "Whether to enable websocket proxy") return flags } @@ -105,34 +109,57 @@ func (o *OpRecipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { peers = append(peers, "flashblocks-rpc") } - svcManager.AddService("bproxy", &BProxy{ - TargetAuthrpc: externalBuilderRef, - Peers: peers, - Flashblocks: o.flashblocks, - FlashblocksBuilderURL: flashblocksBuilderURLRef, - }) + // Only enable bproxy if flashblocks is enabled (since flashblocks-rpc is the only service that needs it) + if o.flashblocks { + svcManager.AddService("bproxy", &BProxy{ + TargetAuthrpc: externalBuilderRef, + Peers: peers, + Flashblocks: o.flashblocks, + FlashblocksBuilderURL: flashblocksBuilderURLRef, + }) + } - svcManager.AddService("websocket-proxy", &WebsocketProxy{ - Upstream: "rollup-boost", - }) + // Only enable websocket-proxy if the flag is set + if o.enableWebsocketProxy { + svcManager.AddService("websocket-proxy", &WebsocketProxy{ + Upstream: "rollup-boost", + }) + } elNode := "op-geth" if o.externalBuilder != "" { elNode = "rollup-boost" + // Use bproxy if flashblocks is enabled, otherwise use external builder directly + builderRef := externalBuilderRef + flashblocksBuilderRef := flashblocksBuilderURLRef + if o.flashblocks { + builderRef = Connect("bproxy", "authrpc") + flashblocksBuilderRef = ConnectWs("bproxy", "flashblocks") + } + svcManager.AddService("rollup-boost", &RollupBoost{ ELNode: "op-geth", - Builder: Connect("bproxy", "authrpc"), + Builder: builderRef, Flashblocks: o.flashblocks, - FlashblocksBuilderURL: ConnectWs("bproxy", "flashblocks"), + FlashblocksBuilderURL: flashblocksBuilderRef, }) } if o.flashblocks { + // Determine which service to use for flashblocks websocket connection + flashblocksWSService := "rollup-boost" + useWebsocketProxy := false + if o.enableWebsocketProxy { + flashblocksWSService = "websocket-proxy" + useWebsocketProxy = true + } + svcManager.AddService("flashblocks-rpc", &FlashblocksRPC{ - FlashblocksWSService: "websocket-proxy", // rollup-boost provides the websocket stream + FlashblocksWSService: flashblocksWSService, BaseOverlay: o.baseOverlay, + UseWebsocketProxy: useWebsocketProxy, }) }