Skip to content
Open
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
83 changes: 73 additions & 10 deletions charts/dv-pod/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -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 \
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
24 changes: 12 additions & 12 deletions charts/dv-pod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -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
```
Expand All @@ -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
```

Expand Down Expand Up @@ -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]
Expand All @@ -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
```
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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=<YOUR_OPERATOR_ADDRESS>
```
Expand All @@ -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=<YOUR_OPERATOR_ADDRESS>
```
Expand Down Expand Up @@ -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. |
Expand Down
22 changes: 11 additions & 11 deletions charts/dv-pod/README.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -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
```
Expand All @@ -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
```

Expand Down Expand Up @@ -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]
Expand All @@ -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
```
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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=<YOUR_OPERATOR_ADDRESS>
```
Expand All @@ -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=<YOUR_OPERATOR_ADDRESS>
```
Expand Down
49 changes: 48 additions & 1 deletion charts/dv-pod/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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 -}}

Expand All @@ -156,7 +166,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 -}}
Expand Down
4 changes: 2 additions & 2 deletions charts/dv-pod/templates/hooks-enr-job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions charts/dv-pod/templates/statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
Loading