本文档描述了以太坊合并转换的测试案例,重点关注了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
[x] [Hive] 重新组织为更高总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B1.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
B1'.totalDifficulty > B1.totalDifficulty
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1' <- P1
B1'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- P1 <- ... <- Pn
</details>
[x] [Hive PR] 合并后重新组织为更高总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B1.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
B1'.totalDifficulty > B1.totalDifficulty
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1 <- P1
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1')
+ forkchoiceUpdated(head: P1')
,其中 B1' <- P1'
B1'
及其后代,并对 forkchoiceUpdated(head: Pn')
响应 {status: VALID, latestValidHash: Pn', validationError: null}
,其中 B1' <- P1' <- ... <- Pn'
</details>
[x] [Hive] 重新组织为更低总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B1.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
B1.totalDifficulty > B1'.totalDifficulty
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1' <- P1
B1'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- P1 <- ... <- Pn
</details>
[x] [Hive PR] 合并后重新组织为更低总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B1.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
B1.totalDifficulty > B1'.totalDifficulty
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1 <- P1
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1')
+ forkchoiceUpdated(head: P1')
,其中 B1' <- P1'
B1'
及其后代,并对 forkchoiceUpdated(head: Pn')
响应 {status: VALID, latestValidHash: Pn', validationError: null}
,其中 B1' <- P1' <- ... <- Pn'
</details>
[x] [Hive] 双区块重新组织为更高总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2
, B: Genesis <- B1' <- B2'
A
开始,EL 客户端 2 从 B
开始TTD
配置B2.totalDifficulty > TTD
, B2'.totalDifficulty > TTD
B2'.totalDifficulty > B2.totalDifficulty
forkchoiceUpdated(head: B2)
{status: VALID, latestValidHash: B2, validationError: null}
forkchoiceUpdated(head: B2')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B2' <- P1
B1'
、B2'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- B2' <- P1 <- ... <- Pn
</details>
[x] [Hive] 双区块重新组织为更低总难度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2
, B: Genesis <- B1' <- B2'
A
开始,EL 客户端 2 从 B
开始TTD
配置B2.totalDifficulty > TTD
, B2'.totalDifficulty > TTD
B2.totalDifficulty > B2'.totalDifficulty
forkchoiceUpdated(head: B2)
{status: VALID, latestValidHash: B2, validationError: null}
forkchoiceUpdated(head: B2')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B2' <- P1
B1'
、B2'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- B2' <- P1 <- ... <- Pn
</details>
[x] [Hive] 重新组织为更高高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1' <- B2'
A
开始,EL 客户端 2 从 B
开始TTD
配置B1.totalDifficulty > TTD
, B2'.totalDifficulty > TTD
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
forkchoiceUpdated(head: B2')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B2' <- P1
B1'
、B2'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- B2' <- P1 <- ... <- Pn
</details>
[x] [Hive PR] 合并后重新组织为更高高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1' <- B2'
A
开始,EL 客户端 2 从 B
开始TTD
配置B1.totalDifficulty > TTD
, B2'.totalDifficulty > TTD
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1 <- P1
forkchoiceUpdated(head: B2')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1')
+ forkchoiceUpdated(head: P1')
,其中 B2' <- P1'
B1'
、B2'
及其后代,并对 forkchoiceUpdated(head: Pn')
响应 {status: VALID, latestValidHash: Pn', validationError: null}
,其中 B1' <- B2' <- P1' <- ... <- Pn'
</details>
[x] [Hive] 重新组织为更低高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B2.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
forkchoiceUpdated(head: B2)
{status: VALID, latestValidHash: B2, validationError: null}
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1' <- P1
B1'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- P1 <- ... <- Pn
</details>
[x] [Hive PR] 合并后重新组织为更低高度 PoW 链 <details> <summary>点击查看详情</summary>
A: Genesis <- B1 <- B2
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B2.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
forkchoiceUpdated(head: B2)
{status: VALID, latestValidHash: B2, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B2 <- P1
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1')
+ forkchoiceUpdated(head: P1')
,其中 B1' <- P1'
B1'
及其后代,并对 forkchoiceUpdated(head: Pn')
响应 {status: VALID, latestValidHash: Pn', validationError: null}
,其中 B1' <- P1' <- ... <- Pn'
</details>
[x] [Hive PR] 重新组织为具有无效终端区块的链(Block.totalDifficulty < TTD
)
<details>
<summary>点击查看详情</summary>
A: Genesis <- B1 <- B2
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置,因此:B2.totalDifficulty > TTD
, B1.totalDifficulty < TTD
, B1'.totalDifficulty < TTD
B1.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
forkchoiceUpdated(head: B2)
{status: VALID, latestValidHash: B2, validationError: null}
forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1' <- P1
B1'
及其后代,但 head
仍然是 B2
</details>
[x] [Hive PR] 重新组织为具有无效终端区块的链(Block.Parent.totalDifficulty > TTD
)
<details>
<summary>点击查看详情</summary>
A: Genesis <- B1
, B: Genesis <- B1' <- B2'
A
开始,EL 客户端 2 从 B
开始TTD
配置,因此:B1.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
B1.totalDifficulty < TTD
, B1'.totalDifficulty < TTD
, B2'.totalDifficulty > TTD
forkchoiceUpdated(head: B1)
{status: VALID, latestValidHash: B1, validationError: null}
forkchoiceUpdated(head: B2')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B2' <- P1
B1'
、B2'
及其后代,但 head
仍然是 B1
</details>
[x] [Hive PR] 使用 PREVRANDAO
操作码交易重新组织为更低高度 PoW 链
<details>
<summary>点击查看详情</summary>
A: Genesis <- B1 <- B2
, B: Genesis <- B1'
A
开始,EL 客户端 2 从 B
开始TTD
配置B2.totalDifficulty > TTD
, B1'.totalDifficulty > TTD
B1
和 B1'
包含 Tx1
B2
包含 Tx2
Tx1
和 Tx2
将 DIFFICULTY
操作码保存到存储forkchoiceUpdated(head: B2)
{status: VALID, latestValidHash: B2, validationError: null}
DIFFICULTY
操作码forkchoiceUpdated(head: B1')
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1' <- P1
P1
包含 Tx2
B1'
及其后代,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1' <- P1 <- ... <- Pn
PREVRANDAO
操作码</details>
[x] [Hive] 停止跟随 PoW 链 <details> <summary>点击查看详情</summary>
Genesis <- B1 <- B2
B1
之前的链开始,EL 客户端 2 从区块 B2
之前的链开始TTD
配置forkchoiceUpdated
未发送到 EL 客户端 1B2
合并到其链中</details>
[x] [Hive] 长 PoW 链同步 <details> <summary>点击查看详情</summary>
Genesis <- B1 <- ... <- B1024
B1
之前的链开始,EL 客户端 2 从区块 B1024
之前的链开始TTD
配置B1024.totalDifficulty > TTD
forkchoiceUpdated(head: B1024)
{status: SYNCING, latestValidHash: null, validationError: null}
newPayload(P1)
+ forkchoiceUpdated(head: P1)
,其中 B1024 <- P1
B1 <- ... <- B1024
,并对 forkchoiceUpdated(head: Pn)
响应 {status: VALID, latestValidHash: Pn, validationError: null}
,其中 B1 <- ... <- B1024 <- P1 <- ... <- Pn
</details>
[x] [Hive] 提议有效的转换区块 <details> <summary>点击查看详情</summary>
Genesis <- ... <- TB
,TB
是有效的终端区块TB
作为头部开始forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)
headBlockHash
{status: VALID, payloadId: mergeTransitionPayloadId}
getPayload(mergeTransitionPayloadId)
ommersHash == 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
difficulty == 0
mixHash == mergeTransitionBlockAttributes.prevRandao
nonce == 0x0000000000000000
newPayload(mergeTransitionPayload)
VALID
</details>
[x] [Hive] 在错过 fcU
的有效链上转换
<details>
<summary>点击查看详情</summary>
Genesis <- ... <- TB <- P1 <- P2 <- P3
,TB
是有效的终端区块TB
作为头部开始newPayload(P1)
{status: VALID, latestValidHash: payload.blockHash}
TB
newPayload(P2)
{status: VALID, latestValidHash: payload.blockHash}
TB
newPayload(P3)
{status: VALID, latestValidHash: payload.blockHash}
TB
forkchoiceUpdated(head: P3, safe: P2, finalized: P1)
P3
eth_getBlockByNumber(safe)
返回 P2
eth_getBlockByNumber(finalized)
返回 P1
</details>
[x] [Hive] 在无效终端区块之上构建 <details> <summary>点击查看详情</summary>
Genesis <- ... <- INV_TB
,INV_TB
是一个有效 PoW 但无效终端区块,即 INV_TB.TD < TTD
;INV_TB.parent.TD >= TTD
无法轻松检查,因为 EL 不会处理此类区块INV_TB
作为头部开始forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)
{status: INVALID, latestValidHash: 0x00..00, payloadId: null}
INV_TB.TD < TTD
,则 EL 的头部指向 INV_TB
,如果 INV_TB.parent.TD >= TTD
,则指向 INV_TB.parent
</details>
[x] [Hive] 在有效链上转换 <details> <summary>点击查看详情</summary>
Genesis <- ... <- TB <- P1 <- P2 <- P3
,TB
是有效的终端区块TB
作为头部开始newPayload(P1)
{status: VALID, latestValidHash: payload.blockHash}
TB
forkchoiceUpdated(head: P1, safe: 0x00..00, finalized: 0x00..00)
{status: VALID, latestValidHash: forkchoiceState.headBlockHash}
P1
eth_getBlockByNumber(safe)
返回 -39001: Unknown block
错误eth_getBlockByNumber(finalized)
返回 -39001: Unknown block
错误newPayload(P2) + forkchoiceUpdated(head: P2, safe: P1, finalized: 0x00..00)
P2
eth_getBlockByNumber(safe)
返回 -39001: Unknown block
错误eth_getBlockByNumber(finalized)
返回 -39001: Unknown block
错误newPayload(P3) + forkchoiceUpdated(head: P3, safe: P2, finalized: P1)
P3
eth_getBlockByNumber(safe)
返回 P2
eth_getBlockByNumber(finalized)
返回 P1
</details>
[x] [Hive] 在无效链上转换 <details> <summary>点击查看详情</summary>
Genesis <- ... <- INV_TB <- P1
,INV_TB
是一个有效 PoW 但无效终端区块:INV_TB.TD < TTD
INV_TB.parent.TD >= TTD
-- 可能需要第二个具有更高 TTD
值的 ELINV_TB
作为头部开始newPayload(P1)
{status: INVALID, latestValidHash: 0x00..00}
INV_TB.TD < TTD
,则 EL 的头部指向 INV_TB
,如果 INV_TB.parent.TD >= TTD
,则指向 INV_TB.parent
</details>
[x] [Hive] 重新组织为具有无效转换区块的链 <details> <summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2
, B: Genesis <- ... <- TB <- INV_P1
,A.TB
和 B.TB
是有效的终端区块A.TB
作为头部开始newPayload(A.P1) + newPayload(A.P2)
{status: VALID, latestValidHash: payload.blockHash}
A.TB
forkchoiceUpdated(head: A.P2, safe: A.P1, finalized: 0x00..00)
A.P2
newPayload(B.INV_P1)
{status: INVALID/ACCEPTED, latestValidHash: null/0x00..00}
A.P2
forkchoiceUpdated(head: B.INV_P1, safe: 0x00..00, finalized: 0x00..00)
{status: INVALID, latestValidHash: 0x00..00}
A.P2
</details>
[x] [Hive] 与具有有效转换的链同步 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn <- TB <- P1
,TB
是有效的终端区块Bn
作为头部开始newPayload(P1) + forkchoiceUpdated(P1)
{status: SYNCING}
Bn
TB <- P1
forkchoiceUpdated(P1)
{status: VALID, latestValidHash: null}
P1
</details>
[x] [Hive] 与具有无效终端区块的链同步 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn <- INV_TB <- P1 <- P2
,INV_TB
是一个有效 PoW 但无效终端区块:INV_TB.TD < TTD
INV_TB.parent.TD >= TTD
-- 可能需要第二个具有更高 TTD
值的 ELBn
作为头部开始newPayload(P1) + forkchoiceUpdated(P1)
{status: SYNCING}
Bn
INV_TB <- P1
forkchoiceUpdated(P1)
{status: INVALID, latestValidHash: 0x00..00}
Bn
</details>
[x] [Hive] 与终端区块对于 EE 无效的链同步 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn <- INV_TB <- P1 <- P2
,INV_TB
满足 TTD
,但在执行方面无效Bn
作为头部开始newPayload(P1) + forkchoiceUpdated(P1)
{status: SYNCING}
Bn
INV_TB <- P1
forkchoiceUpdated(P1)
{status: INVALID, latestValidHash: 0x00..00}
Bn
</details>
[x] [Hive] 与具有无效转换区块的链同步
<* A: Genesis <- ... <- TB <- P1 <- P2
, B: Genesis <- ... <- INV_TB <- P1 <- P2
, B.INV_TB
是一个 有效的PoW 但一个 无效的终端 区块:
INV_TB.TD < TTD
INV_TB.parent.TD >= TTD
TTD
值A.P2
作为头开始newPayload(B.P2) + forkchoiceUpdated(P2)
{status: SYNCING}
A.P2
B: INV_TB <- P1 <- P2
forkchoiceUpdated(B.P2)
{status: INVALID, latestValidHash: 0x00..00}
A.P2
</details>
[x] [Hive] 使用具有无效转换(transition)区块的链进行重组和同步 <details> <summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2
, B: Genesis <- ... <- TB <- INV_P1 <- P2
, B.TB
是一个有效的终端区块, B.INV_P1
是一个无效的 payloadA.P2
作为头开始newPayload(B.P2) + forkchoiceUpdated(B.P2)
{status: SYNCING}
A.P2
forkchoiceUpdated(B.P2)
{status: INVALID, latestValidHash: 0x00..00}
A.P2
</details>
[x] [Hive] 使用具有无效的后转换(post-transition)区块的链进行重组和同步 <details> <summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2 <- P3
, B: Genesis <- ... <- TB <- P1 <- INV_P2 <- P3
, B.TB
是一个有效的终端区块, B.INV_P2
是一个无效的 payloadA.P2
作为头开始newPayload(B.P3) + forkchoiceUpdated(B.P3)
{status: SYNCING}
A.P3
forkchoiceUpdated(B.P3)
{status: INVALID, latestValidHash: B.P1.blockHash}
A.P3
(在这种情况下, fcU
将根本不会被应用, 因为它指向无效链上的一个区块, 因此不应该发生 forkchoice 状态的更新; 通常, 当获得 lvh = B.P1.blockHash
时, CL 会发送 fcU(B.P1)
, 并将规范链切换到 B
, 并以 B.P1
作为头)</details>
[x] [Hive] 停止处理gossiped PoW 区块 <details> <summary>点击查看详情</summary>
</details>
[x] [Hive] 停止处理同步的 PoW 区块 <details> <summary>点击查看详情</summary>
Genesis <- ... <- TB <- B1 <- B2 <- ... <- Bn
链开始, 其中 TB
是一个有效的终端区块TB
</details>
[x] [Hive] 终端区块被gossiped <details> <summary>点击查看详情</summary>
PoW <-> EL1 <-> EL2
视为连接到 EL 客户端 EL1
的 PoW 客户端, 而 EL1
又连接到 EL 客户端 EL2
。EL2
和 PoW
客户端之间没有直接连接。PoW
客户端 gossip 一个终端区块 TB
EL2
客户端的头指向 TB
PoW
客户端 gossip TB
的后代EL2
客户端的头指向 TB
</details>
[x] [Hive] 通过 gossip 在多个终端区块之后构建 Payload <details> <summary>点击查看详情</summary>
PoW <-> EL
视为连接到 EL 客户端 EL
的 PoW 客户端。PoW
客户端生成并 gossip 多个终端区块 TB1
, TB2
, ... TBN
newPayload(TBN)
被发送到 EL
EL
立即返回 {status: VALID, latestValidHash: TBN.BlockHash}
</details>
[x] [Hive] 在有效的链上转换 <details> <summary>点击查看详情</summary>
EL: Genesis <- ... <- TB
, TB
是一个有效的终端区块CL: Genesis <- ... <- Bellatrix
TB
作为头开始或者挖掘一条链直到 TB
Genesis
开始并构建一条链直到 Bellatrix
并升级到 Bellatrix
eth_getBlockByNumber(latest)
返回头eth_getBlockByNumber(safe)
返回最近被证明是合理的区块eth_getBlockByNumber(finalized)
返回最近被最终确定的区块</details>
[x] [Hive] 在无效的终端区块之上构建 <details> <summary>点击查看详情</summary>
Genesis <- ... <- Bn
, Bn
是一个有效的 PoW 但一个 无效的终端 区块, 也就是 Bn.TD < EL.TTD
Bn
是对 CL 观察来说的有效的终端区块, 也就是 CL 的 TERMINAL_TOTAL_DIFFICULTY
被配置成以下方式:Bn.TD >= CL.TTD && Bn.parent.TD < CL.TTD
Bn
作为头开始Genesis
开始并构建一条链直到 BellatrixExecutionPayload()
)</details>
[x] [Hive] 在具有无效的终端区块的链上转换 <details> <summary>点击查看详情</summary>
EL: Genesis <- ... <- Bn
Bn
是对 builder 观察来说的有效的终端区块, 也就是说 builder 的 TERMINAL_TOTAL_DIFFICULTY
被配置成以下方式:Bn.TD >= TTD && Bn.parent.TD < TTD
Bn
是对 importer 观察来说的 无效的 终端区块, 也就是说 builder 的 TERMINAL_TOTAL_DIFFICULTY
被配置成以下方式:Bn.TD < TTD
Bn
作为头开始Genesis
开始并构建一条链直到 Bellatrix 甚至更远</details>
[x] [Hive] 在具有无效的转换区块的链上转换 <details> <summary>点击查看详情</summary>
EL: Genesis <- ... <- Bn
Bn
是对 builder 和 importer 观察来说的有效的终端区块Bn
作为头开始Genesis
开始并且 builder 构建一条链直到 Bellatrix 甚至更远INVALID
</details>
[x] [Hive] 与具有有效的转换区块的链同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn
, EL.B: Genesis <- ... <- Bn
; A
和 B
具有相等的 TD
EL.A
同步, importer 与 EL.B
同步, 两条链上相同的 TD
值阻止了 importer 提前拉取 builder 的链CL: Genesis
开始并且构建一条链直到 Bellatrix 甚至更远EL.A
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY
继续 -- 这可能值得检查</details>
[x] [Hive] 与具有无效的转换区块的链同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn
, EL.B: Genesis <- ... <- Bn
; A
和 B
具有相等的 TD
EL.A
同步, importer 与 EL.B
同步, 两条链上相同的 TD
值阻止了 importer 提前拉取 builder 的链A.Bn
是对 builder 观察来说的有效的终端区块A.Bn
可能是对 importer 观察来说的 无效的 终端区块, 但这不是必须的, 因为 EL mock 将模拟这种无效性CL: Genesis
开始并且构建一条链直到 Bellatrix 甚至更远EL.A
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY
继续 -- 在这个场景中可能不会被检查SYNCING
以便让 importer 的 CL 达到离转换区块更远的点newPayload
和 forkchoiceUpdated
调用使用 {status: INVALID, latestValidHash: 0x00..00}
进行响应 -- 如果终端区块或者转换区块是无效的, 这将会在现实生活中发生</details>
[x] [Hive] 与具有无效的后转换区块的链同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn
, EL.B: Genesis <- ... <- Bn
; A
和 B
具有相等的 TD
EL.A
同步, importer 与 EL.B
同步, 两条链上相同的 TD
值阻止了 importer 提前拉取 builder 的链A.Bn
是对 builder 和 importer 观察来说的有效的终端区块CL: Genesis
开始并且构建一条链直到 Bellatrix 甚至更远EL.A
SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY
继续 -- 在这个场景中可能不会被检查SYNCING
以便让 importer 的 CL 达到离 后转换 区块更远的点newPayload
和 forkchoiceUpdated
调用使用 {status: INVALID, latestValidHash: transitionBlock.blockHash}
进行响应 -- 如果终端区块或者转换区块是无效的, 这将会在现实生活中发生</details>
[x] [Hive] 使用具有无效的终端区块的链进行重组和同步 <details> <summary>点击查看详情</summary>
EL.A: Genesis <- ... <- Bn
, EL.B: Genesis <- ... <- Bn
; A
和 B
具有相等的 TD
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 的观察来说是有效的CL: Genesis
开始并且构建一条链直到 Bellatrix 甚至更远. 他们应该保持在 Bellatrix 之前的共识, 然后从转换区块开始分离SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY
超时进行乐观地应用 -- 这将给 importer 一个遵循有效链的时间{status: INVALID, latestValidHash: 0x00..00}
进行响应</details>
[x] [Hive] Bellatrix 之前的 TTD
<details>
<summary>点击查看详情</summary>
Genesis <- ... <- Bn
Bn
作为工作量证明链的头开始Bn
对所有客户端来说是一个有效的终端区块Bn
之后, 到达 Bellatrix epochBn
之上构建, 因此转换是成功的。</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 。TBH
(TERMINAL_BLOCK_HASH
) 覆盖的 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 == TBH
B: Genesis <- ... <- Bn
, B
链比 A
更重, 除非激活 TBH
覆盖,否则将成为规范链A
和 B
开始forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)
headBlockHash
{status: VALID, payloadId: mergeTransitionPayloadId}
getPayload(mergeTransitionPayloadId)
newPayload(mergeTransitionPayload)
VALID
</details>
[ ] 在启用 TBH
覆盖的情况下,在无效终端区块之上构建
<details>
<summary>点击查看详情</summary>
Genesis <- ... <- INV_TB
, INV_TB
是一个有效的 PoW 但一个无效的终端区块,即 INV_TB.TD < TTD
并且 TBH != INV_TB.blockHash
INV_TB
作为头开始forkchoiceUpdated(headBlockHash: TB.blockHash, payloadAttributes: mergeTransitionBlockAttributes)
{status: INVALID, latestValidHash: 0x00..00, payloadId: null}
INV_TB.TD < TTD
,则 EL 的头指向 INV_TB
,如果 INV_TB.parent.TD >= TTD
,则指向 INV_TB.parent
</details>
[ ] 使用启用的 TBH
覆盖,在有效链上转换
<details>
<summary>点击查看详情</summary>
A: Genesis <- ... <- TB <- P1 <- P2 <- P3
, TB
是一个有效的终端区块, 也就是 TB.blockHash == TBH
B: Genesis <- ... <- Bn
, B
链比 A
更重,除非激活 TBH
覆盖,否则将成为规范链A
导入到 TB
并且 B
导入到 Bn
开始newPayload(A.P1)
{status: VALID, latestValidHash: payload.blockHash}
TB
forkchoiceUpdated(head: P1, safe: 0x00..00, finalized: 0x00..00)
{status: VALID, latestValidHash: forkchoiceState.headBlockHash}
P1
eth_getBlockByNumber(safe)
返回 -39001: Unknown block
错误eth_getBlockByNumber(finalized)
返回 -39001: Unknown block
错误newPayload(P2) + forkchoiceUpdated(head: P2, safe: P1, finalized: 0x00..00)
P2
eth_getBlockByNumber(safe)
返回 -39001: Unknown block
错误eth_getBlockByNumber(finalized)
返回 -39001: Unknown block
错误newPayload(P3) + forkchoiceUpdated(head: P3, safe: P2, finalized: P1)
P3
eth_getBlockByNumber(safe)
返回 P2
eth_getBlockByNumber(finalized)
返回 P1
</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
值的 ELINV_TB
作为头开始newPayload(P1)
{status: INVALID, latestValidHash: 0x00..00}
INV_TB.TD < TTD
,则 EL 的头指向 INV_TB
,如果 INV_TB.parent.TD >= TTD
,则指向 INV_TB.parent
</details>
[ ] 与具有有效转换的链同步,启用 TBH
覆盖
<details>
<summary>点击查看详情</summary>
A: Genesis <- ... <- Bn <- TB <- P1
, TB
是一个有效的终端区块,也就是 TB.blockHash == TBH
B: Genesis <- ... <- Bn
, B
链比 A
更重,除非激活 TBH
覆盖,否则将成为规范链B
开始newPayload(P1) + forkchoiceUpdated(P1)
{status: SYNCING}
Bn
TB <- P1
forkchoiceUpdated(P1)
{status: VALID, latestValidHash: null}
P1
</details>
[ ] 停止处理启用了 TBH
覆盖的同步 PoW 区块
<details>
<summary>点击查看详情</summary>
Genesis <- ... <- TB <- B1 <- B2 <- ... <- Bn
链开始,其中 TB
是一个有效的终端区块,也就是 TB.blockHash == TBH
TB
</details>
在本节中,builder 节点意味着在其上运行所有验证者并因此构建链的节点。 Importer 是一个导入由 builder 构建并从 builder 接收的链的节点。
[ ] 在启用 TBH
覆盖的情况下,在有效链上转换
<details>
<summary>点击查看详情</summary>
EL.A: Genesis <- ... <- TB
, TB
是一个有效的终端区块。也就是 TB.blockHash == TBH
EL.B: Genesis <- ... <- Bn
, B
链比 A
更重,除非激活 TBH
覆盖,否则将成为规范链CL: Genesis <- ... <- Bellatrix
A
和 B
开始TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
大于 BELLATRIX_FORK_EPOCH
Genesis
开始并构建一条链直到 Bellatrix
并升级到 Bellatrix
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
时开始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
Bn
是对 builder 和 importer 观察来说的有效的终端区块,也就是说 TBH == Bn.blockHash
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
比 builder 侧的要大得多Bn
作为头开始Genesis
开始并构建一条链直到 Bellatrix 甚至更远</details>
[ ] 转换与不匹配的 TERMINAL_BLOCK_HASH
<details>
<summary>点击查看详情</summary>
EL: Genesis <- ... <- Bn
Bn
是对 builder 的观察来说的有效的终端区块,也就是说 builder 的 TBH == Bn.blockHash
Bn
是对 importer 的观察来说的 无效的 终端区块,也就是说 builder 的 TBH != Bn.blockHash
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
在 builder 和 importer 侧是相同的Bn
作为头开始Genesis
开始并构建一条链直到 Bellatrix 甚至更远</details>
- 原文链接: github.com/txrx-research...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!