Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/recipes/buildernet.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Deploy a full L1 stack with mev-boost and builder-hub.
## Flags

- `block-time` (duration): Block time to use for the L1. Default to '12s'.
- `builder-config` (string): Builder config in YAML format. Default to ''.
- `builder-ip` (string): IP address of the external builder to register in BuilderHub. Default to '127.0.0.1'.
- `latest-fork` (bool): use the latest fork. Default to 'false'.
- `secondary-el` (string): Address or port to use for the secondary EL (execution layer); Can be a port number (e.g., '8551') in which case the full URL is derived as `http://localhost:<port>` or a complete URL (e.g., `http://docker-container-name:8551`), use `http://host.docker.internal:<port>` to reach a secondary execution client that runs on your host and not within Docker.. Default to ''.
- `use-native-reth` (bool): use the native reth binary. Default to 'false'.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/flashbots/go-template v1.0.0
github.com/flashbots/mev-boost-relay v0.32.0-rc2
github.com/go-chi/httplog/v2 v2.1.1
github.com/goccy/go-yaml v1.17.1
github.com/hashicorp/go-uuid v1.0.3
github.com/holiman/uint256 v1.3.2
github.com/otiai10/copy v1.14.1
Expand Down Expand Up @@ -75,7 +76,6 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/goccy/go-json v0.10.4 // indirect
github.com/goccy/go-yaml v1.17.1 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect
Expand Down
6 changes: 6 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ func runIt(recipe playground.Recipe) error {
return fmt.Errorf("failed to wait for service readiness: %w", err)
}

// run post hook operations
if err := svcManager.ExecutePostHookActions(); err != nil {
dockerRunner.Stop(keepFlag)
return fmt.Errorf("failed to execute post-hook operations: %w", err)
}

slog.Info("All services are healthy! Ready to accept transactions. 🚀", "session-id", svcManager.ID)

// get the output from the recipe
Expand Down
53 changes: 51 additions & 2 deletions playground/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package playground

import (
"fmt"
"os"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -827,7 +828,10 @@ func (c *Contender) Apply(manifest *Manifest) {
}
}

type BuilderHub struct{}
type BuilderHub struct {
BuilderIP string
BuilderConfig string
}

func (b *BuilderHub) Apply(manifest *Manifest) {
// Database service
Expand All @@ -848,7 +852,7 @@ func (b *BuilderHub) Apply(manifest *Manifest) {
})

// API service
manifest.NewService("builder-hub-api").
apiSrv := manifest.NewService("builder-hub-api").
WithImage("docker.io/flashbots/builder-hub").
WithTag("0.3.1-alpha1").
DependsOnHealthy("builder-hub-db").
Expand All @@ -872,6 +876,13 @@ func (b *BuilderHub) Apply(manifest *Manifest) {
StartPeriod: 1 * time.Second,
})

apiSrv.WithPostHook(&postHook{
Name: "register-builder",
Action: func(s *Service) error {
return registerBuilderHook(manifest, s, b)
},
})

// Proxy service
manifest.NewService("builder-hub-proxy").
WithImage("docker.io/flashbots/builder-hub-mock-proxy").
Expand All @@ -888,6 +899,44 @@ func (b *BuilderHub) Apply(manifest *Manifest) {
})
}

func registerBuilderHook(manifest *Manifest, s *Service, b *BuilderHub) error {
genesis, err := manifest.out.Read("genesis.json")
if err != nil {
return err
}

configYaml, err := os.ReadFile(b.BuilderConfig)
if err != nil {
return err
}

// we need to convert the config to JSON because it is what the API server accepts
configJSON, err := yamlToJson([]byte(configYaml))
if err != nil {
return err
}

overrideConfig := map[string]interface{}{
"genesis": genesis,
}
if configJSON, err = overrideJSON(configJSON, overrideConfig); err != nil {
return err
}

endpoint := fmt.Sprintf("http://localhost:%d", s.MustGetPort("admin").HostPort)
input := &builderHubRegisterBuilderInput{
BuilderID: "builder",
BuilderIP: b.BuilderIP,
MeasurementID: "test",
Network: "playground",
Config: string(configJSON),
}
if err := registerBuilder(endpoint, input); err != nil {
return err
}
return nil
}

const (
healthmonBeacon = "beacon"
healthmonExecution = "execution"
Expand Down
27 changes: 26 additions & 1 deletion playground/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package playground
import (
"encoding/json"
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -336,7 +337,8 @@ type Service struct {

UngracefulShutdown bool `json:"ungraceful_shutdown,omitempty"`

release *release
postHook *postHook
release *release
}

type DependsOnCondition string
Expand Down Expand Up @@ -488,6 +490,29 @@ func (s *Service) WithReady(check ReadyCheck) *Service {
return s
}

type postHook struct {
Name string
Action func(s *Service) error
}

func (s *Service) WithPostHook(hook *postHook) *Service {
s.postHook = hook
return s
}

func (m *Manifest) ExecutePostHookActions() error {
for _, svc := range m.Services {
if svc.postHook != nil {
slog.Info("Executing post-hook operation", "name", svc.postHook.Name)
if err := svc.postHook.Action(svc); err != nil {
return err
}
}
}

return nil
}

type ReadyCheck struct {
QueryURL string `json:"query_url"`
Test []string `json:"test"`
Expand Down
33 changes: 32 additions & 1 deletion playground/recipe_buildernet.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"

"github.com/goccy/go-yaml"
flag "github.com/spf13/pflag"
)

Expand All @@ -16,6 +17,9 @@ var _ Recipe = &BuilderNetRecipe{}
type BuilderNetRecipe struct {
// Embed the L1Recipe to reuse its functionality
l1Recipe L1Recipe

builderIP string
builderConfig string
}

func (b *BuilderNetRecipe) Name() string {
Expand All @@ -29,6 +33,8 @@ func (b *BuilderNetRecipe) Description() string {
func (b *BuilderNetRecipe) Flags() *flag.FlagSet {
// Reuse the L1Recipe flags
flags := b.l1Recipe.Flags()
flags.StringVar(&b.builderIP, "builder-ip", "127.0.0.1", "IP address of the external builder to register in BuilderHub")
flags.StringVar(&b.builderConfig, "builder-config", "", "Builder config in YAML format")
return flags
}

Expand All @@ -41,7 +47,10 @@ func (b *BuilderNetRecipe) Apply(svcManager *Manifest) {
// Start with the L1Recipe manifest
b.l1Recipe.Apply(svcManager)

svcManager.AddComponent(&BuilderHub{})
svcManager.AddComponent(&BuilderHub{
BuilderIP: b.builderIP,
BuilderConfig: b.builderConfig,
})

svcManager.RunContenderIfEnabled()
}
Expand Down Expand Up @@ -160,3 +169,25 @@ func registerBuilder(httpEndpoint string, input *builderHubRegisterBuilderInput)

return nil
}

// YAMLToJSON converts a YAML string to a JSON string
func yamlToJson(yamlStr []byte) ([]byte, error) {
// Unmarshal YAML into a map
var data interface{}
err := yaml.Unmarshal(yamlStr, &data)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal YAML: %w", err)
}

if data == nil {
return []byte("{}"), nil
}

// Convert to JSON
jsonBytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
return nil, fmt.Errorf("failed to marshal JSON: %w", err)
}

return jsonBytes, nil
}