Commit d61af8a3 authored by refcell.eth's avatar refcell.eth Committed by GitHub

Merge pull request #8379 from ethereum-optimism/aj/output-cannon-new-contract

challenger: Switch output_cannon to use the new contract type.
parents bd06d4ee a51785e0
...@@ -34,7 +34,6 @@ var ( ...@@ -34,7 +34,6 @@ var (
ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path")
ErrCannonNetworkUnknown = errors.New("unknown cannon network") ErrCannonNetworkUnknown = errors.New("unknown cannon network")
ErrMissingRollupRpc = errors.New("missing rollup rpc url") ErrMissingRollupRpc = errors.New("missing rollup rpc url")
ErrCannonAndOutputCannonConflict = errors.New("trace types cannon and outputCannon cannot be enabled at the same time")
) )
type TraceType string type TraceType string
...@@ -184,12 +183,6 @@ func (c Config) Check() error { ...@@ -184,12 +183,6 @@ func (c Config) Check() error {
if c.RollupRpc == "" { if c.RollupRpc == "" {
return ErrMissingRollupRpc return ErrMissingRollupRpc
} }
if c.TraceTypeEnabled(TraceTypeCannon) && (c.TraceTypeEnabled(TraceTypeOutputCannon) || c.TraceTypeEnabled(TraceTypeOutputAlphabet)) {
return ErrCannonAndOutputCannonConflict
}
}
if c.TraceTypeEnabled(TraceTypeCannon) && c.TraceTypeEnabled(TraceTypeOutputCannon) {
return ErrCannonAndOutputCannonConflict
} }
if c.TraceTypeEnabled(TraceTypeCannon) || c.TraceTypeEnabled(TraceTypeOutputCannon) { if c.TraceTypeEnabled(TraceTypeCannon) || c.TraceTypeEnabled(TraceTypeOutputCannon) {
if c.CannonBin == "" { if c.CannonBin == "" {
......
...@@ -146,12 +146,6 @@ func TestRollupRpcRequired_OutputAlphabet(t *testing.T) { ...@@ -146,12 +146,6 @@ func TestRollupRpcRequired_OutputAlphabet(t *testing.T) {
require.ErrorIs(t, config.Check(), ErrMissingRollupRpc) require.ErrorIs(t, config.Check(), ErrMissingRollupRpc)
} }
func TestCannotEnableBothCannonAndOutputCannonTraceTypes(t *testing.T) {
config := validConfig(TraceTypeOutputCannon)
config.TraceTypes = append(config.TraceTypes, TraceTypeCannon)
require.ErrorIs(t, config.Check(), ErrCannonAndOutputCannonConflict)
}
func TestCannonL2Required(t *testing.T) { func TestCannonL2Required(t *testing.T) {
config := validConfig(TraceTypeCannon) config := validConfig(TraceTypeCannon)
config.CannonL2 = "" config.CannonL2 = ""
...@@ -214,7 +208,7 @@ func TestNetworkMustBeValid(t *testing.T) { ...@@ -214,7 +208,7 @@ func TestNetworkMustBeValid(t *testing.T) {
func TestRequireConfigForMultipleTraceTypes(t *testing.T) { func TestRequireConfigForMultipleTraceTypes(t *testing.T) {
cfg := validConfig(TraceTypeCannon) cfg := validConfig(TraceTypeCannon)
cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAlphabet} cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAlphabet, TraceTypeOutputCannon}
// Set all required options and check its valid // Set all required options and check its valid
cfg.RollupRpc = validRollupRpc cfg.RollupRpc = validRollupRpc
cfg.AlphabetTrace = validAlphabetTrace cfg.AlphabetTrace = validAlphabetTrace
...@@ -228,4 +222,9 @@ func TestRequireConfigForMultipleTraceTypes(t *testing.T) { ...@@ -228,4 +222,9 @@ func TestRequireConfigForMultipleTraceTypes(t *testing.T) {
// Require alphabet specific args // Require alphabet specific args
cfg.AlphabetTrace = "" cfg.AlphabetTrace = ""
require.ErrorIs(t, cfg.Check(), ErrMissingAlphabetTrace) require.ErrorIs(t, cfg.Check(), ErrMissingAlphabetTrace)
cfg.AlphabetTrace = validAlphabetTrace
// Require output cannon specific args
cfg.RollupRpc = ""
require.ErrorIs(t, cfg.Check(), ErrMissingRollupRpc)
} }
...@@ -36,12 +36,7 @@ type GameContract interface { ...@@ -36,12 +36,7 @@ type GameContract interface {
GetMaxGameDepth(ctx context.Context) (uint64, error) GetMaxGameDepth(ctx context.Context) (uint64, error)
} }
type gameTypeResources interface { type resourceCreator func(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (types.TraceAccessor, error)
Contract() GameContract
CreateAccessor(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (types.TraceAccessor, error)
}
type resourceCreator func(addr common.Address) (gameTypeResources, error)
func NewGamePlayer( func NewGamePlayer(
ctx context.Context, ctx context.Context,
...@@ -50,17 +45,11 @@ func NewGamePlayer( ...@@ -50,17 +45,11 @@ func NewGamePlayer(
dir string, dir string,
addr common.Address, addr common.Address,
txMgr txmgr.TxManager, txMgr txmgr.TxManager,
loader GameContract,
creator resourceCreator, creator resourceCreator,
) (*GamePlayer, error) { ) (*GamePlayer, error) {
logger = logger.New("game", addr) logger = logger.New("game", addr)
resources, err := creator(addr)
if err != nil {
return nil, fmt.Errorf("failed to create game resources: %w", err)
}
loader := resources.Contract()
status, err := loader.GetStatus(ctx) status, err := loader.GetStatus(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch game status: %w", err) return nil, fmt.Errorf("failed to fetch game status: %w", err)
...@@ -84,7 +73,7 @@ func NewGamePlayer( ...@@ -84,7 +73,7 @@ func NewGamePlayer(
return nil, fmt.Errorf("failed to fetch the game depth: %w", err) return nil, fmt.Errorf("failed to fetch the game depth: %w", err)
} }
accessor, err := resources.CreateAccessor(ctx, logger, gameDepth, dir) accessor, err := creator(ctx, logger, gameDepth, dir)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create trace accessor: %w", err) return nil, fmt.Errorf("failed to create trace accessor: %w", err)
} }
......
This diff is collapsed.
...@@ -17,8 +17,6 @@ import ( ...@@ -17,8 +17,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const defaultTimeout = 5 * time.Minute
type FaultGameHelper struct { type FaultGameHelper struct {
t *testing.T t *testing.T
require *require.Assertions require *require.Assertions
...@@ -59,14 +57,6 @@ func (g *FaultGameHelper) WaitForClaimCount(ctx context.Context, count int64) { ...@@ -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 { func (g *FaultGameHelper) MaxDepth(ctx context.Context) int64 {
depth, err := g.game.MAXGAMEDEPTH(&bind.CallOpts{Context: ctx}) depth, err := g.game.MAXGAMEDEPTH(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "Failed to load game depth") g.require.NoError(err, "Failed to load game depth")
...@@ -252,12 +242,6 @@ func (g *FaultGameHelper) WaitForInactivity(ctx context.Context, numInactiveBloc ...@@ -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. // 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. // 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. // 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 ...@@ -337,10 +321,6 @@ func (g *FaultGameHelper) Defend(ctx context.Context, claimIdx int64, claim comm
g.require.NoError(err, "Defend transaction was not OK") 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() // StepFails attempts to call step and verifies that it fails with ValidStep()
func (g *FaultGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []byte, proof []byte) { func (g *FaultGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []byte, proof []byte) {
g.t.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack) g.t.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack)
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/dial"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -34,7 +35,7 @@ import ( ...@@ -34,7 +35,7 @@ import (
const alphabetGameType uint8 = 255 const alphabetGameType uint8 = 255
const cannonGameType uint8 = 0 const cannonGameType uint8 = 0
const outputCannonGameType uint8 = 0 // TODO(client-pod#43): This should be a unique game type const outputCannonGameType uint8 = 253 // TODO(client-pod#43): Switch this game type to 1
const alphabetGameDepth = 4 const alphabetGameDepth = 4
var lastAlphabetTraceIndex = big.NewInt(1<<alphabetGameDepth - 1) var lastAlphabetTraceIndex = big.NewInt(1<<alphabetGameDepth - 1)
...@@ -140,7 +141,10 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s ...@@ -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 { 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) ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer cancel() defer cancel()
...@@ -154,23 +158,20 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoin ...@@ -154,23 +158,20 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, rollupEndpoin
h.require.Len(rcpt.Logs, 1, "should have emitted a single DisputeGameCreated event") h.require.Len(rcpt.Logs, 1, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.factory.ParseDisputeGameCreated(*rcpt.Logs[0]) createdEvent, err := h.factory.ParseDisputeGameCreated(*rcpt.Logs[0])
h.require.NoError(err) h.require.NoError(err)
game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.client) game, err := bindings.NewOutputBisectionGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err)
rollupClient, err := dial.DialRollupClientWithTimeout(ctx, 30*time.Second, testlog.Logger(h.t, log.LvlInfo), rollupEndpoint)
h.require.NoError(err) h.require.NoError(err)
return &OutputCannonGameHelper{ return &OutputCannonGameHelper{
FaultGameHelper: FaultGameHelper{ OutputGameHelper: OutputGameHelper{
t: h.t, t: h.t,
require: h.require, require: h.require,
client: h.client, client: h.client,
opts: h.opts, opts: h.opts,
game: game, game: game,
factoryAddr: h.factoryAddr, factoryAddr: h.factoryAddr,
addr: createdEvent.DisputeProxy, addr: createdEvent.DisputeProxy,
rollupClient: rollupClient,
}, },
rollupClient: rollupClient,
} }
} }
...@@ -277,6 +278,15 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, rootClaim common.H ...@@ -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) { func (h *FactoryHelper) createDisputeGameExtraData(ctx context.Context) (extraData []byte, l1Head *big.Int, l2BlockNumber uint64) {
l2BlockNumber = h.waitForProposals(ctx) l2BlockNumber = h.waitForProposals(ctx)
l1Head = h.checkpointL1Block(ctx) l1Head = h.checkpointL1Block(ctx)
......
...@@ -2,19 +2,14 @@ package disputegame ...@@ -2,19 +2,14 @@ package disputegame
import ( import (
"context" "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-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-node/rollup" "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" "github.com/ethereum/go-ethereum/core"
) )
type OutputCannonGameHelper struct { type OutputCannonGameHelper struct {
FaultGameHelper OutputGameHelper
rollupClient *sources.RollupClient
} }
func (g *OutputCannonGameHelper) StartChallenger( func (g *OutputCannonGameHelper) StartChallenger(
...@@ -39,30 +34,3 @@ func (g *OutputCannonGameHelper) StartChallenger( ...@@ -39,30 +34,3 @@ func (g *OutputCannonGameHelper) StartChallenger(
}) })
return c 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) { ...@@ -31,12 +31,19 @@ func TestOutputCannonGame(t *testing.T) {
) )
game.LogGameData(ctx) 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 // 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 splitDepth := game.SplitDepth(ctx)
for i := int64(1); i <= maxDepth/2+1; i += 2 { for i := int64(1); i < splitDepth; i += 2 {
game.WaitForCorrectOutputRoot(ctx, i) game.WaitForCorrectOutputRoot(ctx, i)
game.Attack(ctx, i, common.Hash{0xaa}) game.Attack(ctx, i, common.Hash{0xaa})
game.LogGameData(ctx) 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