本文是Tokamak Network发布的OP Stack Fault Proof系列文章的第二篇,主要介绍了Optimism的FPVM——Cannon的故障证明系统。Cannon通过链下执行和链上验证来确保Layer2状态转换的完整性,文章详细讲解了Cannon的组件及其相互作用,包括MIPS.sol、MIPSEVM、PreimageOracle等,并阐述了它们在争议解决中的作用。
Tokamak Network 旨在为当前对 Optimism 和 Ethereum 生态系统演进感兴趣的开发者提供有价值的信息。
来源:Oplabs 链接
这篇文章是“OP Stack 完整版故障证明系列”的第二期,该系列由 Tokamak Network 计划撰写 3 篇文章。在本文中,我们概述了 Cannon
(Optimism 的 FPVM),它通过链下执行和链上验证来确保 Layer 2 状态转换的完整性。MIPS.sol
、MIPSEVM
等关键组件协同工作,以实现高效的争议解决。
💡 鉴于该系列的相互关联性,我们建议按顺序阅读这些文章,以便获得连贯的理解。
系列 1. Cannon 的故障证明系统: 在本文中,我们介绍了 Optimism 的故障证明程序,并解释了其多重证明架构如何增强 Layer 2 的安全性和可靠性。该程序集成了强大的故障证明机制,以确保准确的状态转换和高效的争议解决。[ 链接 ]
系列 3. 故障争议游戏 (FDG) / 二分游戏: 在本文中,我们探讨了 Optimism 的故障证明系统如何使用链上 (
MIPS.sol
) 和链下 (MIPSEVM
) 组件来解决 Layer 2 状态争议。我们涵盖了提议者和挑战者的角色、PreimageOracle
的数据管理以及确保完整性和安全性的激励结构。此外,我们还解释了二分游戏,它将争议分解为单个指令以进行精确验证。[ 链接 ]
图:整体故障证明系统流程图
此流程图概述了在 Optimism 网络中解决 Layer 2 区块状态转换争议的机制和流程。该过程的核心组件包括 Cannon
和 Op-challenger
之间的交互、二分游戏、通过 MIPS.sol
进行链上验证、通过 Op-program
进行执行跟踪管理以及见证证明的生成。以下是每个步骤的详细说明:
1. 对特定 L2 区块状态转换存在分歧:Cannon
与 Op-challenger
合作处理 MIPS 指令,生成状态见证哈希,以解决对特定 L2 区块状态转换的分歧。
2. 二分游戏:Op-challenger
利用生成的哈希来查明单个 MIPS 指令,即分歧的根源。然后,Cannon
生成一个见证证明(链下),其中包含在链上执行 MIPS 指令所需的所有数据(前像 + 状态信息)。
💡 如果链下生成的见证证明被篡改了怎么办?
▶ 在 MIPS.sol
中争议 MIPS 指令的链上执行是确定性的,确保相同的输入和状态始终产生相同的输出。如果链下证明被篡改,链上执行将通过与预期结果不匹配来暴露差异。
3. 链上验证:有争议的 MIPS 指令在 MIPS.sol
中进行链上执行,以最终确定正确的后状态,从而解决故障争议。由 Cannon
链下生成的见证证明包含此链上执行所需的所有数据。该证明确保了链上验证过程中过程的准确性和完整性。如果指令引用了哈希值,Cannon
会通过 Op-preimage
从 PreimageOracle
检索所需的前像,以在链上验证该指令。
4. 使用 OP-Program 进行执行跟踪:从 Op-program
编译的 ELF 二进制文件被加载并在 Cannon
中执行。Op-program
确保获取所有必要的数据以导出 L2 状态,从而保证相同的输入导致一致的输出和执行跟踪。
5. 见证证明生成:争议游戏中的参与者可以运行 Op-program
以生成相同的见证证明,用于要在链上执行的 MIPS 指令。双方独立验证有争议的 MIPS 指令的正确性。如果需要前像,witness.go
会将相关的前像密钥和偏移量传递给 Op-challenger
,使其可以链上发布到 PreimageOracle.sol
。
💡 见证证明生成过程由位于 cannon/cmd
中的顶级 witness.go
文件启动,而 cannon/mipsevm
中的 witness.go
文件定义了包含特定 MIPS 指令所有必要信息的结构体。如果 MIPS 指令需要前像,则会将其包含在此过程中,以确保准确且完整的验证。
witness.go
将相关的前像密钥和偏移量传递给 Op-challenger
。Op-challenger
将此信息链上发布到 PreimageOracle.sol
。💡 此过程会在 MIPSEVM
执行状态更改之前生成有关要在链上执行的 MIPS 指令的所有相关信息。通过确保在发生这些状态更改之前生成并传递所有必要的信息,该过程可以保证见证证明的准确性和完整性。这可以防止证明编码不正确的后状态,并确保其捕获正确的先验状态以进行正确的争议解决。如果在链下运行指令后生成见证证明,它将编码后状态而不是必要的先验状态。
图:Cannon 组件流程图
1. Cannon Runner
run.go
、instrumented.go
Cannon
中的执行过程。此组件处理顶级执行逻辑,逐步执行 MIPS 指令,并根据用户配置确定其他操作,例如日志记录、停止、拍摄快照或生成见证证据。2. 内存和状态管理
memory.go
、page.go
、state.go
MIPSEVM
进行交互。它确保 Cannon Runner 和 MIPSEVM
都具有一致且最新的内存和状态信息以供其操作。3. MIPSEVM
mips.go
PreimageOracle
(链下)交互,以检索验证哈希值所需的 preimage 数据。它确保链下 MIPS 执行产生与链上执行相同的结果,从而处理内存访问和状态更新。此外,它还跟踪需要内存证明的指令的内存访问。PreimageOracle
(链下)交互以检索所需的前像。4. 见证证明生成
witness.go
MIPS.sol
在链上运行相同指令并导出用于解决争议的后状态所需的必要信息。它还包括将相关的前像密钥和偏移量传递给 Op-challenger
以便链上发布到 PreimageOracle.sol
。6. ELF 加载器(执行跟踪过程)
load_elf.go
、patch.go
、metadata.go
Cannon
中编译为 MIPS 指令的 Op-program
的 ELF 文件。要在 Cannon
中运行 Op-program
,需要一个二进制加载器,它由 load_elf.go、patch.go 和 metadata.go
组成。load_elf.go
:此文件解析顶级参数,读取、加载和修补 ELF 二进制文件,以便 Cannon
可以运行它。patch.go
:此文件解析 ELF 文件的标头以确定存在哪些程序及其内存位置,实例化 MIPSEVM
的执行状态,将每个程序加载到内存中的预期位置,并设置 PC、NextPC、Heap (0x20000000)、Stack (0x7fffd000) 和堆栈指针之上的 Go 运行时参数的初始值。metadata.go
:此文件解析存储在 ELF 文件中的所有符号,有助于识别哪些 ELF 符号存在及其内存位置,这对于函数和其他功能非常重要。💡 ELF 加载器的目的是准备 MIPS 程序以通过加载 ELF 文件、设置初始状态、修补函数和解析符号来执行。它确保挑战者和验证者都从二分游戏中相同的正确状态开始,从而能够精确地识别和演示 MIPS 程序执行中的任何差异。这种准确的设置对于挑战者在发现故障时计算和证明正确的值至关重要。
5. PreimageOracle 服务器
图:PreimageOracle
链上/链下流程图。
功能: PreimageOracle 服务器
(链下)通过提供 MIPS 指令执行期间验证哈希值所需的必要前像数据来支持链下执行环境。该服务器通过访问正确的前像数据来确保链下执行可以产生与链上执行相同的结果。
链下计算:
MIPSEVM
链下执行 MIPS 指令,与 PreimageOracle
服务器交互以检索必要的前像。这允许快速高效的处理。PreimageOracle 服务器
存储和管理验证链下执行期间使用的哈希值所需的前像。链上验证:
PreimageOracle
会提供前像,以确保链上 MIPS.sol
合约可以准确地重新执行该指令并验证结果。MIPS.sol
智能合约是一个链上虚拟机 (VM),它执行 32 位大端 MIPS III 指令集。它与链下对应物 MIPSEVM
(用 Go 编写)一起工作,作为 Cannon
FPVM 系统的关键组件。该系统旨在链上执行 MIPS 指令,以解决 Optimism 的 Layer 2 区块链中的争议。MIPS.sol
的无状态性质及其与其他合约的交互确保了高效且可重复使用的争议解决流程。
💡 “无状态”一词表示 MIPS.sol
只有一个不可变的状态变量: PreimageOracle.sol
合约的地址。它依赖于外部输入和前像数据,确保每次执行都是独立的、高效的且易于验证的,从而通过最大限度地减少对内部状态的依赖来增强安全性和鲁棒性。这种设计允许它在多个争议游戏中使用而无需重新部署。
1. 与其他合约的交互:
MIPS.sol
主要由处理活跃争议的此合约调用。2. 在争议解决中的作用:
MIPS.sol
。此点表示需要链上执行的单个 MIPS 指令,以解决有争议的状态。3. MIPS 指令的执行:
MIPS.sol
使用二进制 Merkle 树结构,使用内存证明确保数据完整性。图:MIPS.sol (来源: github 链接)
function oracle(): 检索 PreimageOracle
地址。
图:MIPS.sol (来源: github 链接)
function outputState(): 此函数会将 MIPS 状态复制到空闲内存位置,记录状态以进行调试,根据退出代码确定 VM 状态,计算状态的 keccak256 哈希,并返回带有设置的状态字节的哈希。
此函数管理并记录执行 MIPS 指令后虚拟机的状态。这是一个更详细的解释:
图:MIPS.sol (来源: github 链接)
function handleSyscall(): MIPS.sol
中的此函数用于管理 MIPS 虚拟机中的系统级操作。这是一个详细的解释:
- 内存分配: 分配内存并更新内存管理结构。
- 程序终止: 终止程序并更新 VM 状态。
- 读取和写入: 管理 I/O 操作、从输入读取和写入输出。
- 文件描述符控制: 控制文件描述符以管理文件操作。
图:MIPS.sol (来源: github 链接)
function handleBranch(): 此函数对于管理 MIPS VM 中的条件执行至关重要。它会根据分支条件的评估来更新程序计数器,从而确保程序执行正确的指令序列。
参数:
图:MIPS.sol (来源: github 链接)
function HandleJump(): 此函数对于管理 MIPS 虚拟机中的跳转指令至关重要。
_dest
参数指定的新目标地址。这会将执行流更改为程序的其他部分。_linkReg
参数指定了链接寄存器,则该函数会将延迟Slot之后指令的地址存储在此寄存器中。这通常用于跳转和链接指令(例如,JAL),其中需要在函数调用返回时保存返回地址以供以后使用。handleJump
函数确保正确管理此Slot,从而保持预期的执行顺序。图:MIPS.sol (来源: github 链接)
function handleHiLo(): 此函数处理 MIPS 指令,这些指令涉及 HI 和 LO 寄存器,用于执行各种操作,例如将值移入/移出 HI/LO、乘法和除法。在执行所需操作后,它会更新 VM 状态并返回哈希状态。
handleHiLo
函数执行必要的操作。例如:
- 乘法: 将 _rs
和 _rt
相乘的结果通常在 HI 和 LO 寄存器之间分开。
- 除法: 将 _rs
除以 _rt
的商和余数分别存储在 LO 和 HI 寄存器中。
- 移动操作: 可以将值移入或移出 HI 和 LO 寄存器。
参数:
图:MIPS.sol (来源: github 链接)
function step(): MIPS.sol
中 step
函数的目的是管理 MIPS 虚拟机中各个指令的执行,确保正确处理程序的每个步骤。它获取并解码指令,执行指定的操作,相应地更新 VM 状态,并返回更新状态的哈希,以确保 VM 在每个步骤的执行的完整性和可验证性。
获取指令: 该函数首先从程序内存中获取当前指令,该内存基于程序计数器 (PC)。
解码指令: 获取指令后,该函数对其进行解码以确定其类型和需要执行的特定操作。指令类型可以是跳转、分支、算术逻辑单元 (ALU) 操作、内存访问或其他类型的指令。
执行操作: 基于解码的指令,该函数执行适当的操作。这包括:
更新 VM 状态: 执行指令后,该函数会更新 VM 状态以反映指令所做的更改。这包括更新 PC、寄存器、内存以及 VM 状态的任何其他相关部分。
返回哈希状态: 最后,该函数计算更新 VM 状态的哈希并返回它。此哈希充当新状态的唯一标识符,确保安全地记录指令的效果并且可以验证。
Cannon
的设计通过将严格的链下处理与可靠的链上验证相结合,确保了 Optimism 生态系统中争议的准确高效解决。这种模块化和可扩展的方法为未来的增强奠定了基础,包括支持各种故障证明机制。_
- 原文链接: medium.com/tokamak-netwo...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!