调查Merkle根不匹配Skill investigate-merkle-root-mismatch

此技能用于调查区块链中relayer和validators之间Merkle根不匹配的警报和问题。通过查询监控系统、端口转发和二进制搜索,识别不匹配的索引和消息ID,并提供详细报告,为后续修复提供依据。关键词:Merkle根不匹配、区块链调试、节点运维、检查点验证、Hyperlane、量化交易分析。

节点运维 0 次安装 0 次浏览 更新于 3/11/2026

name: 调查-merkle-根-不匹配 description: 调查relayer和validators之间的Merkle根不匹配警报。当警报提及“merkle根不匹配”、“检查点根与标准根不匹配”,或当要求调试某个链的relayer merkle树问题时使用。此技能仅进行调查 - 使用/fix-merkle-root-mismatch应用修复。

调查Merkle根不匹配

何时使用

  1. 基于警报的触发:

    • 警报提及“merkle根不匹配”
    • GCP日志显示:“检查点根与来自merkle证明的标准根不匹配”
    • hyperlane_merkle_root_mismatch指标触发
  2. 用户请求触发:

    • “调试[链]的merkle树问题”
    • “调查[链]上的merkle根不匹配”
    • “为什么relayer的merkle树对于[链]是错误的?”

输入参数

参数 必需 默认值 描述
origin - 出现Merkle根不匹配的起源链(例如:paradexethereum
domain_id - 链的域ID(如未提供,则从注册表自动派生)
environment mainnet3 mainnet3testnet4

问题概述

relayer维护一个基于消息ID构建的本地merkle树。当验证器签署检查点时,relayer需要生成merkle证明。如果relayer的树中有错误的消息ID,则根将不匹配,导致消息传递失败。

最可能的原因: Relayer索引了错误的消息ID(可能由于RPC问题或重组),而验证器拥有正确数据。

先决条件

  • 对relayer pods的kubectl访问权限
  • 已配置的Grafana MCP服务器

调查工作流程

步骤1:确认警报

查询Grafana以确认不匹配指标是否触发:

使用 mcp__grafana__query_prometheus,参数:
- datasourceUid: grafanacloud-prom
- expr: hyperlane_merkle_root_mismatch{origin="[origin]"}
- startTime: now-1h
- queryType: instant

如果value1,则确认不匹配。

步骤2:获取最新树插入索引

查询Grafana以获取当前树大小:

使用 mcp__grafana__query_prometheus,参数:
- datasourceUid: grafanacloud-prom
- expr: hyperlane_latest_tree_insertion_index{origin="[origin]", hyperlane_deployment="[environment]"}
- startTime: now-1h
- queryType: instant

这为您提供最新的叶子索引,以便向后工作。

步骤3:获取域ID

如果未提供domain_id,则从注册表获取:

curl -s "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/main/chains/[origin]/metadata.yaml" | grep domainId

步骤4:建立到Relayer的端口转发

检查端口9090是否已被使用:

lsof -i :9090

如果未使用,在后台启动端口转发:

kubectl port-forward omniscient-relayer-hyperlane-agent-relayer-0 9090:9090 -n [environment] &

等待几秒钟以建立端口转发,然后验证其工作:

curl -s "localhost:9090/merkle_tree_insertions?domain_id=[domain_id]&leaf_index_start=0&leaf_index_end=1"

步骤5:二分搜索首次不匹配

比较验证器检查点(来自S3)与relayer merkle证明。使用二分搜索找到首次不匹配的索引。

验证器检查点URL模式:

https://hyperlane-[environment]-[origin]-validator-0.s3.us-east-1.amazonaws.com/checkpoint_[index]_with_id.json

比较函数:

# 检查特定索引
index=[索引]
domain_id=[域ID]
origin=[起源]
environment=[环境]

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:"
echo "  验证器:$validator_root"
echo "  Relayer:0x$relayer_root"
if [ "$validator_root" = "0x$relayer_root" ]; then echo "  ✓ 匹配"; else echo "  ❌ 不匹配"; fi

二分搜索策略:

  1. 从最新索引开始 - 如果不匹配,则跳转到该索引的50%
  2. 如果在50%匹配,则不匹配在50%-100%之间 - 尝试75%
  3. 如果在50%不匹配,则不匹配在0%-50%之间 - 尝试25%
  4. 继续缩小范围,直到找到确切的首次不匹配索引(索引N-1匹配但索引N不匹配)

步骤6:识别不匹配的消息ID

一旦找到首次不匹配索引,比较消息ID:

获取验证器消息ID:

for i in $(seq [首次不匹配] [首次不匹配 + 10]); do
  msg=$(curl -s "https://hyperlane-[environment]-[origin]-validator-0.s3.us-east-1.amazonaws.com/checkpoint_${i}_with_id.json" | jq -r '.value.message_id')
  echo "$i: $msg"
done

获取relayer消息ID:

curl -s "localhost:9090/merkle_tree_insertions?domain_id=[domain_id]&leaf_index_start=[首次不匹配]&leaf_index_end=[首次不匹配 + 10]" | jq -r '.merkle_tree_insertions[] | "\(.leaf_index): \(.message_id)"'

步骤7:获取块时间戳以获取上下文

获取首次不匹配的块号和 timestamp,以了解问题何时开始:

# 从relayer获取块号
curl -s "localhost:9090/merkle_tree_insertions?domain_id=[domain_id]&leaf_index_start=[首次不匹配]&leaf_index_end=[首次不匹配]" | jq '.merkle_tree_insertions[0].insertion_block_number'

对于EVM链,获取 timestamp:

cast block [块号] --rpc-url [rpc_url] -j | jq '.timestamp'

对于Starknet链:

curl -s --request POST --url '[rpc_url]' --header 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"starknet_getBlockWithTxHashes","params":[{"block_number":[块号]}],"id":1}' | jq '.result.timestamp'

