From 9a688b54c9a207cd775f64c870076af49bb58cf3 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 2 Dec 2025 11:20:46 -0500 Subject: [PATCH 1/5] Added possibility to have a secondary el on the host This change, relatively simple and backward compatible, enables syncing an external execution client from the host itself instead of relying on running within Docker. We tested it and to succesfully sync with the inner el peer, one further change is needed which is to expose the P2P address to the public interface (instead of only within the host), PR incoming for this. --- playground/recipe_l1.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/playground/recipe_l1.go b/playground/recipe_l1.go index b45c2b0..e79c408 100644 --- a/playground/recipe_l1.go +++ b/playground/recipe_l1.go @@ -2,6 +2,7 @@ package playground import ( "fmt" + "regexp" flag "github.com/spf13/pflag" ) @@ -15,9 +16,12 @@ type L1Recipe struct { // useRethForValidation signals mev-boost to use the Reth EL node for block validation useRethForValidation bool - // secondaryELPort enables the use of a secondary EL connected to the validator beacon node - // It is enabled through the use of the cl-proxy service - secondaryELPort uint64 + // secondaryEL enables the use of a secondary EL connected to the validator beacon node + // It is enabled through the use of the cl-proxy service. If the input is a plain number, assumed + // it's a port number and the secondary EL is assumed to be running on localhost at that port. + // Otherwise, assume it's a full address (e.g http://some-el:8551) where to reach the secondary EL, + // use http://host.internal.docker.internal: to reach the host machine from within docker. + secondaryEL string // if useNativeReth is set to true, the Reth EL execution client for the validator beacon node // will run on the host machine. This is useful if you want to bind to the Reth database and you @@ -39,7 +43,7 @@ func (l *L1Recipe) Flags() *flag.FlagSet { flags := flag.NewFlagSet("l1", flag.ContinueOnError) flags.BoolVar(&l.latestFork, "latest-fork", false, "use the latest fork") flags.BoolVar(&l.useRethForValidation, "use-reth-for-validation", false, "use reth for validation") - flags.Uint64Var(&l.secondaryELPort, "secondary-el", 0, "port to use for the secondary builder") + flags.StringVar(&l.secondaryEL, "secondary-el", "", "Address or port to use for the secondary builder, if only port provided, address is inferred as http://localhost: (where localhost is within Docker and not on your machine). You can use http://host.docker.internal: to reach your host machine from within Docker.") flags.BoolVar(&l.useNativeReth, "use-native-reth", false, "use the native reth binary") flags.BoolVar(&l.useSeparateMevBoost, "use-separate-mev-boost", false, "use separate mev-boost and mev-boost-relay services") return flags @@ -52,6 +56,8 @@ func (l *L1Recipe) Artifacts() *ArtifactsBuilder { return builder } +var isPortRegex = regexp.MustCompile(`^\d{2,5}$`) + func (l *L1Recipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { svcManager := NewManifest(ctx, artifacts.Out) @@ -61,13 +67,18 @@ func (l *L1Recipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { }) var elService string - if l.secondaryELPort != 0 { + if l.secondaryEL != "" { + address := l.secondaryEL + if isPortRegex.MatchString(l.secondaryEL) { + address = fmt.Sprintf("http://localhost:%s", l.secondaryEL) + } + // we are going to use the cl-proxy service to connect the beacon node to two builders // one the 'el' builder and another one the remote one elService = "cl-proxy" svcManager.AddService("cl-proxy", &ClProxy{ PrimaryBuilder: "el", - SecondaryBuilder: fmt.Sprintf("http://localhost:%d", l.secondaryELPort), + SecondaryBuilder: address, }) } else { elService = "el" From 3d06cb15f47b3bf55c973f3aa67f1792e1c49f20 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 2 Dec 2025 12:44:33 -0500 Subject: [PATCH 2/5] Adjuste `--secondary-el` documentation in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5331b30..581b55a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Flags: - `--latest-fork`: Enable the latest fork at startup - `--use-reth-for-validation`: Use Reth EL for block validation in mev-boost. -- `--secondary-el`: Port to use for a secondary el (enables the internal cl-proxy proxy) +- `--secondary-el`: Host or port to use for a secondary el (enables the internal cl-proxy proxy). Can be a port number (e.g., '8545') in which case the full URL is derived as `http://localhost:` or a complete URL (e.g., `http://remote-host:8545`), use `http://host.docker.internal:` to reach a secondary execution client that runs on your host and not within Docker. - `--use-native-reth`: Run the Reth EL binary on the host instead of docker (recommended to bind to the Reth DB) - `--use-separate-mev-boost`: Spins a seperate service for mev-boost in addition with mev-boost-relay From 5758355223d38d106b324821819c9c6e3a0092b6 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 2 Dec 2025 12:52:19 -0500 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- playground/recipe_l1.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/playground/recipe_l1.go b/playground/recipe_l1.go index e79c408..fd2ebf6 100644 --- a/playground/recipe_l1.go +++ b/playground/recipe_l1.go @@ -17,10 +17,10 @@ type L1Recipe struct { useRethForValidation bool // secondaryEL enables the use of a secondary EL connected to the validator beacon node - // It is enabled through the use of the cl-proxy service. If the input is a plain number, assumed - // it's a port number and the secondary EL is assumed to be running on localhost at that port. - // Otherwise, assume it's a full address (e.g http://some-el:8551) where to reach the secondary EL, - // use http://host.internal.docker.internal: to reach the host machine from within docker. + // It is enabled through the use of the cl-proxy service. If the input is a plain number, it is assumed + // to be a port number and the secondary EL is assumed to be running on localhost at that port. + // Otherwise, it is assumed to be a full address (e.g http://some-el:8551) where to reach the secondary EL, + // use http://host.docker.internal: to reach the host machine from within docker. secondaryEL string // if useNativeReth is set to true, the Reth EL execution client for the validator beacon node @@ -43,7 +43,7 @@ func (l *L1Recipe) Flags() *flag.FlagSet { flags := flag.NewFlagSet("l1", flag.ContinueOnError) flags.BoolVar(&l.latestFork, "latest-fork", false, "use the latest fork") flags.BoolVar(&l.useRethForValidation, "use-reth-for-validation", false, "use reth for validation") - flags.StringVar(&l.secondaryEL, "secondary-el", "", "Address or port to use for the secondary builder, if only port provided, address is inferred as http://localhost: (where localhost is within Docker and not on your machine). You can use http://host.docker.internal: to reach your host machine from within Docker.") + flags.StringVar(&l.secondaryEL, "secondary-el", "", "Address or port to use for the secondary EL (execution layer); if only a port is provided, address is inferred as http://localhost: (where localhost is within Docker and not on your machine). You can use http://host.docker.internal: to reach your host machine from within Docker.") flags.BoolVar(&l.useNativeReth, "use-native-reth", false, "use the native reth binary") flags.BoolVar(&l.useSeparateMevBoost, "use-separate-mev-boost", false, "use separate mev-boost and mev-boost-relay services") return flags From 7a03946b0ddf7abe8eab2408509c93eb3e9cd2cd Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 2 Dec 2025 15:14:58 -0500 Subject: [PATCH 4/5] Quick rename of regex to be better aligned with imperfect intention --- playground/recipe_l1.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playground/recipe_l1.go b/playground/recipe_l1.go index fd2ebf6..cf6f74d 100644 --- a/playground/recipe_l1.go +++ b/playground/recipe_l1.go @@ -56,7 +56,7 @@ func (l *L1Recipe) Artifacts() *ArtifactsBuilder { return builder } -var isPortRegex = regexp.MustCompile(`^\d{2,5}$`) +var looksLikePortRegex = regexp.MustCompile(`^\d{2,5}$`) func (l *L1Recipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { svcManager := NewManifest(ctx, artifacts.Out) @@ -69,7 +69,7 @@ func (l *L1Recipe) Apply(ctx *ExContext, artifacts *Artifacts) *Manifest { var elService string if l.secondaryEL != "" { address := l.secondaryEL - if isPortRegex.MatchString(l.secondaryEL) { + if looksLikePortRegex.MatchString(l.secondaryEL) { address = fmt.Sprintf("http://localhost:%s", l.secondaryEL) } From 92311ce6a95aed0d07623aa429c840d608480276 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 5 Dec 2025 19:01:12 -0500 Subject: [PATCH 5/5] Quick further improvement to documentation --- README.md | 2 +- playground/recipe_l1.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 581b55a..23a23f3 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Flags: - `--latest-fork`: Enable the latest fork at startup - `--use-reth-for-validation`: Use Reth EL for block validation in mev-boost. -- `--secondary-el`: Host or port to use for a secondary el (enables the internal cl-proxy proxy). Can be a port number (e.g., '8545') in which case the full URL is derived as `http://localhost:` or a complete URL (e.g., `http://remote-host:8545`), use `http://host.docker.internal:` to reach a secondary execution client that runs on your host and not within Docker. +- `--secondary-el`: Host or port to use for a secondary el (enables the internal cl-proxy proxy). Can be a port number (e.g., '8551') in which case the full URL is derived as `http://localhost:` or a complete URL (e.g., `http://remote-host:8551`), use `http://host.docker.internal:` to reach a secondary execution client that runs on your host and not within Docker. - `--use-native-reth`: Run the Reth EL binary on the host instead of docker (recommended to bind to the Reth DB) - `--use-separate-mev-boost`: Spins a seperate service for mev-boost in addition with mev-boost-relay diff --git a/playground/recipe_l1.go b/playground/recipe_l1.go index cf6f74d..a67f622 100644 --- a/playground/recipe_l1.go +++ b/playground/recipe_l1.go @@ -43,7 +43,7 @@ func (l *L1Recipe) Flags() *flag.FlagSet { flags := flag.NewFlagSet("l1", flag.ContinueOnError) flags.BoolVar(&l.latestFork, "latest-fork", false, "use the latest fork") flags.BoolVar(&l.useRethForValidation, "use-reth-for-validation", false, "use reth for validation") - flags.StringVar(&l.secondaryEL, "secondary-el", "", "Address or port to use for the secondary EL (execution layer); if only a port is provided, address is inferred as http://localhost: (where localhost is within Docker and not on your machine). You can use http://host.docker.internal: to reach your host machine from within Docker.") + flags.StringVar(&l.secondaryEL, "secondary-el", "", "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:` or a complete URL (e.g., `http://docker-container-name:8551`), use `http://host.docker.internal:` to reach a secondary execution client that runs on your host and not within Docker.") flags.BoolVar(&l.useNativeReth, "use-native-reth", false, "use the native reth binary") flags.BoolVar(&l.useSeparateMevBoost, "use-separate-mev-boost", false, "use separate mev-boost and mev-boost-relay services") return flags