合并转换测试
本文档描述了以太坊合并转换的测试案例,重点关注了TERMINAL_TOTAL_DIFFICULTY和TERMINAL_BLOCK_HASH两个关键参数在以太坊从PoW到PoS过渡期间的作用。测试覆盖了EL和CL客户端在不同场景下的行为,包括链重组、无效终端块处理、以及在启用TERMINAL_BLOCK_HASH覆盖时的特定情况。这些测试旨在验证以太坊客户端在各种合并转换场景中的正确性和鲁棒性。
合并转换测试
本文档中描述的所有测试用例都从合并前的世界开始,并在执行过程中达到终端 PoW,以执行 PoS 转换。
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- 不要编辑此部分,请重新运行 doctoc 以更新 -->
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
TERMINAL_TOTAL_DIFFICULTY
EL 客户端测试
-
[Hive] 重新组织为更高总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B1.totalDifficulty > TTD,B1'.totalDifficulty > TTDB1'.totalDifficulty > B1.totalDifficultyforkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1' <- P1- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive PR] 合并后重新组织为更高总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B1.totalDifficulty > TTD,B1'.totalDifficulty > TTDB1'.totalDifficulty > B1.totalDifficultyforkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1 <- P1forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1')+forkchoiceUpdated(head: P1'),其中B1' <- P1'- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn')响应{status: VALID, latestValidHash: Pn', validationError: null},其中B1' <- P1' <- ... <- Pn'
- EL 最终同步
</details>
-
[Hive] 重新组织为更低总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B1.totalDifficulty > TTD,B1'.totalDifficulty > TTDB1.totalDifficulty > B1'.totalDifficultyforkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1' <- P1- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive PR] 合并后重新组织为更低总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B1.totalDifficulty > TTD,B1'.totalDifficulty > TTDB1.totalDifficulty > B1'.totalDifficultyforkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1 <- P1forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1')+forkchoiceUpdated(head: P1'),其中B1' <- P1'- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn')响应{status: VALID, latestValidHash: Pn', validationError: null},其中B1' <- P1' <- ... <- Pn'
- EL 最终同步
</details>
-
[Hive] 双区块重新组织为更高总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2,B: Genesis <- B1' <- B2'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B2.totalDifficulty > TTD,B2'.totalDifficulty > TTDB2'.totalDifficulty > B2.totalDifficultyforkchoiceUpdated(head: B2)- EL 响应
{status: VALID, latestValidHash: B2, validationError: null}
- EL 响应
forkchoiceUpdated(head: B2')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B2' <- P1- EL 最终同步
B1'、B2'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- B2' <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive] 双区块重新组织为更低总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2,B: Genesis <- B1' <- B2'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B2.totalDifficulty > TTD,B2'.totalDifficulty > TTDB2.totalDifficulty > B2'.totalDifficultyforkchoiceUpdated(head: B2)- EL 响应
{status: VALID, latestValidHash: B2, validationError: null}
- EL 响应
forkchoiceUpdated(head: B2')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B2' <- P1- EL 最终同步
B1'、B2'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- B2' <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive] 重新组织为更高高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1,B: Genesis <- B1' <- B2'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B1.totalDifficulty > TTD,B2'.totalDifficulty > TTDforkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
forkchoiceUpdated(head: B2')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B2' <- P1- EL 最终同步
B1'、B2'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- B2' <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive PR] 合并后重新组织为更高高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1,B: Genesis <- B1' <- B2'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B1.totalDifficulty > TTD,B2'.totalDifficulty > TTDforkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1 <- P1forkchoiceUpdated(head: B2')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1')+forkchoiceUpdated(head: P1'),其中B2' <- P1'- EL 最终同步
B1'、B2'及其后代,并对forkchoiceUpdated(head: Pn')响应{status: VALID, latestValidHash: Pn', validationError: null},其中B1' <- B2' <- P1' <- ... <- Pn'
- EL 最终同步
</details>
-
[Hive] 重新组织为更低高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B2.totalDifficulty > TTD,B1'.totalDifficulty > TTDforkchoiceUpdated(head: B2)- EL 响应
{status: VALID, latestValidHash: B2, validationError: null}
- EL 响应
forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1' <- P1- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive PR] 合并后重新组织为更低高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B2.totalDifficulty > TTD,B1'.totalDifficulty > TTDforkchoiceUpdated(head: B2)- EL 响应
{status: VALID, latestValidHash: B2, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B2 <- P1forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1')+forkchoiceUpdated(head: P1'),其中B1' <- P1'- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn')响应{status: VALID, latestValidHash: Pn', validationError: null},其中B1' <- P1' <- ... <- Pn'
- EL 最终同步
</details>
-
[Hive PR] 重新组织为具有无效终端区块的链(
Block.totalDifficulty < TTD) <details> <summary>点击查看详情</summary>A: Genesis <- B1 <- B2,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - EL 客户端 1 具有比 EL 客户端 2 更高的
TTD配置,因此:- 对于 EL 客户端 1,
B2.totalDifficulty > TTD,B1.totalDifficulty < TTD,B1'.totalDifficulty < TTD - 对于 EL 客户端 2,
B1.totalDifficulty > TTD,B1'.totalDifficulty > TTD
- 对于 EL 客户端 1,
forkchoiceUpdated(head: B2)- EL 响应
{status: VALID, latestValidHash: B2, validationError: null}
- EL 响应
forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1' <- P1- EL 最终同步
B1'及其后代,但head仍然是B2
- EL 最终同步
</details>
-
[Hive PR] 重新组织为具有无效终端区块的链(
Block.Parent.totalDifficulty > TTD) <details> <summary>点击查看详情</summary>A: Genesis <- B1,B: Genesis <- B1' <- B2'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - EL 客户端 1 具有比 EL 客户端 2 更低的
TTD配置,因此:- 对于 EL 客户端 1,
B1.totalDifficulty > TTD,B1'.totalDifficulty > TTD - 对于 EL 客户端 2,
B1.totalDifficulty < TTD,B1'.totalDifficulty < TTD,B2'.totalDifficulty > TTD
- 对于 EL 客户端 1,
forkchoiceUpdated(head: B1)- EL 响应
{status: VALID, latestValidHash: B1, validationError: null}
- EL 响应
forkchoiceUpdated(head: B2')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B2' <- P1- EL 最终同步
B1'、B2'及其后代,但head仍然是B1
- EL 最终同步
</details>
-
[Hive PR] 使用
PREVRANDAO操作码交易重新组织为更低高度 PoW 链 <details> <summary>点击查看详情</summary>A: Genesis <- B1 <- B2,B: Genesis <- B1'- EL 客户端 1 从
A开始,EL 客户端 2 从B开始 - 两个客户端具有相同的
TTD配置 B2.totalDifficulty > TTD,B1'.totalDifficulty > TTDB1和B1'包含Tx1B2包含Tx2Tx1和Tx2将DIFFICULTY操作码保存到存储forkchoiceUpdated(head: B2)- EL 响应
{status: VALID, latestValidHash: B2, validationError: null} - 存储匹配
DIFFICULTY操作码
- EL 响应
forkchoiceUpdated(head: B1')- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1' <- P1P1包含Tx2- EL 最终同步
B1'及其后代,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1' <- P1 <- ... <- Pn - 存储匹配
PREVRANDAO操作码
</details>
-
[Hive] 停止跟随 PoW 链 <details> <summary>点击查看详情</summary>
Genesis <- B1 <- B2- EL 客户端 1 从区块
B1之前的链开始,EL 客户端 2 从区块B2之前的链开始 - EL 客户端 2 具有比 EL 客户端 1 更高的
TTD配置 forkchoiceUpdated未发送到 EL 客户端 1- 等待两分钟
- EL 客户端 1 不会将
B2合并到其链中
- EL 客户端 1 不会将
</details>
-
[Hive] 长 PoW 链同步 <details> <summary>点击查看详情</summary>
Genesis <- B1 <- ... <- B1024- EL 客户端 1 从区块
B1之前的链开始,EL 客户端 2 从区块B1024之前的链开始 - 两个客户端具有相同的
TTD配置 B1024.totalDifficulty > TTDforkchoiceUpdated(head: B1024)- EL 响应
{status: SYNCING, latestValidHash: null, validationError: null}
- EL 响应
newPayload(P1)+forkchoiceUpdated(head: P1),其中B1024 <- P1- EL 最终同步
B1 <- ... <- B1024,并对forkchoiceUpdated(head: Pn)响应{status: VALID, latestValidHash: Pn, validationError: null},其中B1 <- ... <- B1024 <- P1 <- ... <- Pn
- EL 最终同步
</details>
-
[Hive] 提议有效的转换区块 <details> <summary>点击查看详情</summary>
Genesis <- ... <- TB,TB是有效的终端区块- EL 从
TB作为头部开始 forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)- EL 的头部设置为
headBlockHash - EL 返回
{status: VALID, payloadId: mergeTransitionPayloadId}
- EL 的头部设置为
getPayload(mergeTransitionPayloadId)- EL 返回合并转换 payload
ommersHash == 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347difficulty == 0mixHash == mergeTransitionBlockAttributes.prevRandaononce == 0x0000000000000000
- EL 返回合并转换 payload
newPayload(mergeTransitionPayload)- EL 返回
VALID
- EL 返回
</details>
-
[Hive] 在错过
fcU的有效链上转换 <details> <summary>点击查看详情</summary>Genesis <- ... <- TB <- P1 <- P2 <- P3,TB是有效的终端区块- EL 从
TB作为头部开始 newPayload(P1)- EL 返回
{status: VALID, latestValidHash: payload.blockHash} - EL 的头部指向
TB
- EL 返回
newPayload(P2)- EL 返回
{status: VALID, latestValidHash: payload.blockHash} - EL 的头部指向
TB
- EL 返回
newPayload(P3)- EL 返回
{status: VALID, latestValidHash: payload.blockHash} - EL 的头部指向
TB
- EL 返回
forkchoiceUpdated(head: P3, safe: P2, finalized: P1)- EL 的头部更新为
P3 eth_getBlockByNumber(safe)返回P2eth_getBlockByNumber(finalized)返回P1
- EL 的头部更新为
</details>
-
[Hive] 在无效终端区块之上构建 <details> <summary>点击查看详情</summary>
Genesis <- ... <- INV_TB,INV_TB是一个有效 PoW 但无效终端区块,即INV_TB.TD < TTD;INV_TB.parent.TD >= TTD无法轻松检查,因为 EL 不会处理此类区块- EL 从
INV_TB作为头部开始 forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)- EL 返回
{status: INVALID, latestValidHash: 0x00..00, payloadId: null} - 如果
INV_TB.TD < TTD,则 EL 的头部指向INV_TB,如果INV_TB.parent.TD >= TTD,则指向INV_TB.parent
- EL 返回
</details>
-
[Hive] 在有效链上转换 <details> <summary>点击查看详情</summary>
Genesis <- ... <- TB <- P1 <- P2 <- P3,TB是有效的终端区块- EL 从
TB作为头部开始 newPayload(P1)- EL 返回
{status: VALID, latestValidHash: payload.blockHash} - EL 的头部指向
TB
- EL 返回
forkchoiceUpdated(head: P1, safe: 0x00..00, finalized: 0x00..00)- EL 返回
{status: VALID, latestValidHash: forkchoiceState.headBlockHash} - EL 的头部更新为
P1 eth_getBlockByNumber(safe)返回-39001: Unknown block错误eth_getBlockByNumber(finalized)返回-39001: Unknown block错误
- EL 返回
newPayload(P2) + forkchoiceUpdated(head: P2, safe: P1, finalized: 0x00..00)- EL 的头部更新为
P2 eth_getBlockByNumber(safe)返回-39001: Unknown block错误eth_getBlockByNumber(finalized)返回-39001: Unknown block错误
- EL 的头部更新为
newPayload(P3) + forkchoiceUpdated(head: P3, safe: P2, finalized: P1)- EL 的头部更新为
P3 eth_getBlockByNumber(safe)返回P2eth_getBlockByNumber(finalized)返回P1
- EL 的头部更新为
</details>
-
[Hive] 在无效链上转换 <details> <summary>点击查看详情</summary>
Genesis <- ... <- INV_TB <- P1,INV_TB是一个有效 PoW 但无效终端区块:-
INV_TB.TD < TTD -
INV_TB.parent.TD >= TTD-- 可能需要第二个具有更高TTD值的 EL
-
- EL 从
INV_TB作为头部开始 newPayload(P1)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - 如果
INV_TB.TD < TTD,则 EL 的头部指向INV_TB,如果INV_TB.parent.TD >= TTD,则指向INV_TB.parent
- EL 返回
</details>
-
[Hive] 重新组织为具有无效转换区块的链 <details> <summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2,B: Genesis <- ... <- TB <- INV_P1,A.TB和B.TB是有效的终端区块- EL 从
A.TB作为头部开始 newPayload(A.P1) + newPayload(A.P2)- EL 返回
{status: VALID, latestValidHash: payload.blockHash} - EL 的头部指向
A.TB
- EL 返回
forkchoiceUpdated(head: A.P2, safe: A.P1, finalized: 0x00..00)- EL 的头部更新为
A.P2
- EL 的头部更新为
newPayload(B.INV_P1)- EL 返回
{status: INVALID/ACCEPTED, latestValidHash: null/0x00..00} - EL 的头部指向
A.P2
- EL 返回
forkchoiceUpdated(head: B.INV_P1, safe: 0x00..00, finalized: 0x00..00)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - EL 的头部指向
A.P2
- EL 返回
</details>
-
[Hive] 与具有有效转换的链同步 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn <- TB <- P1,TB是有效的终端区块- EL 从
Bn作为头部开始 newPayload(P1) + forkchoiceUpdated(P1)- EL 返回
{status: SYNCING} - EL 的头部指向
Bn
- EL 返回
- EL 应该从网络中提取
TB <- P1 - 轮询
forkchoiceUpdated(P1)- EL 返回
{status: VALID, latestValidHash: null} - EL 的头部指向
P1
- EL 返回
</details>
-
[Hive] 与具有无效终端区块的链同步 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn <- INV_TB <- P1 <- P2,INV_TB是一个有效 PoW 但无效终端区块:- EL 从
Bn作为头部开始 newPayload(P1) + forkchoiceUpdated(P1)- EL 返回
{status: SYNCING} - EL 的头部指向
Bn
- EL 返回
- EL 应该从网络中提取
INV_TB <- P1 - 轮询
forkchoiceUpdated(P1)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - EL 的头部指向
Bn
- EL 返回
</details>
-
[Hive] 与终端区块对于 EE 无效的链同步 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn <- INV_TB <- P1 <- P2,INV_TB满足TTD,但在执行方面无效- EL 从
Bn作为头部开始 newPayload(P1) + forkchoiceUpdated(P1)- EL 返回
{status: SYNCING} - EL 的头部指向
Bn
- EL 返回
- EL 应该从网络中提取
INV_TB <- P1 - 轮询
forkchoiceUpdated(P1)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - EL 的头部指向
Bn
- EL 返回
</details>
-
[Hive] 与具有无效转换区块的链同步 <*
A: Genesis <- ... <- TB <- P1 <- P2,B: Genesis <- ... <- INV_TB <- P1 <- P2,B.INV_TB是一个 有效的PoW 但一个 无效的终端 区块:- [Hive]
INV_TB.TD < TTD - [Hive]
INV_TB.parent.TD >= TTD - 这个场景可能需要第二个EL具有更高的
TTD值 - EL 以
A.P2作为头开始 newPayload(B.P2) + forkchoiceUpdated(P2)- EL 返回
{status: SYNCING} - EL 的头指向
A.P2
- EL 返回
- EL 应该从网络中拉取
B: INV_TB <- P1 <- P2 - 轮询
forkchoiceUpdated(B.P2)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - EL 的头指向
A.P2
- EL 返回
</details>
- [Hive]
-
[Hive] 使用具有无效**转换(transition)**区块的链进行重组和同步 <details> <summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2,B: Genesis <- ... <- TB <- INV_P1 <- P2,B.TB是一个有效的终端区块,B.INV_P1是一个无效的 payload- EL 以
A.P2作为头开始 newPayload(B.P2) + forkchoiceUpdated(B.P2)- EL 返回
{status: SYNCING} - EL 的头指向
A.P2
- EL 返回
- 轮询
forkchoiceUpdated(B.P2)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - EL 的头指向
A.P2
- EL 返回
</details>
-
[Hive] 使用具有无效的**后转换(post-transition)**区块的链进行重组和同步 <details> <summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2 <- P3,B: Genesis <- ... <- TB <- P1 <- INV_P2 <- P3,B.TB是一个有效的终端区块,B.INV_P2是一个无效的 payload- EL 以
A.P2作为头开始 newPayload(B.P3) + forkchoiceUpdated(B.P3)- EL 返回
{status: SYNCING} - EL 的头指向
A.P3
- EL 返回
- 轮询
forkchoiceUpdated(B.P3)- EL 返回
{status: INVALID, latestValidHash: B.P1.blockHash} - EL 的头指向
A.P3(在这种情况下,fcU将根本不会被应用, 因为它指向无效链上的一个区块, 因此不应该发生 forkchoice 状态的更新; 通常, 当获得lvh = B.P1.blockHash时, CL 会发送fcU(B.P1), 并将规范链切换到B, 并以B.P1作为头)
- EL 返回
</details>
-
[Hive] 停止处理gossiped PoW 区块 <details> <summary>点击查看详情</summary>
- PoW/Clique 矿工构建一个链并通过 gossip 广播它; 该链超出终端 PoW 区块
- EL 连接到矿工并且不处理终端区块之后的区块, 也就是头指向终端区块
</details>
-
[Hive] 停止处理同步的 PoW 区块 <details> <summary>点击查看详情</summary>
- PoW 客户端以
Genesis <- ... <- TB <- B1 <- B2 <- ... <- Bn链开始, 其中TB是一个有效的终端区块 - EL 连接到 PoW 客户端并与广播的链同步
- EL 的头指向
TB
- EL 的头指向
</details>
- PoW 客户端以
-
[Hive] 终端区块被gossiped <details> <summary>点击查看详情</summary>
- 将
PoW <-> EL1 <-> EL2视为连接到 EL 客户端EL1的 PoW 客户端, 而EL1又连接到 EL 客户端EL2。EL2和PoW客户端之间没有直接连接。 PoW客户端 gossip 一个终端区块TBEL2客户端的头指向TB
PoW客户端 gossipTB的后代EL2客户端的头指向TB
</details>
- 将
-
[Hive] 通过 gossip 在多个终端区块之后构建 Payload <details> <summary>点击查看详情</summary>
- 将
PoW <-> EL视为连接到 EL 客户端EL的 PoW 客户端。 PoW客户端生成并 gossip 多个终端区块TB1,TB2, ...TBNnewPayload(TBN)被发送到ELEL立即返回{status: VALID, latestValidHash: TBN.BlockHash}
</details>
- 将
CL 客户端测试
-
[Hive] 在有效的链上转换 <details> <summary>点击查看详情</summary>
EL: Genesis <- ... <- TB,TB是一个有效的终端区块CL: Genesis <- ... <- Bellatrix- EL 以
TB作为头开始或者挖掘一条链直到TB - CL 以
Genesis开始并构建一条链直到Bellatrix并升级到Bellatrix - CL 驱动 EL 通过转换并最终确定它
eth_getBlockByNumber(latest)返回头eth_getBlockByNumber(safe)返回最近被证明是合理的区块eth_getBlockByNumber(finalized)返回最近被最终确定的区块
</details>
-
[Hive] 在无效的终端区块之上构建 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn,Bn是一个有效的 PoW 但一个 无效的终端 区块, 也就是Bn.TD < EL.TTDBn是对 CL 观察来说的有效的终端区块, 也就是 CL 的TERMINAL_TOTAL_DIFFICULTY被配置成以下方式:Bn.TD >= CL.TTD && Bn.parent.TD < CL.TTD
- EL 以
Bn作为头开始 - CL 以
Genesis开始并构建一条链直到 Bellatrix- 转换永远不会发生, 也就是说 CL 的头区块总是包含归零的 payload (
ExecutionPayload())
- 转换永远不会发生, 也就是说 CL 的头区块总是包含归零的 payload (
</details>
-
[Hive] 在具有无效的终端区块的链上转换 <details> <summary>点击查看详情</summary>
EL: Genesis <- ... <- Bn- 节点: builder, importer; importer 在两层都连接到 builder
Bn是对 builder 观察来说的有效的终端区块, 也就是说 builder 的TERMINAL_TOTAL_DIFFICULTY被配置成以下方式:Bn.TD >= TTD && Bn.parent.TD < TTD
Bn是对 importer 观察来说的 无效的 终端区块, 也就是说 builder 的TERMINAL_TOTAL_DIFFICULTY被配置成以下方式:Bn.TD < TTD
- EL 以
Bn作为头开始 - builder 以
Genesis开始并构建一条链直到 Bellatrix 甚至更远- Importer 从不导入转换区块并且它的头总是指向转换前的区块
</details>
-
[Hive] 在具有无效的转换区块的链上转换 <details> <summary>点击查看详情</summary>
EL: Genesis <- ... <- Bn- 节点: builder, importer; importer 在两层都连接到 builder
Bn是对 builder 和 importer 观察来说的有效的终端区块- EL 以
Bn作为头开始 - CL 以
Genesis开始并且 builder 构建一条链直到 Bellatrix 甚至更远 - Importer 节点的 EL mock 对转换区块的 payload 返回
INVALID- Importer 从不导入转换区块并且它的头总是指向转换前的区块
</details>
-
[Hive] 与具有有效的转换区块的链同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn,EL.B: Genesis <- ... <- Bn;A和B具有相等的TD- 节点: builder, importer; builder 开始与
EL.A同步, importer 与EL.B同步, 两条链上相同的TD值阻止了 importer 提前拉取 builder 的链 - builder 以
CL: Genesis开始并且构建一条链直到 Bellatrix 甚至更远- Importer 将不得不从 builder 拉取
EL.A - Importer 区块处理暂停并等待
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY继续 -- 这可能值得检查 - 在超时结束后, importer 最终同步并且通过转换
- Importer 将不得不从 builder 拉取
</details>
-
[Hive] 与具有无效的转换区块的链同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn,EL.B: Genesis <- ... <- Bn;A和B具有相等的TD- 节点: builder, importer; builder 开始与
EL.A同步, importer 与EL.B同步, 两条链上相同的TD值阻止了 importer 提前拉取 builder 的链 A.Bn是对 builder 观察来说的有效的终端区块A.Bn可能是对 importer 观察来说的 无效的 终端区块, 但这不是必须的, 因为 EL mock 将模拟这种无效性- builder 以
CL: Genesis开始并且构建一条链直到 Bellatrix 甚至更远- Importer 将不得不从 builder 拉取
EL.A - Importer 区块处理暂停并等待
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY继续 -- 在这个场景中可能不会被检查 - Importer 的 EL mock 有意地持续返回
SYNCING以便让 importer 的 CL 达到离转换区块更远的点 - 一段时间后, EL mock 开始对每一个
newPayload和forkchoiceUpdated调用使用{status: INVALID, latestValidHash: 0x00..00}进行响应 -- 如果终端区块或者转换区块是无效的, 这将会在现实生活中发生 - Importer 必须使从转换区块开始的区块无效, 并且绝不能再次导入转换区块
- Importer 将不得不从 builder 拉取
</details>
-
[Hive] 与具有无效的后转换区块的链同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn,EL.B: Genesis <- ... <- Bn;A和B具有相等的TD- 节点: builder, importer; builder 开始与
EL.A同步, importer 与EL.B同步, 两条链上相同的TD值阻止了 importer 提前拉取 builder 的链 A.Bn是对 builder 和 importer 观察来说的有效的终端区块- builder 以
CL: Genesis开始并且构建一条链直到 Bellatrix 甚至更远- Importer 将不得不从 builder 拉取
EL.A - Importer 区块处理暂停并等待
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY继续 -- 在这个场景中可能不会被检查 - Importer 的 EL mock 有意地持续返回
SYNCING以便让 importer 的 CL 达到离 后转换 区块更远的点 - 一段时间后, EL mock 开始对每一个
newPayload和forkchoiceUpdated调用使用{status: INVALID, latestValidHash: transitionBlock.blockHash}进行响应 -- 如果终端区块或者转换区块是无效的, 这将会在现实生活中发生 - Importer 必须使从后转换区块开始的区块无效, 并且绝不能再次导入后转换区块, 并且头必须指向转换区块
- Importer 将不得不从 builder 拉取
</details>
-
[Hive] 使用具有无效的终端区块的链进行重组和同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn,EL.B: Genesis <- ... <- Bn;A和B具有相等的TD- 节点: 有效的 builder, 无效的 builder, importer; 有效的 builder 和 importer 开始与
EL.A同步, 无效的 builder 和EL.B同步, 两条链上相同的TD值阻止了 importer 和有效的 builder 提前拉取无效的 builder 的链. 有效的 builder 具有1/2n - x的验证者, 无效的 builder 具有1/2 + x的验证者, 其中x是一个很小的数字 A.Bn是对有效的 builder 和 importer 观察来说的有效的终端区块B.Bn是对 importer 的观察来说的 无效的 终端区块, 但是对无效的 builder 的观察来说是有效的- 两个 builder 以
CL: Genesis开始并且构建一条链直到 Bellatrix 甚至更远. 他们应该保持在 Bellatrix 之前的共识, 然后从转换区块开始分离- Importer 的头最终和有效的 builder 一致
- 理想情况下, 有效的 builder 在无效的 builder 做同样的事情 之前 提出一个转换区块 -- 这些可以通过使用验证者分配来实现
- 然后由无效的 builder 提出的转换区块将不得不使用
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY超时进行乐观地应用 -- 这将给 importer 一个遵循有效链的时间 - 无效的链被乐观地应用 (因为无效的 builder 具有更多的证明者并且它的链被 fork 选择规则优先选择) 并且 importer 的 EL 最终在这个链上使用
{status: INVALID, latestValidHash: 0x00..00}进行响应 - 期望 CL 从转换区块开始使无效的链区块无效, 并且切换回较小的, 但有效的链
- 然后由无效的 builder 提出的转换区块将不得不使用
</details>
-
[Hive] Bellatrix 之前的
TTD<details> <summary>点击查看详情</summary>Genesis <- ... <- Bn- EL 客户端以
Bn作为工作量证明链的头开始 Bn对所有客户端来说是一个有效的终端区块- 在所有客户端合并了
Bn之后, 到达 Bellatrix epoch - 当到达 Bellatrix 时, 因为 CL 客户端在
Bn之上构建, 因此转换是成功的。
</details>
[奖励] TERMINAL_BLOCK_HASH
本节中的场景涵盖了通过指定由 TERMINAL_BLOCK_HASH 参数指定的某个 blockHash 值来指定终端 PoW 区块的情况。
此方案也称为 TERMINAL_BLOCK_HASH 覆盖, 是一种紧急情况方案。在 EL 侧, 覆盖涉及指定以下参数 (按照 EIP-3675):
TERMINAL_BLOCK_HASH– 设置为某个区块的哈希,以成为终端 PoW 区块。TERMINAL_BLOCK_NUMBER– 设置为由TERMINAL_BLOCK_HASH指定的区块的编号。TERMINAL_TOTAL_DIFFICULTY– 设置为由TERMINAL_BLOCK_HASH指定的区块的总难度值。
在 CL 侧,必须通过更新 以下参数 来启用覆盖:
TERMINAL_BLOCK_HASH– 设置为某个区块的哈希,以成为终端 PoW 区块。TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH- 设置为 Merge 转换将被激活的 epoch 。
EL 客户端测试
TBH (TERMINAL_BLOCK_HASH) 覆盖的 EL 客户端测试是根据以下 潜在的 实现设计的:
- EL 总是在达到
TERMINAL_TOTAL_DIFFICULTY时触发 Merge 升级 TERMINAL_BLOCK_HASH+TERMINAL_BLOCK_NUMBER将规范链列入白名单
实际上,这种语义给出了想要的结果。但是,如果 EL 有两条已达到 TTD 的链,则 EL 可能不会拒绝建立在 blockHash != TBH 的区块之上的转换 payload。但是我们有 CL 侧来强制执行终端区块的 blockHash == TBH。这意味着省略此检查在 EL 侧是可以的。本节中的测试 不 假设 blockHash == TBH 由 EL 客户端实现强制执行。
考虑到以上想法,本节的目标是检查 TBH 覆盖是否会影响 TTD 区块条件。
-
提出具有启用
TBH覆盖的有效转换区块 <details> <summary>点击查看详情</summary>A: Genesis <- ... <- TB,TB是一个有效的终端区块,TB.blockHash == TBHB: Genesis <- ... <- Bn,B链比A更重, 除非激活TBH覆盖,否则将成为规范链- EL 以导入的
A和B开始 forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)- EL 的头被设置为
headBlockHash - EL 返回
{status: VALID, payloadId: mergeTransitionPayloadId}
- EL 的头被设置为
getPayload(mergeTransitionPayloadId)- EL 返回 merge 转换 payload
newPayload(mergeTransitionPayload)- EL 返回
VALID
- EL 返回
</details>
-
在启用
TBH覆盖的情况下,在无效终端区块之上构建 <details> <summary>点击查看详情</summary>Genesis <- ... <- INV_TB,INV_TB是一个有效的 PoW 但一个无效的终端区块,即INV_TB.TD < TTD并且TBH != INV_TB.blockHash- EL 以
INV_TB作为头开始 forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)- EL 返回
{status: INVALID, latestValidHash: 0x00..00, payloadId: null} - 如果
INV_TB.TD < TTD,则 EL 的头指向INV_TB,如果INV_TB.parent.TD >= TTD,则指向INV_TB.parent
- EL 返回
</details>
-
使用启用的
TBH覆盖,在有效链上转换 <details> <summary>点击查看详情</summary>A: Genesis <- ... <- TB <- P1 <- P2 <- P3,TB是一个有效的终端区块, 也就是TB.blockHash == TBHB: Genesis <- ... <- Bn,B链比A更重,除非激活TBH覆盖,否则将成为规范链- EL 以
A导入到TB并且B导入到Bn开始 newPayload(A.P1)- EL 返回
{status: VALID, latestValidHash: payload.blockHash} - EL 的头指向
TB
- EL 返回
forkchoiceUpdated(head: P1, safe: 0x00..00, finalized: 0x00..00)- EL 返回
{status: VALID, latestValidHash: forkchoiceState.headBlockHash} - EL 的头更新为
P1 eth_getBlockByNumber(safe)返回-39001: Unknown block错误eth_getBlockByNumber(finalized)返回-39001: Unknown block错误
- EL 返回
newPayload(P2) + forkchoiceUpdated(head: P2, safe: P1, finalized: 0x00..00)- EL 的头更新为
P2 eth_getBlockByNumber(safe)返回-39001: Unknown block错误eth_getBlockByNumber(finalized)返回-39001: Unknown block错误
- EL 的头更新为
newPayload(P3) + forkchoiceUpdated(head: P3, safe: P2, finalized: P1)- EL 的头更新为
P3 eth_getBlockByNumber(safe)返回P2eth_getBlockByNumber(finalized)返回P1
- EL 的头更新为
</details>
-
在启用
TBH覆盖的情况下,在无效链上转换 <details> <summary>点击查看详情</summary>Genesis <- ... <- INV_TB <- P1,INV_TB是一个 有效的 PoW 但一个 无效的终端 区块, 也就是说TBH != INV_TB.blockHash并且以下任何一个为真:-
INV_TB.TD < TTD -
INV_TB.parent.TD >= TTD-- 这可能需要第二个具有更高TTD值的 EL
-
- EL 以
INV_TB作为头开始 newPayload(P1)- EL 返回
{status: INVALID, latestValidHash: 0x00..00} - 如果
INV_TB.TD < TTD,则 EL 的头指向INV_TB,如果INV_TB.parent.TD >= TTD,则指向INV_TB.parent
- EL 返回
</details>
-
与具有有效转换的链同步,启用
TBH覆盖 <details> <summary>点击查看详情</summary>A: Genesis <- ... <- Bn <- TB <- P1,TB是一个有效的终端区块,也就是TB.blockHash == TBHB: Genesis <- ... <- Bn,B链比A更重,除非激活TBH覆盖,否则将成为规范链- EL 以导入的
B开始 newPayload(P1) + forkchoiceUpdated(P1)- EL 返回
{status: SYNCING} - EL 的头指向
Bn
- EL 返回
- EL 应该从网络中拉取
TB <- P1 - 轮询
forkchoiceUpdated(P1)- EL 返回
{status: VALID, latestValidHash: null} - EL 的头指向
P1
- EL 返回
</details>
-
停止处理启用了
TBH覆盖的同步 PoW 区块 <details> <summary>点击查看详情</summary>- PoW 客户端以
Genesis <- ... <- TB <- B1 <- B2 <- ... <- Bn链开始,其中TB是一个有效的终端区块,也就是TB.blockHash == TBH - EL 连接到 PoW 客户端并与广播的链同步
- EL 的头指向
TB
- EL 的头指向
</details>
- PoW 客户端以
CL 客户端测试
在本节中,builder 节点意味着在其上运行所有验证者并因此构建链的节点。 Importer 是一个导入由 builder 构建并从 builder 接收的链的节点。
-
在启用
TBH覆盖的情况下,在有效链上转换 <details> <summary>点击查看详情</summary>EL.A: Genesis <- ... <- TB,TB是一个有效的终端区块。也就是TB.blockHash == TBHEL.B: Genesis <- ... <- Bn,B链比A更重,除非激活TBH覆盖,否则将成为规范链CL: Genesis <- ... <- Bellatrix- EL 以导入的
A和B开始 TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH大于BELLATRIX_FORK_EPOCH- CL 以
Genesis开始并构建一条链直到Bellatrix并升级到Bellatrix- 合并转换仅在达到
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH时开始
- 合并转换仅在达到
- CL 驱动 EL 通过转换并最终确定它
- 终端区块是
EL.A.TB,并且 PoS 链建立在该区块之上 eth_getBlockByNumber(latest)返回头eth_getBlockByNumber(safe)返回最近被证明是合理的区块eth_getBlockByNumber(finalized)返回最近被最终确定的区块
- 终端区块是
</details>
-
在
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH之前转换 <details> <summary>点击查看详情</summary>EL: Genesis <- ... <- Bn- 节点: builder, importer; importer 在两层都连接到 builder
Bn是对 builder 和 importer 观察来说的有效的终端区块,也就是说TBH == Bn.blockHash- Importer 侧的
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH比 builder 侧的要大得多 - EL 以
Bn作为头开始 - builder 以
Genesis开始并构建一条链直到 Bellatrix 甚至更远- Importer 从不导入转换区块并且它的头总是指向转换前的区块
</details>
-
转换与不匹配的
TERMINAL_BLOCK_HASH<details> <summary>点击查看详情</summary>EL: Genesis <- ... <- Bn- 节点: builder, importer; importer 在两层都连接到 builder
Bn是对 builder 的观察来说的有效的终端区块,也就是说 builder 的TBH == Bn.blockHashBn是对 importer 的观察来说的 无效的 终端区块,也就是说 builder 的TBH != Bn.blockHashTERMINAL_BLOCK_HASH_ACTIVATION_EPOCH在 builder 和 importer 侧是相同的- EL 以
Bn作为头开始 - builder 以
Genesis开始并构建一条链直到 Bellatrix 甚至更远- Importer 从不导入转换区块并且它的头总是指向转换前的区块
</details>
- 原文链接: github.com/txrx-research...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~