diff --git a/rocketpool-cli/service/config/settings-native-smartnode.go b/rocketpool-cli/service/config/settings-native-smartnode.go index e2800f585..38cffb2af 100644 --- a/rocketpool-cli/service/config/settings-native-smartnode.go +++ b/rocketpool-cli/service/config/settings-native-smartnode.go @@ -23,7 +23,7 @@ func NewNativeSmartnodeConfigPage(home *settingsNativeHome) *NativeSmartnodeConf configPage.page = newPage( home.homePage, "settings-native-smartnode", - "Smartnode and TX Fees", + "Smart Node and TX Fees", "Select this to configure the settings for the Smart Node itself, including the defaults and limits on transaction fees.", configPage.layout.grid, ) @@ -43,7 +43,8 @@ func (configPage *NativeSmartnodeConfigPage) createContent() { layout.setupEscapeReturnHomeHandler(configPage.home.md, configPage.home.homePage) // Set up the form items - formItems := createParameterizedFormItems(masterConfig.Smartnode.GetParameters(), layout.descriptionBox) + params := append(masterConfig.Smartnode.GetParameters(), &masterConfig.EnableIPv6, &masterConfig.Alertmanager.ShowAlertsOnCLI) + formItems := createParameterizedFormItems(params, layout.descriptionBox) for _, formItem := range formItems { if formItem.parameter.ID == config.ProjectNameID { // Ignore the project name ID since it doesn't apply to native mode diff --git a/rocketpool-cli/service/config/settings-smartnode.go b/rocketpool-cli/service/config/settings-smartnode.go index 9b3fc72d4..be4bebae2 100644 --- a/rocketpool-cli/service/config/settings-smartnode.go +++ b/rocketpool-cli/service/config/settings-smartnode.go @@ -24,7 +24,7 @@ func NewSmartnodeConfigPage(home *settingsHome) *SmartnodeConfigPage { configPage.page = newPage( home.homePage, "settings-smartnode", - "Smartnode and TX Fees", + "Smart Node and TX Fees", "Select this to configure the settings for the Smart Node itself, including the defaults and limits on transaction fees.", configPage.layout.grid, ) @@ -67,7 +67,8 @@ func (configPage *SmartnodeConfigPage) createContent() { }) // Set up the form items - formItems := createParameterizedFormItems(masterConfig.Smartnode.GetParameters(), layout.descriptionBox) + params := append(masterConfig.Smartnode.GetParameters(), &masterConfig.EnableIPv6, &masterConfig.Alertmanager.ShowAlertsOnCLI) + formItems := createParameterizedFormItems(params, layout.descriptionBox) for _, formItem := range formItems { layout.form.AddFormItem(formItem.item) layout.parameters[formItem.item] = formItem diff --git a/rocketpool/node/check-port-connectivity.go b/rocketpool/node/check-port-connectivity.go index 369b4612d..a8372e922 100644 --- a/rocketpool/node/check-port-connectivity.go +++ b/rocketpool/node/check-port-connectivity.go @@ -25,9 +25,12 @@ var publicIPResolvers = []struct { addr string // host:port (IP literal) hostname string // special hostname that returns the caller's public IP }{ - {"208.67.222.222:53", "myip.opendns.com"}, // OpenDNS primary - {"208.67.220.220:53", "myip.opendns.com"}, // OpenDNS secondary - {"216.239.32.10:53", "o-o.myaddr.l.google.com"}, // Google ns1 + {"208.67.222.222:53", "myip.opendns.com"}, // OpenDNS primary (IPv4) + {"208.67.220.220:53", "myip.opendns.com"}, // OpenDNS secondary (IPv4) + {"216.239.32.10:53", "o-o.myaddr.l.google.com"}, // Google ns1 (IPv4) + {"[2620:119:35::35]:53", "myip.opendns.com"}, // OpenDNS primary (IPv6) + {"[2620:119:53::53]:53", "myip.opendns.com"}, // OpenDNS secondary (IPv6) + {"[2001:4860:4860::8888]:53", "o-o.myaddr.l.google.com"}, // Google ns1 (IPv6) } // Check port connectivity task @@ -139,7 +142,7 @@ func getPublicIP() (string, error) { // isPortReachable attempts a TCP connection to host:port and returns true if // the connection succeeds within portCheckTimeout. func isPortReachable(host string, port uint16) bool { - address := fmt.Sprintf("%s:%d", host, port) + address := net.JoinHostPort(host, fmt.Sprintf("%d", port)) conn, err := net.DialTimeout("tcp", address, portCheckTimeout) if err != nil { return false diff --git a/shared/services/config/rocket-pool-config.go b/shared/services/config/rocket-pool-config.go index 552f835b5..43d8c7b01 100644 --- a/shared/services/config/rocket-pool-config.go +++ b/shared/services/config/rocket-pool-config.go @@ -75,6 +75,9 @@ type RocketPoolConfig struct { ConsensusClient config.Parameter `yaml:"consensusClient,omitempty"` ExternalConsensusClient config.Parameter `yaml:"externalConsensusClient,omitempty"` + // IPv6 networking + EnableIPv6 config.Parameter `yaml:"enableIPv6,omitempty"` + // Metrics settings EnableMetrics config.Parameter `yaml:"enableMetrics,omitempty"` EnableODaoMetrics config.Parameter `yaml:"enableODaoMetrics,omitempty"` @@ -343,6 +346,17 @@ func NewRocketPoolConfig(rpDir string, isNativeMode bool) *RocketPoolConfig { }}, }, + EnableIPv6: config.Parameter{ + ID: "enableIPv6", + Name: "Enable IPv6", + Description: "Enable IPv6 support for the Docker network used by the Smart Node. Enable this if your machine only has an IPv6 address, or if you want your Ethereum clients to communicate over IPv6.", + Type: config.ParameterType_Bool, + Default: map[config.Network]interface{}{config.Network_All: false}, + AffectsContainers: []config.ContainerID{config.ContainerID_Api, config.ContainerID_Node, config.ContainerID_Watchtower, config.ContainerID_Eth1, config.ContainerID_Eth2, config.ContainerID_Validator, config.ContainerID_Grafana, config.ContainerID_Prometheus, config.ContainerID_Alertmanager, config.ContainerID_Exporter, config.ContainerID_MevBoost, config.ContainerID_CommitBoost}, + CanBeBlank: false, + OverwriteOnUpgrade: false, + }, + EnableMetrics: config.Parameter{ ID: "enableMetrics", Name: "Enable Metrics", @@ -558,6 +572,7 @@ func (cfg *RocketPoolConfig) GetParameters() []*config.Parameter { &cfg.ConsensusClientMode, &cfg.ConsensusClient, &cfg.ExternalConsensusClient, + &cfg.EnableIPv6, &cfg.EnableMetrics, &cfg.EnableODaoMetrics, &cfg.EnableBitflyNodeMetrics, @@ -1307,6 +1322,12 @@ func (cfg *RocketPoolConfig) GetECAdditionalFlags() (string, error) { return "", fmt.Errorf("Unknown Execution Client %s", string(cfg.ExecutionClient.Value.(config.ExecutionClient))) } +// IsIPv6Enabled returns true if IPv6 support is enabled for the Docker network. +// Used by text/template to conditionally add enable_ipv6 to compose network definitions. +func (cfg *RocketPoolConfig) IsIPv6Enabled() bool { + return cfg.EnableIPv6.Value.(bool) +} + // Used by text/template to format eth1.yml func (cfg *RocketPoolConfig) GetExternalIp() string { // Get the external IP address diff --git a/shared/services/config/teku-config.go b/shared/services/config/teku-config.go index a52b23e2d..8514b2cce 100644 --- a/shared/services/config/teku-config.go +++ b/shared/services/config/teku-config.go @@ -6,9 +6,10 @@ import ( ) const ( - tekuTagTest string = "consensys/teku:26.2.0" - tekuTagProd string = "consensys/teku:26.2.0" - defaultTekuMaxPeers uint16 = 100 + tekuTagTest string = "consensys/teku:26.2.0" + tekuTagProd string = "consensys/teku:26.2.0" + defaultTekuMaxPeers uint16 = 100 + defaultTekuP2pIpv6Port uint16 = 9090 ) // Configuration for Teku @@ -36,6 +37,9 @@ type TekuConfig struct { // Custom command line flags for the BN AdditionalBnFlags config.Parameter `yaml:"additionalBnFlags,omitempty"` + // The IPv6 P2P port for Teku (Teku uses a separate port for IPv6) + P2pIpv6Port config.Parameter `yaml:"p2pIpv6Port,omitempty"` + // Custom command line flags for the VC AdditionalVcFlags config.Parameter `yaml:"additionalVcFlags,omitempty"` } @@ -120,6 +124,17 @@ func NewTekuConfig(cfg *RocketPoolConfig) *TekuConfig { OverwriteOnUpgrade: false, }, + P2pIpv6Port: config.Parameter{ + ID: "p2pIpv6Port", + Name: "P2P IPv6 Port", + Description: "The port Teku uses for P2P communication over IPv6. Teku requires a dedicated port for IPv6 (separate from the main P2P port). Only used when IPv6 support is enabled.", + Type: config.ParameterType_Uint16, + Default: map[config.Network]interface{}{config.Network_All: defaultTekuP2pIpv6Port}, + AffectsContainers: []config.ContainerID{config.ContainerID_Eth2}, + CanBeBlank: false, + OverwriteOnUpgrade: false, + }, + AdditionalVcFlags: config.Parameter{ ID: "additionalVcFlags", Name: "Additional Validator Client Flags", @@ -142,6 +157,7 @@ func (cfg *TekuConfig) GetParameters() []*config.Parameter { &cfg.UseSlashingProtection, &cfg.ContainerTag, &cfg.AdditionalBnFlags, + &cfg.P2pIpv6Port, &cfg.AdditionalVcFlags, } } diff --git a/shared/services/rocketpool/assets/install/scripts/start-bn.sh b/shared/services/rocketpool/assets/install/scripts/start-bn.sh index 1a21888bd..f5bed1dc6 100755 --- a/shared/services/rocketpool/assets/install/scripts/start-bn.sh +++ b/shared/services/rocketpool/assets/install/scripts/start-bn.sh @@ -99,6 +99,10 @@ if [ "$CC_CLIENT" = "lighthouse" ]; then CMD="$CMD --monitoring-endpoint $BITFLY_NODE_METRICS_ENDPOINT?apikey=$BITFLY_NODE_METRICS_SECRET&machine=$BITFLY_NODE_METRICS_MACHINE_NAME" fi + if [ "$ENABLE_IPV6" = "true" ]; then + CMD="$CMD --listen-address :: --port6 $BN_P2P_PORT --enr-udp6-port $BN_P2P_PORT --quic-port6 ${BN_P2P_QUIC_PORT:-8001}" + fi + exec ${CMD} fi @@ -140,7 +144,11 @@ if [ "$CC_CLIENT" = "lodestar" ]; then else CMD="$CMD --enr.ip $EXTERNAL_IP --nat" fi - fi + fi + + if [ "$ENABLE_IPV6" = "true" ]; then + CMD="$CMD --listenAddress6 :: --port6 $BN_P2P_PORT" + fi if [ ! -z "$CHECKPOINT_SYNC_URL" ]; then CMD="$CMD --checkpointSyncUrl $CHECKPOINT_SYNC_URL" @@ -311,6 +319,15 @@ if [ "$CC_CLIENT" = "teku" ]; then CMD="$CMD --metrics-publish-endpoint=$BITFLY_NODE_METRICS_ENDPOINT?apikey=$BITFLY_NODE_METRICS_SECRET&machine=$BITFLY_NODE_METRICS_MACHINE_NAME" fi + if [ "$ENABLE_IPV6" = "true" ]; then + CMD="$CMD --p2p-interface=0.0.0.0,:: --p2p-port-ipv6=$BN_IPV6_P2P_PORT" + if [ ! -z "$EXTERNAL_IP" ]; then + if expr "$EXTERNAL_IP" : '.*:' >/dev/null; then + CMD="$CMD --p2p-advertised-ip=$EXTERNAL_IP" + fi + fi + fi + if [ "$TEKU_JVM_HEAP_SIZE" -gt "0" ]; then CMD="env JAVA_OPTS=\"-Xmx${TEKU_JVM_HEAP_SIZE}m\" $CMD" fi diff --git a/shared/services/rocketpool/assets/install/templates/alertmanager.tmpl b/shared/services/rocketpool/assets/install/templates/alertmanager.tmpl index 9f4544124..b4bbdb74c 100644 --- a/shared/services/rocketpool/assets/install/templates/alertmanager.tmpl +++ b/shared/services/rocketpool/assets/install/templates/alertmanager.tmpl @@ -21,5 +21,8 @@ services: - net networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} volumes: alertmanager-data: diff --git a/shared/services/rocketpool/assets/install/templates/api.tmpl b/shared/services/rocketpool/assets/install/templates/api.tmpl index 648d17d9d..77406c68d 100644 --- a/shared/services/rocketpool/assets/install/templates/api.tmpl +++ b/shared/services/rocketpool/assets/install/templates/api.tmpl @@ -28,3 +28,6 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} diff --git a/shared/services/rocketpool/assets/install/templates/commit-boost.tmpl b/shared/services/rocketpool/assets/install/templates/commit-boost.tmpl index 1e0393420..642958a67 100644 --- a/shared/services/rocketpool/assets/install/templates/commit-boost.tmpl +++ b/shared/services/rocketpool/assets/install/templates/commit-boost.tmpl @@ -29,3 +29,6 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} diff --git a/shared/services/rocketpool/assets/install/templates/eth1.tmpl b/shared/services/rocketpool/assets/install/templates/eth1.tmpl index 028960a92..9620f7437 100644 --- a/shared/services/rocketpool/assets/install/templates/eth1.tmpl +++ b/shared/services/rocketpool/assets/install/templates/eth1.tmpl @@ -66,5 +66,8 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} volumes: eth1clientdata: diff --git a/shared/services/rocketpool/assets/install/templates/eth2.tmpl b/shared/services/rocketpool/assets/install/templates/eth2.tmpl index 78cf7edbf..87dbad6aa 100644 --- a/shared/services/rocketpool/assets/install/templates/eth2.tmpl +++ b/shared/services/rocketpool/assets/install/templates/eth2.tmpl @@ -31,10 +31,24 @@ services: ports: - "{{$p2p}}:{{$p2p}}/udp" - "{{$p2p}}:{{$p2p}}/tcp" + {{- if .IsIPv6Enabled}} + - "[::]:{{$p2p}}:{{$p2p}}/udp" + - "[::]:{{$p2p}}:{{$p2p}}/tcp" + {{- end}} {{- if eq .ConsensusClient.String "lighthouse"}} - "{{.Lighthouse.P2pQuicPort}}:{{.Lighthouse.P2pQuicPort}}/udp" + {{- if .IsIPv6Enabled}} + - "[::]:{{.Lighthouse.P2pQuicPort}}:{{.Lighthouse.P2pQuicPort}}/udp" + {{- end}} {{- else if eq .ConsensusClient.String "prysm"}} - "{{.Prysm.P2pQuicPort}}:{{.Prysm.P2pQuicPort}}/udp" + {{- if .IsIPv6Enabled}} + - "[::]:{{.Prysm.P2pQuicPort}}:{{.Prysm.P2pQuicPort}}/udp" + {{- end}} + {{- end}} + {{- if and (eq .ConsensusClient.String "teku") .IsIPv6Enabled}} + - "{{.Teku.P2pIpv6Port}}:{{.Teku.P2pIpv6Port}}/udp" + - "{{.Teku.P2pIpv6Port}}:{{.Teku.P2pIpv6Port}}/tcp" {{- end}} {{- range $entry := .GetBnOpenPorts}} - "{{$entry}}" @@ -64,6 +78,7 @@ services: - ENABLE_METRICS={{.EnableMetrics}} - BN_METRICS_PORT={{.BnMetricsPort}} - EXTERNAL_IP={{.GetExternalIp}} + - ENABLE_IPV6={{.IsIPv6Enabled}} - CHECKPOINT_SYNC_URL={{.ConsensusCommon.CheckpointSyncProvider}} - DOPPELGANGER_DETECTION={{.IsDoppelgangerEnabled}} - BN_ADDITIONAL_FLAGS={{.GetBNAdditionalFlags}} @@ -80,6 +95,7 @@ services: {{- if eq .ConsensusClient.String "teku"}} - TEKU_JVM_HEAP_SIZE={{.Teku.JvmHeapSize}} - TEKU_ARCHIVE_MODE={{.Teku.ArchiveMode}} + - BN_IPV6_P2P_PORT={{.Teku.P2pIpv6Port}} {{- else if eq .ConsensusClient.String "prysm"}} - BN_RPC_PORT={{.Prysm.RpcPort}} - BN_P2P_QUIC_PORT={{.Prysm.P2pQuicPort}} @@ -105,5 +121,8 @@ services: {{- end}} networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} volumes: eth2clientdata: diff --git a/shared/services/rocketpool/assets/install/templates/exporter.tmpl b/shared/services/rocketpool/assets/install/templates/exporter.tmpl index f254922f9..182490a72 100644 --- a/shared/services/rocketpool/assets/install/templates/exporter.tmpl +++ b/shared/services/rocketpool/assets/install/templates/exporter.tmpl @@ -34,3 +34,6 @@ services: network_mode: host networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} diff --git a/shared/services/rocketpool/assets/install/templates/grafana.tmpl b/shared/services/rocketpool/assets/install/templates/grafana.tmpl index af983f657..db08d2486 100644 --- a/shared/services/rocketpool/assets/install/templates/grafana.tmpl +++ b/shared/services/rocketpool/assets/install/templates/grafana.tmpl @@ -23,5 +23,8 @@ services: - net networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} volumes: grafana-storage: diff --git a/shared/services/rocketpool/assets/install/templates/mev-boost.tmpl b/shared/services/rocketpool/assets/install/templates/mev-boost.tmpl index 5e8345be8..5bf52435d 100644 --- a/shared/services/rocketpool/assets/install/templates/mev-boost.tmpl +++ b/shared/services/rocketpool/assets/install/templates/mev-boost.tmpl @@ -30,3 +30,6 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} diff --git a/shared/services/rocketpool/assets/install/templates/node.tmpl b/shared/services/rocketpool/assets/install/templates/node.tmpl index 3f564e086..46385985f 100644 --- a/shared/services/rocketpool/assets/install/templates/node.tmpl +++ b/shared/services/rocketpool/assets/install/templates/node.tmpl @@ -26,3 +26,6 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} diff --git a/shared/services/rocketpool/assets/install/templates/prometheus.tmpl b/shared/services/rocketpool/assets/install/templates/prometheus.tmpl index dc5cfc13a..3f74e3952 100644 --- a/shared/services/rocketpool/assets/install/templates/prometheus.tmpl +++ b/shared/services/rocketpool/assets/install/templates/prometheus.tmpl @@ -28,5 +28,8 @@ services: - "host.docker.internal:host-gateway" networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} volumes: prometheus-data: diff --git a/shared/services/rocketpool/assets/install/templates/validator.tmpl b/shared/services/rocketpool/assets/install/templates/validator.tmpl index 302bee54d..b0bef7f13 100644 --- a/shared/services/rocketpool/assets/install/templates/validator.tmpl +++ b/shared/services/rocketpool/assets/install/templates/validator.tmpl @@ -58,3 +58,6 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}} diff --git a/shared/services/rocketpool/assets/install/templates/watchtower.tmpl b/shared/services/rocketpool/assets/install/templates/watchtower.tmpl index e412411b7..44a445c48 100644 --- a/shared/services/rocketpool/assets/install/templates/watchtower.tmpl +++ b/shared/services/rocketpool/assets/install/templates/watchtower.tmpl @@ -25,3 +25,6 @@ services: - no-new-privileges networks: net: + {{- if .IsIPv6Enabled}} + enable_ipv6: true + {{- end}}