将Unix timestamp转换为可读格式:

date -r [timestamp] -u '+%Y-%m-%d %H:%M:%S UTC'

步骤8:报告发现

呈现调查结果:

  1. 摘要表:
参数
[起源]
域ID [域ID]
环境 [环境]
首次不匹配索引 [索引]
最新索引 [最新]
需要修复的总条目数 [最新 - 首次不匹配 + 1]
不匹配开始时间 [块号] ([timestamp])
  1. 不匹配条目示例:
叶子索引 Relayer消息ID 验证器消息ID 块号
[索引] 0x… 0x… [块号]
  1. 通知用户:要修复此问题,他们应该运行/fix-merkle-root-mismatch

  2. 修复注意事项: 必须修复从首次不匹配到最新的所有条目,因为merkle树是累积的 - 每个根都依赖于所有先前的叶子。

API参考

Relayer端点

端点 方法 参数 描述
/merkle_tree_insertions GET domain_id, leaf_index_start, leaf_index_end 列出merkle树插入
/merkle_proofs GET domain_id, leaf_index, root_index 获取叶子的merkle证明

验证器S3检查点

https://hyperlane-[environment]-[chain]-validator-0.s3.us-east-1.amazonaws.com/checkpoint_[index]_with_id.json

响应结构:

{
  "value": {
    "checkpoint": {
      "merkle_tree_hook_address": "0x...",
      "mailbox_domain": 514051890,
      "root": "0x...",
      "index": 37352
    },
    "message_id": "0x..."
  },
  "signature": { ... }
}

常见问题

  1. 端口转发断开连接: 重新运行kubectl端口转发命令
  2. 验证器S3返回404: 检查点可能尚未存在于该索引处
  3. 二分搜索耗时过长: 初始使用更大的跳跃(例如,10000个索引)
  4. Shell脚本错误: 使用手动curl命令代替rust/scripts/中的bash脚本

下一步

调查后,使用/fix-merkle-root-mismatch应用修复。

运行手册参考

完整运行手册:https://www.notion.so/hyperlanexyz/Merkle-Root-Mismatch-26a6d35200d680a2857dcd0b228d4ab7