--- name: fix-merkle-root-mismatch description: Apply fixes for merkle root mismatch issues in the relayer database. Use after running /investigate-merkle-root-mismatch to investigate and identify the mismatched entries. Requires user confirmation before any database modifications. --- # Fix Merkle Root Mismatch ## When to Use Use this skill AFTER running `/investigate-merkle-root-mismatch` to investigate the issue. 1. **User request triggers:** - "Fix the merkle root mismatch on [chain]" - "Apply the merkle tree fixes" - "Update the relayer database with correct message IDs" ## Input Parameters | Parameter | Required | Default | Description | | ------------------------ | -------- | ---------- | --------------------------------------------------------------- | | `origin` | Yes | - | The origin chain to fix (e.g., `polygonzkevm`, `ethereum`) | | `domain_id` | Yes | - | Domain ID of the chain | | `environment` | No | `mainnet3` | `mainnet3` or `testnet4` | | `merkle_tree_insertions` | Yes | - | List of corrections: `[{leaf_index, message_id, block_number}]` | ## Prerequisites 1. **Investigation completed** - Run `/investigate-merkle-root-mismatch` first to identify mismatched entries 2. `kubectl` access to the relayer pods 3. Port-forward already established to relayer (port 9090) ## Fix Workflow ### Step 0: Find Monorepo Root ```bash MONOREPO_ROOT=$(git rev-parse --show-toplevel) ``` ### Step 1: Verify Port-Forward is Active Check if port 9090 is already in use: ```bash lsof -i :9090 ``` If not in use, start port-forward in background: ```bash kubectl port-forward omniscient-relayer-hyperlane-agent-relayer-0 9090:9090 -n [environment] & ``` Wait a few seconds, then verify it's working: ```bash curl -s "localhost:9090/merkle_tree_insertions?domain_id=[domain_id]&leaf_index_start=0&leaf_index_end=1" ``` ### Step 2: Present Changes for Confirmation **IMPORTANT: User confirmation required before executing.** Before making any changes to the relayer database, you MUST: 1. Present a summary of ALL changes to be made in a clear table format: | Leaf Index | Correct Message ID | Block Number | | ---------- | ------------------------------------------------------------------ | ------------ | | 1477 | 0x4bb3e20db45366a6a360ad2639c5421ea622a69b89b2edb045aa97e2051529b7 | 9891832 | | 1478 | 0xa66dbdc1874acfddf14e75e6a20dd1632e9e3206c5f5855884da0d26d8ca12fa | 9891872 | 2. Use `AskUserQuestion` to get explicit confirmation: - Question: "Do you want to apply these merkle tree fixes to the relayer database?" - Options: "Yes, apply fixes" / "No, cancel" 3. **Only proceed if the user explicitly confirms.** ### Step 3: Apply Merkle Tree Fixes Once confirmed, insert the correct merkle tree insertions via the relayer API: ```bash curl -X POST \ -H 'Content-type: application/json' \ 'localhost:9090/merkle_tree_insertions' \ -d '{ "merkle_tree_insertions": [ { "chain": [domain_id], "insertion_block_number": [block_number], "leaf_index": [index], "message_id": "0x..." } ] }' ``` **Request schema:** ```json { "merkle_tree_insertions": [ { "chain": "", "insertion_block_number": "", "leaf_index": "", "message_id": "<0x-prefixed H256 hash>" } ] } ``` **Verify response:** The API should return a success response with the count of inserted entries. ### Step 4: Restart Relayer **IMPORTANT: User confirmation required before executing.** Use `AskUserQuestion` to confirm: - Question: "Do you want to restart the relayer to apply the database fixes?" - Options: "Yes, restart relayer" / "No, I'll restart manually later" **Only proceed if the user explicitly confirms.** Once confirmed, restart the relayer to rebuild its in-memory merkle tree: ```bash pnpm --dir typescript/infra exec tsx ./scripts/agents/restart-agents.ts -e [environment] --context hyperlane --role relayer ``` ### Step 5: Validate Fix After the relayer restarts, verify the fix: #### 5.1: Get Latest Index Query Grafana for the current tree size: ``` Use mcp__grafana__query_prometheus with: - datasourceUid: grafanacloud-prom - expr: hyperlane_latest_tree_insertion_index{origin="[origin]", hyperlane_deployment="[environment]"} - startTime: now-1h - queryType: instant ``` #### 5.2: Spot-Check Roots at Key Indices Compare validator and relayer roots at three points: first fixed index, middle, and latest. ```bash index=[INDEX] validator_root=$(curl -s "https://hyperlane-[environment]-[origin]-validator-0.s3.us-east-1.amazonaws.com/checkpoint_${index}_with_id.json" | jq -r '.value.checkpoint.root') relayer_root=$(curl -s "localhost:9090/merkle_proofs?domain_id=[domain_id]&leaf_index=${index}&root_index=${index}" | jq -r '.root') echo "Index $index:" echo " Validator: $validator_root" echo " Relayer: 0x$relayer_root" if [ "$validator_root" = "0x$relayer_root" ]; then echo " ✓ Match"; else echo " ❌ MISMATCH"; fi ``` Run this for: 1. First fixed index (e.g., 37352) 2. Middle index (e.g., 39000) 3. Latest index (e.g., 41172) #### 5.3: Verify Mismatch Metric is Clear ``` Use mcp__grafana__query_prometheus with: - datasourceUid: grafanacloud-prom - expr: hyperlane_merkle_root_mismatch{origin="[origin]"} - startTime: now-1h - queryType: instant ``` **Expected result:** Empty result or value of 0. #### 5.4: Report Results Present validation results in a table: | Index | Location | Result | | ----- | ----------- | ------- | | 37352 | First fixed | ✓ Match | | 39000 | Middle | ✓ Match | | 41172 | Latest | ✓ Match | If still mismatched: - Inform the user that additional entries may need fixing - Suggest re-running `/investigate-merkle-root-mismatch` to investigate further ## API Reference ### Relayer Endpoints | Endpoint | Method | Description | | ------------------------- | ------ | ----------------------------------- | | `/merkle_tree_insertions` | GET | List merkle tree insertions from DB | | `/merkle_tree_insertions` | POST | Insert/update merkle tree entries | ### Request/Response Examples **POST /merkle_tree_insertions** Request: ```json { "merkle_tree_insertions": [ { "chain": 1101, "insertion_block_number": 9891832, "leaf_index": 1477, "message_id": "0x4bb3e20db45366a6a360ad2639c5421ea622a69b89b2edb045aa97e2051529b7" } ] } ``` Response (success): ```json { "status": "success", "data": { "count": 1 } } ``` ## Common Issues 1. **Port-forward disconnected:** Re-establish before applying fixes 2. **API returns error:** Check the error message, verify domain_id and message_id format 3. **Relayer restart fails:** Check kubectl access and pod status 4. **Fix didn't work:** May have missed some mismatched indices, re-investigate ## Runbook Reference Full runbook: https://www.notion.so/hyperlanexyz/Merkle-Root-Mismatch-26a6d35200d680a2857dcd0b228d4ab7