cloud-sre

修复 Polygon Erigon 归档节点卡在 87218600 区块的问题

一次 Polygon Erigon 归档节点故障排查:节点在 Chicago hardfork 激活块出现稳定的 gas used mismatch,最终通过从 0xPolygon/erigon v3.5.0 升级到 v3.6.0 修复。

Jun 18, 2026
PolygonErigonarchive-nodehardforktroubleshooting

一个 Polygon Mainnet Erigon 归档节点停止在 87218600 区块附近。 归档节点出问题时,很容易先怀疑磁盘、CPU、内存、peer 数量或者快照数据损坏。 但这次问题不在这些地方。

真正的问题是:节点稳定卡在 Polygon Chicago hardfork 的激活块。 修复方式是把运行中的 0xPolygon/erigonv3.5.0 升级到 v3.6.0,然后保留同一个 /data 数据目录重启容器。

背景解释

区块链节点不是简单地“下载一份数据”。 它会自己重新执行区块里的交易,然后检查自己算出来的结果是否和链上区块头里的结果一致。 所以,即使 CPU、内存、磁盘 I/O 都够,节点仍然可能在某一个区块停住。 原因可能不是机器不够强,而是当前客户端软件不认识这个区块开始生效的新规则。

Polygon 和其他 EVM 链一样,会通过 hardfork 修改执行规则。 hardfork 可以理解成“链协议升级”。 到了某一个指定区块后,新规则开始生效:gas 价格规则可能变化,precompile 行为可能变化,Polygon 自己的系统交易处理方式也可能变化。 如果节点软件没有包含这些新规则,它就会算出和链上区块头不一致的结果,然后认为这个区块无效。

这次的 87218600 正是 Polygon Mainnet 的 Chicago hardfork 激活块。 当时节点实际运行的还是旧的 v3.5.0 build。 它能执行 hardfork 前面的区块,但执行到新规则边界时就失败了。

文中专有名词解释

术语含义
Archive node / 归档节点保存历史状态的节点,可以查询老区块、receipt、trace、合约历史状态。它比普通裁剪节点需要更多磁盘。
Erigon一个以太坊客户端实现。这里用的是 Polygon 维护的 0xPolygon/erigon,用来跟随 Polygon Bor mainnet 规则。
Bor mainnetPolygon PoS 主网的执行链。Erigon 里用 --chain=bor-mainnet 指定。
Hardfork某个指定区块开始生效的协议规则升级。节点必须在到达这个区块前升级到认识新规则的版本。
Chicago hardforkPolygon 的一次 hardfork,在 0xPolygon/erigon v3.6.0 release notes 中写明 Mainnet 激活块是 87218600
Gas used一个区块执行消耗的 gas 总量。节点会自己计算一次,再和区块头里的值对比。
StateSyncPolygon 特有的状态同步事件。在 Polygon 的 fork 规则附近,它可能影响执行校验。
HeimdallPolygon 的共识/checkpoint 层。Erigon 可以通过 --bor.heimdall=... 连接远端 Heimdall。
Fork choice节点判断哪个链头有效的过程。如果执行层认为某个区块无效,fork choice 就不能推进到这个区块。
DatadirErigon 存数据库和快照的目录。这次是 /data

现象

节点反复 unwind 到最后一个有效 tip,然后因为 gas-used mismatch 崩溃:

gas used mismatch block=87218600 header=79467913 execution=62712118
Execution failed block=87218600
err="invalid block, txnIdx=186, gas used by execution: 62712118, in header: 79467913"
pos sync failed: unexpected bad block at finalized waypoint

这里最关键的不是错误文本本身,而是区块号:87218600

这个区块不是随机区块。 0xPolygon/erigonv3.6.0 release notes 明确写着,Polygon Mainnet 的 Chicago 激活块是 87218600,并要求 validator、RPC provider、node operator 和基础设施伙伴在 hardfork 前升级 [1]

实际判断方式是:

  • 如果节点只是在随机区块失败一次,可能是数据、peer 或资源问题。
  • 如果节点反复在同一个 hardfork 激活块失败,先看客户端版本。
  • 在确认实际运行版本之前,不要急着删除数据重同步。

排除项

这个节点已经按归档节点规格做过基础优化:

层级状态
存储15TB 级数据盘,并升级到高 IOPS EBS
内存机器已升级到 128GB 级别
P2P重启后 peer 可以恢复
Heimdall远端 Heimdall scraper 持续前进
快照数据现有 /data 可读,并且能执行到失败区块前

重启后,节点可以重新下载和插入区块:

GoodPeers eth68=3
inserting fetched blocks start=87214502 end=87216293 blocks=1792

