引擎API测试

本文档描述了 Engine API 的测试用例,这些测试用例都是从合并后的世界开始的,即 Genesis 是一个终端PoW块。

Engine API 测试

本文档中描述的所有测试用例都始于合并后的世界,即 Genesis 是一个最终的 PoW 区块。

<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

EL 客户端测试

  • [x] [Hive] 无效的 block_hash <details> <summary>点击查看详情</summary>

    • [Hive] 测试应涵盖当 EL 处于 SYNCING 状态以及不在 SYNCING 状态时 block_hash 的验证,以确保同步不会影响验证
    • 测试应涵盖 block_hash 所有可能的不一致情况,这些情况很容易发生,例如随机哈希、如果区块是有效的 PoW 区块时的哈希等
    • [Hive] EL 响应 {status: INVALID_BLOCK_HASH, latestValidHash: null, validationError: errorMessage | null}

    </details>

  • [x] [Hive] VALID 规范 链 payload <details> <summary>点击查看详情</summary>

    • P 是扩展规范链的 VALID payload
    • newPayload(P)
    • [Hive] EL 响应 {status: VALID, latestValidHash: payload.blockHash, validationError: null}
    • [Hive] EL 没有更新 head(它仍然设置为 P 的父级)
    • forkchoiceUpdated(headBlock: P)
    • [Hive PR] EL 响应 {payloadStatus: {status: VALID, latestValidHash: forkchoiceState.headBlockHash, validationError: null}, payloadId: null}
    • [Hive] EL 将 head 设置为 P

    </details>

  • [x] [Hive PR] 不一致的 ForkchoiceState <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1 &lt;- P2 &lt;- P3B: Genesis &lt;- P1' &lt;- P2' &lt;- P3'
    • EL 客户端以完全导入的 AB 启动
    • forkchoiceUpdated(finalized: A.P1, safe: A.P2, head: A.P3)
    • EL 成功地重新组织为 A.P3finalizedsafe 区块符合预期
    • forkchoiceUpdated(finalized: A.P1, safe: A.P2, head: B.P3')
    • forkchoiceUpdated(finalized: A.P1, safe: B.P2', head: A.P3)
    • forkchoiceUpdated(finalized: B.P1', safe: A.P2, head: A.P3)
    • 在上面列出的所有情况下,都返回 {error: {code: -38002, message: "Invalid forkchoice state"}}
    • forkchoiceUpdated(finalized: B.P1', safe: B.P2', head: B.P3')
    • EL 成功地重新组织为 B.P3finalizedsafe 区块符合预期

    </details>

  • [x] [Hive] INVALID 规范 链 payload <details> <summary>点击查看详情</summary>

    • INV_P 是扩展规范链的 INVALID payload
    • INV_P 具有有效的 block_hash,但由于以下无效属性而被无效:
    • stateRoot 无效
    • receiptsRoot 无效
    • blockNumber 小于或等于 parent.blockNumber 或大于 parent.blockNumber+1
    • gasLimit 大于 parent.gasLimit + parent.gasLimit / 1024 或小于 parent.gasLimit - parent.gasLimit / 1024
    • gasUsed 不等于包含的交易使用的 gas
    • timestamp 小于或等于 parent.timestamp
    • baseFeePerGasparent.baseFeePerGasparent.gasUsed 不一致
    • transactions 具有以下任一情况:
      • 不完整的交易
      • 额外的交易
      • 本质上无效的交易
    • newPayload(INV_P)
    • {status: INVALID, latestValidHash: P.parentHash, validationError: errorMessage | null}
    • 无法通过 eth_getBlockByHash 访问 INV_P

    </details>

  • [x] [Hive] 具有未知父级的 Payload <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1 &lt;- P2 &lt;- P3B: Genesis &lt;- P1' &lt;- P2' &lt;- P3'
    • EL 客户端以 Genesis 区块和状态启动
    • forkchoiceUpdated(A.P1)
    • {status: SYNCING}
    • newPayload(A.P1) + forkchoiceUpdated(A.P1)
    • 轮询 forkchoiceUpdated(A.P1),直到它响应 {status: VALID},head 设置为 A.P1
    • newPayload(B.P2')
    • {status: SYNCING}
    • newPayload(B.P1') + newPayload(B.P2') + forkchoiceUpdated(B.P2')
    • 轮询 forkchoiceUpdated(B.P2'),直到它响应 {status: VALID},head 设置为 B.P2'
    • forkchoiceUpdated(A.P1)
    • 重新组织回 A.P1
    • newPayload(A.P3)
    • {status: SYNCING}
    • newPayload(A.P2) + newPayload(A.P3) + forkchoiceUpdated(A.P3)
    • 轮询 forkchoiceUpdated(A.P3),直到它响应 {status: VALID},head 设置为 A.P3'

    </details>

  • [x] [Hive] SYNCING 具有无效链 <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4B: Genesis &lt;- P1' &lt;- INV_P2' &lt;- P3' &lt;- P4'INV_P2' 是无效的 payload
    • INV_P2' 具有有效的 block_hash,但由于以下无效属性而被无效:
    • stateRoot 无效
    • receiptsRoot 无效
    • blockNumber 小于或等于 parent.blockNumber 或大于 parent.blockNumber+1
    • gasLimit 大于 parent.gasLimit + parent.gasLimit / 1024 或小于 parent.gasLimit - parent.gasLimit / 1024
    • gasUsed 不等于包含的交易使用的 gas
    • timestamp 小于或等于 parent.timestamp
    • baseFeePerGasparent.baseFeePerGasparent.gasUsed 不一致
    • transactions 具有以下任一情况:
      • 不完整的交易
      • 额外的交易
      • 本质上无效的交易
    • EL 客户端以 A: P4 区块和状态启动
    • newPayload(INV_P2') + forkchoiceUpdated(head: INV_P2')
    • EL 响应 {status: SYNCING, latestValidHash: null, validationError: null}
    • EL 从网络上的远程对等点拉取 P1'
    • newPayload(P3')
    • 轮询 newPayload(P3'),直到响应为 INVALID,且 latestValidHash: P1'.blockHash
    • finalizedsafe 和 head 区块没有改变,即来自 A
    • newPayload(P2') + forkchoiceUpdated(head: P2')
    • EL 从网络上的远程对等点拉取 P1'
    • 轮询 forkchoiceUpdated(P2'),直到响应为 INVALID,且 latestValidHash: P1'.blockHash

    </details>

  • [x] [Hive] 构建一个 payload <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1
    • EL 客户端以 Genesis 区块和状态启动
    • newPayload(P1)
    • 成功
    • getPayload(payloaId: random)
    • {error: {code: -38001, message: "Unknown payload"}}
    • forkchoiceUpdated(P1, payloadAttributes: {validTimestamp, validPrevRandao, validFeeRecipient})
    • 记住从此调用返回的 existingPayloadId
    • getPayload(payloaId: random)
    • {error: {code: -38001, message: "Unknown payload"}}
    • getPayload(payloaId: existingPayloadId)
    • 记住从此调用返回的 returnedPayload
    • newPayload(returnedPayload)
    • {status: VALID}
    • forkchoiceUpdated(returnedPayload)
    • {status: VALID}returnedPayload 变为 head
    • forkchoiceUpdated(returnedPayload, payloadAttributes: {validTimestamp, validPrevRandao, validFeeRecipient})
    • 记住从此调用返回的 existingPayloadId2
    • getPayload(payloaId: existingPayloadId2)
    • 记住从此调用返回的 returnedPayload2
    • newPayload(returnedPayload2)
    • {status: VALID}
    • returnedPayload 仍为 head
    • 等待 60 秒
    • getPayload(payloaId: existingPayloadId2)
    • {error: {code: -38001, message: "Unknown payload"}}

    </details>

  • [x] [Hive] 无效的 PayloadAttributes <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1
    • EL 客户端以 Genesis 区块和状态启动
    • newPayload(P1)
    • 成功
    • forkchoiceUpdated(P1, payloadAttributes: {timestamp: 0, validPrevRandao, validFeeRecipient})
    • {error: {code: -38003, message: "Invalid payload attributes"}}
    • head 设置为 P1

    </details>

  • [x] [Hive] VALID 链 payload <details> <summary>点击查看详情</summary>

    • P' 是扩展链的 VALID payload
    • PP' 包含相同的交易,该交易使用 PREVRANDAO 来修改存储
    • PP' 具有不同的 prevRandao
    • newPayload(P')
    • 注意:EL 可能会响应 ACCEPTEDVALID
    • forkchoiceUpdated(headBlock: P')
    • EL 响应 {payloadStatus: {status: VALID, latestValidHash: forkchoiceState.headBlockHash, validationError: null}, payloadId: null}
    • EL 将 head 设置为 P'
    • 存储已使用 P'.prevRandao 正确更新

    </details>

  • [x] [Hive] 更新规范链上的 finalized 和 safe 区块 <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4 是扩展规范链的有效 payload 的子链
    • newPayload(P1) + forkchoiceUpdated(finalized: Genesis, safe: Genesis, head: P1)
    • newPayload(P2) + forkchoiceUpdated(finalized: Genesis, safe: P1, head: P2)
    • EL 将 safe 设置为 P1,将 head 设置为 P2finalized == Genesis
    • newPayload(P3) + forkchoiceUpdated(finalized: P1, safe: P2, head: P3)
    • EL 将 finalized 设置为 P1,将 safe 设置为 P2,将 head 设置为 P3
    • newPayload(P4) + forkchoiceUpdated(finalized: P2, safe: P3, head: P4)
    • EL 将 finalized 设置为 P2,将 safe 设置为 P3,将 head 设置为 P4

    </details>

  • [x] [Hive] 更新链上的 safe 区块 <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1 &lt;- P2 &lt;- P3 是扩展规范链的有效 payload 的子链,B: Genesis &lt;- P1 &lt;- P2' &lt;- P3' 是扩展侧链的有效 payload 的子链
    • 导入 A 并调用 forkchoiceUpdated(finalized: P1, safe: P2, head: P3)
    • EL 将 finalized 设置为 P1,将 safe 设置为 P2,将 head 设置为 P3
    • 通过调用 newPayload(P2') + newPayload(P3') 导入 B 并调用 forkchoiceUpdated(finalized: P1, safe: P2', head: P3')
    • 请注意,此测试可能需要 forkchoiceUpdated 轮询,因为 EL 可能会响应正在同步
    • EL 将 finalized 设置为 P1,将 safe 设置为 P2',将 head 设置为 P3'

    </details>

  • [x] [Hive] SYNCING 具有有效链 <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- ... &lt;- Pn
    • EL 客户端以 Genesis 区块和状态启动
    • newPayload(Pn) + forkchoiceUpdated(head: Pn)
    • EL 响应 {status: SYNCING, latestValidHash: null, validationError: null}
    • EL 客户端应从远程对等点拉取 P1 &lt;- P2 &lt;- P3 &lt;- ... &lt;- Pn-1 并成功完成同步过程
    • newPayload(Pn+1) + forkchoiceUpdated(head: Pn+1)
    • 使用新的 payload 轮询 newPayload + forkchoiceUpdated,直到响应为 VALID
    • finalizedsafe 和 head 区块已相应设置

    </details>

  • [x] [Hive PR] 在 SYNCING 时重新组织回规范链 <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4, B: Genesis &lt;- P1' &lt;- P2' &lt;- P3' &lt;- P4'
    • EL 客户端同步到 A.P3 区块,即 A.P3 是 head
    • newPayload(B.P4') + forkchoiceUpdated(head: B.P4')
    • EL 响应 {status: SYNCING, latestValidHash: null, validationError: null}
    • 请注意,B 链的其余部分应不可用,以使 EL 无法完成其同步过程
    • newPayload(A.P4) + forkchoiceUpdated(A.P4)
    • 轮询 forkchoiceUpdated(finalized: P2, safe: P3, head: P4),直到响应为 VALID
    • finalizedsafe 和 head 区块已相应设置

    </details>

  • [x] [Hive] 重新组织为删除交易的链 <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1B: Genesis &lt;- P1'
    • P1P1' 是有效的 payload
    • P1 包含交易 Tx1,而 P1' 不包含任何交易
    • newPayload(A.P1) + forkchoiceUpdated(head: A.P1)
    • EL 响应 {status: VALID, latestValidHash: A.P1, validationError: null}
    • 使用 JSON-RPC 请求 Tx1 收据
    • 客户端返回 Tx1 收据
    • newPayload(B.P1') + forkchoiceUpdated(head: B.P1')
    • EL 响应 {status: VALID, latestValidHash: B.P1', validationError: null}
    • 使用 JSON-RPC 请求 Tx1 收据
    • 客户端返回错误且没有 Tx1 收据

    </details>

  • [x] [Hive] 具有现有规范链 payload 的 newPayload <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- ... &lt;- Pn
    • newPayload(P1) + forkchoiceUpdated(head: P1)newPayload(Pn) + forkchoiceUpdated(head: Pn)
    • EL head 设置为 Pn
    • newPayload(P1)newPayload(Pn)
    • EL 返回 VALID 且没有错误
    • newPayload(Pn+1) + forkchoiceUpdated(head: Pn+1)
    • 客户端继续构建规范链,没有问题

    </details>

  • [x] [Hive] 导入并重新组织到先前验证的 payload <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4
    • EL 以 head: P4, safe: P3, finalized: P2 启动
    • newPayload(P3)
    • EL 返回 {status: VALID, latestValidHash: P3.blockHash}
    • forkchoiceUpdated(head: P3, safe: P2, finalized: P1)
    • EL 返回 {status: VALID, latestValidHash: P3.blockHash}

    </details>

  • [x] [Hive] 导入并重新组织到侧链上先前验证的 payload <details> <summary>点击查看详情</summary>

    • A: Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4B: Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4
    • EL 以导入的 AB 链以及作为 head 的 A.P4 启动
    • newPayload(B.P3)
    • EL 返回 {status: VALID, latestValidHash: B.P3.blockHash}
    • forkchoiceUpdated(head: B.P3, payloadAttributes: buildProcessAttributes)
    • EL 返回 payloadStatus: {status: VALID, latestValidHash: B.P3.blockHash}, payloadId: buildProcessId
    • getPayload(payloadId: buildProcessId)
    • EL 返回 builtPayload
    • newPayload(builtPayload)
    • EL 返回 {status: VALID, latestValidHash: builtPayload.blockHash}

    </details>

CL 客户端测试

  • [x] [Hive] QUANTITY 字段值已正确编码 <details> <summary>点击查看详情</summary>

    • Payload P1 具有大于 255 的所有 QUANTITY 字段值
    • CL 处理 BeaconBlock(P1)
    • 所有 P1 QUANTITY 字段都是大端序

    </details>

  • [x] [Hive] INVALID 规范 链 payload <details> <summary>点击查看详情</summary>

    • INV_P 是扩展规范链的 INVALID payload
    • CL 导入 BeaconBlock(INV_P)
    • EL 模拟人为地返回 INVALID
    • 无法通过 GET /eth/v1/beacon/headers/{block_id} 访问 BeaconBlock(INV_P)

    </details>

  • [x] [Hive] 无效的 Timestamp <details> <summary>点击查看详情</summary>

    • INV_P 是由 EL 生成的扩展规范链的 INVALID payload,其中 timestamp 值超出当前 slot 时间范围
    • CL 拒绝 INV_P

    </details>

  • [x] [Hive] 无效的 PrevRandao <details> <summary>点击查看详情</summary>

    • INV_P 是由 EL 生成的扩展规范链的 INVALID payload,其中 prevRandao 值不是给定 slot 的预期 randao 混合值
    • CL 拒绝 INV_P

    </details>

  • [x] [Hive] 无效的 block_hash <details> <summary>点击查看详情</summary>

    • Payload P 响应 INVALID_BLOCK_HASH
    • EL 模拟人为地返回此状态
    • CL 丢弃 BeaconBlock(P)

    </details>

  • [x] [Hive] SYNCING 具有无效链 <details> <summary>点击查看详情</summary>

    • Genesis &lt;- P1 &lt;- P2 &lt;- P3 &lt;- P4
    • CL 逐个导入 BeaconBlock(P1) ... BeaconBlock(P4) 区块
    • EL 模拟应在 newPayload(P2) 上响应 SYNCING
    • EL 模拟应在 newPayload(P4) 上响应 status: INVALID, latestValidHash: P1.blockHash
    • CL 的 head 必须是 BeaconBlock(P1)
    • EL 必须收到 forkchoiceUpdated(P1)
    • finalizedsafe 和 head 区块符合预期

    </details>

  • [x] [Hive] baseFee 编码检查 <details> <summary>点击查看详情</summary>

    • EL 生成一个 payload P1,其中 baseFee 字段大于或等于 256
    • CL 接受、广播并验证具有正确 endianess 的 payload
    • BeaconBlock(P1) 已并入链中

    </details>

  • [x] [Hive] 超时 <details> <summary>点击查看详情</summary>

    • P 是扩展规范链的 VALID payload
    • CL 导入 BeaconBlock(P)
    • EL 模拟人为地暂停 newPayloadforkchoiceUpdated,在响应之前暂停 timeout - 1s
    • BeaconBlock(P) 是 CL 链的 head
    • P 是 EL 链的 head

    </details>

  • [x] [Hive PR] 由于乐观同步而没有可行的 head <details> <summary>点击查看详情</summary>

    • 配置
    • SLOTS_PER_EPOCH = 32
    • ... &lt;- P0 &lt;- P1 &lt;- P2 &lt;- ... &lt;- Pn
    • BeaconBlock(P0).slot % SLOTS_PER_EPOCH == 0
    • BeaconBlock(P0).slot >= 128 距离 Genesis 足够远
    • CL builder1 和 CL importer 处理 BeaconBlock(P0), ..., BeaconBlock(P10)
    • EL 模拟返回 status: VALID
    • CL builder1
    • BeaconBlock(P11), ..., BeaconBlock(P33):EL 模拟返回 status: VALID
    • CL importer
    • BeaconBlock(P10), ..., BeaconBlock(P32):EL 模拟返回 status: SYNCING
    • BeaconBlock(P33)
      • 第一种变体
      • newPayload(P33){status: INVALID, latestValidHash: P10.blockHash}
      • 第二种变体
      • newPayload(P33){status: SYNCING}
      • forkChoiceUpdated(P33){status: INVALID, latestValidHash: P10.blockHash}
    • 检查节点是否保持乐观,即 Beacon API 响应中的 execution_optimistic 标志是否为 true
    • CL builder1 关闭
    • CL builder2
    • 启动,与 CL importer 对等并同步到 BeaconBlock(P10)
    • BeaconBlock(P11, slot34), ..., BeaconBlock(Pn, slotN):EL 模拟返回 status: VALID
    • CL importer
    • BeaconBlock(P11, slot34), ..., BeaconBlock(Pn, slotN):EL 模拟返回 status: VALID
    • slotN 应该足够高,以便 importer 可以从乐观状态恢复,N >= 96
    • 检查节点是否不再乐观,并且 BeaconBlock(Pn, slotN) 是 head

    </details>

  • 原文链接: github.com/txrx-research...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
txrx-research
txrx-research
江湖只有他的大名,没有他的介绍。