Commit 82615ff1 authored by Adrian Sutton's avatar Adrian Sutton

op-e2e: Add output_cannon version of TestCannonDefendStep

Currently ignored until contracts select the correct pre-state for steps.
parent 59b5a982
...@@ -2,8 +2,15 @@ package disputegame ...@@ -2,8 +2,15 @@ package disputegame
import ( import (
"context" "context"
"path/filepath"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/log"
) )
type OutputCannonGameHelper struct { type OutputCannonGameHelper struct {
...@@ -30,3 +37,35 @@ func (g *OutputCannonGameHelper) StartChallenger( ...@@ -30,3 +37,35 @@ func (g *OutputCannonGameHelper) StartChallenger(
}) })
return c return c
} }
func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *OutputHonestHelper {
opts := []challenger.Option{
challenger.WithOutputCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), g.system.RollupEndpoint(l2Node), g.system.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
}
opts = append(opts, options...)
cfg := challenger.NewChallengerConfig(g.t, g.system.NodeEndpoint("l1"), opts...)
logger := testlog.Logger(g.t, log.LvlInfo).New("role", "HonestHelper", "game", g.addr)
l2Client := g.system.NodeClient(l2Node)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract, err := contracts.NewOutputBisectionGameContract(g.addr, caller)
g.require.NoError(err, "Failed to create game contact")
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.require.NoError(err, "Failed to load block range")
dir := filepath.Join(cfg.Datadir, "honest")
maxDepth := uint64(g.MaxDepth(ctx))
splitDepth := uint64(g.SplitDepth(ctx))
accessor, err := outputs.NewOutputCannonTraceAccessor(
ctx, logger, metrics.NoopMetrics, cfg, l2Client, contract, dir, maxDepth, splitDepth, prestateBlock, poststateBlock)
g.require.NoError(err, "Failed to create output cannon trace accessor")
return &OutputHonestHelper{
t: g.t,
require: g.require,
game: &g.OutputGameHelper,
contract: contract,
correctTrace: accessor,
}
}
package disputegame
import (
"context"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/stretchr/testify/require"
)
type OutputHonestHelper struct {
t *testing.T
require *require.Assertions
game *OutputGameHelper
contract *contracts.OutputBisectionGameContract
correctTrace types.TraceAccessor
}
func (h *OutputHonestHelper) Attack(ctx context.Context, claimIdx int64) {
// Ensure the claim exists
h.game.WaitForClaimCount(ctx, claimIdx+1)
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
game, claim := h.loadState(ctx, claimIdx)
attackPos := claim.Position.Attack()
h.t.Logf("Attacking at position %v with g index %v", attackPos, attackPos.ToGIndex())
value, err := h.correctTrace.Get(ctx, game, claim, attackPos)
h.require.NoErrorf(err, "Get correct claim at position %v with g index %v", attackPos, attackPos.ToGIndex())
h.t.Log("Performing attack")
h.game.Attack(ctx, claimIdx, value)
h.t.Log("Attack complete")
}
func (h *OutputHonestHelper) Defend(ctx context.Context, claimIdx int64) {
// Ensure the claim exists
h.game.WaitForClaimCount(ctx, claimIdx+1)
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
game, claim := h.loadState(ctx, claimIdx)
defendPos := claim.Position.Defend()
value, err := h.correctTrace.Get(ctx, game, claim, defendPos)
h.game.require.NoErrorf(err, "Get correct claim at position %v with g index %v", defendPos, defendPos.ToGIndex())
h.game.Defend(ctx, claimIdx, value)
}
func (h *OutputHonestHelper) StepFails(ctx context.Context, claimIdx int64, isAttack bool) {
// Ensure the claim exists
h.game.WaitForClaimCount(ctx, claimIdx+1)
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
game, claim := h.loadState(ctx, claimIdx)
pos := claim.Position
if !isAttack {
// If we're defending, then the step will be from the trace to the next one
pos = pos.MoveRight()
}
prestate, proofData, _, err := h.correctTrace.GetStepData(ctx, game, claim, pos)
h.require.NoError(err, "Get step data")
h.game.StepFails(claimIdx, isAttack, prestate, proofData)
}
func (h *OutputHonestHelper) loadState(ctx context.Context, claimIdx int64) (types.Game, types.Claim) {
claims, err := h.contract.GetAllClaims(ctx)
h.require.NoError(err, "Failed to load claims from game")
game := types.NewGameState(claims, uint64(h.game.MaxDepth(ctx)))
claim := game.Claims()[claimIdx]
return game, claim
}
...@@ -111,3 +111,41 @@ func TestOutputCannonDisputeGame(t *testing.T) { ...@@ -111,3 +111,41 @@ func TestOutputCannonDisputeGame(t *testing.T) {
}) })
} }
} }
func TestOutputCannonDefendStep(t *testing.T) {
// TODO(client-pod#247): Fix and enable this.
t.Skip("Currently failing because of invalid pre-state")
op_e2e.InitParallel(t, op_e2e.UsesCannon, op_e2e.UseExecutor(outputCannonTestExecutor))
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", common.Hash{0x01, 0xaa})
require.NotNil(t, game)
game.DisputeLastBlock(ctx)
game.LogGameData(ctx)
game.StartChallenger(ctx, "sequencer", "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
splitDepth := game.SplitDepth(ctx)
game.DefendRootClaim(ctx, func(parentClaimIdx int64) {
// Post invalid claims for most steps to get down into the early part of the trace
if parentClaimIdx < splitDepth+27 {
game.Attack(ctx, parentClaimIdx, common.Hash{byte(parentClaimIdx)})
} else {
// Post our own counter but using the correct hash in low levels to force a defense step
correctTrace.Attack(ctx, parentClaimIdx)
}
})
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true)
game.LogGameData(ctx)
require.EqualValues(t, disputegame.StatusChallengerWins, game.Status(ctx))
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment