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..c2eba2b 100644 --- a/playground/components.go +++ b/playground/components.go @@ -28,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}}`, @@ -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,29 @@ func (w *WebsocketProxy) Apply(manifest *Manifest) { ) } +type ChainMonitor struct { + L1RPC string + L2BlockTime uint64 + L2BuilderAddress string + L2RPC string +} + +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", Connect(c.L1RPC, "http"), + "--l2-block-time", fmt.Sprintf("%ds", c.L2BlockTime), + "--l2-monitor-builder-address", c.L2BuilderAddress, + "--l2-rpc", Connect(c.L2RPC, "http"), + ) +} + type OpBatcher struct { L1Node string L2Node string @@ -257,6 +289,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 +304,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 +387,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 +490,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 +685,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..e658db0 100644 --- a/playground/recipe_opstack.go +++ b/playground/recipe_opstack.go @@ -6,6 +6,8 @@ import ( 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 +38,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 +61,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 +180,15 @@ func (o *OpRecipe) Apply(svcManager *Manifest) { MaxChannelDuration: o.batcherMaxChannelDuration, }) + if o.enableChainMonitor { + svcManager.AddService(&ChainMonitor{ + L1RPC: "el", + L2BlockTime: o.blockTime, + L2BuilderAddress: defaultL2BuilderAddress, + L2RPC: "op-geth", + }) + } + if svcManager.ctx.Contender.TargetChain == "" { svcManager.ctx.Contender.TargetChain = "op-geth" }