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 (
ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path")
ErrCannonNetworkUnknown = errors.New("unknown cannon network")
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
......@@ -184,12 +183,6 @@ func (c Config) Check() error {
if c.RollupRpc == "" {
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.CannonBin == "" {
......
......@@ -146,12 +146,6 @@ func TestRollupRpcRequired_OutputAlphabet(t *testing.T) {
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) {
config := validConfig(TraceTypeCannon)
config.CannonL2 = ""
......@@ -214,7 +208,7 @@ func TestNetworkMustBeValid(t *testing.T) {
func TestRequireConfigForMultipleTraceTypes(t *testing.T) {
cfg := validConfig(TraceTypeCannon)
cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAlphabet}
cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAlphabet, TraceTypeOutputCannon}
// Set all required options and check its valid
cfg.RollupRpc = validRollupRpc
cfg.AlphabetTrace = validAlphabetTrace
......@@ -228,4 +222,9 @@ func TestRequireConfigForMultipleTraceTypes(t *testing.T) {
// Require alphabet specific args
cfg.AlphabetTrace = ""
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 {
GetMaxGameDepth(ctx context.Context) (uint64, error)
}
type gameTypeResources interface {
Contract() GameContract
CreateAccessor(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (types.TraceAccessor, error)
}
type resourceCreator func(addr common.Address) (gameTypeResources, error)
type resourceCreator func(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (types.TraceAccessor, error)
func NewGamePlayer(
ctx context.Context,
......@@ -50,17 +45,11 @@ func NewGamePlayer(
dir string,
addr common.Address,
txMgr txmgr.TxManager,
loader GameContract,
creator resourceCreator,
) (*GamePlayer, error) {
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)
if err != nil {
return nil, fmt.Errorf("failed to fetch game status: %w", err)
......@@ -84,7 +73,7 @@ func NewGamePlayer(
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 {
return nil, fmt.Errorf("failed to create trace accessor: %w", err)
}
......
This diff is collapsed.
......@@ -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 // TODO(client-pod#43): Switch this game type to 1
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