Reth 节点在处理trie更新时出现bug,导致节点计算出错误的状态根。具体原因是,在特定重组期间,Reth产生了不正确的存储trie更新,导致trie表包含旧块的数据,最终导致状态根不匹配。该问题已通过修复is_fork
检查逻辑并在版本1.7.0中发布修复。
Reth 在处理 trie 更新时的一个错误导致 Reth 节点中的 trie 表包含不正确的信息,从而导致节点在后面的区块中计算出不正确的状态根。
9 月 1 日美国东部时间晚上 10:34,我们在 Reth telegram 频道 和 Github 上 收到用户警报,称某些 Reth 节点停滞并显示日志 “mismatched block state root”。
该错误的首次报告:
[\
\
\
\
Reth Stalled on Bad Block - Ethereum Mainnet\
\
\
\
Closed\
\
\
\
\ •\ \ jamesstanleystewart\ \ •\ \ Closed 11 days ago](https://github.com/paradigmxyz/reth/issues/18205)
用户节点停滞在以下区块上:
区块号:
23272427
区块哈希:
0xcab98ac6afa8461e2e9f29bd155e1e22d989cdf91f49ab67293af331767dcdaa
9 月 2 日美国东部时间上午 7:47,我们确定了缓解该问题的步骤,并通过 Twitter 和 Telegram(Reth 支持的标准沟通方法)进行了沟通:
一些运行主网节点的 Reth 用户受到了此错误的影响。并非所有 Reth 用户都受到了影响。OP Reth 节点和其他网络上的节点未受到影响。如果用户的 Reth 节点受到影响,它们将不会继续运行,直到采取缓解措施。一旦缓解步骤完成,用户节点将再次开始运行并同步。
我们确定了该错误的根本原因,并在 1.7.0 版本 中发布了修复程序,并提供了修复工具,以确保 Twitter、Telegram 和 GitHub 上任何剩余的用户数据库不会仍然损坏。
任何尚未升级到 1.7.0 版本的以太坊主网节点运营商都应更新并运行 1.7.0 发行说明中提到的修复脚本。
状态根不匹配的原因是 trie 节点具有不正确的数据,特别是来自 此帐户 的存储 trie 节点包含来自旧区块的数据,具体来说是
23003311
。这意味着某些存储 tries 已损坏。
发生损坏的原因是 Reth 在某些 reorgs 期间产生了不正确的存储 trie 更新。在此实例中,reorg 发生在区块
23003311
,区块按以下顺序到达:
区块
23003310
区块
23003311 (fork)
区块
23003311 (canonical)
区块
23003312
在区块
23003311 (canonical)
交易 0x8342...4be8 中,以下 trie 节点在数据库中创建:
Plain Text
Copy
StorageTrieUpdates {
is\_deleted: false,
storage\_nodes: {
Nibbles(0xf): BranchNodeCompact {
state\_mask: TrieMask(0000000001001000),
tree\_mask: TrieMask(0000000000000000),
hash\_mask: TrieMask(0000000000001000),
hashes: \[0xc2e8ad8f13ee65d4bb21710522cf87c847f9bb0db11d73e6694c7ebc01c996e8\],
root\_hash: None
}
},
removed\_nodes: {}
}
0xf
?如果你打开 Etherscan 上此交易的 状态更改,你将看到唯一修改的存储槽是
0x4193f419339d8d52872c2a4d6ee5a6eb14c99332daf66ad89d1882bf092892be
,其先前值为
0x0
,这意味着它是刚刚创建的。
当
0x4193f419339d8d52872c2a4d6ee5a6eb14c99332daf66ad89d1882bf092892be
存储在 trie 中时,它被编码为
0xf388169196abf4cd20a13828879f10b0985d92fb58854196a68dad916132a0e4
Copy
❯ cast keccak 0x4193f419339d8d52872c2a4d6ee5a6eb14c99332daf66ad89d1882bf092892be
0xf388169196abf4cd20a13828879f10b0985d92fb58854196a68dad916132a0e4
第一个 nibble
f
这个哈希路径是我们的分支节点
0xf
已创建。
通常,Reth 中的 trie 更新仅在基于数据库 tip 的直接后代区块计算时才有效,否则将被丢弃。但是,区块
23003311 (canonical)
的 trie 更新被错误地丢弃,因为 Reth 错误地检查了该区块是否为 fork,即使数据库 tip 位于直接后代处:
接下来,区块
23003312
到达。由于交易 0xf535...2cd6 执行,路径
0xf
的节点应已删除。
0xf
?再次查看 Etherscan 上的 状态更改,我们看到与区块
23003311
中创建的相同的存储槽
0x4193f419339d8d52872c2a4d6ee5a6eb14c99332daf66ad89d1882bf092892be
,但现在其值更改回
0x0
。这将导致删除 0xf 处的分支节点,因为分支节点不能只有一个子节点。
缺少来自区块
23003311 (canonical)
的 trie 更新意味着 Reth 的状态根逻辑无法确定路径
0xf
处的节点已删除,而不仅仅是不存在。这导致状态根逻辑输出此存储 trie 的没有 trie 更新,而不是删除。但由于区块
23003312
不再是 fork 区块,因此 Reth 没有丢弃 trie 更新,并为该区块计算了正确的状态根。未受影响的节点为区块
23003312
生成了这些正确的 trie 更新:
Plain Text
Copy
StorageTrieUpdates {
is\_deleted: false,
storage\_nodes: {},
removed\_nodes: {Nibbles(0xf)}
}
缺少区块
23003311
中的 trie 更新导致 Reth 在持久化到数据库时重新计算它们
但是区块
23003312
的 trie 更新没有被丢弃,因此 Reth 只是按原样获取它们并持久化到数据库。这意味着 trie 节点
0xf
已在
23003311
中创建,但未在
23003312
中删除。这是不正确的,因为在区块
23003312
之后,此存储节点不应存在。
当在区块
23272427
中需要此损坏的存储 trie 来进行状态根计算时,受影响的 Reth 节点遇到了状态根不匹配。
23272427
?原始帐户
0x77d34361f991fa724ff1db9b1d760063a16770db
在 trie 中编码为
0xa86e1856f85373eaf16909d1a6c580f47385e49561d05661462f6c0bebc9ad32
Copy
❯ cast keccak 0x77d34361f991fa724ff1db9b1d760063a16770db
0xa86e1856f85373eaf16909d1a6c580f47385e49561d05661462f6c0bebc9ad32
23272427
修改了一个账户,该账户的前缀与原始账户的编码版本相同,这需要 Reth 查找原始账户的存储根。存储根没有预先计算好存储,因此我们从(损坏的)存储 trie 节点计算它,这导致了不匹配。
通过更改 is_fork
检查来解决此问题,而是确定该区块是否是当前数据库 tip 的后代,并确保缺少 trie 更新的区块不会导致后代区块产生不正确的 trie 更新:
[\
\
\
\
refactor(engine): persistence logic\
\
\
\
Merged\
\
\
\
\ •\ \ shekhirin\ \ •\ \ Merged 14 days ago](https://github.com/paradigmxyz/reth/pull/18318/files)
在修复问题并发布新版本后,Reth 团队立即开始采取措施,以防止将来发生此类事件:
E2E 测试,涵盖所描述的 reorg 场景
[\
\
\
\
chore(trie): add e2e for reorg\
\
\
\
Open\
\
\
\
\ •\ \ yongkangc\ \ •\ \ Opened 17 days ago](https://github.com/paradigmxyz/reth/pull/18293)
诊断工具,将在我们内部的所有配置(存档/完整,Reth/OP Reth,Mainnet/Testnets/Optimism/Base)的节点群上运行,以尽快检测到类似问题,并减少事件解决所需的时间
[\
\
\
\
feat(trie): Add helper sub-command\
\
\
\
Merged\
\
\
\
\ •\ \ mediocregopher\ \ •\ \ Merged 14 days ago](https://github.com/paradigmxyz/reth/pull/18301)
关于重构 trie 计算算法和 trie 更新逻辑的内部讨论,使其更加健壮且不易出错。
- 原文链接: laced-king-de5.notion.si...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!