diff --git a/op-challenger/runner/runner.go b/op-challenger/runner/runner.go index 4c80655cfcdd8..924d7d7c22cda 100644 --- a/op-challenger/runner/runner.go +++ b/op-challenger/runner/runner.go @@ -161,13 +161,16 @@ func (r *Runner) createGameInputs(ctx context.Context, client *sources.RollupCli return utils.LocalGameInputs{}, fmt.Errorf("failed to get rollup sync status: %w", err) } - if status.SafeL2.Number == 0 { + if status.FinalizedL2.Number == 0 { return utils.LocalGameInputs{}, errors.New("safe head is 0") } - blockNumber := status.SafeL2.Number + blockNumber, err := r.findL2BlockNumberToDispute(ctx, client, status.FinalizedL1.Number, status.FinalizedL2.Number) + if err != nil { + return utils.LocalGameInputs{}, fmt.Errorf("failed to find l2 block number to dispute: %w", err) + } // When possible, execute the first block in the submitted batch - if status.SafeL1.Number > 0 { - priorSafeHead, err := client.SafeHeadAtL1Block(ctx, status.SafeL1.Number-1) + if status.FinalizedL1.Number > 0 { + priorSafeHead, err := client.SafeHeadAtL1Block(ctx, status.FinalizedL1.Number-32) if err != nil { r.log.Warn("Failed to get prior safe head", "err", err) } else if priorSafeHead.SafeHead.Number != 0 { // Sanity check to avoid trying to execute genesis @@ -183,7 +186,7 @@ func (r *Runner) createGameInputs(ctx context.Context, client *sources.RollupCli return utils.LocalGameInputs{}, fmt.Errorf("failed to get claim output: %w", err) } localInputs := utils.LocalGameInputs{ - L1Head: status.HeadL1.Hash, + L1Head: status.FinalizedL1.Hash, L2Head: parentOutput.BlockRef.Hash, L2OutputRoot: common.Hash(parentOutput.OutputRoot), L2Claim: common.Hash(claimOutput.OutputRoot), @@ -192,6 +195,32 @@ func (r *Runner) createGameInputs(ctx context.Context, client *sources.RollupCli return localInputs, nil } +func (r *Runner) findL2BlockNumberToDispute(ctx context.Context, client *sources.RollupClient, l1HeadNum uint64, l2BlockNum uint64) (uint64, error) { + // Try to find a L1 block prior to the batch that make l2BlockNum safe + // Limits how far back we search to 10 * 32 blocks + const skipSize = uint64(32) + for i := 0; i < 10; i++ { + if l1HeadNum < skipSize { + // Too close to genesis, give up and just use the original block + r.log.Info("Failed to find prior batch.") + return l2BlockNum, nil + } + l1HeadNum -= skipSize + priorSafeHead, err := client.SafeHeadAtL1Block(ctx, l1HeadNum) + if err != nil { + return 0, fmt.Errorf("failed to get prior safe head at L1 block %v: %w", l1HeadNum, err) + } + if priorSafeHead.SafeHead.Number < l2BlockNum { + // We walked back far enough to be before the batch that included l2BlockNum + // So use the first block after the prior safe head as the disputed block. + // It must be the first block in a batch. + return priorSafeHead.SafeHead.Number + 1, nil + } + } + r.log.Warn("Failed to find prior batch", "l2BlockNum", l2BlockNum, "earliestCheckL1Block", l1HeadNum) + return l2BlockNum, nil +} + func (r *Runner) getPrestateHash(ctx context.Context, traceType types.TraceType, caller *batching.MultiCaller) (common.Hash, error) { gameFactory := contracts.NewDisputeGameFactoryContract(r.m, r.cfg.GameFactoryAddress, caller) gameImplAddr, err := gameFactory.GetGameImpl(ctx, traceType.GameType())