Skip to content

Commit 3c11289

Browse files
committed
Fixed replace-operator flow
1 parent cb9be72 commit 3c11289

4 files changed

Lines changed: 41 additions & 125 deletions

File tree

.claude/skills/replace-operator/SKILL.md

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ After completion, the script will print commands to start containers manually. R
5151

5252
**Script**: `scripts/edit/replace-operator/new-operator.sh`
5353

54-
This is a **three-step process**:
54+
This is a **two-step process**:
5555

5656
#### Step 1: Generate ENR
5757

@@ -79,14 +79,9 @@ After receiving the current `cluster-lock.json` from remaining operators (BEFORE
7979

8080
The new operator runs this **at the same time** as the remaining operators run their ceremony. All operators must participate together.
8181

82-
#### Step 3: Install New Cluster Lock
82+
After the ceremony completes, the script automatically:
83+
- Backs up the old `.charon` directory
84+
- Moves the output directory to `.charon` (contains complete configuration)
85+
- Prints commands to start containers
8386

84-
After the ceremony completes, install the new cluster-lock:
85-
86-
```bash
87-
./scripts/edit/replace-operator/new-operator.sh \
88-
--install-lock ./output/cluster-lock.json \
89-
[--dry-run]
90-
```
91-
92-
The script will verify the ENR is present in the cluster-lock, install the configuration, and print commands to start containers manually. Note: the new operator does NOT have slashing protection history (fresh start).
87+
Note: the new operator does NOT have slashing protection history (fresh start).

scripts/edit/replace-operator/README.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Automates the complete workflow for operators staying in the cluster:
6060

6161
## For New Operators
6262

63-
Three-step workflow for the new operator joining the cluster.
63+
Two-step workflow for the new operator joining the cluster.
6464

6565
**Step 1:** Generate ENR and share with remaining operators:
6666

@@ -76,19 +76,14 @@ Three-step workflow for the new operator joining the cluster.
7676
--old-enr "enr:-..."
7777
```
7878

79-
**Step 3:** After the ceremony completes, install the new cluster-lock:
80-
81-
```bash
82-
./scripts/edit/replace-operator/new-operator.sh --install-lock ./output/cluster-lock.json
83-
```
79+
After the ceremony completes, the script automatically backs up the old `.charon` directory and installs the new configuration from the output directory.
8480

8581
### Options
8682

8783
| Option | Required | Description |
8884
|--------|----------|-------------|
8985
| `--cluster-lock <path>` | No | Path to cluster-lock.json (for ceremony) |
9086
| `--old-enr <enr>` | No | ENR of the operator being replaced (for ceremony) |
91-
| `--install-lock <path>` | No | Install the new cluster-lock after ceremony |
9287
| `--generate-enr` | No | Generate new ENR private key |
9388
| `--dry-run` | No | Preview without executing |
9489
| `-h, --help` | No | Show help message |

scripts/edit/replace-operator/new-operator.sh

Lines changed: 24 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Replace-Operator Script for NEW Operator - See README.md for documentation
44
# The new operator participates in the ceremony together with remaining operators.
5+
# Both run the same `charon alpha edit replace-operator` command.
56

67
set -euo pipefail
78

@@ -11,7 +12,6 @@ cd "$REPO_ROOT"
1112

1213
# Default values
1314
CLUSTER_LOCK_PATH=""
14-
INSTALL_LOCK_PATH=""
1515
OLD_ENR=""
1616
GENERATE_ENR=false
1717
DRY_RUN=false
@@ -38,11 +38,11 @@ Usage: ./scripts/edit/replace-operator/new-operator.sh [OPTIONS]
3838
3939
Helps a new operator join an existing cluster by participating in the
4040
replace-operator ceremony together with the remaining operators.
41+
Both remaining and new operators run the same ceremony command.
4142
4243
Options:
4344
--cluster-lock <path> Path to the current cluster-lock.json (for ceremony)
4445
--old-enr <enr> ENR of the operator being replaced (for ceremony)
45-
--install-lock <path> Install the new cluster-lock after ceremony
4646
--generate-enr Generate a new ENR private key if not present
4747
--dry-run Show what would be done without executing
4848
-h, --help Show this help message
@@ -56,9 +56,6 @@ Examples:
5656
--cluster-lock ./received-cluster-lock.json \
5757
--old-enr "enr:-..."
5858
59-
# Step 3: Install the new cluster-lock after ceremony completes
60-
./scripts/edit/replace-operator/new-operator.sh --install-lock ./output/cluster-lock.json
61-
6259
Prerequisites:
6360
- .env file with NETWORK and VC variables set
6461
- For --generate-enr: Docker installed
@@ -74,10 +71,6 @@ while [[ $# -gt 0 ]]; do
7471
CLUSTER_LOCK_PATH="$2"
7572
shift 2
7673
;;
77-
--install-lock)
78-
INSTALL_LOCK_PATH="$2"
79-
shift 2
80-
;;
8174
--old-enr)
8275
OLD_ENR="$2"
8376
shift 2
@@ -297,91 +290,29 @@ if [ -n "$CLUSTER_LOCK_PATH" ] && [ -n "$OLD_ENR" ]; then
297290
echo " [DRY-RUN] docker run --rm ... charon alpha edit replace-operator ..."
298291
fi
299292

300-
echo ""
301-
echo "╔════════════════════════════════════════════════════════════════╗"
302-
echo "║ Ceremony COMPLETED ║"
303-
echo "╚════════════════════════════════════════════════════════════════╝"
304-
echo ""
305-
log_info "New cluster-lock generated at $OUTPUT_DIR/cluster-lock.json"
306-
echo ""
307-
log_info "Now install the new cluster-lock with:"
308-
echo " ./scripts/edit/replace-operator/new-operator.sh --install-lock $OUTPUT_DIR/cluster-lock.json"
309-
echo ""
310-
311-
exit 0
312-
fi
313-
314-
# Install-lock mode: --install-lock
315-
if [ -n "$INSTALL_LOCK_PATH" ]; then
316-
log_step "Step 1: Checking prerequisites..."
317-
318-
if [ "$DRY_RUN" = false ]; then
319-
if [ ! -d .charon ]; then
320-
log_error ".charon directory not found"
321-
log_info "First generate your ENR with: ./scripts/edit/replace-operator/new-operator.sh --generate-enr"
322-
exit 1
323-
fi
324-
325-
if [ ! -f .charon/charon-enr-private-key ]; then
326-
log_error ".charon/charon-enr-private-key not found"
327-
log_info "First generate your ENR with: ./scripts/edit/replace-operator/new-operator.sh --generate-enr"
328-
exit 1
329-
fi
330-
331-
if [ ! -f "$INSTALL_LOCK_PATH" ]; then
332-
log_error "Cluster-lock file not found: $INSTALL_LOCK_PATH"
333-
exit 1
334-
fi
335-
fi
336-
337-
log_info "Prerequisites OK"
293+
log_info "Ceremony completed successfully"
338294

339295
echo ""
340296

341-
# Step 2: Stop any running containers
342-
log_step "Step 2: Stopping any running containers..."
297+
# Step 4: Backup and install new .charon directory
298+
log_step "Step 4: Installing new cluster configuration..."
343299

344-
run_cmd docker compose stop "$VC" charon 2>/dev/null || true
300+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
301+
mkdir -p "$BACKUP_DIR"
345302

346-
log_info "Containers stopped"
303+
run_cmd mv .charon "$BACKUP_DIR/.charon.$TIMESTAMP"
304+
log_info "Old .charon backed up to $BACKUP_DIR/.charon.$TIMESTAMP"
347305

348-
echo ""
349-
350-
# Step 3: Install new cluster-lock
351-
log_step "Step 3: Installing new cluster-lock..."
352-
353-
if [ -f .charon/cluster-lock.json ]; then
354-
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
355-
mkdir -p "$BACKUP_DIR"
356-
run_cmd cp .charon/cluster-lock.json "$BACKUP_DIR/cluster-lock.json.$TIMESTAMP"
357-
log_info "Old cluster-lock backed up to $BACKUP_DIR/cluster-lock.json.$TIMESTAMP"
358-
fi
359-
360-
# Remove existing file first (may be read-only from Charon)
361-
rm -f .charon/cluster-lock.json
362-
run_cmd cp "$INSTALL_LOCK_PATH" .charon/cluster-lock.json
363-
log_info "New cluster-lock installed"
364-
365-
echo ""
366-
367-
# Step 4: Verify cluster-lock matches our ENR
368-
log_step "Step 4: Verifying cluster-lock configuration..."
306+
run_cmd mv "$OUTPUT_DIR" .charon
307+
log_info "New configuration installed to .charon/"
369308

309+
# Verify our ENR is in the new cluster-lock
370310
if [ "$DRY_RUN" = false ] && [ -f .charon/cluster-lock.json ]; then
371-
# Get our ENR
372-
OUR_ENR=$(docker run --rm \
373-
-v "$REPO_ROOT/.charon:/opt/charon/.charon" \
374-
"obolnetwork/charon:${CHARON_VERSION:-v1.9.0-rc3}" \
375-
enr 2>/dev/null || echo "")
376-
377-
if [ -n "$OUR_ENR" ]; then
378-
# Check if our ENR is in the cluster-lock
379-
if grep -q "${OUR_ENR:0:50}" .charon/cluster-lock.json 2>/dev/null; then
380-
log_info "Verified: Your ENR is present in the cluster-lock"
381-
else
382-
log_warn "Your ENR may not be in this cluster-lock."
383-
log_warn "Make sure you received the correct cluster-lock from the ceremony."
384-
fi
311+
if grep -q "${OUR_ENR:0:50}" .charon/cluster-lock.json 2>/dev/null; then
312+
log_info "Verified: Your ENR is present in the new cluster-lock"
313+
else
314+
log_warn "Your ENR may not be in this cluster-lock."
315+
log_warn "Please verify the ceremony completed successfully."
385316
fi
386317

387318
# Show cluster info
@@ -394,11 +325,12 @@ if [ -n "$INSTALL_LOCK_PATH" ]; then
394325

395326
echo ""
396327
echo "╔════════════════════════════════════════════════════════════════╗"
397-
echo "New Operator Setup COMPLETED "
328+
echo "Replace-Operator Workflow COMPLETED ║"
398329
echo "╚════════════════════════════════════════════════════════════════╝"
399330
echo ""
400331
log_info "Summary:"
401-
log_info " - Cluster-lock installed in: .charon/cluster-lock.json"
332+
log_info " - Old .charon backed up to: $BACKUP_DIR/.charon.$TIMESTAMP"
333+
log_info " - New configuration installed to: .charon/"
402334
echo ""
403335
log_warn "╔════════════════════════════════════════════════════════════════╗"
404336
log_warn "║ IMPORTANT: Wait at least 2 epochs (~13 min) before starting ║"
@@ -416,16 +348,17 @@ if [ -n "$INSTALL_LOCK_PATH" ]; then
416348
log_warn "Note: As a new operator, you do NOT have any slashing protection history."
417349
log_warn "Your VC will start fresh."
418350
echo ""
351+
log_warn "Keep the backup until you've verified normal operation for several epochs."
352+
echo ""
419353

420354
exit 0
421355
fi
422356

423357
# Error: missing required arguments
424358
log_error "Missing required arguments."
425359
echo ""
426-
echo "To generate ENR: --generate-enr"
427-
echo "To run ceremony: --cluster-lock <path> --old-enr <enr>"
428-
echo "To install after ceremony: --install-lock <path>"
360+
echo "To generate ENR: --generate-enr"
361+
echo "To run ceremony: --cluster-lock <path> --old-enr <enr>"
429362
echo ""
430363
echo "Use --help for full usage information."
431364
exit 1

scripts/edit/test/e2e_test.sh

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -753,22 +753,15 @@ EOF
753753
return 1
754754
fi
755755

756-
# Post-ceremony: run new-operator.sh to install the cluster-lock
757-
local new_lock="$new_op_dir/output/cluster-lock.json"
758-
if [ ! -f "$new_lock" ]; then
759-
# Fall back to a remaining operator's output
760-
new_lock="$TMP_DIR/operator0/.charon/cluster-lock.json"
761-
fi
762-
(
763-
WORK_DIR="$new_op_dir" \
764-
COMPOSE_FILE="$new_op_dir/docker-compose.e2e.yml" \
765-
COMPOSE_PROJECT_NAME="e2e-op-replace-new" \
766-
"$REPO_ROOT/scripts/edit/replace-operator/new-operator.sh" \
767-
--install-lock "$new_lock"
768-
) < /dev/null > "$logs_dir/new-operator-setup.log" 2>&1
769-
if [ $? -ne 0 ]; then
770-
log_error "New operator post-ceremony setup failed. Log:"
771-
sed 's/\r$//' "$logs_dir/new-operator-setup.log" | while IFS= read -r line; do echo " $line"; done || true
756+
# Post-ceremony: install the new .charon directory for the new operator
757+
# (The script now does this automatically, but since we ran raw docker for the test,
758+
# we do it manually here)
759+
if [ -d "$new_op_dir/output" ]; then
760+
mv "$new_op_dir/.charon" "$new_op_dir/.charon-backup" 2>/dev/null || true
761+
mv "$new_op_dir/output" "$new_op_dir/.charon"
762+
log_info "New operator: installed output to .charon"
763+
else
764+
log_error "New operator: output directory not found after ceremony"
772765
all_ok=false
773766
fi
774767

0 commit comments

Comments
 (0)