Skip to content

feat: Add builder-hub component and buildernet-recipe #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 31, 2025
76 changes: 76 additions & 0 deletions internal/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,79 @@ func (m *MevBoostRelay) Watchdog(out io.Writer, service *service, ctx context.Co

return watchGroup.wait()
}

type BuilderHub struct {
}

func (b *BuilderHub) Run(service *service, ctx *ExContext) {
// Start the builder-hub service
service.
WithImage("ghcr.io/flashbots/builder-hub/builder-hub").
WithTag("latest").
WithArgs(
"--listen-addr", fmt.Sprintf("0.0.0.0:%s", `{{Port "http" 8080}}`),
"--admin-addr", fmt.Sprintf("0.0.0.0:%s", `{{Port "admin" 8081}}`),
"--internal-addr", fmt.Sprintf("0.0.0.0:%s", `{{Port "internal" 8082}}`),
"--metrics-addr", fmt.Sprintf("0.0.0.0:%s", `{{Port "metrics" 8090}}`),
"--log-json", "true",
"--log-debug",
// Use proper template format for postgres connection
"--postgres-dsn", `postgres://postgres:postgres@{{Service "builder-hub-postgres" "postgres"}}/postgres?sslmode=disable`,
)
}

// BuilderHubPostgres is a component that runs the postgres database for builder-hub
type BuilderHubPostgres struct {
}

func (b *BuilderHubPostgres) Run(service *service, ctx *ExContext) {
// Start the postgres database
service.
WithImage("postgres").
WithTag("latest").
WithPort("postgres", 5432).
WithLabel("POSTGRES_USER", "postgres").
WithLabel("POSTGRES_PASSWORD", "postgres").
WithLabel("POSTGRES_DB", "postgres")
}

var _ ServiceReady = &BuilderHubPostgres{}

func (b *BuilderHubPostgres) Ready(out io.Writer, service *service, ctx context.Context) error {
// Wait for postgresql to be ready
logs := service.logs
if err := logs.WaitForLog("database system is ready to accept connections", 30*time.Second); err != nil {
return err
}

fmt.Fprintln(out, "PostgreSQL is ready for builder-hub")
return nil
}

// BuilderHubInitDB is a component that initializes the builder-hub database
type BuilderHubInitDB struct {
}

func (b *BuilderHubInitDB) Run(service *service, ctx *ExContext) {
// This component runs and exits - it just initializes the database with SQL scripts
service.
WithImage("ghcr.io/flashbots/builder-hub/builder-hub").
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better use docker hub, it's easier to use as it doesn't require auth?

WithTag("latest").
WithEntrypoint("/bin/sh").
WithArgs(
"-c",
// Use proper template format for postgres connection
`for file in schema/*.sql; do psql "postgres://postgres:postgres@{{Service "builder-hub-postgres" "postgres"}}/postgres?sslmode=disable" -f $file; done`,
)
}

var _ ServiceReady = &BuilderHubInitDB{}

func (b *BuilderHubInitDB) Ready(out io.Writer, service *service, ctx context.Context) error {
// The completion of SQL file execution won't necessarily produce a specific log message,
// so we'll just wait for a few seconds to allow the scripts to complete
time.Sleep(5 * time.Second)

fmt.Fprintln(out, "BuilderHub database migrations completed")
return nil
}
69 changes: 69 additions & 0 deletions internal/recipe_buildernet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package internal

import (
"fmt"

flag "github.com/spf13/pflag"
)

var _ Recipe = &BuilderNetRecipe{}

// BuilderNetRecipe is a recipe that extends the L1 recipe to include builder-hub
type BuilderNetRecipe struct {
// Embed the L1Recipe to reuse its functionality
l1Recipe L1Recipe
}

func (b *BuilderNetRecipe) Name() string {
return "buildernet"
}

func (b *BuilderNetRecipe) Description() string {
return "Deploy a full L1 stack with mev-boost and builder-hub"
}

func (b *BuilderNetRecipe) Flags() *flag.FlagSet {
// Reuse the L1Recipe flags
flags := b.l1Recipe.Flags()
return flags
}

func (b *BuilderNetRecipe) Artifacts() *ArtifactsBuilder {
// Reuse the L1Recipe artifacts builder
return b.l1Recipe.Artifacts()
}

func (b *BuilderNetRecipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest {
// Start with the L1Recipe manifest
svcManager := b.l1Recipe.Apply(ctx, artifacts)

// Add builder-hub-postgres service
svcManager.AddService("builder-hub-postgres", &BuilderHubPostgres{})

// Add the builder-hub-init-db service to initialize the database
svcManager.AddService("builder-hub-init-db", &BuilderHubInitDB{})

// Add the builder-hub service
svcManager.AddService("builder-hub", &BuilderHub{})

return svcManager
}

func (b *BuilderNetRecipe) Output(manifest *Manifest) map[string]interface{} {
// Start with the L1Recipe output
output := b.l1Recipe.Output(manifest)

// Add builder-hub service info
builderHubService, ok := manifest.GetService("builder-hub")
if ok {
http := builderHubService.MustGetPort("http")
admin := builderHubService.MustGetPort("admin")
internal := builderHubService.MustGetPort("internal")

output["builder-hub-http"] = fmt.Sprintf("http://localhost:%d", http.HostPort)
output["builder-hub-admin"] = fmt.Sprintf("http://localhost:%d", admin.HostPort)
output["builder-hub-internal"] = fmt.Sprintf("http://localhost:%d", internal.HostPort)
}

return output
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var cookCmd = &cobra.Command{
var recipes = []internal.Recipe{
&internal.L1Recipe{},
&internal.OpRecipe{},
&internal.BuilderNetRecipe{},
}

func main() {
Expand Down