From 3b374fb43179df72414ae766f70bcaeb7e429524 Mon Sep 17 00:00:00 2001 From: bussyjd Date: Thu, 13 Nov 2025 11:41:39 -0300 Subject: [PATCH 1/5] Enhance validator client type validation with actionable error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improves the validator client type validation error messages to provide better user guidance when invalid types are specified. Changes: - Add generic fuzzy matching for "did you mean" suggestions * Known typos map: loki→lodestar, prism→prysm, lighthose→lighthouse * Prefix matching: tek→teku, nim→nimbus, lodest→lodestar * Substring matching for partial matches - Provide actionable fix instructions showing: * CLI flag syntax: --set validatorClient.type= * values.yaml format with proper indentation * Custom values file approach - Include documentation reference to README.md - Use suggested type in examples when available Example error output: ERROR: Invalid validator client type 'loki'. Valid options: lighthouse, lodestar, teku, prysm, nimbus ⚠️ Did you mean 'lodestar'? How to fix this: • Using --set flag: --set validatorClient.type=lodestar • In your values.yaml file: validatorClient: type: lodestar Tested with all validator client types and various typos. All valid types (lighthouse, lodestar, teku, prysm, nimbus) still work correctly. Addresses user feedback from PR #148 that validation errors needed more actionable guidance. --- charts/dv-pod/templates/_helpers.tpl | 39 +++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/charts/dv-pod/templates/_helpers.tpl b/charts/dv-pod/templates/_helpers.tpl index 1305d76..219768a 100644 --- a/charts/dv-pod/templates/_helpers.tpl +++ b/charts/dv-pod/templates/_helpers.tpl @@ -156,7 +156,44 @@ Validate validator client type {{- $validTypes := list "lighthouse" "lodestar" "teku" "prysm" "nimbus" -}} {{- $currentType := .Values.validatorClient.type -}} {{- if not (has $currentType $validTypes) -}} -{{- fail (printf "ERROR: Invalid validator client type '%s'. Valid options are: %s" $currentType (join ", " $validTypes)) -}} +{{- $errorMsg := printf "\n\nERROR: Invalid validator client type '%s'.\n\nValid options: %s" $currentType (join ", " $validTypes) -}} +{{- /* Try to find the closest match using simple heuristics */ -}} +{{- $suggestion := "" -}} +{{- $currentLower := lower $currentType -}} +{{- /* Check for common typos and confusions */ -}} +{{- $typoMap := dict "loki" "lodestar" "lodestar-" "lodestar" "lighthose" "lighthouse" "lighthouse-" "lighthouse" "tekku" "teku" "teku-" "teku" "prisim" "prysm" "prism" "prysm" "prysm-" "prysm" "nimbos" "nimbus" "nimbus-" "nimbus" -}} +{{- if hasKey $typoMap $currentLower -}} +{{- $suggestion = get $typoMap $currentLower -}} +{{- else -}} +{{- /* Check for prefix matches (at least 2 characters) */ -}} +{{- range $validType := $validTypes -}} +{{- $validLower := lower $validType -}} +{{- if and (gt (len $currentLower) 1) (hasPrefix $validLower (substr 0 2 $currentLower)) -}} +{{- $suggestion = $validType -}} +{{- end -}} +{{- if and (gt (len $currentLower) 2) (hasPrefix $validLower (substr 0 3 $currentLower)) -}} +{{- $suggestion = $validType -}} +{{- end -}} +{{- /* Check if valid type contains the input or vice versa */ -}} +{{- if and (gt (len $currentLower) 2) (contains $validLower $currentLower) -}} +{{- $suggestion = $validType -}} +{{- end -}} +{{- if and (gt (len $currentLower) 2) (contains $currentLower $validLower) -}} +{{- $suggestion = $validType -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{- /* Add suggestion to error message if found */ -}} +{{- if $suggestion -}} +{{- $errorMsg = printf "%s\n\n⚠️ Did you mean '%s'?" $errorMsg $suggestion -}} +{{- end -}} +{{- /* Use suggestion if available, otherwise use lodestar as example */ -}} +{{- $exampleType := "lodestar" -}} +{{- if $suggestion -}} +{{- $exampleType = $suggestion -}} +{{- end -}} +{{- $errorMsg = printf "%s\n\nHow to fix this:\n • Using --set flag:\n --set validatorClient.type=%s\n\n • In your values.yaml file:\n validatorClient:\n type: %s\n\n • Using custom values file:\n helm install my-dv-pod obol/dv-pod -f myvalues.yaml\n\nFor more information, see the Validator Client section in charts/dv-pod/README.md\n" $errorMsg $exampleType $exampleType -}} +{{- fail $errorMsg -}} {{- end -}} {{- end -}} {{- end -}} From 47e770322fc9713083ec40123418ebd526666ab2 Mon Sep 17 00:00:00 2001 From: bussyjd Date: Thu, 13 Nov 2025 12:00:43 -0300 Subject: [PATCH 2/5] Fix FIPS 140 mode compatibility in ENR job kubectl commands Adds --validate=false flag to kubectl commands in the ENR job to prevent validation errors when running in FIPS 140-only mode environments. Issue: When the ENR generation job runs in FIPS 140-only mode, kubectl validation fails with error: "crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode" This occurs during: 1. kubectl apply when creating new ENR secrets 2. kubectl patch when updating existing secrets with missing ENR field Solution: Add --validate=false flag to both kubectl commands (lines 210, 226): - kubectl patch: --validate=false flag added - kubectl apply: --validate=false flag added The GODEBUG environment variable (x509sha1=1,tls13=0) is already set for the kubectl-secret-creator container, but validation needs to be explicitly disabled for kubectl operations in FIPS mode. This allows the ENR job to complete successfully in FIPS-compliant Kubernetes clusters while maintaining the same functional behavior. --- charts/dv-pod/templates/hooks-enr-job.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/dv-pod/templates/hooks-enr-job.yaml b/charts/dv-pod/templates/hooks-enr-job.yaml index 6fd1c8e..7db3ff4 100644 --- a/charts/dv-pod/templates/hooks-enr-job.yaml +++ b/charts/dv-pod/templates/hooks-enr-job.yaml @@ -207,7 +207,7 @@ spec: if [ -f /enr-shared/generate-enr-only ]; then echo "INFO: Adding missing public ENR field to existing secret '$SECRET_NAME'..." # Use kubectl patch to add only the missing field - kubectl patch secret "${SECRET_NAME}" -n "${NAMESPACE}" --type='merge' -p="{\"data\":{\"${ENR_PUBLIC_ADDRESS_DATA_NAME}\":\"$(echo -n "$PUBLIC_ENR" | base64 -w 0)\"}}" + kubectl patch secret "${SECRET_NAME}" -n "${NAMESPACE}" --type='merge' --validate=false -p="{\"data\":{\"${ENR_PUBLIC_ADDRESS_DATA_NAME}\":\"$(echo -n "$PUBLIC_ENR" | base64 -w 0)\"}}" echo "Secret '$SECRET_NAME' updated with missing ENR field successfully." else # Check again if the secret already exists (race condition protection) @@ -223,7 +223,7 @@ spec: --namespace="${NAMESPACE}" \ --from-literal=charon-enr-private-key="${PRIVATE_KEY}" \ --from-literal=enr="${PUBLIC_ENR}" \ - --dry-run=client -o yaml | kubectl apply -f - + --dry-run=client -o yaml | kubectl apply --validate=false -f - echo "Secret '$SECRET_NAME' created successfully." fi From 54bc95f16aba362e0c6af60b378e347f4f91c027 Mon Sep 17 00:00:00 2001 From: bussyjd Date: Thu, 13 Nov 2025 12:11:11 -0300 Subject: [PATCH 3/5] docs(dv-pod): improve Helm commands and migrate to network parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit includes several documentation and usability improvements: 1. Migrate from chainId to network parameter (breaking change) - Replace all chainId references with network parameter in docs - Update QUICKSTART.md examples: chainId=1 → network=mainnet - Update values-examples to use network instead of chainId - Templates already supported network-based helpers 2. Update all Helm commands to use 'helm upgrade --install' - Updated 8+ instances in README.md - Provides idempotent commands for both install and upgrade scenarios - Better user experience and less confusion 3. Add Challenge & Testing documentation - New comprehensive section in QUICKSTART.md - Examples for overriding API endpoints (dev/staging) - Examples for using specific DKG sidecar commits/branches - Complete challenge example with all parameters - Helpful for testing and development workflows 4. Implement intelligent fallback beacon node endpoints - Auto-select publicnode.com endpoints based on network - mainnet → ethereum-beacon-api.publicnode.com - sepolia → ethereum-sepolia-beacon-api.publicnode.com - hoodi → ethereum-hoodi-beacon-api.publicnode.com - Pods can now start without manual fallback configuration - Users can still override with custom endpoints Files modified: - charts/dv-pod/QUICKSTART.md - charts/dv-pod/README.md - charts/dv-pod/README.md.gotmpl - charts/dv-pod/templates/_helpers.tpl - charts/dv-pod/templates/statefulset.yaml - charts/dv-pod/values-examples/with-target-config-hash.yaml - charts/dv-pod/values.yaml BREAKING CHANGE: Users must now use --set network=mainnet instead of --set chainId=1 --- charts/dv-pod/QUICKSTART.md | 83 ++++++++++++++++--- charts/dv-pod/README.md | 24 +++--- charts/dv-pod/README.md.gotmpl | 22 ++--- charts/dv-pod/templates/_helpers.tpl | 10 +++ charts/dv-pod/templates/statefulset.yaml | 5 +- .../with-target-config-hash.yaml | 2 +- charts/dv-pod/values.yaml | 6 +- 7 files changed, 115 insertions(+), 37 deletions(-) diff --git a/charts/dv-pod/QUICKSTART.md b/charts/dv-pod/QUICKSTART.md index efbb4db..61581d4 100644 --- a/charts/dv-pod/QUICKSTART.md +++ b/charts/dv-pod/QUICKSTART.md @@ -20,7 +20,7 @@ Each operator deploys their node: ```bash helm upgrade --install my-dv-pod charts/dv-pod/ \ --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS \ - --set chainId=1 \ + --set network=mainnet \ --namespace=dv-pod \ --timeout=10m --create-namespace ``` @@ -122,7 +122,7 @@ Expected output: `["charon-enr-private-key", "enr"]` helm upgrade --install my-dv-pod charts/dv-pod/ \ --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS \ --set charon.dkgSidecar.targetConfigHash=0xYOUR_CONFIG_HASH \ - --set chainId=1 \ + --set network=mainnet \ --set 'charon.beaconNodeEndpoints[0]=http://YOUR_BEACON_NODE:5052' \ --set charon.enr.existingSecret.name=charon-enr-private-key \ --namespace=dv-pod \ @@ -156,16 +156,13 @@ kubectl exec -n dv-pod my-dv-pod-dv-pod-0 -- ls -la /charon-data/cluster-lock.js ```bash # Mainnet (default) ---set chainId=1 +--set network=mainnet # Sepolia testnet ---set chainId=11155111 +--set network=sepolia # Hoodi testnet ---set chainId=560048 - -# Gnosis Chain ---set chainId=100 +--set network=hoodi ``` ### Custom DKG Sidecar Image @@ -198,8 +195,7 @@ kubectl exec -n dv-pod my-dv-pod-dv-pod-0 -- ls -la /charon-data/cluster-lock.js --set validatorClient.type=teku # Prysm ---set validatorClient.type=prysm \ ---set validatorClient.config.prysm.acceptTermsOfUse=true +--set validatorClient.type=prysm # Lodestar --set validatorClient.type=lodestar @@ -293,6 +289,73 @@ kubectl port-forward -n dv-pod my-dv-pod-dv-pod-0 3620:3620 --- +## Challenge & Testing Environments + +For testing, development, or challenge environments, you may need to override the default API endpoint or use a specific DKG sidecar version. + +### Override API Endpoint + +To point to a different Obol API (e.g., dev, staging, or local): + +```bash +# Using development API +helm upgrade --install my-dv-pod charts/dv-pod/ \ + --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS \ + --set charon.dkgSidecar.apiEndpoint=https://obol-api-nonprod-dev.dev.obol.tech \ + --set network=hoodi \ + --namespace=dv-pod \ + --timeout=10m --create-namespace + +# Using local API for development +helm upgrade --install my-dv-pod charts/dv-pod/ \ + --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS \ + --set charon.dkgSidecar.apiEndpoint=http://localhost:3000 \ + --set network=hoodi \ + --namespace=dv-pod \ + --timeout=10m --create-namespace +``` + +### Use Specific DKG Sidecar Commit + +To test with a specific DKG sidecar commit or branch: + +```bash +# Using a specific commit SHA +helm upgrade --install my-dv-pod charts/dv-pod/ \ + --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS \ + --set charon.dkgSidecar.image.tag=90a1656 \ + --set charon.dkgSidecar.image.pullPolicy=Always \ + --set network=hoodi \ + --namespace=dv-pod \ + --timeout=10m --create-namespace + +### Complete Challenge Example + +Full example combining custom API endpoint, specific DKG sidecar commit, and hoodi testnet: + +```bash +helm upgrade --install challenge-dv-pod charts/dv-pod/ \ + --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS \ + --set network=hoodi \ + --set 'charon.fallbackBeaconNodeEndpoints[0]=https://ethereum-hoodi-beacon-api.publicnode.com' \ + --set charon.dkgSidecar.apiEndpoint=https://obol-api-nonprod-dev.dev.obol.tech \ + --set charon.dkgSidecar.image.tag=90a1656 \ + --set charon.dkgSidecar.image.pullPolicy=Always \ + --set validatorClient.type=prysm \ + --set centralMonitoring.enabled=true \ + --set-string centralMonitoring.token='YOUR_MONITORING_TOKEN' \ + --namespace=dv-pod \ + --timeout=10m --create-namespace +``` + +**Key Parameters for Challenges:** +- `network=hoodi` - Use Hoodi testnet for testing +- `charon.dkgSidecar.apiEndpoint` - Point to dev/staging API +- `charon.dkgSidecar.image.tag` - Specific commit SHA or branch name +- `charon.dkgSidecar.image.pullPolicy=Always` - Force pull latest image + +--- + ## Next Steps After successful DKG: diff --git a/charts/dv-pod/README.md b/charts/dv-pod/README.md index c102925..50596aa 100644 --- a/charts/dv-pod/README.md +++ b/charts/dv-pod/README.md @@ -66,7 +66,7 @@ kubectl create secret generic validator-keys \ kubectl create configmap cluster-lock --from-file=cluster/node0/cluster-lock.json # Install the chart, referencing your ConfigMap and Secrets -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.clusterLock=cluster-lock \ --set validatorClient.keystores.secretName=validator-keys ``` @@ -102,7 +102,7 @@ kubectl create configmap cluster-lock \ --from-file=.charon/cluster-lock.json # Install the chart -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.clusterLock=cluster-lock \ --set validatorClient.keystores.secretName=validator-keys ``` @@ -119,7 +119,7 @@ If you don't have pre-existing artifacts, the chart can automatically: Simply deploy the chart with your operator address: ```sh -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS ``` @@ -168,13 +168,13 @@ validatorClient: - --suggested-fee-recipient=0xYOUR_FEE_RECIPIENT_ADDRESS ``` -With a `helm install` command for pre-existing artifacts. +With a `helm upgrade --install` command for pre-existing artifacts. ```sh -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.clusterLock=cluster-lock \ --set validatorClient.keystores.secretName=validator-keys \ - --set validatorClient.type=prysm --set validatorClient.config.prysm.acceptTermsOfUse=true + --set validatorClient.type=prysm ``` > [!NOTE] @@ -197,7 +197,7 @@ kubectl create secret generic validator-keys \ --from-file=keystore-1.txt # Deploy the chart with the keystore secret -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set validatorClient.keystores.secretName=validator-keys \ --set configMaps.clusterLock=my-cluster-lock ``` @@ -225,11 +225,11 @@ The ENR (Ethereum Node Record) secret **MUST** be created in the same namespace ```bash # Wrong approach - secret and chart in different namespaces kubectl create secret generic charon-enr-private-key -n dv-pod --from-literal=... -helm install my-dv-pod obol/dv-pod # Installs in default namespace - ENR will be regenerated! +helm upgrade --install my-dv-pod obol/dv-pod # Installs in default namespace - ENR will be regenerated! # Correct approach - both in same namespace kubectl create secret generic charon-enr-private-key -n dv-pod --from-literal=... -helm install my-dv-pod obol/dv-pod -n dv-pod # Both in dv-pod namespace +helm upgrade --install my-dv-pod obol/dv-pod -n dv-pod # Both in dv-pod namespace ``` ## Advanced Usage @@ -276,7 +276,7 @@ In this case, you have two options: 2. Install the chart with the lockHash value: ```sh - helm install my-dv-pod obol/dv-pod \ + helm upgrade --install my-dv-pod obol/dv-pod \ --set charon.lockHash=$LOCK_HASH \ --set charon.operatorAddress= ``` @@ -292,7 +292,7 @@ In this case, you have two options: 2. Install the chart referencing the ConfigMap: ```sh - helm install my-dv-pod obol/dv-pod \ + helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.lockHash=cluster-lock-hash \ --set charon.operatorAddress= ``` @@ -344,7 +344,7 @@ The command removes all the Kubernetes components associated with the chart and | charon.enr.privateKey | string | `""` | Provide the ENR private key directly (hex format, e.g., 0x...). If set, 'generate' and 'existingSecret' are ignored. | | charon.enrJob.enabled | bool | `true` | Enable or disable the Kubernetes Job that generates/manages the ENR. Note: This is typically not needed as the job automatically detects existing secrets. The job will check if the ENR secret already exists and skip generation if found. Only set to false for advanced use cases where you need to completely disable the job. | | charon.executionClientRpcEndpoint | string | `""` | Optional: Execution client RPC endpoint URL (e.g., your Ethereum execution client) Note: Charon currently only supports a single execution endpoint This is only needed if an operator in the cluster uses a smart contract wallet for an operator signature. If that does not apply to this cluster, this field can be left unset. | -| charon.fallbackBeaconNodeEndpoints | list | `["https://ethereum-beacon-api.publicnode.com"]` | Fallback beacon node endpoints (optional) These will be used if the primary beaconNodeEndpoints are unavailable | +| charon.fallbackBeaconNodeEndpoints | list | `["https://ethereum-beacon-api.publicnode.com"]` | Fallback beacon node endpoints (optional) These will be used if the primary beaconNodeEndpoints are unavailable If not specified, intelligent defaults based on network will be used: - mainnet: https://ethereum-beacon-api.publicnode.com - sepolia: https://ethereum-sepolia-beacon-api.publicnode.com - hoodi: https://ethereum-hoodi-beacon-api.publicnode.com | | charon.featureSet | string | `"stable"` | Minimum feature set to enable by default: alpha, beta, or stable. Warning: modify at own risk. (default "stable") | | charon.featureSetDisable | string | `""` | Comma-separated list of features to disable, overriding the default minimum feature set. | | charon.featureSetEnable | string | `""` | Comma-separated list of features to enable, overriding the default minimum feature set. | diff --git a/charts/dv-pod/README.md.gotmpl b/charts/dv-pod/README.md.gotmpl index 4f0d20c..334e27b 100644 --- a/charts/dv-pod/README.md.gotmpl +++ b/charts/dv-pod/README.md.gotmpl @@ -67,7 +67,7 @@ kubectl create secret generic validator-keys \ kubectl create configmap cluster-lock --from-file=cluster/node0/cluster-lock.json # Install the chart, referencing your ConfigMap and Secrets -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.clusterLock=cluster-lock \ --set validatorClient.keystores.secretName=validator-keys ``` @@ -103,7 +103,7 @@ kubectl create configmap cluster-lock \ --from-file=.charon/cluster-lock.json # Install the chart -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.clusterLock=cluster-lock \ --set validatorClient.keystores.secretName=validator-keys ``` @@ -121,7 +121,7 @@ If you don't have pre-existing artifacts, the chart can automatically: Simply deploy the chart with your operator address: ```sh -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set charon.operatorAddress=0xYOUR_OPERATOR_ADDRESS ``` @@ -170,13 +170,13 @@ validatorClient: - --suggested-fee-recipient=0xYOUR_FEE_RECIPIENT_ADDRESS ``` -With a `helm install` command for pre-existing artifacts. +With a `helm upgrade --install` command for pre-existing artifacts. ```sh -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.clusterLock=cluster-lock \ --set validatorClient.keystores.secretName=validator-keys \ - --set validatorClient.type=prysm --set validatorClient.config.prysm.acceptTermsOfUse=true + --set validatorClient.type=prysm ``` > [!NOTE] @@ -199,7 +199,7 @@ kubectl create secret generic validator-keys \ --from-file=keystore-1.txt # Deploy the chart with the keystore secret -helm install my-dv-pod obol/dv-pod \ +helm upgrade --install my-dv-pod obol/dv-pod \ --set validatorClient.keystores.secretName=validator-keys \ --set configMaps.clusterLock=my-cluster-lock ``` @@ -227,11 +227,11 @@ The ENR (Ethereum Node Record) secret **MUST** be created in the same namespace ```bash # Wrong approach - secret and chart in different namespaces kubectl create secret generic charon-enr-private-key -n dv-pod --from-literal=... -helm install my-dv-pod obol/dv-pod # Installs in default namespace - ENR will be regenerated! +helm upgrade --install my-dv-pod obol/dv-pod # Installs in default namespace - ENR will be regenerated! # Correct approach - both in same namespace kubectl create secret generic charon-enr-private-key -n dv-pod --from-literal=... -helm install my-dv-pod obol/dv-pod -n dv-pod # Both in dv-pod namespace +helm upgrade --install my-dv-pod obol/dv-pod -n dv-pod # Both in dv-pod namespace ``` ## Advanced Usage @@ -278,7 +278,7 @@ In this case, you have two options: 2. Install the chart with the lockHash value: ```sh - helm install my-dv-pod obol/dv-pod \ + helm upgrade --install my-dv-pod obol/dv-pod \ --set charon.lockHash=$LOCK_HASH \ --set charon.operatorAddress= ``` @@ -294,7 +294,7 @@ In this case, you have two options: 2. Install the chart referencing the ConfigMap: ```sh - helm install my-dv-pod obol/dv-pod \ + helm upgrade --install my-dv-pod obol/dv-pod \ --set configMaps.lockHash=cluster-lock-hash \ --set charon.operatorAddress= ``` diff --git a/charts/dv-pod/templates/_helpers.tpl b/charts/dv-pod/templates/_helpers.tpl index 1305d76..0fd65b0 100644 --- a/charts/dv-pod/templates/_helpers.tpl +++ b/charts/dv-pod/templates/_helpers.tpl @@ -141,10 +141,20 @@ Create comma-separated list of primary beacon node endpoints {{/* Create comma-separated list of fallback beacon node endpoints +Returns user-specified endpoints or intelligent defaults based on network */}} {{- define "dv-pod.fallbackBeaconNodeEndpoints" -}} {{- if .Values.charon.fallbackBeaconNodeEndpoints -}} {{- join "," .Values.charon.fallbackBeaconNodeEndpoints -}} +{{- else -}} +{{- $network := .Values.network -}} +{{- if eq $network "mainnet" -}} +https://ethereum-beacon-api.publicnode.com +{{- else if eq $network "sepolia" -}} +https://ethereum-sepolia-beacon-api.publicnode.com +{{- else if eq $network "hoodi" -}} +https://ethereum-hoodi-beacon-api.publicnode.com +{{- end -}} {{- end -}} {{- end -}} diff --git a/charts/dv-pod/templates/statefulset.yaml b/charts/dv-pod/templates/statefulset.yaml index bbf48a4..827d90c 100644 --- a/charts/dv-pod/templates/statefulset.yaml +++ b/charts/dv-pod/templates/statefulset.yaml @@ -517,8 +517,9 @@ spec: {{- if and .Values.charon.beaconNodeHeaders (not .Values.charon.beaconNodeHeadersSecretName) }} --beacon-node-headers={{ .Values.charon.beaconNodeHeaders | quote }} {{- end }} - {{- if .Values.charon.fallbackBeaconNodeEndpoints }} - --fallback-beacon-node-endpoints={{ include "dv-pod.fallbackBeaconNodeEndpoints" . }} + {{- $fallbackEndpoints := include "dv-pod.fallbackBeaconNodeEndpoints" . }} + {{- if $fallbackEndpoints }} + --fallback-beacon-node-endpoints={{ $fallbackEndpoints }} {{- end }} {{- if .Values.charon.lockFile }} --lock-file={{ .Values.charon.lockFile }} diff --git a/charts/dv-pod/values-examples/with-target-config-hash.yaml b/charts/dv-pod/values-examples/with-target-config-hash.yaml index b25e9b7..10465af 100644 --- a/charts/dv-pod/values-examples/with-target-config-hash.yaml +++ b/charts/dv-pod/values-examples/with-target-config-hash.yaml @@ -42,4 +42,4 @@ charon: retryDelayFactor: 2 # Other standard configurations -chainId: "11155111" # Sepolia +network: sepolia diff --git a/charts/dv-pod/values.yaml b/charts/dv-pod/values.yaml index fbc4aad..6b21332 100644 --- a/charts/dv-pod/values.yaml +++ b/charts/dv-pod/values.yaml @@ -46,8 +46,12 @@ charon: # -- Fallback beacon node endpoints (optional) # These will be used if the primary beaconNodeEndpoints are unavailable + # If not specified, intelligent defaults based on network will be used: + # - mainnet: https://ethereum-beacon-api.publicnode.com + # - sepolia: https://ethereum-sepolia-beacon-api.publicnode.com + # - hoodi: https://ethereum-hoodi-beacon-api.publicnode.com fallbackBeaconNodeEndpoints: - # Example: + # Example for custom fallback endpoints: - "https://ethereum-beacon-api.publicnode.com" # - "http://backup-beacon-2:5052" From 4d535fee3cbe2ef7436b6ff78d1272616118c7e9 Mon Sep 17 00:00:00 2001 From: bussyjd Date: Mon, 12 Jan 2026 14:37:19 +0400 Subject: [PATCH 4/5] fix: use proximity detection instead of hardcoded typo list Replace the hardcoded typoMap with dynamic proximity detection: - Check if input shares 3-char prefix with valid types - Check if input contains or is contained by valid type This is more maintainable and catches typos automatically without needing to maintain a list of known typos. --- charts/dv-pod/templates/_helpers.tpl | 39 ++++++++++++---------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/charts/dv-pod/templates/_helpers.tpl b/charts/dv-pod/templates/_helpers.tpl index ea317e4..04420d9 100644 --- a/charts/dv-pod/templates/_helpers.tpl +++ b/charts/dv-pod/templates/_helpers.tpl @@ -167,40 +167,33 @@ Validate validator client type {{- $currentType := .Values.validatorClient.type -}} {{- if not (has $currentType $validTypes) -}} {{- $errorMsg := printf "\n\nERROR: Invalid validator client type '%s'.\n\nValid options: %s" $currentType (join ", " $validTypes) -}} -{{- /* Try to find the closest match using simple heuristics */ -}} -{{- $suggestion := "" -}} +{{- /* Try to find the closest match using proximity detection */ -}} {{- $currentLower := lower $currentType -}} -{{- /* Check for common typos and confusions */ -}} -{{- $typoMap := dict "loki" "lodestar" "lodestar-" "lodestar" "lighthose" "lighthouse" "lighthouse-" "lighthouse" "tekku" "teku" "teku-" "teku" "prisim" "prysm" "prism" "prysm" "prysm-" "prysm" "nimbos" "nimbus" "nimbus-" "nimbus" -}} -{{- if hasKey $typoMap $currentLower -}} -{{- $suggestion = get $typoMap $currentLower -}} -{{- else -}} -{{- /* Check for prefix matches (at least 2 characters) */ -}} +{{- $ctx := dict "suggestion" "" -}} {{- range $validType := $validTypes -}} {{- $validLower := lower $validType -}} -{{- if and (gt (len $currentLower) 1) (hasPrefix $validLower (substr 0 2 $currentLower)) -}} -{{- $suggestion = $validType -}} -{{- end -}} -{{- if and (gt (len $currentLower) 2) (hasPrefix $validLower (substr 0 3 $currentLower)) -}} -{{- $suggestion = $validType -}} -{{- end -}} -{{- /* Check if valid type contains the input or vice versa */ -}} -{{- if and (gt (len $currentLower) 2) (contains $validLower $currentLower) -}} -{{- $suggestion = $validType -}} +{{- /* Check if they share at least 3 character prefix */ -}} +{{- $minLen := min (len $currentLower) (len $validLower) -}} +{{- if ge $minLen 3 -}} +{{- $inputPrefix := substr 0 3 $currentLower -}} +{{- $validPrefix := substr 0 3 $validLower -}} +{{- if eq $inputPrefix $validPrefix -}} +{{- $_ := set $ctx "suggestion" $validType -}} {{- end -}} -{{- if and (gt (len $currentLower) 2) (contains $currentLower $validLower) -}} -{{- $suggestion = $validType -}} {{- end -}} +{{- /* Check if one contains the other */ -}} +{{- if or (contains $currentLower $validLower) (contains $validLower $currentLower) -}} +{{- $_ := set $ctx "suggestion" $validType -}} {{- end -}} {{- end -}} {{- /* Add suggestion to error message if found */ -}} -{{- if $suggestion -}} -{{- $errorMsg = printf "%s\n\n⚠️ Did you mean '%s'?" $errorMsg $suggestion -}} +{{- if $ctx.suggestion -}} +{{- $errorMsg = printf "%s\n\n⚠️ Did you mean '%s'?" $errorMsg $ctx.suggestion -}} {{- end -}} {{- /* Use suggestion if available, otherwise use lodestar as example */ -}} {{- $exampleType := "lodestar" -}} -{{- if $suggestion -}} -{{- $exampleType = $suggestion -}} +{{- if $ctx.suggestion -}} +{{- $exampleType = $ctx.suggestion -}} {{- end -}} {{- $errorMsg = printf "%s\n\nHow to fix this:\n • Using --set flag:\n --set validatorClient.type=%s\n\n • In your values.yaml file:\n validatorClient:\n type: %s\n\n • Using custom values file:\n helm install my-dv-pod obol/dv-pod -f myvalues.yaml\n\nFor more information, see the Validator Client section in charts/dv-pod/README.md\n" $errorMsg $exampleType $exampleType -}} {{- fail $errorMsg -}} From 0f765efa2c0b84997328e93f0f92f2baa869a790 Mon Sep 17 00:00:00 2001 From: bussyjd Date: Mon, 12 Jan 2026 14:48:36 +0400 Subject: [PATCH 5/5] chore: regenerate README.md files with helm-docs --- charts/charon-cluster/README.md | 4 ++-- charts/charon/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/charon-cluster/README.md b/charts/charon-cluster/README.md index cab27d8..5b9473d 100755 --- a/charts/charon-cluster/README.md +++ b/charts/charon-cluster/README.md @@ -2,7 +2,7 @@ Charon Cluster =========== -![Version: 0.3.10](https://img.shields.io/badge/Version-0.3.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.7.1](https://img.shields.io/badge/AppVersion-1.7.1-informational?style=flat-square) +![Version: 0.3.12](https://img.shields.io/badge/Version-0.3.12-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.8.1](https://img.shields.io/badge/AppVersion-1.8.1-informational?style=flat-square) Charon is an open-source Ethereum Distributed validator middleware written in golang. This chart deploys a full Charon cluster. @@ -52,7 +52,7 @@ Charon is an open-source Ethereum Distributed validator middleware written in go | config.validatorApiAddress | string | `"0.0.0.0:3600"` | Listening address (ip and port) for validator-facing traffic proxying the beacon-node API. (default "127.0.0.1:3600") | | containerSecurityContext | object | See `values.yaml` | The security context for containers | | fullnameOverride | string | `""` | Provide a name to substitute for the full names of resources | -| image | object | `{"pullPolicy":"IfNotPresent","repository":"obolnetwork/charon","tag":"v1.7.1"}` | Charon image repository, pull policy, and tag version | +| image | object | `{"pullPolicy":"IfNotPresent","repository":"obolnetwork/charon","tag":"v1.8.1"}` | Charon image repository, pull policy, and tag version | | imagePullSecrets | list | `[]` | Credentials to fetch images from private registry # ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ | | livenessProbe | object | `{"enabled":false,"httpGet":{"path":"/livez"},"initialDelaySeconds":10,"periodSeconds":5}` | Configure liveness probes # ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | | nameOverride | string | `""` | Provide a name in place of lighthouse for `app:` labels | diff --git a/charts/charon/README.md b/charts/charon/README.md index a0d86ee..4abdbff 100755 --- a/charts/charon/README.md +++ b/charts/charon/README.md @@ -2,7 +2,7 @@ Charon =========== -![Version: 0.4.10](https://img.shields.io/badge/Version-0.4.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.7.1](https://img.shields.io/badge/AppVersion-1.7.1-informational?style=flat-square) +![Version: 0.4.12](https://img.shields.io/badge/Version-0.4.12-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.8.1](https://img.shields.io/badge/AppVersion-1.8.1-informational?style=flat-square) Charon is an open-source Ethereum Distributed validator middleware written in golang. @@ -56,7 +56,7 @@ Charon is an open-source Ethereum Distributed validator middleware written in go | extraVolumes | list | `[]` | Additional volumes | | fullnameOverride | string | `""` | Provide a name to substitute for the full names of resources | | httpPort | int | `3600` | HTTP Port | -| image | object | `{"pullPolicy":"IfNotPresent","repository":"obolnetwork/charon","tag":"v1.7.1"}` | Charon image repository, pull policy, and tag version | +| image | object | `{"pullPolicy":"IfNotPresent","repository":"obolnetwork/charon","tag":"v1.8.1"}` | Charon image repository, pull policy, and tag version | | imagePullSecrets | list | `[]` | Credentials to fetch images from private registry # ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ | | initContainers | list | `[]` | Additional init containers | | jaegerPort | int | `6831` | Jaeger Port |