From 69bd9b752718ad44ce9ff62257dc877f3caaf8cf Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:14:17 -0400 Subject: [PATCH 1/2] feat: add `chain-monitor` # Conflicts: # playground/components.go # Conflicts: # playground/catalog.go # Conflicts: # playground/catalog.go --- playground/catalog.go | 1 + playground/components.go | 85 +++++++++++++++++++++++++++++++++--- playground/recipe_opstack.go | 22 ++++++++++ 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/playground/catalog.go b/playground/catalog.go index cf392f7..d0a6c63 100644 --- a/playground/catalog.go +++ b/playground/catalog.go @@ -25,4 +25,5 @@ func init() { register(&BProxy{}) register(&WebsocketProxy{}) register(&BuilderHub{}) + register(&ChainMonitor{}) } diff --git a/playground/components.go b/playground/components.go index 8606228..ee0b6cf 100644 --- a/playground/components.go +++ b/playground/components.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "net" "strconv" "strings" "time" @@ -74,10 +75,18 @@ func (o *OpRbuilder) Apply(manifest *Manifest) { "--metrics", `0.0.0.0:{{Port "metrics" 9090}}`, "--port", `{{Port "rpc" 30303}}`, "--builder.enable-revert-protection", + "--rollup.builder-secret-key", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", ). WithArtifact("/data/jwtsecret", "jwtsecret"). WithArtifact("/data/l2-genesis.json", "l2-genesis.json"). - WithVolume("data", "/data_op_reth") + WithVolume("data", "/data_op_reth"). + WithReady(ReadyCheck{ + QueryURL: "http://localhost:8545", + Interval: 1 * time.Second, + Timeout: 10 * time.Second, + Retries: 20, + StartPeriod: 1 * time.Second, + }) if manifest.ctx.Bootnode != nil { service.WithArgs("--trusted-peers", manifest.ctx.Bootnode.Connect()) @@ -211,6 +220,47 @@ func (w *WebsocketProxy) Apply(manifest *Manifest) { ) } +func (w *WebsocketProxy) Name() string { + return "websocket-proxy" +} + +type ChainMonitor struct { + L1RPC string + L2BlockTime string + L2BuilderAddress string + L2RPC string + ServerListenAddress string +} + +func (c *ChainMonitor) Run(service *Service, ctx *ExContext) { + serverListenAddress := c.ServerListenAddress + if serverListenAddress == "" { + serverListenAddress = "0.0.0.0:{{Port \"metrics\" 8080}}" + } + + // we need to extract the port to register this service as exposing metrics + if _, portStr, err := net.SplitHostPort(serverListenAddress); err == nil { + if portNum, err := strconv.Atoi(portStr); err == nil { + service.WithPort("metrics", portNum) + } + } + + service.WithImage("ghcr.io/flashbots/chain-monitor"). + WithTag("v0.0.54"). + WithArgs( + "serve", + "--l1-rpc", c.L1RPC, + "--l2-block-time", c.L2BlockTime, + "--l2-monitor-builder-address", c.L2BuilderAddress, + "--l2-rpc", c.L2RPC, + "--server-listen-address", serverListenAddress, + ) +} + +func (c *ChainMonitor) Name() string { + return "chain-monitor" +} + type OpBatcher struct { L1Node string L2Node string @@ -257,6 +307,9 @@ func (o *OpNode) Apply(manifest *Manifest) { "--l1.http-poll-interval", "6s", "--l2", Connect(o.L2Node, "authrpc"), "--l2.jwt-secret", "/data/jwtsecret", + "--metrics.enabled", + "--metrics.addr", "0.0.0.0", + "--metrics.port", `{{Port "metrics" 7300}}`, "--sequencer.enabled", "--sequencer.l1-confs", "0", "--verifier.l1-confs", "0", @@ -269,9 +322,6 @@ func (o *OpNode) Apply(manifest *Manifest) { "--p2p.listen.udp", `{{PortUDP "p2p" 9003}}`, "--p2p.scoring.peers", "light", "--p2p.ban.peers", "true", - "--metrics.enabled", - "--metrics.addr", "0.0.0.0", - "--metrics.port", `{{Port "metrics" 7300}}`, "--pprof.enabled", "--rpc.enable-admin", "--safedb.path", "/data_db", @@ -355,7 +405,14 @@ func (o *OpGeth) Apply(manifest *Manifest) { WithReadyFn(opGethReadyFn). WithArtifact("/data/l2-genesis.json", "l2-genesis.json"). WithArtifact("/data/jwtsecret", "jwtsecret"). - WithArtifact("/data/p2p_key.txt", o.Enode.Artifact) + WithArtifact("/data/p2p_key.txt", o.Enode.Artifact). + WithReady(ReadyCheck{ + QueryURL: "http://localhost:8545", + Interval: 1 * time.Second, + Timeout: 10 * time.Second, + Retries: 20, + StartPeriod: 1 * time.Second, + }) } func opGethReadyFn(ctx context.Context, instance *instance) error { @@ -451,7 +508,14 @@ func (r *RethEL) Apply(manifest *Manifest) { }). WithArtifact("/data/genesis.json", "genesis.json"). WithArtifact("/data/jwtsecret", "jwtsecret"). - WithVolume("data", "/data_reth") + WithVolume("data", "/data_reth"). + WithReady(ReadyCheck{ + QueryURL: "http://localhost:8545", + Interval: 1 * time.Second, + Timeout: 10 * time.Second, + Retries: 20, + StartPeriod: 1 * time.Second, + }) if r.UseNativeReth { // we need to use this otherwise the db cannot be binded @@ -639,7 +703,14 @@ func (o *OpReth) Apply(manifest *Manifest) { }). WithArtifact("/data/jwtsecret", "jwtsecret"). WithArtifact("/data/l2-genesis.json", "l2-genesis.json"). - WithVolume("data", "/data_op_reth") + WithVolume("data", "/data_op_reth"). + WithReady(ReadyCheck{ + QueryURL: "http://localhost:8545", + Interval: 1 * time.Second, + Timeout: 10 * time.Second, + Retries: 20, + StartPeriod: 1 * time.Second, + }) } type MevBoost struct { diff --git a/playground/recipe_opstack.go b/playground/recipe_opstack.go index 2181306..ebf0dd3 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -1,11 +1,14 @@ package playground import ( + "fmt" flag "github.com/spf13/pflag" ) var _ Recipe = &OpRecipe{} +const defaultL2BuilderAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + // OpRecipe is a recipe that deploys an OP stack type OpRecipe struct { // externalBuilder is the URL of the external builder to use. If enabled, the recipe deploys @@ -36,6 +39,9 @@ type OpRecipe struct { // whether to enable websocket proxy enableWebsocketProxy bool + + // whether to enable chain-monitor + enableChainMonitor bool } func (o *OpRecipe) Name() string { @@ -56,6 +62,7 @@ func (o *OpRecipe) Flags() *flag.FlagSet { 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") + flags.BoolVar(&o.enableChainMonitor, "chain-monitor", false, "Whether to enable chain-monitor") return flags } @@ -174,6 +181,21 @@ func (o *OpRecipe) Apply(svcManager *Manifest) { MaxChannelDuration: o.batcherMaxChannelDuration, }) + if o.enableChainMonitor { + l2BlockTime := fmt.Sprintf("%ds", o.blockTime) + + svcManager.AddService("chain-monitor", &ChainMonitor{ + L1RPC: Connect("el", "http"), + L2BlockTime: l2BlockTime, + L2BuilderAddress: defaultL2BuilderAddress, + L2RPC: Connect("op-geth", "http"), + }) + + svcManager.MustGetService("chain-monitor"). + DependsOnHealthy("el"). + DependsOnHealthy("op-geth") + } + if svcManager.ctx.Contender.TargetChain == "" { svcManager.ctx.Contender.TargetChain = "op-geth" } From c5c730a572a244d2b7fa0e1ec73f021d67cdf113 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 11 Dec 2025 17:44:54 -0400 Subject: [PATCH 2/2] apply suggestions --- playground/components.go | 42 +++++++++++------------------------- playground/recipe_opstack.go | 15 ++++--------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/playground/components.go b/playground/components.go index ee0b6cf..c2eba2b 100644 --- a/playground/components.go +++ b/playground/components.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "net" "strconv" "strings" "time" @@ -29,6 +28,7 @@ func (r *RollupBoost) Apply(manifest *Manifest) { service := manifest.NewService("rollup-boost"). WithImage("docker.io/flashbots/rollup-boost"). WithTag("v0.7.5"). + DependsOnHealthy(r.ELNode). WithArgs( "--rpc-host", "0.0.0.0", "--rpc-port", `{{Port "authrpc" 8551}}`, @@ -220,47 +220,29 @@ func (w *WebsocketProxy) Apply(manifest *Manifest) { ) } -func (w *WebsocketProxy) Name() string { - return "websocket-proxy" -} - type ChainMonitor struct { L1RPC string - L2BlockTime string + L2BlockTime uint64 L2BuilderAddress string L2RPC string - ServerListenAddress string } -func (c *ChainMonitor) Run(service *Service, ctx *ExContext) { - serverListenAddress := c.ServerListenAddress - if serverListenAddress == "" { - serverListenAddress = "0.0.0.0:{{Port \"metrics\" 8080}}" - } - - // we need to extract the port to register this service as exposing metrics - if _, portStr, err := net.SplitHostPort(serverListenAddress); err == nil { - if portNum, err := strconv.Atoi(portStr); err == nil { - service.WithPort("metrics", portNum) - } - } - - service.WithImage("ghcr.io/flashbots/chain-monitor"). - WithTag("v0.0.54"). +func (c *ChainMonitor) Apply(manifest *Manifest) { + manifest.NewService("chain-monitor"). + WithPort("metrics", 8080). + WithImage("ghcr.io/flashbots/chain-monitor"). + WithTag("v0.0.54"). + DependsOnHealthy(c.L1RPC). + DependsOnHealthy(c.L2RPC). WithArgs( "serve", - "--l1-rpc", c.L1RPC, - "--l2-block-time", c.L2BlockTime, + "--l1-rpc", Connect(c.L1RPC, "http"), + "--l2-block-time", fmt.Sprintf("%ds", c.L2BlockTime), "--l2-monitor-builder-address", c.L2BuilderAddress, - "--l2-rpc", c.L2RPC, - "--server-listen-address", serverListenAddress, + "--l2-rpc", Connect(c.L2RPC, "http"), ) } -func (c *ChainMonitor) Name() string { - return "chain-monitor" -} - type OpBatcher struct { L1Node string L2Node string diff --git a/playground/recipe_opstack.go b/playground/recipe_opstack.go index ebf0dd3..e658db0 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -1,7 +1,6 @@ package playground import ( - "fmt" flag "github.com/spf13/pflag" ) @@ -182,18 +181,12 @@ func (o *OpRecipe) Apply(svcManager *Manifest) { }) if o.enableChainMonitor { - l2BlockTime := fmt.Sprintf("%ds", o.blockTime) - - svcManager.AddService("chain-monitor", &ChainMonitor{ - L1RPC: Connect("el", "http"), - L2BlockTime: l2BlockTime, + svcManager.AddService(&ChainMonitor{ + L1RPC: "el", + L2BlockTime: o.blockTime, L2BuilderAddress: defaultL2BuilderAddress, - L2RPC: Connect("op-geth", "http"), + L2RPC: "op-geth", }) - - svcManager.MustGetService("chain-monitor"). - DependsOnHealthy("el"). - DependsOnHealthy("op-geth") } if svcManager.ctx.Contender.TargetChain == "" {