这说明它不是随机资源耗尽,也不是网络完全不可用。 它每次都能执行到同一个 hardfork 边界,然后在同一类校验上失败。

GitHub 上的匹配问题

0xPolygon/erigon 仓库里已经有同类 open issue:

  • Issue #143 报告了 bor-mainnet + v3.5.0-230b11a7 上相同的 gas mismatch 模式,并指向 StateSync gas 处理问题 [2]
  • Issue #133 报告了 pos sync failed: unexpected bad block at finalized waypoint [3]
  • Issue #100 是更早版本里的同类 gas used by execution ... in header ... 问题 [4]

这些 issue 本身不能单独当作修复依据。 但它们足以改变排查方向:这更像 client/fork rule mismatch,而不是磁盘或者 peer 问题。

决定性检查:真正运行的版本

容器实际还在运行旧版本:

Build info git_tag=v3.5.0-dirty git_commit=230b11a713...

当时虽然已经 clone 了 v3.6.0 源码,但还没有 build 新镜像,也没有用新镜像启动容器。 这点很重要:源码目录存在,不代表 Docker 正在跑这个版本。

正确的确认命令是:

docker logs --tail 100 polygon-erigon | grep 'Build info'
docker images | grep polygon-erigon

修复前,镜像列表里只有 local-v3.5.0

修复步骤

先构建 v3.6.0 镜像:

docker stop polygon-erigon
rm -rf /opt/erigon-v3.6.0
git clone --branch v3.6.0 --single-branch https://github.com/0xPolygon/erigon.git /opt/erigon-v3.6.0
cd /opt/erigon-v3.6.0
DOCKER_BUILDKIT=1 docker build -t polygon-erigon:local-v3.6.0 .

然后删除旧容器,用同一个 /data 启动新容器:

docker update --restart=no polygon-erigon
docker rm -f polygon-erigon
docker network create erigon-net 2>/dev/null || true

核心变化只有运行镜像:

polygon-erigon:local-v3.6.0

归档数据没有删除。 节点继续使用:

--chain=bor-mainnet
--datadir=/data
--prune.mode=archive
--db.size.limit=12TB
--db.pagesize=16KB
--bor.heimdall=https://heimdall-api.polygon.technology

为了避免重新暴露公网 RPC,Docker 端口发布层把 JSON-RPC 和 metrics 绑定在本机:

-p 127.0.0.1:8545:8545
-p 127.0.0.1:6060:6060

这样本机验证仍然可用,但公网不能直接访问 RPC。

验证

新容器启动后,日志显示版本正确:

Build info git_tag=v3.6.0-dirty git_commit=231d67e50b...
Initialised chain configuration ... Chicago: 87218600

刚启动时出现过短暂 peer 警告:

can't use any peers to download blocks
No GoodPeers

这是暂时现象。随后节点找到 peer,并恢复插入区块:

GoodPeers eth68=3
inserting fetched blocks start=87214502 end=87216293 blocks=1792

真正的验证点是越过原来的失败区块:

blk=87218538
blk=87218647
blk=87218727
blk=87218801

这说明 v3.6.0 已经越过 87218600。 以下旧错误没有再次出现:

gas used mismatch block=87218600
unexpected bad block
Execution failed

可复用 Runbook

遇到这类 Polygon Erigon 故障时:

  1. 先确认失败区块号。
  2. 确认正在运行的 binary 版本,而不是只看源码目录。
  3. 把失败区块和 Polygon hardfork 激活块对照。
  4. 搜索上游 issue 里的精确错误文本。
  5. 升级到包含对应 hardfork 规则的 release。
  6. 除非上游明确要求重建数据库,否则保留现有 datadir。
  7. 验证是否越过精确失败区块。

最有用的两个命令是:

docker logs --tail 100 polygon-erigon | grep 'Build info'

以及:

docker logs --since 15m polygon-erigon | \
  grep -E 'gas used mismatch|unexpected bad block|Execution failed|polygon.sync.*crashed'

第一个命令确认真实运行版本。 第二个命令确认旧故障是否还在。

这次故障的教训

这次问题一开始很像性能问题,因为节点此前已经经历过磁盘和实例规格调优。 但性能调优无法修复 hardfork 规则不匹配。

如果一个区块链节点稳定卡在同一个区块,尤其是已知 hardfork 激活块,先看 client 版本。

参考资料

  1. 0xPolygon/erigon v3.6.0 release notes
  2. 0xPolygon/erigon issue #143: Block 76879430 - same gas mismatch pattern
  3. 0xPolygon/erigon issue #133: pos sync failed: unexpected bad block at finalized waypoint
  4. 0xPolygon/erigon issue #100: gas used by execution mismatch
  5. Polygon documentation: Erigon archive node