这篇文章上次修改于 315 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
整体逻辑
Staker 源码
func (s *Staker) Act(ctx context.Context) (*types.Transaction, error) {
// 处理超时的挑战,将 loser 的 stake 罚没一半,奖励给 winner
arbTx, err := s.resolveTimedOutChallenges(ctx)
// 解决冲突,执行 func (m *ChallengeManager) Act()
s.handleConflict(ctx, rawInfo)
// 质押
s.advanceStake(ctx, &info, effectiveStrategy)
// 提出挑战
s.createConflict(ctx, rawInfo)
}
处理超时的挑战
timedOutChallenges() -> timeout() -> _nextWin():将 loser 的 stake 罚没一半,奖励给 winner
解决冲突
执行 func (m *ChallengeManager) Act()
- LoadExecChallengeIfExists():通过解析 event ExecutionChallengeBegun 检查挑战是否已经存在。如果已经存在,但是没有 execution challenge backend,则创建;否则,如果有 backend,则删除该 backend
- IsMyTurn():查看是不是轮到自己回应了,不是的话结束:currentResponder()
- GetChallengeState():通过 challengeInfo() 获取挑战,根据挑战的 state hash,通过解析 event Bisected 得到完整的挑战状态,如 segments
- ScanChallengeState():当前的 responder 应选择一对相邻的 segment 进行挑战,所以需要获得意见不同的 segment 的前一个 segment
- bisect():如果挑战没有缩减到只剩一步,则缩减挑战, bisectExecution() -> emit Bisected(selection.challengeStart, selection.challengeLength)
否则
IssueOneStepProof():如果有 execution challenge backend,说明挑战缩减到只剩一步,则执行 oneStepProveExecution()
当前的 responder 需要提供 proof,以还原出执行前的状态,执行 one step 后会得到执行后的状态,并与提交的状态进行比对,如果不同,则当前的 responder 赢 _currentWin()
_currentWin() 中仅仅将 state hash 设成 0,这样下次轮到对手时,对手无法进行任何合法的操作,c从而导致 challenge 超时,从而执行 _nextWin()
IssueExecChallenge():否则,说明挑战只是缩减到了某个 block,执行 challengeExecution() -> emit Bisected(challengeStart = 0, challengeLength = machineFinalStepCount, mode = ChallengeLib.ChallengeMode.EXECUTION), emit ExecutionChallengeBegun
当前的 responder 需要提供 global state 和 machine state
提出挑战
- 如果当前 staker 已经在挑战中了,结束
- 获取 staker 列表:getStakers
- 找到没有处于挑战中且质押的 node 不同的 staker:findStakerConflict()
- 找到冲突的两个 node 信息:getNodeCreationBlockForLogLookup() / getNode(),event NodeCreated
- 根据 node 信息解出 globalState()
提出挑战:createChallenge() -> emit Bisected(challengeStart = 0, challengeLength = numBlocks, mode = ChallengeLib.ChallengeMode.BLOCK)
第一个 Bisected event 只包含 2 个 segment
// 节点 _, err = s.rollup.CreateChallenge( auth, [2]common.Address{staker1, staker2}, [2]uint64{conflictInfo.Node1, conflictInfo.Node2}, node1Info.MachineStatuses(), node1Info.GlobalStates(), node1Info.Assertion.NumBlocks, node2Info.Assertion.ExecutionHash(), [2]*big.Int{new(big.Int).SetUint64(node1Info.L1BlockProposed), new(big.Int).SetUint64(node2Info.L1BlockProposed)}, [2][32]byte{node1Info.WasmModuleRoot, node2Info.WasmModuleRoot}, ) // 合约 function createChallenge( address[2] calldata stakers, uint64[2] calldata nodeNums, MachineStatus[2] calldata machineStatuses, GlobalState[2] calldata globalStates, uint64 numBlocks, bytes32 secondExecutionHash, uint256[2] calldata proposedBlocks, bytes32[2] calldata wasmModuleRoots ) external onlyValidator whenNotPaused { // Start a challenge between staker1 and staker2. Staker1 will defend the correctness of node1, and staker2 will challenge it. challengeManager.createChallenge() -> emit Bisected } emit Bisected( challengeIndex, challengeStateHash, challengeStart, challengeLength, newSegments ); // 定义 event Bisected( uint64 indexed challengeIndex, bytes32 indexed challengeRoot, uint256 challengedSegmentStart, uint256 challengedSegmentLength, bytes32[] chainHashes );
没有评论