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