omo检测冲突指令过程

0. 整体步骤

下面的内容是 simple_challenge 合约与 OMO 的交互过程,因为我们先不关注区块的构建和执行,只保留核心的二分查找冲突指令,以及 L1 仲裁的核心过程。

总体上分为三个步骤:

  • 执行 OMO 拿到 初始状态和最终状态

  • OMO 配合 L1 合约找到冲突的mips指令

  • 调用 L1 合约仲裁,判断是 challenge 还是 defender 作恶

1. 执行 OMO 得到初始状态和最终状态

  1. OMO 将 mips elf 加载到 unicorn,但是不执行,拿到一个初始状态 (initial_state)。

  2. OMO 将 mips elf 加载到 unicorn 并且完全执行,得到一个最终状态 和最终执行到 mips 指令的哪一步(final_state, step_count)。

L2 要依靠 L1 合约,做二分查找来帮助找到冲突指令,所以整个整个 mips elf 程序的执行开始和执行结束的状态都需要。

因为如果恰好是第二条 mips 指令,或者倒数第二条 mips 指令是冲突指令,如果没有开始和结束的内存状态,就无法依靠二分查找来找到冲突指令。
而且完整执行一遍 mips elf 程序之后,还可以在 L1 合约中判断 L2 执行 mips 指令的过程是否正确,以及内存写入的位置是否正确等校验性质的工作。

2. 找到冲突的mips指令

下面就是链下查找冲突指令的过程,不过在此之前,先介绍几个重要的 L1 合约函数:

  • init_challenge() 使用 initial_state 和 final_state + step_count,初始化一个challenge 。

  • is_searching() 判断是否找到了冲突指令。

  • step_number() 返回当前二分查找所在的步骤。

  • propose_state() challenger 多次调用,每次都将 L2 执行到某个 step 的 state_root 保存到 L1 合约。

  • respond_state() defender 多次调用,每次都将 L2 执行到某个 step 的 state_root 保存到 L1 合约,并且会对比本轮(一轮两次:challenge和defender在同样的step_number各执行一次) 双方的 state_root 是否一致,并更新二分搜索的边界。

  • confirm_state_transition() challenger 调用,执行 step_state = mips.run(c.chanllenge_state[c.L]),再判断 stepState == c.chanllenge_state[c.R] 如果是 true,说明 challenge 获胜。因为按照二分查找法,冲突指令是 c.L+1 = c.R

  • deny_state_transition() defender 调用,执行 step_state = mips.run(c.defender_state[c.L]),再判断 stepState == c.defender_state[c.R] 如果是 true,说明 defender 获胜。

而在链下,需要一些列过程,调用OMO并将与 L1 交互。

下面的伪代码,是链下的过程:

challenge_id = init_challenge(initial_state, final_state, step_count) // 找到的冲突指令 conflicted_step = 0 // 25次查找,最大支持包含 32M条指令的 mips 可执行程序 for i=0; i<25; i++ { // 当前二分搜索的步骤 step = contract.get_step_number(challenge_id) // 找到了冲突的指令步骤,跳出循环 if !contract.is_searching(challenge_id) { // 冲突指令同样保存在 L1 合约中 conflicted_step = step break } // 执行 omo 得到某个 step 的 内存状态 step_state = get_state_at_step(step) // 将内存状态,保存到 L1 合约中 challenge 和 defender 保存状态的地方 if is_challenge() { contract.propose_state(challenge_id, step_state) } else { contract.respond_state(challenge_id, step_state) } }

3. 发起链上仲裁

// 找到了冲突指令,让 L1 合约的仲裁 is_challenge_win = contract.confirm_state_transition(challenge_id) is_defender_win = contract.deny_state_transition(challenge_id)

confirm_state_transition()deny_state_transition() 这两个合约函数中,如果某一方获胜,就执行扣除 challenger 或 defender 押金的动作,作为对作恶行为的处罚。