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..38a0c61 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,35 @@ 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) { - service.WithImage("flashbots/flashblocks-rpc"). - WithTag("sha-7caffb9"). - WithArgs( - "node", + 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"). + WithTag("latest"). + WithEntrypoint("/app/base-reth-node"). + WithArgs( + "node", + "--websocket-url", websocketURL, + ) + } else { + service.WithImage("flashbots/flashblocks-rpc"). + WithTag("sha-7caffb9"). + WithArgs( + "node", + "--flashblocks.enabled", + "--flashblocks.websocket-url", websocketURL, + ) + } + service.WithArgs( "--authrpc.port", `{{Port "authrpc" 8551}}`, "--authrpc.addr", "0.0.0.0", "--authrpc.jwtsecret", "/data/jwtsecret", @@ -119,8 +142,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 +158,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..9da5652 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -30,6 +30,12 @@ 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 + + // whether to enable websocket proxy + enableWebsocketProxy bool } func (o *OpRecipe) Name() string { @@ -47,7 +53,9 @@ 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") + flags.BoolVar(&o.enableWebsocketProxy, "enable-websocket-proxy", false, "Whether to enable websocket proxy") return flags } @@ -70,6 +78,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) @@ -96,21 +105,61 @@ func (o *OpRecipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { flashblocksBuilderURLRef = ConnectWs("op-rbuilder", "flashblocks") } + if o.flashblocks { + peers = append(peers, "flashblocks-rpc") + } + + // 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, + }) + } + + // 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: externalBuilderRef, + Builder: builderRef, Flashblocks: o.flashblocks, - FlashblocksBuilderURL: flashblocksBuilderURLRef, + 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: "rollup-boost", // rollup-boost provides the websocket stream + FlashblocksWSService: flashblocksWSService, + BaseOverlay: o.baseOverlay, + UseWebsocketProxy: useWebsocketProxy, }) }