Commit aebb0ccd authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

Merge pull request #8472 from ethereum-optimism/aj/use-system

op-e2e: Refactor dispute game helpers
parents 3019c6c4 83723b85
......@@ -9,11 +9,8 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
......@@ -21,35 +18,33 @@ type CannonGameHelper struct {
FaultGameHelper
}
func (g *CannonGameHelper) StartChallenger(ctx context.Context, rollupCfg *rollup.Config, l2Genesis *core.Genesis, l1Endpoint string, l2Endpoint string, name string, options ...challenger.Option) *challenger.Helper {
func (g *CannonGameHelper) StartChallenger(ctx context.Context, l2Node string, name string, options ...challenger.Option) *challenger.Helper {
opts := []challenger.Option{
challenger.WithCannon(g.t, rollupCfg, l2Genesis, l2Endpoint),
challenger.WithCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), g.system.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, l1Endpoint, name, opts...)
c := challenger.NewChallenger(g.t, ctx, g.system.NodeEndpoint("l1"), name, opts...)
g.t.Cleanup(func() {
_ = c.Close()
})
return c
}
func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rollup.Config, l2Genesis *core.Genesis, l1Client *ethclient.Client, l1Endpoint string, l2Endpoint string, options ...challenger.Option) *HonestHelper {
func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *HonestHelper {
opts := []challenger.Option{
challenger.WithCannon(g.t, rollupCfg, l2Genesis, l2Endpoint),
challenger.WithCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), g.system.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
}
opts = append(opts, options...)
cfg := challenger.NewChallengerConfig(g.t, l1Endpoint, opts...)
cfg := challenger.NewChallengerConfig(g.t, g.system.NodeEndpoint("l1"), opts...)
logger := testlog.Logger(g.t, log.LvlInfo).New("role", "CorrectTrace")
maxDepth := g.MaxDepth(ctx)
gameContract, err := contracts.NewFaultDisputeGameContract(g.addr, batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize))
gameContract, err := contracts.NewFaultDisputeGameContract(g.addr, batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize))
g.require.NoError(err, "Create game contract bindings")
l2Client, err := ethclient.DialContext(ctx, cfg.CannonL2)
g.require.NoErrorf(err, "dial l2 client %v", cfg.CannonL2)
defer l2Client.Close() // Not needed after fetching the inputs
l2Client := g.system.NodeClient(l2Node)
localInputs, err := cannon.FetchLocalInputs(ctx, gameContract, l2Client)
g.require.NoError(err, "fetch cannon local inputs")
provider := cannon.NewTraceProvider(logger, metrics.NoopMetrics, cfg, types.NoLocalContext, localInputs, filepath.Join(cfg.Datadir, "honest"), uint64(maxDepth))
......
......@@ -25,6 +25,7 @@ type FaultGameHelper struct {
game *bindings.FaultDisputeGame
factoryAddr common.Address
addr common.Address
system DisputeSystem
}
func (g *FaultGameHelper) Addr() common.Address {
......
......@@ -22,7 +22,6 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/dial"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
......@@ -67,9 +66,21 @@ func (s Status) String() string {
var CorrectAlphabet = "abcdefghijklmnop"
type DisputeSystem interface {
NodeEndpoint(name string) string
NodeClient(name string) *ethclient.Client
RollupEndpoint(name string) string
RollupClient(name string) *sources.RollupClient
L1Deployments() *genesis.L1Deployments
RollupCfg() *rollup.Config
L2Genesis() *core.Genesis
}
type FactoryHelper struct {
t *testing.T
require *require.Assertions
system DisputeSystem
client *ethclient.Client
opts *bind.TransactOpts
factoryAddr common.Address
......@@ -78,29 +89,31 @@ type FactoryHelper struct {
l2ooHelper *l2oo.L2OOHelper
}
func NewFactoryHelper(t *testing.T, ctx context.Context, deployments *genesis.L1Deployments, client *ethclient.Client) *FactoryHelper {
func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *FactoryHelper {
require := require.New(t)
client := system.NodeClient("l1")
chainID, err := client.ChainID(ctx)
require.NoError(err)
opts, err := bind.NewKeyedTransactorWithChainID(deployer.TestKey, chainID)
require.NoError(err)
require.NotNil(deployments, "No deployments")
factoryAddr := deployments.DisputeGameFactoryProxy
l1Deployments := system.L1Deployments()
factoryAddr := l1Deployments.DisputeGameFactoryProxy
factory, err := bindings.NewDisputeGameFactory(factoryAddr, client)
require.NoError(err)
blockOracle, err := bindings.NewBlockOracle(deployments.BlockOracle, client)
blockOracle, err := bindings.NewBlockOracle(l1Deployments.BlockOracle, client)
require.NoError(err)
return &FactoryHelper{
t: t,
require: require,
system: system,
client: client,
opts: opts,
factory: factory,
factoryAddr: factoryAddr,
blockOracle: blockOracle,
l2ooHelper: l2oo.NewL2OOHelperReadOnly(t, deployments, client),
l2ooHelper: l2oo.NewL2OOHelperReadOnly(t, l1Deployments, client),
}
}
......@@ -131,6 +144,7 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
FaultGameHelper: FaultGameHelper{
t: h.t,
require: h.require,
system: h.system,
client: h.client,
opts: h.opts,
game: game,
......@@ -141,11 +155,9 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
}
}
func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoint string, rootClaim common.Hash) *OutputCannonGameHelper {
func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string, rootClaim common.Hash) *OutputCannonGameHelper {
logger := testlog.Logger(h.t, log.LvlInfo).New("role", "OutputCannonGameHelper")
rollupClient, err := dial.DialRollupClientWithTimeout(ctx, 30*time.Second, logger, rollupEndpoint)
h.require.NoError(err)
h.t.Cleanup(rollupClient.Close)
rollupClient := h.system.RollupClient(l2Node)
extraData, _ := h.createBisectionGameExtraData(ctx, rollupClient)
......@@ -182,6 +194,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoin
factoryAddr: h.factoryAddr,
addr: createdEvent.DisputeProxy,
correctOutputProvider: provider,
system: h.system,
},
}
......@@ -192,24 +205,21 @@ func (h *FactoryHelper) StartCannonGame(ctx context.Context, rootClaim common.Ha
return h.createCannonGame(ctx, rootClaim, extraData)
}
func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, rollupCfg *rollup.Config, l2Genesis *core.Genesis, l1Endpoint string, l2Endpoint string, options ...challenger.Option) (*CannonGameHelper, *HonestHelper) {
func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, l2Node string, options ...challenger.Option) (*CannonGameHelper, *HonestHelper) {
extraData, l1Head, l2BlockNumber := h.createDisputeGameExtraData(ctx)
challengerOpts := []challenger.Option{
challenger.WithCannon(h.t, rollupCfg, l2Genesis, l2Endpoint),
challenger.WithCannon(h.t, h.system.RollupCfg(), h.system.L2Genesis(), h.system.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(h.factoryAddr),
}
challengerOpts = append(challengerOpts, options...)
cfg := challenger.NewChallengerConfig(h.t, l1Endpoint, challengerOpts...)
cfg := challenger.NewChallengerConfig(h.t, h.system.NodeEndpoint("l1"), challengerOpts...)
opts := &bind.CallOpts{Context: ctx}
challengedOutput := h.l2ooHelper.GetL2OutputAfter(ctx, l2BlockNumber)
agreedOutput := h.l2ooHelper.GetL2OutputBefore(ctx, l2BlockNumber)
l1BlockInfo, err := h.blockOracle.Load(opts, l1Head)
h.require.NoError(err, "Fetch L1 block info")
l2Client, err := ethclient.DialContext(ctx, cfg.CannonL2)
if err != nil {
h.require.NoErrorf(err, "Failed to dial l2 client %v", l2Endpoint)
}
l2Client := h.system.NodeClient(l2Node)
defer l2Client.Close()
agreedHeader, err := l2Client.HeaderByNumber(ctx, agreedOutput.L2BlockNumber)
if err != nil {
......@@ -280,6 +290,7 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, rootClaim common.H
FaultGameHelper: FaultGameHelper{
t: h.t,
require: h.require,
system: h.system,
client: h.client,
opts: h.opts,
game: game,
......@@ -318,12 +329,12 @@ func (h *FactoryHelper) createDisputeGameExtraData(ctx context.Context) (extraDa
return
}
func (h *FactoryHelper) StartChallenger(ctx context.Context, l1Endpoint string, name string, options ...challenger.Option) *challenger.Helper {
func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, options ...challenger.Option) *challenger.Helper {
opts := []challenger.Option{
challenger.WithFactoryAddress(h.factoryAddr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(h.t, ctx, l1Endpoint, name, opts...)
c := challenger.NewChallenger(h.t, ctx, h.system.NodeEndpoint("l1"), name, opts...)
h.t.Cleanup(func() {
_ = c.Close()
})
......
......@@ -2,10 +2,15 @@ package disputegame
import (
"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-node/rollup"
"github.com/ethereum/go-ethereum/core"
"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 {
......@@ -14,23 +19,53 @@ type OutputCannonGameHelper struct {
func (g *OutputCannonGameHelper) StartChallenger(
ctx context.Context,
rollupCfg *rollup.Config,
l2Genesis *core.Genesis,
rollupEndpoint string,
l1Endpoint string,
l2Endpoint string,
l2Node string,
name string,
options ...challenger.Option,
) *challenger.Helper {
rollupEndpoint := g.system.RollupEndpoint(l2Node)
l2Endpoint := g.system.NodeEndpoint(l2Node)
opts := []challenger.Option{
challenger.WithOutputCannon(g.t, rollupCfg, l2Genesis, rollupEndpoint, l2Endpoint),
challenger.WithOutputCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), rollupEndpoint, l2Endpoint),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, l1Endpoint, name, opts...)
c := challenger.NewChallenger(g.t, ctx, g.system.NodeEndpoint("l1"), name, opts...)
g.t.Cleanup(func() {
_ = c.Close()
})
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,
}
}
......@@ -29,6 +29,7 @@ type OutputGameHelper struct {
factoryAddr common.Address
addr common.Address
correctOutputProvider *outputs.OutputTraceProvider
system DisputeSystem
}
func (g *OutputGameHelper) Addr() common.Address {
......
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
}
......@@ -88,7 +88,7 @@ func TestChallengerCompleteDisputeGame(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartAlphabetGame(ctx, test.rootClaimAlphabet)
require.NotNil(t, game)
gameDuration := game.GameDuration(ctx)
......@@ -123,7 +123,7 @@ func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
rootClaimedAlphabet := disputegame.CorrectAlphabet
if !isRootCorrect {
rootClaimedAlphabet = "abcdexyz"
......
......@@ -32,14 +32,12 @@ func TestCannonDisputeGame(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartCannonGame(ctx, common.Hash{0x01, 0xaa})
require.NotNil(t, game)
game.LogGameData(ctx)
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, sys.NodeEndpoint("l1"), sys.NodeEndpoint("sequencer"), "Challenger",
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
game.StartChallenger(ctx, "sequencer", "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
game.DefendRootClaim(
ctx,
......@@ -68,20 +66,14 @@ func TestCannonDefendStep(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartCannonGame(ctx, common.Hash{0x01, 0xaa})
require.NotNil(t, game)
game.LogGameData(ctx)
l1Endpoint := sys.NodeEndpoint("l1")
l2Endpoint := sys.NodeEndpoint("sequencer")
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint, "Challenger",
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
game.StartChallenger(ctx, "sequencer", "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Client, l1Endpoint, l2Endpoint,
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory),
)
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
game.DefendRootClaim(ctx, func(parentClaimIdx int64) {
// Post invalid claims for most steps to get down into the early part of the trace
......@@ -186,11 +178,8 @@ func TestCannonPoisonedPostState(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
l1Endpoint := sys.NodeEndpoint("l1")
l2Endpoint := sys.NodeEndpoint("sequencer")
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
game, correctTrace := disputeGameFactory.StartCannonGameWithCorrectRoot(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint,
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game, correctTrace := disputeGameFactory.StartCannonGameWithCorrectRoot(ctx, "sequencer",
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory),
)
require.NotNil(t, game)
......@@ -209,9 +198,7 @@ func TestCannonPoisonedPostState(t *testing.T) {
correctTrace.Attack(ctx, 3)
// Start the honest challenger
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint, "Honest",
challenger.WithPrivKey(sys.Cfg.Secrets.Bob),
)
game.StartChallenger(ctx, "sequencer", "Honest", challenger.WithPrivKey(sys.Cfg.Secrets.Bob))
// Start dishonest challenger that posts correct claims
// It participates in the subgame root the honest claim index 4
......@@ -255,17 +242,14 @@ func TestCannonChallengeWithCorrectRoot(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
l1Endpoint := sys.NodeEndpoint("l1")
l2Endpoint := sys.NodeEndpoint("sequencer")
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
game, correctTrace := disputeGameFactory.StartCannonGameWithCorrectRoot(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint,
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game, correctTrace := disputeGameFactory.StartCannonGameWithCorrectRoot(ctx, "sequencer",
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory),
)
require.NotNil(t, game)
game.LogGameData(ctx)
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint, "Challenger",
game.StartChallenger(ctx, "sequencer", "Challenger",
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
......
......@@ -22,9 +22,9 @@ func TestMultipleCannonGames(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
gameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
gameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
// Start a challenger with the correct alphabet trace
challenger := gameFactory.StartChallenger(ctx, sys.NodeEndpoint("l1"), "TowerDefense",
challenger := gameFactory.StartChallenger(ctx, "TowerDefense",
challenger.WithCannon(t, sys.RollupConfig, sys.L2GenesisCfg, sys.NodeEndpoint("sequencer")),
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
......@@ -78,12 +78,12 @@ func TestMultipleGameTypes(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon, op_e2e.UseExecutor(0))
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, _ := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
gameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
gameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
// Start a challenger with both cannon and alphabet support
gameFactory.StartChallenger(ctx, sys.NodeEndpoint("l1"), "TowerDefense",
gameFactory.StartChallenger(ctx, "TowerDefense",
challenger.WithCannon(t, sys.RollupConfig, sys.L2GenesisCfg, sys.NodeEndpoint("sequencer")),
challenger.WithAlphabet(disputegame.CorrectAlphabet),
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
......
......@@ -20,18 +20,11 @@ func TestOutputCannonGame(t *testing.T) {
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
rollupEndpoint := sys.RollupNodes["sequencer"].HTTPEndpoint()
l1Endpoint := sys.NodeEndpoint("l1")
l2Endpoint := sys.NodeEndpoint("sequencer")
require.NotEqual(t, rollupEndpoint, l2Endpoint)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
game := disputeGameFactory.StartOutputCannonGame(ctx, rollupEndpoint, common.Hash{0x01})
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", common.Hash{0x01})
game.LogGameData(ctx)
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, rollupEndpoint, l1Endpoint, l2Endpoint, "Challenger",
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
game.StartChallenger(ctx, "sequencer", "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
game.LogGameData(ctx)
// Challenger should post an output root to counter claims down to the leaf level of the top game
......@@ -89,19 +82,16 @@ func TestOutputCannonDisputeGame(t *testing.T) {
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
rollupEndpoint := sys.RollupNodes["sequencer"].HTTPEndpoint()
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
game := disputeGameFactory.StartOutputCannonGame(ctx, rollupEndpoint, common.Hash{0x01, 0xaa})
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", common.Hash{0x01, 0xaa})
require.NotNil(t, game)
game.LogGameData(ctx)
game.DisputeLastBlock(ctx)
splitDepth := game.SplitDepth(ctx)
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, rollupEndpoint, sys.NodeEndpoint("l1"), sys.NodeEndpoint("sequencer"), "Challenger",
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
game.StartChallenger(ctx, "sequencer", "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
game.DefendRootClaim(
ctx,
......@@ -121,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))
}
......@@ -45,19 +45,14 @@ func setupDisputeGameForInvalidOutputRoot(t *testing.T, outputRoot common.Hash)
// Submit an invalid output root
l2oo.PublishNextOutput(ctx, outputRoot)
l1Endpoint := sys.NodeEndpoint("l1")
l2Endpoint := sys.NodeEndpoint("sequencer")
// Dispute the new output root by creating a new game with the correct cannon trace.
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.Cfg.L1Deployments, l1Client)
game, correctTrace := disputeGameFactory.StartCannonGameWithCorrectRoot(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint,
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game, correctTrace := disputeGameFactory.StartCannonGameWithCorrectRoot(ctx, "sequencer",
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory),
)
require.NotNil(t, game)
// Start the honest challenger
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, l1Endpoint, l2Endpoint, "Defender",
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory),
)
game.StartChallenger(ctx, "sequencer", "Defender", challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
return sys, l1Client, game, correctTrace
}
......@@ -16,6 +16,7 @@ import (
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-service/dial"
ds "github.com/ipfs/go-datastore"
dsSync "github.com/ipfs/go-datastore/sync"
ic "github.com/libp2p/go-libp2p/core/crypto"
......@@ -278,12 +279,48 @@ type System struct {
t *testing.T
closed atomic.Bool
// rollupClients caches the lazily created RollupClient instances so they can be reused and closed
rollupClients map[string]*sources.RollupClient
}
func (sys *System) NodeEndpoint(name string) string {
return selectEndpoint(sys.EthInstances[name])
}
func (sys *System) NodeClient(name string) *ethclient.Client {
return sys.Clients[name]
}
func (sys *System) RollupEndpoint(name string) string {
return sys.RollupNodes[name].HTTPEndpoint()
}
func (sys *System) RollupClient(name string) *sources.RollupClient {
client, ok := sys.rollupClients[name]
if ok {
return client
}
logger := testlog.Logger(sys.t, log.LvlInfo).New("rollupClient", name)
endpoint := sys.RollupEndpoint(name)
client, err := dial.DialRollupClientWithTimeout(context.Background(), 30*time.Second, logger, endpoint)
require.NoErrorf(sys.t, err, "Failed to dial rollup client %v", name)
sys.rollupClients[name] = client
return client
}
func (sys *System) L1Deployments() *genesis.L1Deployments {
return sys.Cfg.L1Deployments
}
func (sys *System) RollupCfg() *rollup.Config {
return sys.RollupConfig
}
func (sys *System) L2Genesis() *core.Genesis {
return sys.L2GenesisCfg
}
func (sys *System) Close() {
if !sys.closed.CompareAndSwap(false, true) {
// Already closed.
......@@ -314,6 +351,9 @@ func (sys *System) Close() {
combinedErr = errors.Join(combinedErr, fmt.Errorf("stop EthInstance %v: %w", name, err))
}
}
for _, client := range sys.rollupClients {
client.Close()
}
if sys.Mocknet != nil {
if err := sys.Mocknet.Close(); err != nil {
combinedErr = errors.Join(combinedErr, fmt.Errorf("stop Mocknet: %w", err))
......@@ -360,12 +400,13 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
}
sys := &System{
t: t,
Cfg: cfg,
EthInstances: make(map[string]EthInstance),
Clients: make(map[string]*ethclient.Client),
RawClients: make(map[string]*rpc.Client),
RollupNodes: make(map[string]*rollupNode.OpNode),
t: t,
rollupClients: make(map[string]*sources.RollupClient),
}
// Automatically stop the system at the end of the test
t.Cleanup(sys.Close)
......
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