Commit 110f4e84 authored by Adrian Sutton's avatar Adrian Sutton

op-e2e: Add ability to deploy dispute game contracts and test that games can be resolved.

parent 70d4d030
......@@ -28,6 +28,7 @@
"L1BlockNumber",
"DisputeGameFactory",
"FaultDisputeGame",
"AlphabetVM",
"StandardBridge",
"CrossDomainMessenger",
"MIPS",
......
This diff is collapsed.
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"encoding/json"
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const AlphabetVMStorageLayoutJSON = "{\"storage\":null,\"types\":{}}"
var AlphabetVMStorageLayout = new(solc.StorageLayout)
var AlphabetVMDeployedBin = "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f8e0cb9614610030575b600080fd5b61004361003e366004610157565b610055565b60405190815260200160405180910390f35b60008060007f0000000000000000000000000000000000000000000000000000000000000000878760405161008b9291906101c3565b6040518091039020036100af57600091506100a8868801886101d3565b90506100ce565b6100bb868801886101ec565b9092509050816100ca8161023d565b9250505b816100da826001610275565b6040805160208101939093528201526060016040516020818303038152906040528051906020012092505050949350505050565b60008083601f84011261012057600080fd5b50813567ffffffffffffffff81111561013857600080fd5b60208301915083602082850101111561015057600080fd5b9250929050565b6000806000806040858703121561016d57600080fd5b843567ffffffffffffffff8082111561018557600080fd5b6101918883890161010e565b909650945060208701359150808211156101aa57600080fd5b506101b78782880161010e565b95989497509550505050565b8183823760009101908152919050565b6000602082840312156101e557600080fd5b5035919050565b600080604083850312156101ff57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361026e5761026e61020e565b5060010190565b600082198211156102885761028861020e565b50019056fea164736f6c634300080f000a"
func init() {
if err := json.Unmarshal([]byte(AlphabetVMStorageLayoutJSON), AlphabetVMStorageLayout); err != nil {
panic(err)
}
layouts["AlphabetVM"] = AlphabetVMStorageLayout
deployedBytecodes["AlphabetVM"] = AlphabetVMDeployedBin
}
package disputegame
import (
"context"
"math/big"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require"
)
// deployDisputeGameContracts deploys the DisputeGameFactory, AlphabetVM and FaultDisputeGame contracts
// It configures the alphabet fault game as game type 0 (faultGameType)
// If/when the dispute game factory becomes a predeployed contract this can be removed and just use the
func deployDisputeGameContracts(require *require.Assertions, ctx context.Context, client *ethclient.Client, opts *bind.TransactOpts, gameDuration uint64) *bindings.DisputeGameFactory {
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()
// Deploy the proxy
_, tx, proxy, err := bindings.DeployProxy(opts, client, deployer.TestAddress)
require.NoError(err)
proxyAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err)
// Deploy the dispute game factory implementation
_, tx, _, err = bindings.DeployDisputeGameFactory(opts, client)
require.NoError(err)
factoryAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err)
// Point the proxy at the implementation and create bindings going via the proxy
disputeGameFactoryAbi, err := bindings.DisputeGameFactoryMetaData.GetAbi()
require.NoError(err)
data, err := disputeGameFactoryAbi.Pack("initialize", deployer.TestAddress)
require.NoError(err)
_, err = proxy.UpgradeToAndCall(opts, factoryAddr, data)
require.NoError(err)
factory, err := bindings.NewDisputeGameFactory(proxyAddr, client)
require.NoError(err)
// Now setup the fault dispute game type
// Start by deploying the AlphabetVM
_, tx, _, err = bindings.DeployAlphabetVM(opts, client, alphabetVMAbsolutePrestate)
require.NoError(err)
alphaVMAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err)
// Deploy the fault dispute game implementation
_, tx, _, err = bindings.DeployFaultDisputeGame(opts, client, alphabetVMAbsolutePrestate, big.NewInt(alphabetGameDepth), gameDuration, alphaVMAddr)
require.NoError(err)
faultDisputeGameAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err)
// Set the fault game type implementation
_, err = factory.SetImplementation(opts, faultGameType, faultDisputeGameAddr)
require.NoError(err)
return factory
}
package disputegame
import (
"context"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"
)
const faultGameType uint8 = 0
const alphabetGameDepth = 4
type Status uint8
const (
StatusInProgress Status = iota
StatusChallengerWins
StatusDefenderWins
)
var alphaExtraData = common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")
var alphabetVMAbsolutePrestate = uint256.NewInt(140).Bytes32()
type FactoryHelper struct {
require *require.Assertions
client *ethclient.Client
opts *bind.TransactOpts
factory *bindings.DisputeGameFactory
}
func NewFactoryHelper(t *testing.T, ctx context.Context, client *ethclient.Client, gameDuration uint64) *FactoryHelper {
require := require.New(t)
chainID, err := client.ChainID(ctx)
require.NoError(err)
opts, err := bind.NewKeyedTransactorWithChainID(deployer.TestKey, chainID)
require.NoError(err)
factory := deployDisputeGameContracts(require, ctx, client, opts, gameDuration)
return &FactoryHelper{
require: require,
client: client,
opts: opts,
factory: factory,
}
}
func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet string) *FaultHelper {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
trace := fault.NewAlphabetProvider(claimedAlphabet, 4)
rootClaim, err := trace.Get(2 ^ alphabetGameDepth - 1)
h.require.NoError(err)
tx, err := h.factory.Create(h.opts, faultGameType, rootClaim, alphaExtraData)
h.require.NoError(err)
rcpt, err := utils.WaitReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err)
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)
return &FaultHelper{
require: h.require,
client: h.client,
opts: h.opts,
game: game,
}
}
type FaultHelper struct {
require *require.Assertions
client *ethclient.Client
opts *bind.TransactOpts
game *bindings.FaultDisputeGame
}
func (g *FaultHelper) Resolve(ctx context.Context) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
tx, err := g.game.Resolve(g.opts)
g.require.NoError(err)
_, err = utils.WaitReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err)
}
func (g *FaultHelper) AssertStatusEquals(expected Status) {
status, err := g.game.Status(&bind.CallOpts{
From: g.opts.From,
})
g.require.NoError(err)
g.require.Equal(expected, Status(status))
}
......@@ -5,37 +5,36 @@ import (
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/stretchr/testify/require"
)
func TestTimeTravel(t *testing.T) {
func TestResolveDisputeGame(t *testing.T) {
InitParallel(t)
ctx := context.Background()
cfg := DefaultSystemConfig(t)
cfg.DeployConfig.L1BlockTime = 1
delete(cfg.Nodes, "verifier")
delete(cfg.Nodes, "sequencer")
cfg.SupportL1TimeTravel = true
sys, err := cfg.Start()
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l1Client := sys.Clients["l1"]
preTravel, err := l1Client.BlockByNumber(context.Background(), nil)
require.NoError(t, err)
sys.TimeTravelClock.AdvanceTime(24 * time.Hour)
// Check that the L1 chain reaches the new time reasonably quickly (ie without taking a week)
// It should be able to jump straight to the new time with just a single block
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
err = utils.WaitFor(ctx, time.Second, func() (bool, error) {
postTravel, err := l1Client.BlockByNumber(context.Background(), nil)
if err != nil {
return false, err
}
diff := time.Duration(postTravel.Time()-preTravel.Time()) * time.Second
return diff.Hours() > 23, nil
})
require.NoError(t, err)
gameDuration := 24 * time.Hour
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, l1Client, uint64(gameDuration.Seconds()))
game := disputeGameFactory.StartAlphabetGame(ctx, "abcdefg")
require.NotNil(t, game)
game.AssertStatusEquals(disputegame.StatusInProgress)
sys.TimeTravelClock.AdvanceTime(gameDuration)
require.NoError(t, utils.WaitNextBlock(ctx, l1Client))
game.Resolve(ctx)
game.AssertStatusEquals(disputegame.StatusDefenderWins)
}
......@@ -616,6 +616,10 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
}
}
// Don't start batch submitter and proposer if there's no sequencer.
if sys.RollupNodes["sequencer"] == nil {
return sys, nil
}
// L2Output Submitter
sys.L2OutputSubmitter, err = l2os.NewL2OutputSubmitterFromCLIConfig(l2os.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
......
......@@ -59,6 +59,14 @@ func WaitBlock(ctx context.Context, client *ethclient.Client, n uint64) error {
return nil
}
func WaitNextBlock(ctx context.Context, client *ethclient.Client) error {
current, err := client.BlockNumber(ctx)
if err != nil {
return fmt.Errorf("get starting block number: %w", err)
}
return WaitBlock(ctx, client, current+1)
}
func WaitFor(ctx context.Context, rate time.Duration, cb func() (bool, error)) error {
tick := time.NewTicker(rate)
defer tick.Stop()
......
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