Commit d4706dad authored by Park Changwan's avatar Park Changwan Committed by GitHub

op-e2e: Refactor for asterisc e2e (#10214)

* op-e2e: Expose fields for asterisc e2e

* op-e2e: Add Helper Initializer methods

* op-e2e: Apply initializer methods and exposed fields

* op-e2e: Expose methods for asterisc e2e
parent 1667124c
......@@ -40,6 +40,16 @@ type Helper struct {
chl cliapp.Lifecycle
}
func NewHelper(log log.Logger, t *testing.T, require *require.Assertions, dir string, chl cliapp.Lifecycle) *Helper {
return &Helper{
log: log,
t: t,
require: require,
dir: dir,
chl: chl,
}
}
type Option func(config2 *config.Config)
func WithFactoryAddress(addr common.Address) Option {
......@@ -66,9 +76,9 @@ func WithPollInterval(pollInterval time.Duration) Option {
}
}
// findMonorepoRoot finds the relative path to the monorepo root
// FindMonorepoRoot finds the relative path to the monorepo root
// Different tests might be nested in subdirectories of the op-e2e dir.
func findMonorepoRoot(t *testing.T) string {
func FindMonorepoRoot(t *testing.T) string {
path := "./"
// Only search up 5 directories
// Avoids infinite recursion if the root isn't found for some reason
......@@ -94,7 +104,7 @@ func applyCannonConfig(
) {
require := require.New(t)
c.L2Rpc = l2Endpoint
root := findMonorepoRoot(t)
root := FindMonorepoRoot(t)
c.CannonBin = root + "cannon/bin/cannon"
c.CannonServer = root + "op-program/bin/op-program"
c.CannonAbsolutePreState = root + "op-program/bin/prestate.json"
......
......@@ -15,53 +15,53 @@ import (
type ClaimHelper struct {
require *require.Assertions
game *OutputGameHelper
index int64
parentIndex uint32
position types.Position
Index int64
ParentIndex uint32
Position types.Position
claim common.Hash
}
func newClaimHelper(game *OutputGameHelper, idx int64, claim ContractClaim) *ClaimHelper {
return &ClaimHelper{
require: game.require,
require: game.Require,
game: game,
index: idx,
parentIndex: claim.ParentIndex,
position: types.NewPositionFromGIndex(claim.Position),
Index: idx,
ParentIndex: claim.ParentIndex,
Position: types.NewPositionFromGIndex(claim.Position),
claim: claim.Claim,
}
}
func (c *ClaimHelper) AgreesWithOutputRoot() bool {
return c.position.Depth()%2 == 0
return c.Position.Depth()%2 == 0
}
func (c *ClaimHelper) IsRootClaim() bool {
return c.position.IsRootPosition()
return c.Position.IsRootPosition()
}
func (c *ClaimHelper) IsOutputRoot(ctx context.Context) bool {
splitDepth := c.game.SplitDepth(ctx)
return c.position.Depth() <= splitDepth
return c.Position.Depth() <= splitDepth
}
func (c *ClaimHelper) IsOutputRootLeaf(ctx context.Context) bool {
splitDepth := c.game.SplitDepth(ctx)
return c.position.Depth() == splitDepth
return c.Position.Depth() == splitDepth
}
func (c *ClaimHelper) IsBottomGameRoot(ctx context.Context) bool {
splitDepth := c.game.SplitDepth(ctx)
return c.position.Depth() == splitDepth+1
return c.Position.Depth() == splitDepth+1
}
func (c *ClaimHelper) IsMaxDepth(ctx context.Context) bool {
maxDepth := c.game.MaxDepth(ctx)
return c.position.Depth() == maxDepth
return c.Position.Depth() == maxDepth
}
func (c *ClaimHelper) Depth() types.Depth {
return c.position.Depth()
return c.Position.Depth()
}
// WaitForCounterClaim waits for the claim to be countered by another claim being posted.
......@@ -72,8 +72,8 @@ func (c *ClaimHelper) WaitForCounterClaim(ctx context.Context, ignoreClaims ...*
// This is the first claim we need to run cannon on, so give it more time
timeout = timeout * 2
}
counterIdx, counterClaim := c.game.waitForClaim(ctx, timeout, fmt.Sprintf("failed to find claim with parent idx %v", c.index), func(claimIdx int64, claim ContractClaim) bool {
return int64(claim.ParentIndex) == c.index && !containsClaim(claimIdx, ignoreClaims)
counterIdx, counterClaim := c.game.waitForClaim(ctx, timeout, fmt.Sprintf("failed to find claim with parent idx %v", c.Index), func(claimIdx int64, claim ContractClaim) bool {
return int64(claim.ParentIndex) == c.Index && !containsClaim(claimIdx, ignoreClaims)
})
return newClaimHelper(c.game, counterIdx, counterClaim)
}
......@@ -83,28 +83,28 @@ func (c *ClaimHelper) WaitForCountered(ctx context.Context) {
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := wait.For(timedCtx, time.Second, func() (bool, error) {
latestData := c.game.getClaim(ctx, c.index)
latestData := c.game.getClaim(ctx, c.Index)
return latestData.CounteredBy != common.Address{}, nil
})
if err != nil { // Avoid waiting time capturing game data when there's no error
c.require.NoErrorf(err, "Claim %v was not countered\n%v", c.index, c.game.gameData(ctx))
c.require.NoErrorf(err, "Claim %v was not countered\n%v", c.Index, c.game.GameData(ctx))
}
}
func (c *ClaimHelper) RequireCorrectOutputRoot(ctx context.Context) {
c.require.True(c.IsOutputRoot(ctx), "Should not expect a valid output root in the bottom game")
expected, err := c.game.correctOutputProvider.Get(ctx, c.position)
expected, err := c.game.CorrectOutputProvider.Get(ctx, c.Position)
c.require.NoError(err, "Failed to get correct output root")
c.require.Equalf(expected, c.claim, "Should have correct output root in claim %v and position %v", c.index, c.position)
c.require.Equalf(expected, c.claim, "Should have correct output root in claim %v and position %v", c.Index, c.Position)
}
func (c *ClaimHelper) Attack(ctx context.Context, value common.Hash, opts ...MoveOpt) *ClaimHelper {
c.game.Attack(ctx, c.index, value, opts...)
c.game.Attack(ctx, c.Index, value, opts...)
return c.WaitForCounterClaim(ctx)
}
func (c *ClaimHelper) Defend(ctx context.Context, value common.Hash, opts ...MoveOpt) *ClaimHelper {
c.game.Defend(ctx, c.index, value, opts...)
c.game.Defend(ctx, c.Index, value, opts...)
return c.WaitForCounterClaim(ctx)
}
......@@ -115,19 +115,19 @@ func (c *ClaimHelper) RequireDifferentClaimValue(other *ClaimHelper) {
func (c *ClaimHelper) RequireOnlyCounteredBy(ctx context.Context, expected ...*ClaimHelper) {
claims := c.game.getAllClaims(ctx)
for idx, claim := range claims {
if int64(claim.ParentIndex) != c.index {
if int64(claim.ParentIndex) != c.Index {
// Doesn't counter this claim, so ignore
continue
}
if !containsClaim(int64(idx), expected) {
// Found a countering claim not in the expected list. Fail.
c.require.FailNowf("Found unexpected countering claim", "Parent claim index: %v Game state:\n%v", c.index, c.game.gameData(ctx))
c.require.FailNowf("Found unexpected countering claim", "Parent claim index: %v Game state:\n%v", c.Index, c.game.GameData(ctx))
}
}
}
func containsClaim(claimIdx int64, haystack []*ClaimHelper) bool {
return slices.ContainsFunc(haystack, func(candidate *ClaimHelper) bool {
return candidate.index == claimIdx
return candidate.Index == claimIdx
})
}
......@@ -39,7 +39,7 @@ func (d *DishonestHelper) ExhaustDishonestClaims(ctx context.Context, rootClaim
}
d.LogGameData(ctx)
d.OutputGameHelper.t.Logf("Dishonest moves against claimIndex %d", claimIndex)
d.OutputGameHelper.T.Logf("Dishonest moves against claimIndex %d", claimIndex)
agreeWithLevel := d.defender == (pos.Depth()%2 == 0)
if !agreeWithLevel {
d.OutputHonestHelper.Attack(ctx, claimIndex, WithIgnoreDuplicates())
......@@ -53,7 +53,7 @@ func (d *DishonestHelper) ExhaustDishonestClaims(ctx context.Context, rootClaim
}
}
numClaimsSeen := rootClaim.index
numClaimsSeen := rootClaim.Index
for {
// Use a short timeout since we don't know the challenger will respond,
// and this is only designed for the alphabet game where the response should be fast.
......@@ -63,7 +63,7 @@ func (d *DishonestHelper) ExhaustDishonestClaims(ctx context.Context, rootClaim
// There's nothing to respond to.
break
}
d.OutputGameHelper.require.NoError(err)
d.OutputGameHelper.Require.NoError(err)
for ; numClaimsSeen < newCount; numClaimsSeen++ {
claimData := d.getClaim(ctx, numClaimsSeen)
......
......@@ -64,27 +64,27 @@ func (s Status) String() string {
}
}
type gameCfg struct {
type GameCfg struct {
allowFuture bool
allowUnsafe bool
}
type GameOpt interface {
Apply(cfg *gameCfg)
Apply(cfg *GameCfg)
}
type gameOptFn func(c *gameCfg)
type gameOptFn func(c *GameCfg)
func (g gameOptFn) Apply(cfg *gameCfg) {
func (g gameOptFn) Apply(cfg *GameCfg) {
g(cfg)
}
func WithUnsafeProposal() GameOpt {
return gameOptFn(func(c *gameCfg) {
return gameOptFn(func(c *GameCfg) {
c.allowUnsafe = true
})
}
func WithFutureProposal() GameOpt {
return gameOptFn(func(c *gameCfg) {
return gameOptFn(func(c *GameCfg) {
c.allowFuture = true
})
}
......@@ -104,13 +104,13 @@ type DisputeSystem interface {
}
type FactoryHelper struct {
t *testing.T
require *require.Assertions
system DisputeSystem
client *ethclient.Client
opts *bind.TransactOpts
factoryAddr common.Address
factory *bindings.DisputeGameFactory
T *testing.T
Require *require.Assertions
System DisputeSystem
Client *ethclient.Client
Opts *bind.TransactOpts
FactoryAddr common.Address
Factory *bindings.DisputeGameFactory
}
func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *FactoryHelper {
......@@ -127,33 +127,33 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *
require.NoError(err)
return &FactoryHelper{
t: t,
require: require,
system: system,
client: client,
opts: opts,
factory: factory,
factoryAddr: factoryAddr,
T: t,
Require: require,
System: system,
Client: client,
Opts: opts,
Factory: factory,
FactoryAddr: factoryAddr,
}
}
func (h *FactoryHelper) PreimageHelper(ctx context.Context) *preimage.Helper {
opts := &bind.CallOpts{Context: ctx}
gameAddr, err := h.factory.GameImpls(opts, cannonGameType)
h.require.NoError(err)
game, err := bindings.NewFaultDisputeGameCaller(gameAddr, h.client)
h.require.NoError(err)
gameAddr, err := h.Factory.GameImpls(opts, cannonGameType)
h.Require.NoError(err)
game, err := bindings.NewFaultDisputeGameCaller(gameAddr, h.Client)
h.Require.NoError(err)
vmAddr, err := game.Vm(opts)
h.require.NoError(err)
vm, err := bindings.NewMIPSCaller(vmAddr, h.client)
h.require.NoError(err)
h.Require.NoError(err)
vm, err := bindings.NewMIPSCaller(vmAddr, h.Client)
h.Require.NoError(err)
oracleAddr, err := vm.Oracle(opts)
h.require.NoError(err)
return preimage.NewHelper(h.t, h.opts, h.client, oracleAddr)
h.Require.NoError(err)
return preimage.NewHelper(h.T, h.Opts, h.Client, oracleAddr)
}
func newGameCfg(opts ...GameOpt) *gameCfg {
cfg := &gameCfg{}
func NewGameCfg(opts ...GameOpt) *GameCfg {
cfg := &GameCfg{}
for _, opt := range opts {
opt.Apply(cfg)
}
......@@ -161,159 +161,139 @@ func newGameCfg(opts ...GameOpt) *gameCfg {
}
func (h *FactoryHelper) StartOutputCannonGameWithCorrectRoot(ctx context.Context, l2Node string, l2BlockNumber uint64, opts ...GameOpt) *OutputCannonGameHelper {
cfg := newGameCfg(opts...)
h.waitForBlock(l2Node, l2BlockNumber, cfg)
output, err := h.system.RollupClient(l2Node).OutputAtBlock(ctx, l2BlockNumber)
h.require.NoErrorf(err, "Failed to get output at block %v", l2BlockNumber)
cfg := NewGameCfg(opts...)
h.WaitForBlock(l2Node, l2BlockNumber, cfg)
output, err := h.System.RollupClient(l2Node).OutputAtBlock(ctx, l2BlockNumber)
h.Require.NoErrorf(err, "Failed to get output at block %v", l2BlockNumber)
return h.StartOutputCannonGame(ctx, l2Node, l2BlockNumber, common.Hash(output.OutputRoot), opts...)
}
func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string, l2BlockNumber uint64, rootClaim common.Hash, opts ...GameOpt) *OutputCannonGameHelper {
cfg := newGameCfg(opts...)
logger := testlog.Logger(h.t, log.LevelInfo).New("role", "OutputCannonGameHelper")
rollupClient := h.system.RollupClient(l2Node)
cfg := NewGameCfg(opts...)
logger := testlog.Logger(h.T, log.LevelInfo).New("role", "OutputCannonGameHelper")
rollupClient := h.System.RollupClient(l2Node)
extraData := h.createBisectionGameExtraData(l2Node, l2BlockNumber, cfg)
extraData := h.CreateBisectionGameExtraData(l2Node, l2BlockNumber, cfg)
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer cancel()
tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.factory.Create(opts, cannonGameType, rootClaim, extraData)
tx, err := transactions.PadGasEstimate(h.Opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.Factory.Create(opts, cannonGameType, rootClaim, extraData)
})
h.require.NoError(err, "create fault dispute game")
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err, "wait for create fault dispute game receipt to be OK")
h.require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.factory.ParseDisputeGameCreated(*rcpt.Logs[1])
h.require.NoError(err)
game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err)
h.Require.NoError(err, "create fault dispute game")
rcpt, err := wait.ForReceiptOK(ctx, h.Client, tx.Hash())
h.Require.NoError(err, "wait for create fault dispute game receipt to be OK")
h.Require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.Factory.ParseDisputeGameCreated(*rcpt.Logs[1])
h.Require.NoError(err)
game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.Client)
h.Require.NoError(err)
callOpts := &bind.CallOpts{Context: ctx}
prestateBlock, err := game.StartingBlockNumber(callOpts)
h.require.NoError(err, "Failed to load starting block number")
h.Require.NoError(err, "Failed to load starting block number")
poststateBlock, err := game.L2BlockNumber(callOpts)
h.require.NoError(err, "Failed to load l2 block number")
h.Require.NoError(err, "Failed to load l2 block number")
splitDepth, err := game.SplitDepth(callOpts)
h.require.NoError(err, "Failed to load split depth")
l1Head := h.getL1Head(ctx, game)
h.Require.NoError(err, "Failed to load split depth")
l1Head := h.GetL1Head(ctx, game)
prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock.Uint64())
provider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l1Head, faultTypes.Depth(splitDepth.Uint64()), prestateBlock.Uint64(), poststateBlock.Uint64())
return &OutputCannonGameHelper{
OutputGameHelper: OutputGameHelper{
t: h.t,
require: h.require,
client: h.client,
opts: h.opts,
game: game,
factoryAddr: h.factoryAddr,
addr: createdEvent.DisputeProxy,
correctOutputProvider: provider,
system: h.system,
},
OutputGameHelper: *NewOutputGameHelper(h.T, h.Require, h.Client, h.Opts, game, h.FactoryAddr, createdEvent.DisputeProxy, provider, h.System),
}
}
func (h *FactoryHelper) getL1Head(ctx context.Context, game *bindings.FaultDisputeGame) eth.BlockID {
func (h *FactoryHelper) GetL1Head(ctx context.Context, game *bindings.FaultDisputeGame) eth.BlockID {
l1HeadHash, err := game.L1Head(&bind.CallOpts{Context: ctx})
h.require.NoError(err, "Failed to load L1 head")
l1Header, err := h.client.HeaderByHash(ctx, l1HeadHash)
h.require.NoError(err, "Failed to load L1 header")
h.Require.NoError(err, "Failed to load L1 head")
l1Header, err := h.Client.HeaderByHash(ctx, l1HeadHash)
h.Require.NoError(err, "Failed to load L1 header")
l1Head := eth.HeaderBlockID(l1Header)
return l1Head
}
func (h *FactoryHelper) StartOutputAlphabetGameWithCorrectRoot(ctx context.Context, l2Node string, l2BlockNumber uint64, opts ...GameOpt) *OutputAlphabetGameHelper {
cfg := newGameCfg(opts...)
h.waitForBlock(l2Node, l2BlockNumber, cfg)
output, err := h.system.RollupClient(l2Node).OutputAtBlock(ctx, l2BlockNumber)
h.require.NoErrorf(err, "Failed to get output at block %v", l2BlockNumber)
cfg := NewGameCfg(opts...)
h.WaitForBlock(l2Node, l2BlockNumber, cfg)
output, err := h.System.RollupClient(l2Node).OutputAtBlock(ctx, l2BlockNumber)
h.Require.NoErrorf(err, "Failed to get output at block %v", l2BlockNumber)
return h.StartOutputAlphabetGame(ctx, l2Node, l2BlockNumber, common.Hash(output.OutputRoot))
}
func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node string, l2BlockNumber uint64, rootClaim common.Hash, opts ...GameOpt) *OutputAlphabetGameHelper {
cfg := newGameCfg(opts...)
logger := testlog.Logger(h.t, log.LevelInfo).New("role", "OutputAlphabetGameHelper")
rollupClient := h.system.RollupClient(l2Node)
cfg := NewGameCfg(opts...)
logger := testlog.Logger(h.T, log.LevelInfo).New("role", "OutputAlphabetGameHelper")
rollupClient := h.System.RollupClient(l2Node)
extraData := h.createBisectionGameExtraData(l2Node, l2BlockNumber, cfg)
extraData := h.CreateBisectionGameExtraData(l2Node, l2BlockNumber, cfg)
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer cancel()
tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.factory.Create(opts, alphabetGameType, rootClaim, extraData)
tx, err := transactions.PadGasEstimate(h.Opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.Factory.Create(opts, alphabetGameType, rootClaim, extraData)
})
h.require.NoError(err, "create output bisection game")
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err, "wait for create output bisection game receipt to be OK")
h.require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.factory.ParseDisputeGameCreated(*rcpt.Logs[1])
h.require.NoError(err)
game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err)
h.Require.NoError(err, "create output bisection game")
rcpt, err := wait.ForReceiptOK(ctx, h.Client, tx.Hash())
h.Require.NoError(err, "wait for create output bisection game receipt to be OK")
h.Require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.Factory.ParseDisputeGameCreated(*rcpt.Logs[1])
h.Require.NoError(err)
game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.Client)
h.Require.NoError(err)
callOpts := &bind.CallOpts{Context: ctx}
prestateBlock, err := game.StartingBlockNumber(callOpts)
h.require.NoError(err, "Failed to load starting block number")
h.Require.NoError(err, "Failed to load starting block number")
poststateBlock, err := game.L2BlockNumber(callOpts)
h.require.NoError(err, "Failed to load l2 block number")
h.Require.NoError(err, "Failed to load l2 block number")
splitDepth, err := game.SplitDepth(callOpts)
h.require.NoError(err, "Failed to load split depth")
l1Head := h.getL1Head(ctx, game)
h.Require.NoError(err, "Failed to load split depth")
l1Head := h.GetL1Head(ctx, game)
prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock.Uint64())
provider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l1Head, faultTypes.Depth(splitDepth.Uint64()), prestateBlock.Uint64(), poststateBlock.Uint64())
return &OutputAlphabetGameHelper{
OutputGameHelper: OutputGameHelper{
t: h.t,
require: h.require,
client: h.client,
opts: h.opts,
game: game,
factoryAddr: h.factoryAddr,
addr: createdEvent.DisputeProxy,
correctOutputProvider: provider,
system: h.system,
},
OutputGameHelper: *NewOutputGameHelper(h.T, h.Require, h.Client, h.Opts, game, h.FactoryAddr, createdEvent.DisputeProxy, provider, h.System),
}
}
func (h *FactoryHelper) createBisectionGameExtraData(l2Node string, l2BlockNumber uint64, cfg *gameCfg) []byte {
h.waitForBlock(l2Node, l2BlockNumber, cfg)
h.t.Logf("Creating game with l2 block number: %v", l2BlockNumber)
func (h *FactoryHelper) CreateBisectionGameExtraData(l2Node string, l2BlockNumber uint64, cfg *GameCfg) []byte {
h.WaitForBlock(l2Node, l2BlockNumber, cfg)
h.T.Logf("Creating game with l2 block number: %v", l2BlockNumber)
extraData := make([]byte, 32)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
return extraData
}
func (h *FactoryHelper) waitForBlock(l2Node string, l2BlockNumber uint64, cfg *gameCfg) {
func (h *FactoryHelper) WaitForBlock(l2Node string, l2BlockNumber uint64, cfg *GameCfg) {
if cfg.allowFuture {
// Proposing a block that doesn't exist yet, so don't perform any checks
return
}
l2Client := h.system.NodeClient(l2Node)
l2Client := h.System.NodeClient(l2Node)
if cfg.allowUnsafe {
_, err := geth.WaitForBlock(new(big.Int).SetUint64(l2BlockNumber), l2Client, 1*time.Minute)
h.require.NoErrorf(err, "Block number %v did not become unsafe", l2BlockNumber)
h.Require.NoErrorf(err, "Block number %v did not become unsafe", l2BlockNumber)
} else {
_, err := geth.WaitForBlockToBeSafe(new(big.Int).SetUint64(l2BlockNumber), l2Client, 1*time.Minute)
h.require.NoErrorf(err, "Block number %v did not become safe", l2BlockNumber)
h.Require.NoErrorf(err, "Block number %v did not become safe", l2BlockNumber)
}
}
func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, options ...challenger.Option) *challenger.Helper {
opts := []challenger.Option{
challenger.WithFactoryAddress(h.factoryAddr),
challenger.WithFactoryAddress(h.FactoryAddr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(h.t, ctx, h.system, name, opts...)
h.t.Cleanup(func() {
c := challenger.NewChallenger(h.T, ctx, h.System, name, opts...)
h.T.Cleanup(func() {
_ = c.Close()
})
return c
......
......@@ -24,37 +24,31 @@ func (g *OutputAlphabetGameHelper) StartChallenger(
options ...challenger.Option,
) *challenger.Helper {
opts := []challenger.Option{
challenger.WithAlphabet(g.system.RollupEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
challenger.WithAlphabet(g.System.RollupEndpoint(l2Node)),
challenger.WithFactoryAddress(g.FactoryAddr),
challenger.WithGameAddress(g.Addr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, g.system, name, opts...)
g.t.Cleanup(func() {
c := challenger.NewChallenger(g.T, ctx, g.System, name, opts...)
g.T.Cleanup(func() {
_ = c.Close()
})
return c
}
func (g *OutputAlphabetGameHelper) CreateHonestActor(ctx context.Context, l2Node string) *OutputHonestHelper {
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "HonestHelper", "game", g.addr)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.addr, caller)
logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr)
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller)
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.require.NoError(err, "Get block range")
g.Require.NoError(err, "Get block range")
splitDepth := g.SplitDepth(ctx)
l1Head := g.getL1Head(ctx)
rollupClient := g.system.RollupClient(l2Node)
l1Head := g.GetL1Head(ctx)
rollupClient := g.System.RollupClient(l2Node)
prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock)
correctTrace, err := outputs.NewOutputAlphabetTraceAccessor(logger, metrics.NoopMetrics, prestateProvider, rollupClient, l1Head, splitDepth, prestateBlock, poststateBlock)
g.require.NoError(err, "Create trace accessor")
return &OutputHonestHelper{
t: g.t,
require: g.require,
game: &g.OutputGameHelper,
contract: contract,
correctTrace: correctTrace,
}
g.Require.NoError(err, "Create trace accessor")
return NewOutputHonestHelper(g.T, g.Require, &g.OutputGameHelper, contract, correctTrace)
}
func (g *OutputAlphabetGameHelper) CreateDishonestHelper(ctx context.Context, l2Node string, defender bool) *DishonestHelper {
......
......@@ -40,16 +40,16 @@ func (g *OutputCannonGameHelper) StartChallenger(
name string,
options ...challenger.Option,
) *challenger.Helper {
rollupEndpoint := g.system.RollupEndpoint(l2Node)
l2Endpoint := g.system.NodeEndpoint(l2Node)
rollupEndpoint := g.System.RollupEndpoint(l2Node)
l2Endpoint := g.System.NodeEndpoint(l2Node)
opts := []challenger.Option{
challenger.WithCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), rollupEndpoint, l2Endpoint),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
challenger.WithCannon(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, g.system, name, opts...)
g.t.Cleanup(func() {
c := challenger.NewChallenger(g.T, ctx, g.System, name, opts...)
g.T.Cleanup(func() {
_ = c.Close()
})
return c
......@@ -58,30 +58,24 @@ func (g *OutputCannonGameHelper) StartChallenger(
func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *OutputHonestHelper {
opts := g.defaultChallengerOptions(l2Node)
opts = append(opts, options...)
cfg := challenger.NewChallengerConfig(g.t, g.system, opts...)
cfg := challenger.NewChallengerConfig(g.T, g.System, opts...)
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "HonestHelper", "game", g.addr)
l2Client := g.system.NodeClient(l2Node)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.addr, caller)
logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr)
l2Client := g.System.NodeClient(l2Node)
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller)
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.require.NoError(err, "Failed to load block range")
g.Require.NoError(err, "Failed to load block range")
dir := filepath.Join(cfg.Datadir, "honest")
splitDepth := g.SplitDepth(ctx)
rollupClient := g.system.RollupClient(l2Node)
rollupClient := g.System.RollupClient(l2Node)
prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock)
l1Head := g.getL1Head(ctx)
l1Head := g.GetL1Head(ctx)
accessor, err := outputs.NewOutputCannonTraceAccessor(
logger, metrics.NoopMetrics, cfg, l2Client, prestateProvider, rollupClient, dir, l1Head, 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,
}
g.Require.NoError(err, "Failed to create output cannon trace accessor")
return NewOutputHonestHelper(g.T, g.Require, &g.OutputGameHelper, contract, accessor)
}
type PreimageLoadCheck func(types.TraceProvider, uint64) error
......@@ -94,7 +88,7 @@ func (g *OutputCannonGameHelper) CreateStepLargePreimageLoadCheck(ctx context.Co
// Get the preimage data
execDepth := g.ExecDepth(ctx)
_, _, preimageData, err := provider.GetStepData(ctx, types.NewPosition(execDepth, big.NewInt(int64(targetTraceIndex))))
g.require.NoError(err)
g.Require.NoError(err)
// Wait until the challenge period has started by checking until the challenge
// period start time is not zero by calling the ChallengePeriodStartTime method
......@@ -104,11 +98,11 @@ func (g *OutputCannonGameHelper) CreateStepLargePreimageLoadCheck(ctx context.Co
challengePeriodEnd := challengePeriodStart + challengePeriod
// Time travel past the challenge period.
g.system.AdvanceTime(time.Duration(challengePeriod) * time.Second)
g.require.NoError(wait.ForBlockWithTimestamp(ctx, g.system.NodeClient("l1"), challengePeriodEnd))
g.System.AdvanceTime(time.Duration(challengePeriod) * time.Second)
g.Require.NoError(wait.ForBlockWithTimestamp(ctx, g.System.NodeClient("l1"), challengePeriodEnd))
// Assert that the preimage was indeed loaded by an honest challenger
g.waitForPreimageInOracle(ctx, preimageData)
g.WaitForPreimageInOracle(ctx, preimageData)
return nil
}
}
......@@ -117,8 +111,8 @@ func (g *OutputCannonGameHelper) CreateStepPreimageLoadCheck(ctx context.Context
return func(provider types.TraceProvider, targetTraceIndex uint64) error {
execDepth := g.ExecDepth(ctx)
_, _, preimageData, err := provider.GetStepData(ctx, types.NewPosition(execDepth, big.NewInt(int64(targetTraceIndex))))
g.require.NoError(err)
g.waitForPreimageInOracle(ctx, preimageData)
g.Require.NoError(err)
g.WaitForPreimageInOracle(ctx, preimageData)
return nil
}
}
......@@ -133,49 +127,49 @@ func (g *OutputCannonGameHelper) ChallengeToPreimageLoad(ctx context.Context, ou
// Identifying the first state transition that loads a global preimage
provider, _ := g.createCannonTraceProvider(ctx, "sequencer", outputRootClaim, challenger.WithPrivKey(challengerKey))
targetTraceIndex, err := provider.FindStep(ctx, 0, preimage)
g.require.NoError(err)
g.Require.NoError(err)
splitDepth := g.SplitDepth(ctx)
execDepth := g.ExecDepth(ctx)
g.require.NotEqual(outputRootClaim.position.TraceIndex(execDepth).Uint64(), targetTraceIndex, "cannot move to defend a terminal trace index")
g.require.EqualValues(splitDepth+1, outputRootClaim.Depth(), "supplied claim must be the root of an execution game")
g.require.EqualValues(execDepth%2, 1, "execution game depth must be odd") // since we're challenging the execution root claim
g.Require.NotEqual(outputRootClaim.Position.TraceIndex(execDepth).Uint64(), targetTraceIndex, "cannot move to defend a terminal trace index")
g.Require.EqualValues(splitDepth+1, outputRootClaim.Depth(), "supplied claim must be the root of an execution game")
g.Require.EqualValues(execDepth%2, 1, "execution game depth must be odd") // since we're challenging the execution root claim
if preloadPreimage {
_, _, preimageData, err := provider.GetStepData(ctx, types.NewPosition(execDepth, big.NewInt(int64(targetTraceIndex))))
g.require.NoError(err)
g.uploadPreimage(ctx, preimageData, challengerKey)
g.waitForPreimageInOracle(ctx, preimageData)
g.Require.NoError(err)
g.UploadPreimage(ctx, preimageData, challengerKey)
g.WaitForPreimageInOracle(ctx, preimageData)
}
// Descending the execution game tree to reach the step that loads the preimage
bisectTraceIndex := func(claim *ClaimHelper) *ClaimHelper {
execClaimPosition, err := claim.position.RelativeToAncestorAtDepth(splitDepth + 1)
g.require.NoError(err)
execClaimPosition, err := claim.Position.RelativeToAncestorAtDepth(splitDepth + 1)
g.Require.NoError(err)
claimTraceIndex := execClaimPosition.TraceIndex(execDepth).Uint64()
g.t.Logf("Bisecting: Into targetTraceIndex %v: claimIndex=%v at depth=%v. claimPosition=%v execClaimPosition=%v claimTraceIndex=%v",
targetTraceIndex, claim.index, claim.Depth(), claim.position, execClaimPosition, claimTraceIndex)
g.T.Logf("Bisecting: Into targetTraceIndex %v: claimIndex=%v at depth=%v. claimPosition=%v execClaimPosition=%v claimTraceIndex=%v",
targetTraceIndex, claim.Index, claim.Depth(), claim.Position, execClaimPosition, claimTraceIndex)
// We always want to position ourselves such that the challenger generates proofs for the targetTraceIndex as prestate
if execClaimPosition.Depth() == execDepth-1 {
if execClaimPosition.TraceIndex(execDepth).Uint64() == targetTraceIndex {
newPosition := execClaimPosition.Attack()
correct, err := provider.Get(ctx, newPosition)
g.require.NoError(err)
g.t.Logf("Bisecting: Attack correctly for step at newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
g.Require.NoError(err)
g.T.Logf("Bisecting: Attack correctly for step at newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
return claim.Attack(ctx, correct)
} else if execClaimPosition.TraceIndex(execDepth).Uint64() > targetTraceIndex {
g.t.Logf("Bisecting: Attack incorrectly for step")
g.T.Logf("Bisecting: Attack incorrectly for step")
return claim.Attack(ctx, common.Hash{0xdd})
} else if execClaimPosition.TraceIndex(execDepth).Uint64()+1 == targetTraceIndex {
g.t.Logf("Bisecting: Defend incorrectly for step")
g.T.Logf("Bisecting: Defend incorrectly for step")
return claim.Defend(ctx, common.Hash{0xcc})
} else {
newPosition := execClaimPosition.Defend()
correct, err := provider.Get(ctx, newPosition)
g.require.NoError(err)
g.t.Logf("Bisecting: Defend correctly for step at newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
g.Require.NoError(err)
g.T.Logf("Bisecting: Defend correctly for step at newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
return claim.Defend(ctx, correct)
}
}
......@@ -185,23 +179,23 @@ func (g *OutputCannonGameHelper) ChallengeToPreimageLoad(ctx context.Context, ou
if execClaimPosition.TraceIndex(execDepth).Uint64() < targetTraceIndex && claim.Depth() != splitDepth+1 {
newPosition := execClaimPosition.Defend()
if newPosition.TraceIndex(execDepth).Uint64() < targetTraceIndex {
g.t.Logf("Bisecting: Defend correct. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
g.T.Logf("Bisecting: Defend correct. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
correct, err := provider.Get(ctx, newPosition)
g.require.NoError(err)
g.Require.NoError(err)
return claim.Defend(ctx, correct)
} else {
g.t.Logf("Bisecting: Defend incorrect. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
g.T.Logf("Bisecting: Defend incorrect. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
return claim.Defend(ctx, common.Hash{0xaa})
}
} else {
newPosition := execClaimPosition.Attack()
if newPosition.TraceIndex(execDepth).Uint64() < targetTraceIndex {
g.t.Logf("Bisecting: Attack correct. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
g.T.Logf("Bisecting: Attack correct. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
correct, err := provider.Get(ctx, newPosition)
g.require.NoError(err)
g.Require.NoError(err)
return claim.Attack(ctx, correct)
} else {
g.t.Logf("Bisecting: Attack incorrect. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
g.T.Logf("Bisecting: Attack incorrect. newPosition=%v execIndexAtDepth=%v", newPosition, newPosition.TraceIndex(execDepth))
return claim.Attack(ctx, common.Hash{0xbb})
}
}
......@@ -213,7 +207,7 @@ func (g *OutputCannonGameHelper) ChallengeToPreimageLoad(ctx context.Context, ou
leafClaim := g.DefendClaim(ctx, mover, bisectTraceIndex, WithoutWaitingForStep())
// Validate that the preimage was loaded correctly
g.require.NoError(preimageCheck(provider, targetTraceIndex))
g.Require.NoError(preimageCheck(provider, targetTraceIndex))
// Now the preimage is available wait for the step call to succeed.
leafClaim.WaitForCountered(ctx)
......@@ -229,45 +223,45 @@ func (g *OutputCannonGameHelper) VerifyPreimage(ctx context.Context, outputRootC
found := false
for offset := uint32(0); ; offset += 4 {
preimageOpt := utils.PreimageLoad(preimageKey, offset)
g.t.Logf("Searching for step with key %x and offset %v", preimageKey.PreimageKey(), offset)
g.T.Logf("Searching for step with key %x and offset %v", preimageKey.PreimageKey(), offset)
targetTraceIndex, err := provider.FindStep(ctx, start, preimageOpt)
if errors.Is(err, io.EOF) {
// Did not find any more reads
g.require.True(found, "Should have found at least one preimage read")
g.t.Logf("Searching for step with key %x and offset %v did not find another read", preimageKey.PreimageKey(), offset)
g.Require.True(found, "Should have found at least one preimage read")
g.T.Logf("Searching for step with key %x and offset %v did not find another read", preimageKey.PreimageKey(), offset)
return
}
g.require.NoError(err, "Failed to find step that loads requested preimage")
g.Require.NoError(err, "Failed to find step that loads requested preimage")
start = targetTraceIndex
found = true
g.t.Logf("Target trace index: %v", targetTraceIndex)
g.T.Logf("Target trace index: %v", targetTraceIndex)
pos := types.NewPosition(execDepth, new(big.Int).SetUint64(targetTraceIndex))
g.require.Equal(targetTraceIndex, pos.TraceIndex(execDepth).Uint64())
g.Require.Equal(targetTraceIndex, pos.TraceIndex(execDepth).Uint64())
prestate, proof, oracleData, err := provider.GetStepData(ctx, pos)
g.require.NoError(err, "Failed to get step data")
g.require.NotNil(oracleData, "Should have had required preimage oracle data")
g.require.Equal(common.Hash(preimageKey.PreimageKey()).Bytes(), oracleData.OracleKey, "Must have correct preimage key")
g.Require.NoError(err, "Failed to get step data")
g.Require.NotNil(oracleData, "Should have had required preimage oracle data")
g.Require.Equal(common.Hash(preimageKey.PreimageKey()).Bytes(), oracleData.OracleKey, "Must have correct preimage key")
tx, err := g.game.AddLocalData(g.opts,
tx, err := g.Game.AddLocalData(g.Opts,
oracleData.GetIdent(),
big.NewInt(outputRootClaim.index),
big.NewInt(outputRootClaim.Index),
new(big.Int).SetUint64(uint64(oracleData.OracleOffset)))
g.require.NoError(err)
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err)
g.Require.NoError(err)
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err)
expectedPostState, err := provider.Get(ctx, pos)
g.require.NoError(err, "Failed to get expected post state")
g.Require.NoError(err, "Failed to get expected post state")
callOpts := &bind.CallOpts{Context: ctx}
vmAddr, err := g.game.Vm(callOpts)
g.require.NoError(err, "Failed to get VM address")
vmAddr, err := g.Game.Vm(callOpts)
g.Require.NoError(err, "Failed to get VM address")
abi, err := bindings.MIPSMetaData.GetAbi()
g.require.NoError(err, "Failed to load MIPS ABI")
caller := batching.NewMultiCaller(g.client.Client(), batching.DefaultBatchSize)
g.Require.NoError(err, "Failed to load MIPS ABI")
caller := batching.NewMultiCaller(g.Client.Client(), batching.DefaultBatchSize)
result, err := caller.SingleCall(ctx, rpcblock.Latest, &batching.ContractCall{
Abi: abi,
Addr: vmAddr,
......@@ -275,41 +269,41 @@ func (g *OutputCannonGameHelper) VerifyPreimage(ctx context.Context, outputRootC
Args: []interface{}{
prestate, proof, localContext,
},
From: g.addr,
From: g.Addr,
})
g.require.NoError(err, "Failed to call step")
g.Require.NoError(err, "Failed to call step")
actualPostState := result.GetBytes32(0)
g.require.Equal(expectedPostState, common.Hash(actualPostState))
g.Require.Equal(expectedPostState, common.Hash(actualPostState))
}
}
func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context, l2Node string, outputRootClaim *ClaimHelper, options ...challenger.Option) (*cannon.CannonTraceProviderForTest, common.Hash) {
splitDepth := g.SplitDepth(ctx)
g.require.EqualValues(outputRootClaim.Depth(), splitDepth+1, "outputRootClaim must be the root of an execution game")
g.Require.EqualValues(outputRootClaim.Depth(), splitDepth+1, "outputRootClaim must be the root of an execution game")
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "CannonTraceProvider", "game", g.addr)
logger := testlog.Logger(g.T, log.LevelInfo).New("role", "CannonTraceProvider", "game", g.Addr)
opt := g.defaultChallengerOptions(l2Node)
opt = append(opt, options...)
cfg := challenger.NewChallengerConfig(g.t, g.system, opt...)
cfg := challenger.NewChallengerConfig(g.T, g.System, opt...)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
l2Client := g.system.NodeClient(l2Node)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.addr, caller)
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
l2Client := g.System.NodeClient(l2Node)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller)
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.require.NoError(err, "Failed to load block range")
rollupClient := g.system.RollupClient(l2Node)
g.Require.NoError(err, "Failed to load block range")
rollupClient := g.System.RollupClient(l2Node)
prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock)
l1Head := g.getL1Head(ctx)
l1Head := g.GetL1Head(ctx)
outputProvider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l1Head, splitDepth, prestateBlock, poststateBlock)
var localContext common.Hash
selector := split.NewSplitProviderSelector(outputProvider, splitDepth, func(ctx context.Context, depth types.Depth, pre types.Claim, post types.Claim) (types.TraceProvider, error) {
agreed, disputed, err := outputs.FetchProposals(ctx, outputProvider, pre, post)
g.require.NoError(err)
g.t.Logf("Using trace between blocks %v and %v\n", agreed.L2BlockNumber, disputed.L2BlockNumber)
g.Require.NoError(err)
g.T.Logf("Using trace between blocks %v and %v\n", agreed.L2BlockNumber, disputed.L2BlockNumber)
localInputs, err := utils.FetchLocalInputsFromProposals(ctx, l1Head.Hash, l2Client, agreed, disputed)
g.require.NoError(err, "Failed to fetch local inputs")
g.Require.NoError(err, "Failed to fetch local inputs")
localContext = outputs.CreateLocalContext(pre, post)
dir := filepath.Join(cfg.Datadir, "cannon-trace")
subdir := filepath.Join(dir, localContext.Hex())
......@@ -317,19 +311,19 @@ func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context,
})
claims, err := contract.GetAllClaims(ctx, rpcblock.Latest)
g.require.NoError(err)
g.Require.NoError(err)
game := types.NewGameState(claims, g.MaxDepth(ctx))
provider, err := selector(ctx, game, game.Claims()[outputRootClaim.parentIndex], outputRootClaim.position)
g.require.NoError(err)
provider, err := selector(ctx, game, game.Claims()[outputRootClaim.ParentIndex], outputRootClaim.Position)
g.Require.NoError(err)
translatingProvider := provider.(*trace.TranslatingProvider)
return translatingProvider.Original().(*cannon.CannonTraceProviderForTest), localContext
}
func (g *OutputCannonGameHelper) defaultChallengerOptions(l2Node string) []challenger.Option {
return []challenger.Option{
challenger.WithCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), g.system.RollupEndpoint(l2Node), g.system.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
challenger.WithCannon(g.T, g.System.RollupCfg(), g.System.L2Genesis(), g.System.RollupEndpoint(l2Node), g.System.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(g.FactoryAddr),
challenger.WithGameAddress(g.Addr),
}
}
......@@ -30,19 +30,34 @@ import (
const defaultTimeout = 5 * time.Minute
type OutputGameHelper struct {
t *testing.T
require *require.Assertions
client *ethclient.Client
opts *bind.TransactOpts
game *bindings.FaultDisputeGame
factoryAddr common.Address
addr common.Address
correctOutputProvider *outputs.OutputTraceProvider
system DisputeSystem
T *testing.T
Require *require.Assertions
Client *ethclient.Client
Opts *bind.TransactOpts
Game *bindings.FaultDisputeGame
FactoryAddr common.Address
Addr common.Address
CorrectOutputProvider *outputs.OutputTraceProvider
System DisputeSystem
}
func NewOutputGameHelper(t *testing.T, require *require.Assertions, client *ethclient.Client, opts *bind.TransactOpts,
game *bindings.FaultDisputeGame, factoryAddr common.Address, addr common.Address, correctOutputProvider *outputs.OutputTraceProvider, system DisputeSystem) *OutputGameHelper {
return &OutputGameHelper{
T: t,
Require: require,
Client: client,
Opts: opts,
Game: game,
FactoryAddr: factoryAddr,
Addr: addr,
CorrectOutputProvider: correctOutputProvider,
System: system,
}
}
type moveCfg struct {
opts *bind.TransactOpts
Opts *bind.TransactOpts
ignoreDupes bool
}
......@@ -56,9 +71,9 @@ func (f moveOptFn) Apply(c *moveCfg) {
f(c)
}
func WithTransactOpts(opts *bind.TransactOpts) MoveOpt {
func WithTransactOpts(Opts *bind.TransactOpts) MoveOpt {
return moveOptFn(func(c *moveCfg) {
c.opts = opts
c.Opts = Opts
})
}
......@@ -68,13 +83,9 @@ func WithIgnoreDuplicates() MoveOpt {
})
}
func (g *OutputGameHelper) Addr() common.Address {
return g.addr
}
func (g *OutputGameHelper) SplitDepth(ctx context.Context) types.Depth {
splitDepth, err := g.game.SplitDepth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to load split depth")
splitDepth, err := g.Game.SplitDepth(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "failed to load split depth")
return types.Depth(splitDepth.Uint64())
}
......@@ -83,14 +94,14 @@ func (g *OutputGameHelper) ExecDepth(ctx context.Context) types.Depth {
}
func (g *OutputGameHelper) L2BlockNum(ctx context.Context) uint64 {
blockNum, err := g.game.L2BlockNumber(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to load l2 block number")
blockNum, err := g.Game.L2BlockNumber(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "failed to load l2 block number")
return blockNum.Uint64()
}
func (g *OutputGameHelper) StartingBlockNum(ctx context.Context) uint64 {
blockNum, err := g.game.StartingBlockNumber(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to load starting block number")
blockNum, err := g.Game.StartingBlockNumber(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "failed to load starting block number")
return blockNum.Uint64()
}
......@@ -112,8 +123,8 @@ func (g *OutputGameHelper) DisputeBlock(ctx context.Context, disputeBlockNum uin
}
pos := types.NewPositionFromGIndex(big.NewInt(1))
getClaimValue := func(parentClaim *ClaimHelper, claimPos types.Position) common.Hash {
claimBlockNum, err := g.correctOutputProvider.ClaimedBlockNumber(claimPos)
g.require.NoError(err, "failed to calculate claim block number")
claimBlockNum, err := g.CorrectOutputProvider.ClaimedBlockNumber(claimPos)
g.Require.NoError(err, "failed to calculate claim block number")
if claimBlockNum < disputeBlockNum {
// Use the correct output root for all claims prior to the dispute block number
// This pushes the game to dispute the last block in the range
......@@ -130,8 +141,8 @@ func (g *OutputGameHelper) DisputeBlock(ctx context.Context, disputeBlockNum uin
claim := g.RootClaim(ctx)
for !claim.IsOutputRootLeaf(ctx) {
parentClaimBlockNum, err := g.correctOutputProvider.ClaimedBlockNumber(pos)
g.require.NoError(err, "failed to calculate parent claim block number")
parentClaimBlockNum, err := g.CorrectOutputProvider.ClaimedBlockNumber(pos)
g.Require.NoError(err, "failed to calculate parent claim block number")
if parentClaimBlockNum >= disputeBlockNum {
pos = pos.Attack()
claim = claim.Attack(ctx, getClaimValue(claim, pos))
......@@ -152,18 +163,18 @@ func (g *OutputGameHelper) WaitForCorrectOutputRoot(ctx context.Context, claimId
g.WaitForClaimCount(ctx, claimIdx+1)
claim := g.getClaim(ctx, claimIdx)
output := g.correctOutputRoot(ctx, types.NewPositionFromGIndex(claim.Position))
g.require.EqualValuesf(output, claim.Claim, "Incorrect output root at claim %v at position %v", claimIdx, claim.Position.Uint64())
g.Require.EqualValuesf(output, claim.Claim, "Incorrect output root at claim %v at position %v", claimIdx, claim.Position.Uint64())
}
func (g *OutputGameHelper) correctOutputRoot(ctx context.Context, pos types.Position) common.Hash {
outputRoot, err := g.correctOutputProvider.Get(ctx, pos)
g.require.NoErrorf(err, "Failed to get correct output for position %v", pos)
outputRoot, err := g.CorrectOutputProvider.Get(ctx, pos)
g.Require.NoErrorf(err, "Failed to get correct output for position %v", pos)
return outputRoot
}
func (g *OutputGameHelper) MaxClockDuration(ctx context.Context) time.Duration {
duration, err := g.game.MaxClockDuration(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to get max clock duration")
duration, err := g.Game.MaxClockDuration(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "failed to get max clock duration")
return time.Duration(duration) * time.Second
}
......@@ -171,43 +182,43 @@ func (g *OutputGameHelper) WaitForNoAvailableCredit(ctx context.Context, addr co
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := wait.For(timedCtx, time.Second, func() (bool, error) {
bal, err := g.game.Credit(&bind.CallOpts{Context: timedCtx}, addr)
bal, err := g.Game.Credit(&bind.CallOpts{Context: timedCtx}, addr)
if err != nil {
return false, err
}
g.t.Log("Waiting for zero available credit", "current", bal, "addr", addr)
g.T.Log("Waiting for zero available credit", "current", bal, "addr", addr)
return bal.Cmp(big.NewInt(0)) == 0, nil
})
if err != nil {
g.LogGameData(ctx)
g.require.NoError(err, "Failed to wait for zero available credit")
g.Require.NoError(err, "Failed to wait for zero available credit")
}
}
func (g *OutputGameHelper) AvailableCredit(ctx context.Context, addr common.Address) *big.Int {
credit, err := g.game.Credit(&bind.CallOpts{Context: ctx}, addr)
g.require.NoErrorf(err, "Failed to fetch available credit for %v", addr)
credit, err := g.Game.Credit(&bind.CallOpts{Context: ctx}, addr)
g.Require.NoErrorf(err, "Failed to fetch available credit for %v", addr)
return credit
}
func (g *OutputGameHelper) CreditUnlockDuration(ctx context.Context) time.Duration {
weth, err := g.game.Weth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.client)
g.require.NoError(err)
weth, err := g.Game.Weth(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.Client)
g.Require.NoError(err)
period, err := contract.Delay(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get WETH unlock period")
g.Require.NoError(err, "Failed to get WETH unlock period")
float, _ := period.Float64()
return time.Duration(float) * time.Second
}
func (g *OutputGameHelper) WethBalance(ctx context.Context, addr common.Address) *big.Int {
weth, err := g.game.Weth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.client)
g.require.NoError(err)
weth, err := g.Game.Weth(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.Client)
g.Require.NoError(err)
balance, err := contract.BalanceOf(&bind.CallOpts{Context: ctx}, addr)
g.require.NoError(err, "Failed to get WETH balance")
g.Require.NoError(err, "Failed to get WETH balance")
return balance
}
......@@ -218,16 +229,16 @@ func (g *OutputGameHelper) WaitForClaimCount(ctx context.Context, count int64) {
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := wait.For(timedCtx, time.Second, func() (bool, error) {
actual, err := g.game.ClaimDataLen(&bind.CallOpts{Context: timedCtx})
actual, err := g.Game.ClaimDataLen(&bind.CallOpts{Context: timedCtx})
if err != nil {
return false, err
}
g.t.Log("Waiting for claim count", "current", actual, "expected", count, "game", g.addr)
g.T.Log("Waiting for claim count", "current", actual, "expected", count, "game", g.Addr)
return actual.Cmp(big.NewInt(count)) >= 0, nil
})
if err != nil {
g.LogGameData(ctx)
g.require.NoErrorf(err, "Did not find expected claim count %v", count)
g.Require.NoErrorf(err, "Did not find expected claim count %v", count)
}
}
......@@ -242,8 +253,8 @@ type ContractClaim struct {
}
func (g *OutputGameHelper) MaxDepth(ctx context.Context) types.Depth {
depth, err := g.game.MaxGameDepth(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to load game depth")
depth, err := g.Game.MaxGameDepth(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "Failed to load game depth")
return types.Depth(depth.Uint64())
}
......@@ -253,13 +264,13 @@ func (g *OutputGameHelper) waitForClaim(ctx context.Context, timeout time.Durati
var matchedClaim ContractClaim
var matchClaimIdx int64
err := wait.For(timedCtx, time.Second, func() (bool, error) {
count, err := g.game.ClaimDataLen(&bind.CallOpts{Context: timedCtx})
count, err := g.Game.ClaimDataLen(&bind.CallOpts{Context: timedCtx})
if err != nil {
return false, fmt.Errorf("retrieve number of claims: %w", err)
}
// Search backwards because the new claims are at the end and more likely the ones we want.
for i := count.Int64() - 1; i >= 0; i-- {
claimData, err := g.game.ClaimData(&bind.CallOpts{Context: timedCtx}, big.NewInt(i))
claimData, err := g.Game.ClaimData(&bind.CallOpts{Context: timedCtx}, big.NewInt(i))
if err != nil {
return false, fmt.Errorf("retrieve claim %v: %w", i, err)
}
......@@ -272,7 +283,7 @@ func (g *OutputGameHelper) waitForClaim(ctx context.Context, timeout time.Durati
return false, nil
})
if err != nil { // Avoid waiting time capturing game data when there's no error
g.require.NoErrorf(err, "%v\n%v", errorMsg, g.gameData(ctx))
g.Require.NoErrorf(err, "%v\n%v", errorMsg, g.GameData(ctx))
}
return matchClaimIdx, matchedClaim
}
......@@ -281,13 +292,13 @@ func (g *OutputGameHelper) waitForNoClaim(ctx context.Context, errorMsg string,
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := wait.For(timedCtx, time.Second, func() (bool, error) {
count, err := g.game.ClaimDataLen(&bind.CallOpts{Context: timedCtx})
count, err := g.Game.ClaimDataLen(&bind.CallOpts{Context: timedCtx})
if err != nil {
return false, fmt.Errorf("retrieve number of claims: %w", err)
}
// Search backwards because the new claims are at the end and more likely the ones we will fail on.
for i := count.Int64() - 1; i >= 0; i-- {
claimData, err := g.game.ClaimData(&bind.CallOpts{Context: timedCtx}, big.NewInt(i))
claimData, err := g.Game.ClaimData(&bind.CallOpts{Context: timedCtx}, big.NewInt(i))
if err != nil {
return false, fmt.Errorf("retrieve claim %v: %w", i, err)
}
......@@ -298,7 +309,7 @@ func (g *OutputGameHelper) waitForNoClaim(ctx context.Context, errorMsg string,
return true, nil
})
if err != nil { // Avoid waiting time capturing game data when there's no error
g.require.NoErrorf(err, "%v\n%v", errorMsg, g.gameData(ctx))
g.Require.NoErrorf(err, "%v\n%v", errorMsg, g.GameData(ctx))
}
}
......@@ -320,9 +331,9 @@ func (g *OutputGameHelper) getAllClaims(ctx context.Context) []ContractClaim {
// getClaim retrieves the claim data for a specific index.
// Note that it is deliberately not exported as tests should use WaitForClaim to avoid race conditions.
func (g *OutputGameHelper) getClaim(ctx context.Context, claimIdx int64) ContractClaim {
claimData, err := g.game.ClaimData(&bind.CallOpts{Context: ctx}, big.NewInt(claimIdx))
claimData, err := g.Game.ClaimData(&bind.CallOpts{Context: ctx}, big.NewInt(claimIdx))
if err != nil {
g.require.NoErrorf(err, "retrieve claim %v", claimIdx)
g.Require.NoErrorf(err, "retrieve claim %v", claimIdx)
}
return claimData
}
......@@ -362,40 +373,40 @@ func (g *OutputGameHelper) WaitForAllClaimsCountered(ctx context.Context) {
func (g *OutputGameHelper) Resolve(ctx context.Context) {
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
tx, err := g.game.Resolve(g.opts)
g.require.NoError(err)
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err)
tx, err := g.Game.Resolve(g.Opts)
g.Require.NoError(err)
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err)
}
func (g *OutputGameHelper) Status(ctx context.Context) Status {
status, err := g.game.Status(&bind.CallOpts{Context: ctx})
g.require.NoError(err)
status, err := g.Game.Status(&bind.CallOpts{Context: ctx})
g.Require.NoError(err)
return Status(status)
}
func (g *OutputGameHelper) WaitForGameStatus(ctx context.Context, expected Status) {
g.t.Logf("Waiting for game %v to have status %v", g.addr, expected)
g.T.Logf("Waiting for game %v to have status %v", g.Addr, expected)
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
err := wait.For(timedCtx, time.Second, func() (bool, error) {
ctx, cancel := context.WithTimeout(timedCtx, 30*time.Second)
defer cancel()
status, err := g.game.Status(&bind.CallOpts{Context: ctx})
status, err := g.Game.Status(&bind.CallOpts{Context: ctx})
if err != nil {
return false, fmt.Errorf("game status unavailable: %w", err)
}
g.t.Logf("Game %v has state %v, waiting for state %v", g.addr, Status(status), expected)
g.T.Logf("Game %v has state %v, waiting for state %v", g.Addr, Status(status), expected)
return expected == Status(status), nil
})
g.require.NoErrorf(err, "wait for game status. Game state: \n%v", g.gameData(ctx))
g.Require.NoErrorf(err, "wait for Game status. Game state: \n%v", g.GameData(ctx))
}
func (g *OutputGameHelper) WaitForInactivity(ctx context.Context, numInactiveBlocks int, untilGameEnds bool) {
g.t.Logf("Waiting for game %v to have no activity for %v blocks", g.addr, numInactiveBlocks)
g.T.Logf("Waiting for game %v to have no activity for %v blocks", g.Addr, numInactiveBlocks)
headCh := make(chan *gethtypes.Header, 100)
headSub, err := g.client.SubscribeNewHead(ctx, headCh)
g.require.NoError(err)
headSub, err := g.Client.SubscribeNewHead(ctx, headCh)
g.Require.NoError(err)
defer headSub.Unsubscribe()
var lastActiveBlock uint64
......@@ -411,22 +422,22 @@ func (g *OutputGameHelper) WaitForInactivity(ctx context.Context, numInactiveBlo
} else if lastActiveBlock+uint64(numInactiveBlocks) < head.Number.Uint64() {
return
}
block, err := g.client.BlockByNumber(ctx, head.Number)
g.require.NoError(err)
block, err := g.Client.BlockByNumber(ctx, head.Number)
g.Require.NoError(err)
numActions := 0
for _, tx := range block.Transactions() {
if tx.To().Hex() == g.addr.Hex() {
if tx.To().Hex() == g.Addr.Hex() {
numActions++
}
}
if numActions != 0 {
g.t.Logf("Game %v has %v actions in block %d. Resetting inactivity timeout", g.addr, numActions, block.NumberU64())
g.T.Logf("Game %v has %v actions in block %d. Resetting inactivity timeout", g.Addr, numActions, block.NumberU64())
lastActiveBlock = head.Number.Uint64()
}
case err := <-headSub.Err():
g.require.NoError(err)
g.Require.NoError(err)
case <-ctx.Done():
g.require.Fail("Context canceled", ctx.Err())
g.Require.Fail("Context canceled", ctx.Err())
}
}
}
......@@ -453,10 +464,10 @@ func WithoutWaitingForStep() DefendClaimOpt {
// It is assumed that the specified claim is invalid and that an honest op-challenger is already running.
// When the game has reached the maximum depth it waits for the honest challenger to counter the leaf claim with step.
// Returns the final leaf claim
func (g *OutputGameHelper) DefendClaim(ctx context.Context, claim *ClaimHelper, performMove Mover, opts ...DefendClaimOpt) *ClaimHelper {
g.t.Logf("Defending claim %v at depth %v", claim.index, claim.Depth())
func (g *OutputGameHelper) DefendClaim(ctx context.Context, claim *ClaimHelper, performMove Mover, Opts ...DefendClaimOpt) *ClaimHelper {
g.T.Logf("Defending claim %v at depth %v", claim.Index, claim.Depth())
cfg := &defendClaimCfg{}
for _, opt := range opts {
for _, opt := range Opts {
opt(cfg)
}
for !claim.IsMaxDepth(ctx) {
......@@ -495,12 +506,12 @@ func (g *OutputGameHelper) ChallengeClaim(ctx context.Context, claim *ClaimHelpe
g.LogGameData(ctx)
// It's on us to call step if we want to win but shouldn't be possible
attemptStep(claim.index)
attemptStep(claim.Index)
}
func (g *OutputGameHelper) getClaimCount(ctx context.Context) int64 {
claimCount, err := g.game.ClaimDataLen(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to get current claim count")
claimCount, err := g.Game.ClaimDataLen(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "Failed to get current claim count")
return claimCount.Int64()
}
......@@ -513,7 +524,7 @@ func (g *OutputGameHelper) waitForNewClaim(ctx context.Context, checkPoint int64
defer cancel()
var newClaimLen int64
err := wait.For(timedCtx, time.Second, func() (bool, error) {
actual, err := g.game.ClaimDataLen(&bind.CallOpts{Context: ctx})
actual, err := g.Game.ClaimDataLen(&bind.CallOpts{Context: ctx})
if err != nil {
return false, err
}
......@@ -523,55 +534,55 @@ func (g *OutputGameHelper) waitForNewClaim(ctx context.Context, checkPoint int64
return newClaimLen, err
}
func (g *OutputGameHelper) moveCfg(opts ...MoveOpt) *moveCfg {
func (g *OutputGameHelper) moveCfg(Opts ...MoveOpt) *moveCfg {
cfg := &moveCfg{
opts: g.opts,
Opts: g.Opts,
}
for _, opt := range opts {
for _, opt := range Opts {
opt.Apply(cfg)
}
return cfg
}
func (g *OutputGameHelper) Attack(ctx context.Context, claimIdx int64, claim common.Hash, opts ...MoveOpt) {
g.t.Logf("Attacking claim %v with value %v", claimIdx, claim)
cfg := g.moveCfg(opts...)
func (g *OutputGameHelper) Attack(ctx context.Context, claimIdx int64, claim common.Hash, Opts ...MoveOpt) {
g.T.Logf("Attacking claim %v with value %v", claimIdx, claim)
cfg := g.moveCfg(Opts...)
claimData, err := g.game.ClaimData(&bind.CallOpts{Context: ctx}, big.NewInt(claimIdx))
g.require.NoError(err, "Failed to get claim data")
claimData, err := g.Game.ClaimData(&bind.CallOpts{Context: ctx}, big.NewInt(claimIdx))
g.Require.NoError(err, "Failed to get claim data")
pos := types.NewPositionFromGIndex(claimData.Position)
attackPos := pos.Attack()
transactOpts := g.makeBondedTransactOpts(ctx, pos.Attack().ToGIndex(), cfg.opts)
transactOpts := g.makeBondedTransactOpts(ctx, pos.Attack().ToGIndex(), cfg.Opts)
err = g.sendMove(ctx, func() (*gethtypes.Transaction, error) {
return g.game.Attack(transactOpts, big.NewInt(claimIdx), claim)
return g.Game.Attack(transactOpts, big.NewInt(claimIdx), claim)
})
if err != nil {
if cfg.ignoreDupes && g.hasClaim(ctx, claimIdx, attackPos, claim) {
return
}
g.require.NoErrorf(err, "Defend transaction failed. Game state: \n%v", g.gameData(ctx))
g.Require.NoErrorf(err, "Defend transaction failed. Game state: \n%v", g.GameData(ctx))
}
}
func (g *OutputGameHelper) Defend(ctx context.Context, claimIdx int64, claim common.Hash, opts ...MoveOpt) {
g.t.Logf("Defending claim %v with value %v", claimIdx, claim)
cfg := g.moveCfg(opts...)
func (g *OutputGameHelper) Defend(ctx context.Context, claimIdx int64, claim common.Hash, Opts ...MoveOpt) {
g.T.Logf("Defending claim %v with value %v", claimIdx, claim)
cfg := g.moveCfg(Opts...)
claimData, err := g.game.ClaimData(&bind.CallOpts{Context: ctx}, big.NewInt(claimIdx))
g.require.NoError(err, "Failed to get claim data")
claimData, err := g.Game.ClaimData(&bind.CallOpts{Context: ctx}, big.NewInt(claimIdx))
g.Require.NoError(err, "Failed to get claim data")
pos := types.NewPositionFromGIndex(claimData.Position)
defendPos := pos.Defend()
transactOpts := g.makeBondedTransactOpts(ctx, defendPos.ToGIndex(), cfg.opts)
transactOpts := g.makeBondedTransactOpts(ctx, defendPos.ToGIndex(), cfg.Opts)
err = g.sendMove(ctx, func() (*gethtypes.Transaction, error) {
return g.game.Defend(transactOpts, big.NewInt(claimIdx), claim)
return g.Game.Defend(transactOpts, big.NewInt(claimIdx), claim)
})
if err != nil {
if cfg.ignoreDupes && g.hasClaim(ctx, claimIdx, defendPos, claim) {
return
}
g.require.NoErrorf(err, "Defend transaction failed. Game state: \n%v", g.gameData(ctx))
g.Require.NoErrorf(err, "Defend transaction failed. Game state: \n%v", g.GameData(ctx))
}
}
......@@ -590,19 +601,19 @@ func (g *OutputGameHelper) sendMove(ctx context.Context, send func() (*gethtypes
if err != nil {
return fmt.Errorf("transaction did not send: %w", err)
}
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
if err != nil {
return fmt.Errorf("transaction was not ok: %w", err)
}
return nil
}
func (g *OutputGameHelper) makeBondedTransactOpts(ctx context.Context, pos *big.Int, opts *bind.TransactOpts) *bind.TransactOpts {
bopts := *opts
bond, err := g.game.GetRequiredBond(&bind.CallOpts{Context: ctx}, pos)
g.require.NoError(err, "Failed to get required bond")
bopts.Value = bond
return &bopts
func (g *OutputGameHelper) makeBondedTransactOpts(ctx context.Context, pos *big.Int, Opts *bind.TransactOpts) *bind.TransactOpts {
bOpts := *Opts
bond, err := g.Game.GetRequiredBond(&bind.CallOpts{Context: ctx}, pos)
g.Require.NoError(err, "Failed to get required bond")
bOpts.Value = bond
return &bOpts
}
type ErrWithData interface {
......@@ -611,19 +622,19 @@ type ErrWithData interface {
// StepFails attempts to call step and verifies that it fails with ValidStep()
func (g *OutputGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []byte, proof []byte) {
g.t.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack)
_, err := g.game.Step(g.opts, big.NewInt(claimIdx), isAttack, stateData, proof)
g.T.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack)
_, err := g.Game.Step(g.Opts, big.NewInt(claimIdx), isAttack, stateData, proof)
errData, ok := err.(ErrWithData)
g.require.Truef(ok, "Error should provide ErrorData method: %v", err)
g.require.Equal("0xfb4e40dd", errData.ErrorData(), "Revert reason should be abi encoded ValidStep()")
g.Require.Truef(ok, "Error should provide ErrorData method: %v", err)
g.Require.Equal("0xfb4e40dd", errData.ErrorData(), "Revert reason should be abi encoded ValidStep()")
}
// ResolveClaim resolves a single subgame
func (g *OutputGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) {
tx, err := g.game.ResolveClaim(g.opts, big.NewInt(claimIdx), common.Big0)
g.require.NoError(err, "ResolveClaim transaction did not send")
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err, "ResolveClaim transaction was not OK")
tx, err := g.Game.ResolveClaim(g.Opts, big.NewInt(claimIdx), common.Big0)
g.Require.NoError(err, "ResolveClaim transaction did not send")
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err, "ResolveClaim transaction was not OK")
}
// ChallengePeriod returns the challenge period fetched from the PreimageOracle contract.
......@@ -631,7 +642,7 @@ func (g *OutputGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) {
func (g *OutputGameHelper) ChallengePeriod(ctx context.Context) uint64 {
oracle := g.oracle(ctx)
period, err := oracle.ChallengePeriod(ctx)
g.require.NoError(err, "Failed to get challenge period")
g.Require.NoError(err, "Failed to get challenge period")
return period
}
......@@ -643,12 +654,12 @@ func (g *OutputGameHelper) WaitForChallengePeriodStart(ctx context.Context, send
ctx, cancel := context.WithTimeout(timedCtx, 30*time.Second)
defer cancel()
timestamp := g.ChallengePeriodStartTime(ctx, sender, data)
g.t.Log("Waiting for challenge period start", "timestamp", timestamp, "key", data.OracleKey, "game", g.addr)
g.T.Log("Waiting for challenge period start", "timestamp", timestamp, "key", data.OracleKey, "game", g.Addr)
return timestamp > 0, nil
})
if err != nil {
g.LogGameData(ctx)
g.require.NoErrorf(err, "Failed to get challenge start period for preimage data %v", data)
g.Require.NoErrorf(err, "Failed to get challenge start period for preimage data %v", data)
}
}
......@@ -661,68 +672,68 @@ func (g *OutputGameHelper) ChallengePeriodStartTime(ctx context.Context, sender
Claimant: sender,
UUID: uuid,
})
g.require.NoError(err, "Failed to get proposal metadata")
g.Require.NoError(err, "Failed to get proposal metadata")
if len(metadata) == 0 {
return 0
}
return metadata[0].Timestamp
}
func (g *OutputGameHelper) waitForPreimageInOracle(ctx context.Context, data *types.PreimageOracleData) {
func (g *OutputGameHelper) WaitForPreimageInOracle(ctx context.Context, data *types.PreimageOracleData) {
timedCtx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
oracle := g.oracle(ctx)
err := wait.For(timedCtx, time.Second, func() (bool, error) {
g.t.Logf("Waiting for preimage (%v) to be present in oracle", common.Bytes2Hex(data.OracleKey))
g.T.Logf("Waiting for preimage (%v) to be present in oracle", common.Bytes2Hex(data.OracleKey))
return oracle.GlobalDataExists(ctx, data)
})
g.require.NoErrorf(err, "Did not find preimage (%v) in oracle", common.Bytes2Hex(data.OracleKey))
g.Require.NoErrorf(err, "Did not find preimage (%v) in oracle", common.Bytes2Hex(data.OracleKey))
}
func (g *OutputGameHelper) uploadPreimage(ctx context.Context, data *types.PreimageOracleData, privateKey *ecdsa.PrivateKey) {
func (g *OutputGameHelper) UploadPreimage(ctx context.Context, data *types.PreimageOracleData, privateKey *ecdsa.PrivateKey) {
oracle := g.oracle(ctx)
boundOracle, err := bindings.NewPreimageOracle(oracle.Addr(), g.client)
g.require.NoError(err)
boundOracle, err := bindings.NewPreimageOracle(oracle.Addr(), g.Client)
g.Require.NoError(err)
var tx *gethtypes.Transaction
switch data.OracleKey[0] {
case byte(preimage.PrecompileKeyType):
tx, err = boundOracle.LoadPrecompilePreimagePart(
g.opts,
g.Opts,
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPrecompileAddress(),
data.GetPrecompileInput(),
)
default:
tx, err = boundOracle.LoadKeccak256PreimagePart(g.opts, new(big.Int).SetUint64(uint64(data.OracleOffset)), data.GetPreimageWithoutSize())
tx, err = boundOracle.LoadKeccak256PreimagePart(g.Opts, new(big.Int).SetUint64(uint64(data.OracleOffset)), data.GetPreimageWithoutSize())
}
g.require.NoError(err, "Failed to load preimage part")
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err)
g.Require.NoError(err, "Failed to load preimage part")
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err)
}
func (g *OutputGameHelper) oracle(ctx context.Context) *contracts.PreimageOracleContract {
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.addr, caller)
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller)
oracle, err := contract.GetOracle(ctx)
g.require.NoError(err, "Failed to create oracle contract")
g.Require.NoError(err, "Failed to create oracle contract")
return oracle
}
func (g *OutputGameHelper) gameData(ctx context.Context) string {
opts := &bind.CallOpts{Context: ctx}
func (g *OutputGameHelper) GameData(ctx context.Context) string {
Opts := &bind.CallOpts{Context: ctx}
maxDepth := g.MaxDepth(ctx)
splitDepth := g.SplitDepth(ctx)
claimCount, err := g.game.ClaimDataLen(opts)
claimCount, err := g.Game.ClaimDataLen(Opts)
info := fmt.Sprintf("Claim count: %v\n", claimCount)
g.require.NoError(err, "Fetching claim count")
g.Require.NoError(err, "Fetching claim count")
for i := int64(0); i < claimCount.Int64(); i++ {
claim, err := g.game.ClaimData(opts, big.NewInt(i))
g.require.NoErrorf(err, "Fetch claim %v", i)
claim, err := g.Game.ClaimData(Opts, big.NewInt(i))
g.Require.NoErrorf(err, "Fetch claim %v", i)
pos := types.NewPositionFromGIndex(claim.Position)
extra := ""
if pos.Depth() <= splitDepth {
blockNum, err := g.correctOutputProvider.ClaimedBlockNumber(pos)
blockNum, err := g.CorrectOutputProvider.ClaimedBlockNumber(pos)
if err != nil {
} else {
extra = fmt.Sprintf("Block num: %v", blockNum)
......@@ -732,28 +743,28 @@ func (g *OutputGameHelper) gameData(ctx context.Context) string {
i, claim.Position.Int64(), pos.Depth(), pos.IndexAtDepth(), pos.TraceIndex(maxDepth), common.Hash(claim.Claim).Hex(), claim.CounteredBy, claim.ParentIndex, claim.Claimant, claim.Bond, extra)
}
l2BlockNum := g.L2BlockNum(ctx)
status, err := g.game.Status(opts)
g.require.NoError(err, "Load game status")
status, err := g.Game.Status(Opts)
g.Require.NoError(err, "Load game status")
return fmt.Sprintf("Game %v - %v - L2 Block: %v - Split Depth: %v - Max Depth: %v:\n%v\n",
g.addr, Status(status), l2BlockNum, splitDepth, maxDepth, info)
g.Addr, Status(status), l2BlockNum, splitDepth, maxDepth, info)
}
func (g *OutputGameHelper) LogGameData(ctx context.Context) {
g.t.Log(g.gameData(ctx))
g.T.Log(g.GameData(ctx))
}
func (g *OutputGameHelper) Credit(ctx context.Context, addr common.Address) *big.Int {
opts := &bind.CallOpts{Context: ctx}
amt, err := g.game.Credit(opts, addr)
g.require.NoError(err)
Opts := &bind.CallOpts{Context: ctx}
amt, err := g.Game.Credit(Opts, addr)
g.Require.NoError(err)
return amt
}
func (g *OutputGameHelper) getL1Head(ctx context.Context) eth.BlockID {
l1HeadHash, err := g.game.L1Head(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to load L1 head")
l1Header, err := g.client.HeaderByHash(ctx, l1HeadHash)
g.require.NoError(err, "Failed to load L1 header")
func (g *OutputGameHelper) GetL1Head(ctx context.Context) eth.BlockID {
l1HeadHash, err := g.Game.L1Head(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "Failed to load L1 head")
l1Header, err := g.Client.HeaderByHash(ctx, l1HeadHash)
g.Require.NoError(err, "Failed to load L1 header")
l1Head := eth.HeaderBlockID(l1Header)
return l1Head
}
......@@ -21,8 +21,18 @@ type OutputHonestHelper struct {
correctTrace types.TraceAccessor
}
func NewOutputHonestHelper(t *testing.T, require *require.Assertions, game *OutputGameHelper, contract *contracts.FaultDisputeGameContract, correctTrace types.TraceAccessor) *OutputHonestHelper {
return &OutputHonestHelper{
t: t,
require: require,
game: game,
contract: contract,
correctTrace: correctTrace,
}
}
func (h *OutputHonestHelper) CounterClaim(ctx context.Context, claim *ClaimHelper, opts ...MoveOpt) *ClaimHelper {
game, target := h.loadState(ctx, claim.index)
game, target := h.loadState(ctx, claim.Index)
value, err := h.correctTrace.Get(ctx, game, target, target.Position)
h.require.NoErrorf(err, "Failed to determine correct claim at position %v with g index %v", target.Position, target.Position.ToGIndex())
if value == claim.claim {
......@@ -33,12 +43,12 @@ func (h *OutputHonestHelper) CounterClaim(ctx context.Context, claim *ClaimHelpe
}
func (h *OutputHonestHelper) AttackClaim(ctx context.Context, claim *ClaimHelper, opts ...MoveOpt) *ClaimHelper {
h.Attack(ctx, claim.index, opts...)
h.Attack(ctx, claim.Index, opts...)
return claim.WaitForCounterClaim(ctx)
}
func (h *OutputHonestHelper) DefendClaim(ctx context.Context, claim *ClaimHelper, opts ...MoveOpt) *ClaimHelper {
h.Defend(ctx, claim.index, opts...)
h.Defend(ctx, claim.Index, opts...)
return claim.WaitForCounterClaim(ctx)
}
......@@ -68,12 +78,12 @@ func (h *OutputHonestHelper) Defend(ctx context.Context, claimIdx int64, opts ..
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.Require.NoErrorf(err, "Get correct claim at position %v with g index %v", defendPos, defendPos.ToGIndex())
h.game.Defend(ctx, claimIdx, value, opts...)
}
func (h *OutputHonestHelper) StepClaimFails(ctx context.Context, claim *ClaimHelper, isAttack bool) {
h.StepFails(ctx, claim.index, isAttack)
h.StepFails(ctx, claim.Index, isAttack)
}
func (h *OutputHonestHelper) StepFails(ctx context.Context, claimIdx int64, isAttack bool) {
......
......@@ -15,7 +15,7 @@ import (
func TestChallengeLargePreimages_ChallengeFirst(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
sys, _ := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -34,7 +34,7 @@ func TestChallengeLargePreimages_ChallengeFirst(t *testing.T) {
func TestChallengeLargePreimages_ChallengeMiddle(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
sys, _ := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
disputeGameFactory.StartChallenger(ctx, "Challenger",
......@@ -52,7 +52,7 @@ func TestChallengeLargePreimages_ChallengeMiddle(t *testing.T) {
func TestChallengeLargePreimages_ChallengeLast(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
sys, _ := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
disputeGameFactory.StartChallenger(ctx, "Challenger",
......
......@@ -14,7 +14,7 @@ func TestMultipleGameTypes(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
sys, _ := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
gameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......
......@@ -18,7 +18,7 @@ import (
func TestOutputAlphabetGame_ChallengerWins(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -75,7 +75,7 @@ func TestOutputAlphabetGame_ChallengerWins(t *testing.T) {
func TestOutputAlphabetGame_ReclaimBond(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -83,7 +83,7 @@ func TestOutputAlphabetGame_ReclaimBond(t *testing.T) {
game.LogGameData(ctx)
// The dispute game should have a zero balance
balance := game.WethBalance(ctx, game.Addr())
balance := game.WethBalance(ctx, game.Addr)
require.Zero(t, balance.Uint64())
alice := sys.Cfg.Secrets.Addresses().Alice
......@@ -105,7 +105,7 @@ func TestOutputAlphabetGame_ReclaimBond(t *testing.T) {
_ = claim.WaitForCounterClaim(ctx)
// Expect posted claims so the game balance is non-zero
balance = game.WethBalance(ctx, game.Addr())
balance = game.WethBalance(ctx, game.Addr)
require.Truef(t, balance.Cmp(big.NewInt(0)) > 0, "Expected game balance to be above zero")
sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
......@@ -130,13 +130,13 @@ func TestOutputAlphabetGame_ReclaimBond(t *testing.T) {
game.WaitForNoAvailableCredit(ctx, alice)
// The dispute game delayed weth balance should be zero since it's all claimed
require.True(t, game.WethBalance(ctx, game.Addr()).Cmp(big.NewInt(0)) == 0)
require.True(t, game.WethBalance(ctx, game.Addr).Cmp(big.NewInt(0)) == 0)
}
func TestOutputAlphabetGame_ValidOutputRoot(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -169,7 +169,7 @@ func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) {
testCase := func(t *testing.T, isRootCorrect bool) {
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -234,7 +234,7 @@ func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) {
func TestOutputAlphabetGame_FreeloaderEarnsNothing(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
freeloaderOpts, err := bind.NewKeyedTransactorWithChainID(sys.Cfg.Secrets.Mallory, sys.Cfg.L1ChainIDBig())
......
......@@ -21,7 +21,7 @@ import (
func TestOutputCannonGame(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -77,7 +77,7 @@ func TestOutputCannon_ChallengeAllZeroClaim(t *testing.T) {
// The dishonest actor always posts claims with all zeros.
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -116,7 +116,7 @@ func TestOutputCannon_PublishCannonRootClaim(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
sys, _ := StartFaultDisputeSystem(t)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", test.disputeL2BlockNumber, common.Hash{0x01})
......@@ -147,7 +147,7 @@ func TestOutputCannonDisputeGame(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -184,7 +184,7 @@ func TestOutputCannonDefendStep(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -220,7 +220,7 @@ func TestOutputCannonStepWithLargePreimage(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t, withBatcherStopped())
sys, _ := StartFaultDisputeSystem(t, WithBatcherStopped())
t.Cleanup(sys.Close)
// Manually send a tx from the correct batcher key to the batcher input with very large (invalid) data
......@@ -263,7 +263,7 @@ func TestOutputCannonStepWithPreimage(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t, withBlobBatches())
sys, _ := StartFaultDisputeSystem(t, WithBlobBatches())
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -306,7 +306,7 @@ func TestOutputCannonStepWithKZGPointEvaluation(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t, withEcotone())
sys, _ := StartFaultDisputeSystem(t, WithEcotone())
t.Cleanup(sys.Close)
// NOTE: Flake prevention
......@@ -315,7 +315,7 @@ func TestOutputCannonStepWithKZGPointEvaluation(t *testing.T) {
require.NoError(t, err)
require.NoError(t, wait.ForSafeBlock(ctx, sys.RollupClient("sequencer"), safeBlock.NumberU64()+3))
receipt := sendKZGPointEvaluationTx(t, sys, "sequencer", sys.Cfg.Secrets.Alice)
receipt := SendKZGPointEvaluationTx(t, sys, "sequencer", sys.Cfg.Secrets.Alice)
precompileBlock := receipt.BlockNumber
t.Logf("KZG Point Evaluation block number: %d", precompileBlock)
......@@ -406,7 +406,7 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -440,7 +440,7 @@ func TestOutputCannonPoisonedPostState(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -504,7 +504,7 @@ func TestDisputeOutputRootBeyondProposedBlock_ValidOutputRoot(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -554,7 +554,7 @@ func TestDisputeOutputRootBeyondProposedBlock_InvalidOutputRoot(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -605,7 +605,7 @@ func TestDisputeOutputRoot_ChangeClaimedOutputRoot(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......@@ -693,7 +693,7 @@ func TestInvalidateUnsafeProposal(t *testing.T) {
test := test
t.Run(test.name, func(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
sys, l1Client := startFaultDisputeSystem(t, withSequencerWindowSize(100000), withBatcherStopped())
sys, l1Client := StartFaultDisputeSystem(t, WithSequencerWindowSize(100000), WithBatcherStopped())
t.Cleanup(sys.Close)
blockNum := uint64(1)
......@@ -755,7 +755,7 @@ func TestInvalidateProposalForFutureBlock(t *testing.T) {
test := test
t.Run(test.name, func(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
sys, l1Client := startFaultDisputeSystem(t, withSequencerWindowSize(100000))
sys, l1Client := StartFaultDisputeSystem(t, WithSequencerWindowSize(100000))
t.Cleanup(sys.Close)
farFutureBlockNum := uint64(10_000_000)
......
......@@ -32,7 +32,7 @@ func TestLocalPreimages(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
sys, _ := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
......
......@@ -15,13 +15,13 @@ import (
type faultDisputeConfigOpts func(cfg *op_e2e.SystemConfig)
func withBatcherStopped() faultDisputeConfigOpts {
func WithBatcherStopped() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
cfg.DisableBatcher = true
}
}
func withBlobBatches() faultDisputeConfigOpts {
func WithBlobBatches() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
cfg.DataAvailabilityType = batcherFlags.BlobsType
......@@ -32,7 +32,7 @@ func withBlobBatches() faultDisputeConfigOpts {
}
}
func withEcotone() faultDisputeConfigOpts {
func WithEcotone() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
genesisActivation := hexutil.Uint64(0)
cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation
......@@ -41,13 +41,13 @@ func withEcotone() faultDisputeConfigOpts {
}
}
func withSequencerWindowSize(size uint64) faultDisputeConfigOpts {
func WithSequencerWindowSize(size uint64) faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
cfg.DeployConfig.SequencerWindowSize = size
}
}
func startFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_e2e.System, *ethclient.Client) {
func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_e2e.System, *ethclient.Client) {
cfg := op_e2e.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier")
for _, opt := range opts {
......@@ -64,7 +64,7 @@ func startFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_
return sys, sys.Clients["l1"]
}
func sendKZGPointEvaluationTx(t *testing.T, sys *op_e2e.System, l2Node string, privateKey *ecdsa.PrivateKey) *types.Receipt {
func SendKZGPointEvaluationTx(t *testing.T, sys *op_e2e.System, l2Node string, privateKey *ecdsa.PrivateKey) *types.Receipt {
return op_e2e.SendL2Tx(t, sys.Cfg, sys.Clients[l2Node], privateKey, func(opts *op_e2e.TxOpts) {
precompile := common.BytesToAddress([]byte{0x0a})
opts.Gas = 100_000
......
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