Commit 5edd8208 authored by Adrian Sutton's avatar Adrian Sutton

challenger: Switch output_cannon to use the new contract type.

parent 918459c4
......@@ -23,7 +23,7 @@ import (
var (
cannonGameType = uint8(0)
outputCannonGameType = uint8(0) // TODO(client-pod#260): Switch the output cannon game type to 1
outputCannonGameType = uint8(253) // TODO(client-pod#260): Switch the output cannon game type to 1
outputAlphabetGameType = uint8(254)
alphabetGameType = uint8(255)
)
......@@ -133,9 +133,7 @@ func registerOutputCannon(
caller *batching.MultiCaller,
l2Client cannon.L2HeaderSource) {
resourceCreator := func(addr common.Address) (gameTypeResources, error) {
// Currently still using the old fault dispute game contracts for output_cannon
// as the output bisection+cannon contract isn't being deployed.
contract, err := contracts.NewFaultDisputeGameContract(addr, caller)
contract, err := contracts.NewOutputBisectionGameContract(addr, caller)
if err != nil {
return nil, err
}
......@@ -156,7 +154,7 @@ type outputCannonResources struct {
m metrics.Metricer
cfg *config.Config
l2Client cannon.L2HeaderSource
contract *contracts.FaultDisputeGameContract // TODO(client-pod#260): Use the OutputBisectionGame Contract
contract *contracts.OutputBisectionGameContract
}
func (r *outputCannonResources) Contract() GameContract {
......@@ -165,12 +163,11 @@ func (r *outputCannonResources) Contract() GameContract {
func (r *outputCannonResources) CreateAccessor(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (faultTypes.TraceAccessor, error) {
// TODO(client-pod#44): Validate absolute pre-state for split games
// TODO(client-pod#43): Updated contracts should expose this as the pre and post state blocks
agreed, disputed, err := r.contract.GetProposals(ctx)
agreed, disputed, err := r.contract.GetBlockRange(ctx)
if err != nil {
return nil, err
}
accessor, err := outputs.NewOutputCannonTraceAccessor(ctx, logger, r.m, r.cfg, r.l2Client, r.contract, dir, gameDepth, agreed.L2BlockNumber.Uint64(), disputed.L2BlockNumber.Uint64())
accessor, err := outputs.NewOutputCannonTraceAccessor(ctx, logger, r.m, r.cfg, r.l2Client, r.contract, dir, gameDepth, agreed, disputed)
if err != nil {
return nil, err
}
......
......@@ -17,8 +17,6 @@ import (
"github.com/stretchr/testify/require"
)
const defaultTimeout = 5 * time.Minute
type FaultGameHelper struct {
t *testing.T
require *require.Assertions
......@@ -59,14 +57,6 @@ func (g *FaultGameHelper) WaitForClaimCount(ctx context.Context, count int64) {
}
}
type ContractClaim struct {
ParentIndex uint32
Countered bool
Claim [32]byte
Position *big.Int
Clock *big.Int
}
func (g *FaultGameHelper) MaxDepth(ctx context.Context) int64 {
depth, err := g.game.MAXGAMEDEPTH(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to load game depth")
......@@ -252,12 +242,6 @@ func (g *FaultGameHelper) WaitForInactivity(ctx context.Context, numInactiveBloc
}
}
// Mover is a function that either attacks or defends the claim at parentClaimIdx
type Mover func(parentClaimIdx int64)
// Stepper is a function that attempts to perform a step against the claim at parentClaimIdx
type Stepper func(parentClaimIdx int64)
// DefendRootClaim uses the supplied Mover to perform moves in an attempt to defend the root claim.
// It is assumed that the output root being disputed is valid 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.
......@@ -337,10 +321,6 @@ func (g *FaultGameHelper) Defend(ctx context.Context, claimIdx int64, claim comm
g.require.NoError(err, "Defend transaction was not OK")
}
type ErrWithData interface {
ErrorData() interface{}
}
// StepFails attempts to call step and verifies that it fails with ValidStep()
func (g *FaultGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []byte, proof []byte) {
g.t.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack)
......
......@@ -22,6 +22,7 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/dial"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
......@@ -34,7 +35,7 @@ import (
const alphabetGameType uint8 = 255
const cannonGameType uint8 = 0
const outputCannonGameType uint8 = 0 // TODO(client-pod#43): This should be a unique game type
const outputCannonGameType uint8 = 253
const alphabetGameDepth = 4
var lastAlphabetTraceIndex = big.NewInt(1<<alphabetGameDepth - 1)
......@@ -140,7 +141,10 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
}
func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoint string, rootClaim common.Hash) *OutputCannonGameHelper {
extraData, _, _ := h.createDisputeGameExtraData(ctx)
rollupClient, err := dial.DialRollupClientWithTimeout(ctx, 30*time.Second, testlog.Logger(h.t, log.LvlInfo), rollupEndpoint)
h.require.NoError(err)
extraData, _ := h.createBisectionGameExtraData(ctx, rollupClient)
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer cancel()
......@@ -154,14 +158,11 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoin
h.require.Len(rcpt.Logs, 1, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.factory.ParseDisputeGameCreated(*rcpt.Logs[0])
h.require.NoError(err)
game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err)
rollupClient, err := dial.DialRollupClientWithTimeout(ctx, 30*time.Second, testlog.Logger(h.t, log.LvlInfo), rollupEndpoint)
game, err := bindings.NewOutputBisectionGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err)
return &OutputCannonGameHelper{
FaultGameHelper: FaultGameHelper{
OutputGameHelper: OutputGameHelper{
t: h.t,
require: h.require,
client: h.client,
......@@ -169,8 +170,8 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoin
game: game,
factoryAddr: h.factoryAddr,
addr: createdEvent.DisputeProxy,
},
rollupClient: rollupClient,
},
}
}
......@@ -277,6 +278,15 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, rootClaim common.H
}
}
func (h *FactoryHelper) createBisectionGameExtraData(ctx context.Context, client *sources.RollupClient) (extraData []byte, l2BlockNumber uint64) {
syncStatus, err := client.SyncStatus(ctx)
h.require.NoError(err, "failed to get sync status")
l2BlockNumber = syncStatus.SafeL2.Number
extraData = make([]byte, 32)
binary.BigEndian.PutUint64(extraData, l2BlockNumber)
return
}
func (h *FactoryHelper) createDisputeGameExtraData(ctx context.Context) (extraData []byte, l1Head *big.Int, l2BlockNumber uint64) {
l2BlockNumber = h.waitForProposals(ctx)
l1Head = h.checkpointL1Block(ctx)
......
......@@ -2,19 +2,14 @@ package disputegame
import (
"context"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"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"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core"
)
type OutputCannonGameHelper struct {
FaultGameHelper
rollupClient *sources.RollupClient
OutputGameHelper
}
func (g *OutputCannonGameHelper) StartChallenger(
......@@ -39,30 +34,3 @@ func (g *OutputCannonGameHelper) StartChallenger(
})
return c
}
func (g *OutputCannonGameHelper) WaitForCorrectOutputRoot(ctx context.Context, claimIdx int64) {
g.WaitForClaimCount(ctx, claimIdx+1)
claim := g.getClaim(ctx, claimIdx)
err, blockNum := g.blockNumForClaim(ctx, claim)
g.require.NoError(err)
output, err := g.rollupClient.OutputAtBlock(ctx, blockNum)
g.require.NoErrorf(err, "Failed to get output at block %v", blockNum)
g.require.EqualValuesf(output.OutputRoot, claim.Claim, "Incorrect output root at claim %v. Expected to be from block %v", claimIdx, blockNum)
}
func (g *OutputCannonGameHelper) blockNumForClaim(ctx context.Context, claim ContractClaim) (error, uint64) {
proposals, err := g.game.Proposals(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to retrieve proposals")
prestateBlockNum := proposals.Starting.L2BlockNumber
disputedBlockNum := proposals.Disputed.L2BlockNumber
gameDepth := g.MaxDepth(ctx)
// TODO(client-pod#43): Load this from the contract
topDepth := gameDepth / 2
traceIdx := types.NewPositionFromGIndex(claim.Position).TraceIndex(int(topDepth))
blockNum := new(big.Int).Add(prestateBlockNum, traceIdx).Uint64() + 1
if blockNum > disputedBlockNum.Uint64() {
blockNum = disputedBlockNum.Uint64()
}
return err, blockNum
}
This diff is collapsed.
......@@ -31,12 +31,19 @@ func TestOutputCannonGame(t *testing.T) {
)
game.LogGameData(ctx)
maxDepth := game.MaxDepth(ctx)
// Challenger should post an output root to counter claims down to the leaf level of the top game
// TODO(client-pod#43): Load the depth of the top game from the contract instead of deriving it
for i := int64(1); i <= maxDepth/2+1; i += 2 {
splitDepth := game.SplitDepth(ctx)
for i := int64(1); i < splitDepth; i += 2 {
game.WaitForCorrectOutputRoot(ctx, i)
game.Attack(ctx, i, common.Hash{0xaa})
game.LogGameData(ctx)
}
game.WaitForCorrectOutputRoot(ctx, splitDepth)
// Post the first cannon output root (with 01 status code to show the output root is invalid)
game.Attack(ctx, splitDepth, common.Hash{0x01})
// Challenger should counter
game.WaitForClaimAtDepth(ctx, int(splitDepth+2))
game.LogGameData(ctx)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment