Commit 12900b75 authored by clabby's avatar clabby Committed by GitHub

feat(ctb): Consolidate `OutputBisectionGame` -> `FaultDisputeGame` (#8787)

* Consolidate `OutputBisectionGame` -> `FaultDisputeGame`

* Deploy fix

* deploy config updates

* challenger/op-e2e: Consolidate `OutputBisectionGame` -> `FaultDisputeGame`

* lint

* e2e helper refactor

* Remove `AlphabetTrace` config option

* Rename contract binding

* Update packages/contracts-bedrock/scripts/Deploy.s.sol
Co-authored-by: default avatarrefcell.eth <abigger87@gmail.com>

* @refcell comment nit
Co-Authored-By: default avatarrefcell <abigger87@gmail.com>

* fmt

* @refcell nit

* Revert @ajsutton's alphabet config change

---------
Co-authored-by: default avatarrefcell.eth <abigger87@gmail.com>
parent b01f7802
...@@ -29,14 +29,11 @@ ...@@ -29,14 +29,11 @@
"L1BlockNumber", "L1BlockNumber",
"DisputeGameFactory", "DisputeGameFactory",
"FaultDisputeGame", "FaultDisputeGame",
"OutputBisectionGame",
"AlphabetVM", "AlphabetVM",
"AlphabetVM2",
"StandardBridge", "StandardBridge",
"CrossDomainMessenger", "CrossDomainMessenger",
"MIPS", "MIPS",
"PreimageOracle", "PreimageOracle",
"BlockOracle",
"EAS", "EAS",
"SchemaRegistry", "SchemaRegistry",
"ProtocolVersions", "ProtocolVersions",
......
This diff is collapsed.
...@@ -13,7 +13,7 @@ const AlphabetVMStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\": ...@@ -13,7 +13,7 @@ const AlphabetVMStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":
var AlphabetVMStorageLayout = new(solc.StorageLayout) var AlphabetVMStorageLayout = new(solc.StorageLayout)
var AlphabetVMDeployedBin = "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80637dc0d1d01461003b578063e14ced3214610085575b600080fd5b60005461005b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610098610093366004610213565b6100a6565b60405190815260200161007c565b600080600060087f0000000000000000000000000000000000000000000000000000000000000000901b600889896040516100e2929190610287565b6040518091039020901b03610108576000915061010187890189610297565b9050610127565b610114878901896102b0565b90925090508161012381610301565b9250505b81610133826001610339565b604080516020810193909352820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001798975050505050505050565b60008083601f8401126101dc57600080fd5b50813567ffffffffffffffff8111156101f457600080fd5b60208301915083602082850101111561020c57600080fd5b9250929050565b60008060008060006060868803121561022b57600080fd5b853567ffffffffffffffff8082111561024357600080fd5b61024f89838a016101ca565b9097509550602088013591508082111561026857600080fd5b50610275888289016101ca565b96999598509660400135949350505050565b8183823760009101908152919050565b6000602082840312156102a957600080fd5b5035919050565b600080604083850312156102c357600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610332576103326102d2565b5060010190565b6000821982111561034c5761034c6102d2565b50019056fea164736f6c634300080f000a" var AlphabetVMDeployedBin = "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80637dc0d1d01461003b578063e14ced3214610085575b600080fd5b60005461005b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610098610093366004610395565b6100a6565b60405190815260200161007c565b600080600060087f0000000000000000000000000000000000000000000000000000000000000000901b600889896040516100e2929190610409565b6040518091039020901b036101d9576000805473ffffffffffffffffffffffffffffffffffffffff1663e03110e161011b60048861029f565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526004810191909152600060248201526044016040805180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101999190610419565b50640ffffffff0607c82901c169350905063ffffffff608082901c1660006101c38a8c018c61043d565b90506101cf8582610485565b9350505050610206565b6101e58789018961049d565b9092509050816101f4816104bf565b9250508080610202906104bf565b9150505b6040805160208101849052908101829052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001798975050505050505050565b7f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831617610345818360408051600093845233602052918152606090922091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b9392505050565b60008083601f84011261035e57600080fd5b50813567ffffffffffffffff81111561037657600080fd5b60208301915083602082850101111561038e57600080fd5b9250929050565b6000806000806000606086880312156103ad57600080fd5b853567ffffffffffffffff808211156103c557600080fd5b6103d189838a0161034c565b909750955060208801359150808211156103ea57600080fd5b506103f78882890161034c565b96999598509660400135949350505050565b8183823760009101908152919050565b6000806040838503121561042c57600080fd5b505080516020909101519092909150565b60006020828403121561044f57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561049857610498610456565b500190565b600080604083850312156104b057600080fd5b50508035926020909101359150565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036104f0576104f0610456565b506001019056fea164736f6c634300080f000a"
func init() { func init() {
......
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 BlockOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"src/dispute/BlockOracle.sol:BlockOracle\",\"label\":\"blocks\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_uint256,t_struct(BlockInfo)1001_storage)\"}],\"types\":{\"t_mapping(t_uint256,t_struct(BlockInfo)1001_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct BlockOracle.BlockInfo)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BlockInfo)1001_storage\"},\"t_struct(BlockInfo)1001_storage\":{\"encoding\":\"inplace\",\"label\":\"struct BlockOracle.BlockInfo\",\"numberOfBytes\":\"64\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_userDefinedValueType(Hash)1002\":{\"encoding\":\"inplace\",\"label\":\"Hash\",\"numberOfBytes\":\"32\"},\"t_userDefinedValueType(Timestamp)1003\":{\"encoding\":\"inplace\",\"label\":\"Timestamp\",\"numberOfBytes\":\"8\"}}}"
var BlockOracleStorageLayout = new(solc.StorageLayout)
var BlockOracleDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806354fd4d501461004657806399d548aa14610098578063c2c4c5c1146100d0575b600080fd5b6100826040518060400160405280600581526020017f302e302e3100000000000000000000000000000000000000000000000000000081525081565b60405161008f9190610210565b60405180910390f35b6100ab6100a6366004610283565b6100e6565b604080518251815260209283015167ffffffffffffffff16928101929092520161008f565b6100d8610165565b60405190815260200161008f565b604080518082018252600080825260209182018190528381528082528281208351808501909452805480855260019091015467ffffffffffffffff169284019290925203610160576040517f37cf270500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b600061017260014361029c565b60408051808201825282408082524267ffffffffffffffff81811660208086018281526000898152918290528782209651875551600190960180547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016969093169590951790915593519495509093909291849186917fb67ff58b33060fd371a35ae2d9f1c3cdaec9b8197969f6efe2594a1ff4ba68c691a4505090565b600060208083528351808285015260005b8181101561023d57858101830151858201604001528201610221565b8181111561024f576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561029557600080fd5b5035919050565b6000828210156102d5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50039056fea164736f6c634300080f000a"
func init() {
if err := json.Unmarshal([]byte(BlockOracleStorageLayoutJSON), BlockOracleStorageLayout); err != nil {
panic(err)
}
layouts["BlockOracle"] = BlockOracleStorageLayout
deployedBytecodes["BlockOracle"] = BlockOracleDeployedBin
immutableReferences["BlockOracle"] = false
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -212,12 +212,12 @@ type DeployConfig struct { ...@@ -212,12 +212,12 @@ type DeployConfig struct {
// game can run for before it is ready to be resolved. Each side receives half of this value // game can run for before it is ready to be resolved. Each side receives half of this value
// on their chess clock at the inception of the dispute. // on their chess clock at the inception of the dispute.
FaultGameMaxDuration uint64 `json:"faultGameMaxDuration"` FaultGameMaxDuration uint64 `json:"faultGameMaxDuration"`
// OutputBisectionGameGenesisBlock is the block number for genesis. // FaultGameGenesisBlock is the block number for genesis.
OutputBisectionGameGenesisBlock uint64 `json:"outputBisectionGameGenesisBlock"` FaultGameGenesisBlock uint64 `json:"faultGameGenesisBlock"`
// OutputBisectionGameGenesisOutputRoot is the output root for the genesis block. // FaultGameGenesisOutputRoot is the output root for the genesis block.
OutputBisectionGameGenesisOutputRoot common.Hash `json:"outputBisectionGameGenesisOutputRoot"` FaultGameGenesisOutputRoot common.Hash `json:"faultGameGenesisOutputRoot"`
// OutputBisectionGameSplitDepth is the depth at which the output bisection game splits. // FaultGameSplitDepth is the depth at which the fault dispute game splits from output roots to execution trace claims.
OutputBisectionGameSplitDepth uint64 `json:"outputBisectionGameSplitDepth"` FaultGameSplitDepth uint64 `json:"faultGameSplitDepth"`
// FundDevAccounts configures whether or not to fund the dev accounts. Should only be used // FundDevAccounts configures whether or not to fund the dev accounts. Should only be used
// during devnet deployments. // during devnet deployments.
FundDevAccounts bool `json:"fundDevAccounts"` FundDevAccounts bool `json:"fundDevAccounts"`
......
...@@ -68,9 +68,9 @@ ...@@ -68,9 +68,9 @@
"faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameMaxDepth": 63, "faultGameMaxDepth": 63,
"faultGameMaxDuration": 604800, "faultGameMaxDuration": 604800,
"outputBisectionGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"outputBisectionGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"outputBisectionGameSplitDepth": 0, "faultGameSplitDepth": 0,
"systemConfigStartBlock": 0, "systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000" "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000"
......
...@@ -28,7 +28,6 @@ var ( ...@@ -28,7 +28,6 @@ var (
datadir = "./test_data" datadir = "./test_data"
cannonL2 = "http://example.com:9545" cannonL2 = "http://example.com:9545"
rollupRpc = "http://example.com:8555" rollupRpc = "http://example.com:8555"
alphabetTrace = "abcdefghijz"
) )
func TestLogLevel(t *testing.T) { func TestLogLevel(t *testing.T) {
...@@ -50,7 +49,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { ...@@ -50,7 +49,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet)) cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet))
defaultCfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, datadir, config.TraceTypeAlphabet) defaultCfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, datadir, config.TraceTypeAlphabet)
// Add in the extra CLI options required when using alphabet trace type // Add in the extra CLI options required when using alphabet trace type
defaultCfg.AlphabetTrace = alphabetTrace defaultCfg.RollupRpc = rollupRpc
require.Equal(t, defaultCfg, cfg) require.Equal(t, defaultCfg, cfg)
} }
...@@ -58,7 +57,7 @@ func TestDefaultConfigIsValid(t *testing.T) { ...@@ -58,7 +57,7 @@ func TestDefaultConfigIsValid(t *testing.T) {
cfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, datadir, config.TraceTypeAlphabet) cfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, datadir, config.TraceTypeAlphabet)
// Add in options that are required based on the specific trace type // Add in options that are required based on the specific trace type
// To avoid needing to specify unused options, these aren't included in the params for NewConfig // To avoid needing to specify unused options, these aren't included in the params for NewConfig
cfg.AlphabetTrace = alphabetTrace cfg.RollupRpc = rollupRpc
require.NoError(t, cfg.Check()) require.NoError(t, cfg.Check())
} }
...@@ -96,19 +95,17 @@ func TestTraceType(t *testing.T) { ...@@ -96,19 +95,17 @@ func TestTraceType(t *testing.T) {
func TestMultipleTraceTypes(t *testing.T) { func TestMultipleTraceTypes(t *testing.T) {
t.Run("WithAllOptions", func(t *testing.T) { t.Run("WithAllOptions", func(t *testing.T) {
argsMap := requiredArgs(config.TraceTypeCannon) argsMap := requiredArgs(config.TraceTypeCannon)
addRequiredOutputCannonArgs(argsMap) addRequiredOutputArgs(argsMap)
addRequiredAlphabetArgs(argsMap)
args := toArgList(argsMap) args := toArgList(argsMap)
// Add extra trace types (cannon is already specified) // Add extra trace types (cannon is already specified)
args = append(args, args = append(args,
"--trace-type", config.TraceTypeOutputCannon.String(),
"--trace-type", config.TraceTypeAlphabet.String()) "--trace-type", config.TraceTypeAlphabet.String())
cfg := configForArgs(t, args) cfg := configForArgs(t, args)
require.Equal(t, []config.TraceType{config.TraceTypeCannon, config.TraceTypeOutputCannon, config.TraceTypeAlphabet}, cfg.TraceTypes) require.Equal(t, []config.TraceType{config.TraceTypeCannon, config.TraceTypeAlphabet}, cfg.TraceTypes)
}) })
t.Run("WithSomeOptions", func(t *testing.T) { t.Run("WithSomeOptions", func(t *testing.T) {
argsMap := requiredArgs(config.TraceTypeCannon) argsMap := requiredArgs(config.TraceTypeCannon)
addRequiredAlphabetArgs(argsMap) addRequiredOutputArgs(argsMap)
args := toArgList(argsMap) args := toArgList(argsMap)
// Add extra trace types (cannon is already specified) // Add extra trace types (cannon is already specified)
args = append(args, args = append(args,
...@@ -270,20 +267,16 @@ func TestDataDir(t *testing.T) { ...@@ -270,20 +267,16 @@ func TestDataDir(t *testing.T) {
} }
func TestRollupRpc(t *testing.T) { func TestRollupRpc(t *testing.T) {
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { t.Run("RequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--rollup-rpc")) verifyArgsInvalid(t, "flag rollup-rpc is required", addRequiredArgsExcept(config.TraceTypeAlphabet, "--rollup-rpc"))
})
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeCannon, "--rollup-rpc"))
}) })
t.Run("RequiredForOutputCannonTrace", func(t *testing.T) { t.Run("RequiredForCannonTrace", func(t *testing.T) {
verifyArgsInvalid(t, "flag rollup-rpc is required", addRequiredArgsExcept(config.TraceTypeOutputCannon, "--rollup-rpc")) verifyArgsInvalid(t, "flag rollup-rpc is required", addRequiredArgsExcept(config.TraceTypeCannon, "--rollup-rpc"))
}) })
t.Run("Valid", func(t *testing.T) { t.Run("Valid", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeOutputCannon)) cfg := configForArgs(t, addRequiredArgs(config.TraceTypeCannon))
require.Equal(t, rollupRpc, cfg.RollupRpc) require.Equal(t, rollupRpc, cfg.RollupRpc)
}) })
} }
...@@ -462,41 +455,25 @@ func requiredArgs(traceType config.TraceType) map[string]string { ...@@ -462,41 +455,25 @@ func requiredArgs(traceType config.TraceType) map[string]string {
"--datadir": datadir, "--datadir": datadir,
} }
switch traceType { switch traceType {
case config.TraceTypeAlphabet:
addRequiredAlphabetArgs(args)
case config.TraceTypeCannon: case config.TraceTypeCannon:
addRequiredCannonArgs(args) addRequiredCannonArgs(args)
case config.TraceTypeOutputCannon: case config.TraceTypeAlphabet:
addRequiredOutputCannonArgs(args) addRequiredOutputArgs(args)
case config.TraceTypeOutputAlphabet:
addRequiredOutputAlphabetArgs(args)
} }
return args return args
} }
func addRequiredAlphabetArgs(args map[string]string) {
args["--alphabet"] = alphabetTrace
}
func addRequiredOutputAlphabetArgs(args map[string]string) {
addRequiredOutputArgs(args)
}
func addRequiredOutputCannonArgs(args map[string]string) {
addRequiredCannonArgs(args)
addRequiredOutputArgs(args)
}
func addRequiredOutputArgs(args map[string]string) {
args["--rollup-rpc"] = rollupRpc
}
func addRequiredCannonArgs(args map[string]string) { func addRequiredCannonArgs(args map[string]string) {
args["--cannon-network"] = cannonNetwork args["--cannon-network"] = cannonNetwork
args["--cannon-bin"] = cannonBin args["--cannon-bin"] = cannonBin
args["--cannon-server"] = cannonServer args["--cannon-server"] = cannonServer
args["--cannon-prestate"] = cannonPreState args["--cannon-prestate"] = cannonPreState
args["--cannon-l2"] = cannonL2 args["--cannon-l2"] = cannonL2
addRequiredOutputArgs(args)
}
func addRequiredOutputArgs(args map[string]string) {
args["--rollup-rpc"] = rollupRpc
} }
func toArgList(req map[string]string) []string { func toArgList(req map[string]string) []string {
......
...@@ -23,7 +23,6 @@ var ( ...@@ -23,7 +23,6 @@ var (
ErrMissingCannonBin = errors.New("missing cannon bin") ErrMissingCannonBin = errors.New("missing cannon bin")
ErrMissingCannonServer = errors.New("missing cannon server") ErrMissingCannonServer = errors.New("missing cannon server")
ErrMissingCannonAbsolutePreState = errors.New("missing cannon absolute pre-state") ErrMissingCannonAbsolutePreState = errors.New("missing cannon absolute pre-state")
ErrMissingAlphabetTrace = errors.New("missing alphabet trace")
ErrMissingL1EthRPC = errors.New("missing l1 eth rpc url") ErrMissingL1EthRPC = errors.New("missing l1 eth rpc url")
ErrMissingGameFactoryAddress = errors.New("missing game factory address") ErrMissingGameFactoryAddress = errors.New("missing game factory address")
ErrMissingCannonSnapshotFreq = errors.New("missing cannon snapshot freq") ErrMissingCannonSnapshotFreq = errors.New("missing cannon snapshot freq")
...@@ -41,8 +40,6 @@ type TraceType string ...@@ -41,8 +40,6 @@ type TraceType string
const ( const (
TraceTypeAlphabet TraceType = "alphabet" TraceTypeAlphabet TraceType = "alphabet"
TraceTypeCannon TraceType = "cannon" TraceTypeCannon TraceType = "cannon"
TraceTypeOutputCannon TraceType = "output_cannon"
TraceTypeOutputAlphabet TraceType = "output_alphabet"
// Mainnet games // Mainnet games
CannonFaultGameID = 0 CannonFaultGameID = 0
...@@ -51,7 +48,7 @@ const ( ...@@ -51,7 +48,7 @@ const (
AlphabetFaultGameID = 255 AlphabetFaultGameID = 255
) )
var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon, TraceTypeOutputCannon, TraceTypeOutputAlphabet} var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon}
// GameIdToString maps game IDs to their string representation. // GameIdToString maps game IDs to their string representation.
var GameIdToString = map[uint8]string{ var GameIdToString = map[uint8]string{
...@@ -111,9 +108,6 @@ type Config struct { ...@@ -111,9 +108,6 @@ type Config struct {
TraceTypes []TraceType // Type of traces supported TraceTypes []TraceType // Type of traces supported
// Specific to the alphabet trace provider
AlphabetTrace string // String for the AlphabetTraceProvider
// Specific to the output cannon trace type // Specific to the output cannon trace type
RollupRpc string RollupRpc string
...@@ -167,6 +161,9 @@ func (c Config) Check() error { ...@@ -167,6 +161,9 @@ func (c Config) Check() error {
if c.L1EthRpc == "" { if c.L1EthRpc == "" {
return ErrMissingL1EthRPC return ErrMissingL1EthRPC
} }
if c.RollupRpc == "" {
return ErrMissingRollupRpc
}
if c.GameFactoryAddress == (common.Address{}) { if c.GameFactoryAddress == (common.Address{}) {
return ErrMissingGameFactoryAddress return ErrMissingGameFactoryAddress
} }
...@@ -179,12 +176,7 @@ func (c Config) Check() error { ...@@ -179,12 +176,7 @@ func (c Config) Check() error {
if c.MaxConcurrency == 0 { if c.MaxConcurrency == 0 {
return ErrMaxConcurrencyZero return ErrMaxConcurrencyZero
} }
if c.TraceTypeEnabled(TraceTypeOutputCannon) || c.TraceTypeEnabled(TraceTypeOutputAlphabet) { if c.TraceTypeEnabled(TraceTypeCannon) {
if c.RollupRpc == "" {
return ErrMissingRollupRpc
}
}
if c.TraceTypeEnabled(TraceTypeCannon) || c.TraceTypeEnabled(TraceTypeOutputCannon) {
if c.CannonBin == "" { if c.CannonBin == "" {
return ErrMissingCannonBin return ErrMissingCannonBin
} }
...@@ -222,9 +214,6 @@ func (c Config) Check() error { ...@@ -222,9 +214,6 @@ func (c Config) Check() error {
return ErrMissingCannonInfoFreq return ErrMissingCannonInfoFreq
} }
} }
if c.TraceTypeEnabled(TraceTypeAlphabet) && c.AlphabetTrace == "" {
return ErrMissingAlphabetTrace
}
if err := c.TxMgrConfig.Check(); err != nil { if err := c.TxMgrConfig.Check(); err != nil {
return err return err
} }
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
var ( var (
validL1EthRpc = "http://localhost:8545" validL1EthRpc = "http://localhost:8545"
validGameFactoryAddress = common.Address{0x23} validGameFactoryAddress = common.Address{0x23}
validAlphabetTrace = "abcdefgh"
validCannonBin = "./bin/cannon" validCannonBin = "./bin/cannon"
validCannonOpProgramBin = "./bin/op-program" validCannonOpProgramBin = "./bin/op-program"
validCannonNetwork = "mainnet" validCannonNetwork = "mainnet"
...@@ -25,19 +24,14 @@ var ( ...@@ -25,19 +24,14 @@ var (
func validConfig(traceType TraceType) Config { func validConfig(traceType TraceType) Config {
cfg := NewConfig(validGameFactoryAddress, validL1EthRpc, validDatadir, traceType) cfg := NewConfig(validGameFactoryAddress, validL1EthRpc, validDatadir, traceType)
switch traceType { if traceType == TraceTypeCannon {
case TraceTypeAlphabet:
cfg.AlphabetTrace = validAlphabetTrace
case TraceTypeCannon, TraceTypeOutputCannon:
cfg.CannonBin = validCannonBin cfg.CannonBin = validCannonBin
cfg.CannonServer = validCannonOpProgramBin cfg.CannonServer = validCannonOpProgramBin
cfg.CannonAbsolutePreState = validCannonAbsolutPreState cfg.CannonAbsolutePreState = validCannonAbsolutPreState
cfg.CannonL2 = validCannonL2 cfg.CannonL2 = validCannonL2
cfg.CannonNetwork = validCannonNetwork cfg.CannonNetwork = validCannonNetwork
} }
if traceType == TraceTypeOutputCannon || traceType == TraceTypeOutputAlphabet {
cfg.RollupRpc = validRollupRpc cfg.RollupRpc = validRollupRpc
}
return cfg return cfg
} }
...@@ -78,18 +72,6 @@ func TestGameAllowlistNotRequired(t *testing.T) { ...@@ -78,18 +72,6 @@ func TestGameAllowlistNotRequired(t *testing.T) {
require.NoError(t, config.Check()) require.NoError(t, config.Check())
} }
func TestAlphabetTraceRequired(t *testing.T) {
config := validConfig(TraceTypeAlphabet)
config.AlphabetTrace = ""
require.ErrorIs(t, config.Check(), ErrMissingAlphabetTrace)
}
func TestAlphabetTraceNotRequiredForOutputAlphabet(t *testing.T) {
config := validConfig(TraceTypeOutputAlphabet)
config.AlphabetTrace = ""
require.NoError(t, config.Check())
}
func TestCannonBinRequired(t *testing.T) { func TestCannonBinRequired(t *testing.T) {
config := validConfig(TraceTypeCannon) config := validConfig(TraceTypeCannon)
config.CannonBin = "" config.CannonBin = ""
...@@ -134,14 +116,14 @@ func TestHttpPollInterval(t *testing.T) { ...@@ -134,14 +116,14 @@ func TestHttpPollInterval(t *testing.T) {
}) })
} }
func TestRollupRpcRequired_OutputCannon(t *testing.T) { func TestRollupRpcRequired_Cannon(t *testing.T) {
config := validConfig(TraceTypeOutputCannon) config := validConfig(TraceTypeCannon)
config.RollupRpc = "" config.RollupRpc = ""
require.ErrorIs(t, config.Check(), ErrMissingRollupRpc) require.ErrorIs(t, config.Check(), ErrMissingRollupRpc)
} }
func TestRollupRpcRequired_OutputAlphabet(t *testing.T) { func TestRollupRpcRequired_Alphabet(t *testing.T) {
config := validConfig(TraceTypeOutputAlphabet) config := validConfig(TraceTypeAlphabet)
config.RollupRpc = "" config.RollupRpc = ""
require.ErrorIs(t, config.Check(), ErrMissingRollupRpc) require.ErrorIs(t, config.Check(), ErrMissingRollupRpc)
} }
...@@ -208,10 +190,9 @@ func TestNetworkMustBeValid(t *testing.T) { ...@@ -208,10 +190,9 @@ 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, TraceTypeOutputCannon} cfg.TraceTypes = []TraceType{TraceTypeCannon, TraceTypeAlphabet}
// 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
require.NoError(t, cfg.Check()) require.NoError(t, cfg.Check())
// Require cannon specific args // Require cannon specific args
...@@ -219,11 +200,6 @@ func TestRequireConfigForMultipleTraceTypes(t *testing.T) { ...@@ -219,11 +200,6 @@ func TestRequireConfigForMultipleTraceTypes(t *testing.T) {
require.ErrorIs(t, cfg.Check(), ErrMissingCannonL2) require.ErrorIs(t, cfg.Check(), ErrMissingCannonL2)
cfg.CannonL2 = validCannonL2 cfg.CannonL2 = validCannonL2
// Require alphabet specific args
cfg.AlphabetTrace = ""
require.ErrorIs(t, cfg.Check(), ErrMissingAlphabetTrace)
cfg.AlphabetTrace = validAlphabetTrace
// Require output cannon specific args // Require output cannon specific args
cfg.RollupRpc = "" cfg.RollupRpc = ""
require.ErrorIs(t, cfg.Check(), ErrMissingRollupRpc) require.ErrorIs(t, cfg.Check(), ErrMissingRollupRpc)
......
...@@ -73,11 +73,6 @@ var ( ...@@ -73,11 +73,6 @@ var (
Usage: "HTTP provider URL for the rollup node", Usage: "HTTP provider URL for the rollup node",
EnvVars: prefixEnvVars("ROLLUP_RPC"), EnvVars: prefixEnvVars("ROLLUP_RPC"),
} }
AlphabetFlag = &cli.StringFlag{
Name: "alphabet",
Usage: "Correct Alphabet Trace (alphabet trace type only)",
EnvVars: prefixEnvVars("ALPHABET"),
}
CannonNetworkFlag = &cli.StringFlag{ CannonNetworkFlag = &cli.StringFlag{
Name: "cannon-network", Name: "cannon-network",
Usage: fmt.Sprintf( Usage: fmt.Sprintf(
...@@ -149,7 +144,6 @@ var optionalFlags = []cli.Flag{ ...@@ -149,7 +144,6 @@ var optionalFlags = []cli.Flag{
MaxConcurrencyFlag, MaxConcurrencyFlag,
HTTPPollInterval, HTTPPollInterval,
RollupRpcFlag, RollupRpcFlag,
AlphabetFlag,
GameAllowlistFlag, GameAllowlistFlag,
CannonNetworkFlag, CannonNetworkFlag,
CannonRollupConfigFlag, CannonRollupConfigFlag,
...@@ -213,18 +207,10 @@ func CheckRequired(ctx *cli.Context, traceTypes []config.TraceType) error { ...@@ -213,18 +207,10 @@ func CheckRequired(ctx *cli.Context, traceTypes []config.TraceType) error {
if err := CheckCannonFlags(ctx); err != nil { if err := CheckCannonFlags(ctx); err != nil {
return err return err
} }
case config.TraceTypeAlphabet:
if !ctx.IsSet(AlphabetFlag.Name) {
return fmt.Errorf("flag %s is required", "alphabet")
}
case config.TraceTypeOutputCannon:
if err := CheckCannonFlags(ctx); err != nil {
return err
}
if !ctx.IsSet(RollupRpcFlag.Name) { if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name) return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
} }
case config.TraceTypeOutputAlphabet: case config.TraceTypeAlphabet:
if !ctx.IsSet(RollupRpcFlag.Name) { if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name) return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
} }
...@@ -291,7 +277,6 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) { ...@@ -291,7 +277,6 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
MaxConcurrency: maxConcurrency, MaxConcurrency: maxConcurrency,
PollInterval: ctx.Duration(HTTPPollInterval.Name), PollInterval: ctx.Duration(HTTPPollInterval.Name),
RollupRpc: ctx.String(RollupRpcFlag.Name), RollupRpc: ctx.String(RollupRpcFlag.Name),
AlphabetTrace: ctx.String(AlphabetFlag.Name),
CannonNetwork: ctx.String(CannonNetworkFlag.Name), CannonNetwork: ctx.String(CannonNetworkFlag.Name),
CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name), CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name),
CannonL2GenesisPath: ctx.String(CannonL2GenesisFlag.Name), CannonL2GenesisPath: ctx.String(CannonL2GenesisFlag.Name),
......
...@@ -13,12 +13,9 @@ import ( ...@@ -13,12 +13,9 @@ import (
) )
const ( const (
methodGameDurationV0 = "GAME_DURATION" methodGameDuration = "gameDuration"
methodMaxGameDepthV0 = "MAX_GAME_DEPTH" methodMaxGameDepth = "maxGameDepth"
methodAbsolutePrestateV0 = "ABSOLUTE_PRESTATE" methodAbsolutePrestate = "absolutePrestate"
methodGameDurationV1 = "gameDuration"
methodMaxGameDepthV1 = "maxGameDepth"
methodAbsolutePrestateV1 = "absolutePrestate"
methodStatus = "status" methodStatus = "status"
methodClaimCount = "claimDataLen" methodClaimCount = "claimDataLen"
methodClaim = "claimData" methodClaim = "claimData"
...@@ -29,26 +26,12 @@ const ( ...@@ -29,26 +26,12 @@ const (
methodDefend = "defend" methodDefend = "defend"
methodStep = "step" methodStep = "step"
methodAddLocalData = "addLocalData" methodAddLocalData = "addLocalData"
methodVMV0 = "VM" methodVM = "vm"
methodVMV1 = "vm"
) )
type disputeGameContract struct { type disputeGameContract struct {
multiCaller *batching.MultiCaller multiCaller *batching.MultiCaller
contract *batching.BoundContract contract *batching.BoundContract
// The version byte signifies the version of the dispute game contract due to mismatching function selectors.
// 0 = `FaultDisputeGame`
// 1 = `OutputBisectionGame`
version uint8
}
// contractProposal matches the structure for output root proposals used by the contracts.
// It must exactly match the contract structure. The exposed API uses Proposal to decouple the contract
// and challenger representations of the proposal data.
type contractProposal struct {
Index *big.Int
L2BlockNumber *big.Int
OutputRoot common.Hash
} }
type Proposal struct { type Proposal struct {
...@@ -56,21 +39,7 @@ type Proposal struct { ...@@ -56,21 +39,7 @@ type Proposal struct {
OutputRoot common.Hash OutputRoot common.Hash
} }
func asProposal(p contractProposal) Proposal {
return Proposal{
L2BlockNumber: p.L2BlockNumber,
OutputRoot: p.OutputRoot,
}
}
func (f *disputeGameContract) GetGameDuration(ctx context.Context) (uint64, error) { func (f *disputeGameContract) GetGameDuration(ctx context.Context) (uint64, error) {
var methodGameDuration string
if f.version == 1 {
methodGameDuration = methodGameDurationV1
} else {
methodGameDuration = methodGameDurationV0
}
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodGameDuration)) result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodGameDuration))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to fetch game duration: %w", err) return 0, fmt.Errorf("failed to fetch game duration: %w", err)
...@@ -79,13 +48,6 @@ func (f *disputeGameContract) GetGameDuration(ctx context.Context) (uint64, erro ...@@ -79,13 +48,6 @@ func (f *disputeGameContract) GetGameDuration(ctx context.Context) (uint64, erro
} }
func (f *disputeGameContract) GetMaxGameDepth(ctx context.Context) (uint64, error) { func (f *disputeGameContract) GetMaxGameDepth(ctx context.Context) (uint64, error) {
var methodMaxGameDepth string
if f.version == 1 {
methodMaxGameDepth = methodMaxGameDepthV1
} else {
methodMaxGameDepth = methodMaxGameDepthV0
}
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodMaxGameDepth)) result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodMaxGameDepth))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to fetch max game depth: %w", err) return 0, fmt.Errorf("failed to fetch max game depth: %w", err)
...@@ -94,13 +56,6 @@ func (f *disputeGameContract) GetMaxGameDepth(ctx context.Context) (uint64, erro ...@@ -94,13 +56,6 @@ func (f *disputeGameContract) GetMaxGameDepth(ctx context.Context) (uint64, erro
} }
func (f *disputeGameContract) GetAbsolutePrestateHash(ctx context.Context) (common.Hash, error) { func (f *disputeGameContract) GetAbsolutePrestateHash(ctx context.Context) (common.Hash, error) {
var methodAbsolutePrestate string
if f.version == 1 {
methodAbsolutePrestate = methodAbsolutePrestateV1
} else {
methodAbsolutePrestate = methodAbsolutePrestateV0
}
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodAbsolutePrestate)) result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodAbsolutePrestate))
if err != nil { if err != nil {
return common.Hash{}, fmt.Errorf("failed to fetch absolute prestate hash: %w", err) return common.Hash{}, fmt.Errorf("failed to fetch absolute prestate hash: %w", err)
...@@ -164,13 +119,6 @@ func (f *disputeGameContract) GetAllClaims(ctx context.Context) ([]types.Claim, ...@@ -164,13 +119,6 @@ func (f *disputeGameContract) GetAllClaims(ctx context.Context) ([]types.Claim,
} }
func (f *disputeGameContract) vm(ctx context.Context) (*VMContract, error) { func (f *disputeGameContract) vm(ctx context.Context) (*VMContract, error) {
var methodVM string
if f.version == 1 {
methodVM = methodVMV1
} else {
methodVM = methodVMV0
}
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodVM)) result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodVM))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch VM addr: %w", err) return nil, fmt.Errorf("failed to fetch VM addr: %w", err)
......
...@@ -49,7 +49,7 @@ func runCommonDisputeGameTests(t *testing.T, setup disputeGameSetupFunc) { ...@@ -49,7 +49,7 @@ func runCommonDisputeGameTests(t *testing.T, setup disputeGameSetupFunc) {
func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
tests := []struct { tests := []struct {
methodAlias string methodAlias string
method func(game *disputeGameContract) string method string
args []interface{} args []interface{}
result interface{} result interface{}
expected interface{} // Defaults to expecting the same as result expected interface{} // Defaults to expecting the same as result
...@@ -57,7 +57,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -57,7 +57,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}{ }{
{ {
methodAlias: "status", methodAlias: "status",
method: func(game *disputeGameContract) string { return methodStatus }, method: methodStatus,
result: types.GameStatusChallengerWon, result: types.GameStatusChallengerWon,
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
return game.GetStatus(context.Background()) return game.GetStatus(context.Background())
...@@ -65,13 +65,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -65,13 +65,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}, },
{ {
methodAlias: "gameDuration", methodAlias: "gameDuration",
method: func(game *disputeGameContract) string { method: methodGameDuration,
if game.version == 1 {
return methodGameDurationV1
} else {
return methodGameDurationV0
}
},
result: uint64(5566), result: uint64(5566),
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
return game.GetGameDuration(context.Background()) return game.GetGameDuration(context.Background())
...@@ -79,13 +73,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -79,13 +73,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}, },
{ {
methodAlias: "maxGameDepth", methodAlias: "maxGameDepth",
method: func(game *disputeGameContract) string { method: methodMaxGameDepth,
if game.version == 1 {
return methodMaxGameDepthV1
} else {
return methodMaxGameDepthV0
}
},
result: big.NewInt(128), result: big.NewInt(128),
expected: uint64(128), expected: uint64(128),
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
...@@ -94,13 +82,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -94,13 +82,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}, },
{ {
methodAlias: "absolutePrestate", methodAlias: "absolutePrestate",
method: func(game *disputeGameContract) string { method: methodAbsolutePrestate,
if game.version == 1 {
return methodAbsolutePrestateV1
} else {
return methodAbsolutePrestateV0
}
},
result: common.Hash{0xab}, result: common.Hash{0xab},
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
return game.GetAbsolutePrestateHash(context.Background()) return game.GetAbsolutePrestateHash(context.Background())
...@@ -108,7 +90,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -108,7 +90,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}, },
{ {
methodAlias: "claimCount", methodAlias: "claimCount",
method: func(game *disputeGameContract) string { return methodClaimCount }, method: methodClaimCount,
result: big.NewInt(9876), result: big.NewInt(9876),
expected: uint64(9876), expected: uint64(9876),
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
...@@ -117,7 +99,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -117,7 +99,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}, },
{ {
methodAlias: "l1Head", methodAlias: "l1Head",
method: func(game *disputeGameContract) string { return methodL1Head }, method: methodL1Head,
result: common.Hash{0xdd, 0xbb}, result: common.Hash{0xdd, 0xbb},
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
return game.GetL1Head(context.Background()) return game.GetL1Head(context.Background())
...@@ -125,7 +107,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -125,7 +107,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
}, },
{ {
methodAlias: "resolve", methodAlias: "resolve",
method: func(game *disputeGameContract) string { return methodResolve }, method: methodResolve,
result: types.GameStatusInProgress, result: types.GameStatusInProgress,
call: func(game *disputeGameContract) (any, error) { call: func(game *disputeGameContract) (any, error) {
return game.CallResolve(context.Background()) return game.CallResolve(context.Background())
...@@ -136,7 +118,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) { ...@@ -136,7 +118,7 @@ func runSimpleGettersTest(t *testing.T, setup disputeGameSetupFunc) {
test := test test := test
t.Run(test.methodAlias, func(t *testing.T) { t.Run(test.methodAlias, func(t *testing.T) {
stubRpc, game := setup(t) stubRpc, game := setup(t)
stubRpc.SetResponse(fdgAddr, test.method(game), batching.BlockLatest, nil, []interface{}{test.result}) stubRpc.SetResponse(fdgAddr, test.method, batching.BlockLatest, nil, []interface{}{test.result})
status, err := test.call(game) status, err := test.call(game)
require.NoError(t, err) require.NoError(t, err)
expected := test.expected expected := test.expected
......
...@@ -12,8 +12,11 @@ import ( ...@@ -12,8 +12,11 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
const ( var (
methodProposals = "proposals" methodGenesisBlockNumber = "genesisBlockNumber"
methodGenesisOutputRoot = "genesisOutputRoot"
methodSplitDepth = "splitDepth"
methodL2BlockNumber = "l2BlockNumber"
) )
type FaultDisputeGameContract struct { type FaultDisputeGameContract struct {
...@@ -21,7 +24,7 @@ type FaultDisputeGameContract struct { ...@@ -21,7 +24,7 @@ type FaultDisputeGameContract struct {
} }
func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCaller) (*FaultDisputeGameContract, error) { func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCaller) (*FaultDisputeGameContract, error) {
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi() contractAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load fault dispute game ABI: %w", err) return nil, fmt.Errorf("failed to load fault dispute game ABI: %w", err)
} }
...@@ -29,37 +32,58 @@ func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCall ...@@ -29,37 +32,58 @@ func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCall
return &FaultDisputeGameContract{ return &FaultDisputeGameContract{
disputeGameContract: disputeGameContract{ disputeGameContract: disputeGameContract{
multiCaller: caller, multiCaller: caller,
contract: batching.NewBoundContract(fdgAbi, addr), contract: batching.NewBoundContract(contractAbi, addr),
version: 0,
}, },
}, nil }, nil
} }
// GetProposals returns the agreed and disputed proposals // GetBlockRange returns the block numbers of the absolute pre-state block (typically genesis or the bedrock activation block)
func (f *FaultDisputeGameContract) GetProposals(ctx context.Context) (Proposal, Proposal, error) { // and the post-state block (that the proposed output root is for).
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodProposals)) func (c *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateBlock uint64, poststateBlock uint64, retErr error) {
results, err := c.multiCaller.Call(ctx, batching.BlockLatest,
c.contract.Call(methodGenesisBlockNumber),
c.contract.Call(methodL2BlockNumber))
if err != nil { if err != nil {
return Proposal{}, Proposal{}, fmt.Errorf("failed to fetch proposals: %w", err) retErr = fmt.Errorf("failed to retrieve game block range: %w", err)
return
} }
if len(results) != 2 {
retErr = fmt.Errorf("expected 2 results but got %v", len(results))
return
}
prestateBlock = results[0].GetBigInt(0).Uint64()
poststateBlock = results[1].GetBigInt(0).Uint64()
return
}
func (c *FaultDisputeGameContract) GetGenesisOutputRoot(ctx context.Context) (common.Hash, error) {
genesisOutputRoot, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodGenesisOutputRoot))
if err != nil {
return common.Hash{}, fmt.Errorf("failed to retrieve genesis output root: %w", err)
}
return genesisOutputRoot.GetHash(0), nil
}
var agreed, disputed contractProposal func (c *FaultDisputeGameContract) GetSplitDepth(ctx context.Context) (uint64, error) {
result.GetStruct(0, &agreed) splitDepth, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodSplitDepth))
result.GetStruct(1, &disputed) if err != nil {
return asProposal(agreed), asProposal(disputed), nil return 0, fmt.Errorf("failed to retrieve split depth: %w", err)
}
return splitDepth.GetBigInt(0).Uint64(), nil
} }
func (f *FaultDisputeGameContract) UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContract) UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
if data.IsLocal { if data.IsLocal {
return f.addLocalDataTx(data) return f.addLocalDataTx(claimIdx, data)
} }
return f.addGlobalDataTx(ctx, data) return f.addGlobalDataTx(ctx, data)
} }
func (f *FaultDisputeGameContract) addLocalDataTx(data *types.PreimageOracleData) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContract) addLocalDataTx(claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
call := f.contract.Call( call := f.contract.Call(
methodAddLocalData, methodAddLocalData,
data.GetIdent(), data.GetIdent(),
types.NoLocalContext, new(big.Int).SetUint64(claimIdx),
new(big.Int).SetUint64(uint64(data.OracleOffset)), new(big.Int).SetUint64(uint64(data.OracleOffset)),
) )
return call.ToTxCandidate() return call.ToTxCandidate()
......
...@@ -20,39 +20,34 @@ func TestFaultDisputeGameContract_CommonTests(t *testing.T) { ...@@ -20,39 +20,34 @@ func TestFaultDisputeGameContract_CommonTests(t *testing.T) {
}) })
} }
func TestGetProposals(t *testing.T) { func TestGetBlockRange(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) stubRpc, contract := setupFaultDisputeGameTest(t)
agreedIndex := big.NewInt(5) expectedStart := uint64(65)
agreedBlockNum := big.NewInt(6) expectedEnd := uint64(102)
agreedRoot := common.Hash{0xaa} stubRpc.SetResponse(fdgAddr, methodGenesisBlockNumber, batching.BlockLatest, nil, []interface{}{new(big.Int).SetUint64(expectedStart)})
disputedIndex := big.NewInt(7) stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, batching.BlockLatest, nil, []interface{}{new(big.Int).SetUint64(expectedEnd)})
disputedBlockNum := big.NewInt(8) start, end, err := contract.GetBlockRange(context.Background())
disputedRoot := common.Hash{0xdd} require.NoError(t, err)
agreed := contractProposal{ require.Equal(t, expectedStart, start)
Index: agreedIndex, require.Equal(t, expectedEnd, end)
L2BlockNumber: agreedBlockNum, }
OutputRoot: agreedRoot,
} func TestGetSplitDepth(t *testing.T) {
disputed := contractProposal{ stubRpc, contract := setupFaultDisputeGameTest(t)
Index: disputedIndex, expectedSplitDepth := uint64(15)
L2BlockNumber: disputedBlockNum, stubRpc.SetResponse(fdgAddr, methodSplitDepth, batching.BlockLatest, nil, []interface{}{new(big.Int).SetUint64(expectedSplitDepth)})
OutputRoot: disputedRoot, splitDepth, err := contract.GetSplitDepth(context.Background())
} require.NoError(t, err)
expectedAgreed := Proposal{ require.Equal(t, expectedSplitDepth, splitDepth)
L2BlockNumber: agreed.L2BlockNumber, }
OutputRoot: agreed.OutputRoot,
} func TestGetGenesisOutputRoot(t *testing.T) {
expectedDisputed := Proposal{ stubRpc, contract := setupFaultDisputeGameTest(t)
L2BlockNumber: disputed.L2BlockNumber, expectedOutputRoot := common.HexToHash("0x1234")
OutputRoot: disputed.OutputRoot, stubRpc.SetResponse(fdgAddr, methodGenesisOutputRoot, batching.BlockLatest, nil, []interface{}{expectedOutputRoot})
} genesisOutputRoot, err := contract.GetGenesisOutputRoot(context.Background())
stubRpc.SetResponse(fdgAddr, methodProposals, batching.BlockLatest, []interface{}{}, []interface{}{
agreed, disputed,
})
actualAgreed, actualDisputed, err := game.GetProposals(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expectedAgreed, actualAgreed) require.Equal(t, expectedOutputRoot, genesisOutputRoot)
require.Equal(t, expectedDisputed, actualDisputed)
} }
func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) { func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
...@@ -67,7 +62,7 @@ func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) { ...@@ -67,7 +62,7 @@ func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
claimIdx := uint64(6) claimIdx := uint64(6)
stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{ stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{
data.GetIdent(), data.GetIdent(),
faultTypes.NoLocalContext, new(big.Int).SetUint64(claimIdx),
new(big.Int).SetUint64(uint64(data.OracleOffset)), new(big.Int).SetUint64(uint64(data.OracleOffset)),
}, nil) }, nil)
tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data) tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data)
...@@ -84,7 +79,7 @@ func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) { ...@@ -84,7 +79,7 @@ func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
OracleOffset: 16, OracleOffset: 16,
} }
claimIdx := uint64(6) claimIdx := uint64(6)
stubRpc.SetResponse(fdgAddr, methodVMV0, batching.BlockLatest, nil, []interface{}{vmAddr}) stubRpc.SetResponse(fdgAddr, methodVM, batching.BlockLatest, nil, []interface{}{vmAddr})
stubRpc.SetResponse(vmAddr, methodOracle, batching.BlockLatest, nil, []interface{}{oracleAddr}) stubRpc.SetResponse(vmAddr, methodOracle, batching.BlockLatest, nil, []interface{}{oracleAddr})
stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, batching.BlockLatest, []interface{}{ stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, batching.BlockLatest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)), new(big.Int).SetUint64(uint64(data.OracleOffset)),
......
package contracts
import (
"context"
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
)
var (
methodGenesisBlockNumber = "genesisBlockNumber"
methodGenesisOutputRoot = "genesisOutputRoot"
methodSplitDepth = "splitDepth"
methodL2BlockNumber = "l2BlockNumber"
)
type OutputBisectionGameContract struct {
disputeGameContract
}
func NewOutputBisectionGameContract(addr common.Address, caller *batching.MultiCaller) (*OutputBisectionGameContract, error) {
contractAbi, err := bindings.OutputBisectionGameMetaData.GetAbi()
if err != nil {
return nil, fmt.Errorf("failed to load output bisection game ABI: %w", err)
}
return &OutputBisectionGameContract{
disputeGameContract: disputeGameContract{
multiCaller: caller,
contract: batching.NewBoundContract(contractAbi, addr),
version: 1,
},
}, nil
}
// GetBlockRange returns the block numbers of the absolute pre-state block (typically genesis or the bedrock activation block)
// and the post-state block (that the proposed output root is for).
func (c *OutputBisectionGameContract) GetBlockRange(ctx context.Context) (prestateBlock uint64, poststateBlock uint64, retErr error) {
results, err := c.multiCaller.Call(ctx, batching.BlockLatest,
c.contract.Call(methodGenesisBlockNumber),
c.contract.Call(methodL2BlockNumber))
if err != nil {
retErr = fmt.Errorf("failed to retrieve game block range: %w", err)
return
}
if len(results) != 2 {
retErr = fmt.Errorf("expected 2 results but got %v", len(results))
return
}
prestateBlock = results[0].GetBigInt(0).Uint64()
poststateBlock = results[1].GetBigInt(0).Uint64()
return
}
func (c *OutputBisectionGameContract) GetGenesisOutputRoot(ctx context.Context) (common.Hash, error) {
genesisOutputRoot, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodGenesisOutputRoot))
if err != nil {
return common.Hash{}, fmt.Errorf("failed to retrieve genesis output root: %w", err)
}
return genesisOutputRoot.GetHash(0), nil
}
func (c *OutputBisectionGameContract) GetSplitDepth(ctx context.Context) (uint64, error) {
splitDepth, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodSplitDepth))
if err != nil {
return 0, fmt.Errorf("failed to retrieve split depth: %w", err)
}
return splitDepth.GetBigInt(0).Uint64(), nil
}
func (f *OutputBisectionGameContract) UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
if data.IsLocal {
return f.addLocalDataTx(claimIdx, data)
}
return f.addGlobalDataTx(ctx, data)
}
func (f *OutputBisectionGameContract) addLocalDataTx(claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
call := f.contract.Call(
methodAddLocalData,
data.GetIdent(),
new(big.Int).SetUint64(claimIdx),
new(big.Int).SetUint64(uint64(data.OracleOffset)),
)
return call.ToTxCandidate()
}
func (f *OutputBisectionGameContract) addGlobalDataTx(ctx context.Context, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
vm, err := f.vm(ctx)
if err != nil {
return txmgr.TxCandidate{}, err
}
oracle, err := vm.Oracle(ctx)
if err != nil {
return txmgr.TxCandidate{}, err
}
return oracle.AddGlobalDataTx(data)
}
package contracts
import (
"context"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestOutputBisectionGameContract_CommonTests(t *testing.T) {
runCommonDisputeGameTests(t, func(t *testing.T) (*batchingTest.AbiBasedRpc, *disputeGameContract) {
stubRpc, contract := setupOutputBisectionGameTest(t)
return stubRpc, &contract.disputeGameContract
})
}
func TestGetBlockRange(t *testing.T) {
stubRpc, contract := setupOutputBisectionGameTest(t)
expectedStart := uint64(65)
expectedEnd := uint64(102)
stubRpc.SetResponse(fdgAddr, methodGenesisBlockNumber, batching.BlockLatest, nil, []interface{}{new(big.Int).SetUint64(expectedStart)})
stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, batching.BlockLatest, nil, []interface{}{new(big.Int).SetUint64(expectedEnd)})
start, end, err := contract.GetBlockRange(context.Background())
require.NoError(t, err)
require.Equal(t, expectedStart, start)
require.Equal(t, expectedEnd, end)
}
func TestGetSplitDepth(t *testing.T) {
stubRpc, contract := setupOutputBisectionGameTest(t)
expectedSplitDepth := uint64(15)
stubRpc.SetResponse(fdgAddr, methodSplitDepth, batching.BlockLatest, nil, []interface{}{new(big.Int).SetUint64(expectedSplitDepth)})
splitDepth, err := contract.GetSplitDepth(context.Background())
require.NoError(t, err)
require.Equal(t, expectedSplitDepth, splitDepth)
}
func TestGetGenesisOutputRoot(t *testing.T) {
stubRpc, contract := setupOutputBisectionGameTest(t)
expectedOutputRoot := common.HexToHash("0x1234")
stubRpc.SetResponse(fdgAddr, methodGenesisOutputRoot, batching.BlockLatest, nil, []interface{}{expectedOutputRoot})
genesisOutputRoot, err := contract.GetGenesisOutputRoot(context.Background())
require.NoError(t, err)
require.Equal(t, expectedOutputRoot, genesisOutputRoot)
}
func TestOutputBisectionGame_UpdateOracleTx(t *testing.T) {
t.Run("Local", func(t *testing.T) {
stubRpc, game := setupOutputBisectionGameTest(t)
data := &faultTypes.PreimageOracleData{
IsLocal: true,
OracleKey: common.Hash{0xbc}.Bytes(),
OracleData: []byte{1, 2, 3, 4, 5, 6, 7},
OracleOffset: 16,
}
claimIdx := uint64(6)
stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{
data.GetIdent(),
new(big.Int).SetUint64(claimIdx),
new(big.Int).SetUint64(uint64(data.OracleOffset)),
}, nil)
tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Global", func(t *testing.T) {
stubRpc, game := setupOutputBisectionGameTest(t)
data := &faultTypes.PreimageOracleData{
IsLocal: false,
OracleKey: common.Hash{0xbc}.Bytes(),
OracleData: []byte{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15},
OracleOffset: 16,
}
claimIdx := uint64(6)
stubRpc.SetResponse(fdgAddr, methodVMV1, batching.BlockLatest, nil, []interface{}{vmAddr})
stubRpc.SetResponse(vmAddr, methodOracle, batching.BlockLatest, nil, []interface{}{oracleAddr})
stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, batching.BlockLatest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPreimageWithoutSize(),
}, nil)
tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
func setupOutputBisectionGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *OutputBisectionGameContract) {
fdgAbi, err := bindings.OutputBisectionGameMetaData.GetAbi()
require.NoError(t, err)
vmAbi, err := bindings.MIPSMetaData.GetAbi()
require.NoError(t, err)
oracleAbi, err := bindings.PreimageOracleMetaData.GetAbi()
require.NoError(t, err)
stubRpc := batchingTest.NewAbiBasedRpc(t, fdgAddr, fdgAbi)
stubRpc.AddContract(vmAddr, vmAbi)
stubRpc.AddContract(oracleAddr, oracleAbi)
caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize)
game, err := NewOutputBisectionGameContract(fdgAddr, caller)
require.NoError(t, err)
return stubRpc, game
}
...@@ -6,8 +6,6 @@ import ( ...@@ -6,8 +6,6 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
...@@ -22,8 +20,6 @@ import ( ...@@ -22,8 +20,6 @@ import (
var ( var (
cannonGameType = uint8(0) cannonGameType = uint8(0)
outputCannonGameType = uint8(1)
outputAlphabetGameType = uint8(254)
alphabetGameType = uint8(255) alphabetGameType = uint8(255)
) )
...@@ -45,7 +41,7 @@ func RegisterGameTypes( ...@@ -45,7 +41,7 @@ func RegisterGameTypes(
) (CloseFunc, error) { ) (CloseFunc, error) {
var closer CloseFunc var closer CloseFunc
var l2Client *ethclient.Client var l2Client *ethclient.Client
if cfg.TraceTypeEnabled(config.TraceTypeCannon) || cfg.TraceTypeEnabled(config.TraceTypeOutputCannon) { if cfg.TraceTypeEnabled(config.TraceTypeCannon) {
l2, err := ethclient.DialContext(ctx, cfg.CannonL2) l2, err := ethclient.DialContext(ctx, cfg.CannonL2)
if err != nil { if err != nil {
return nil, fmt.Errorf("dial l2 client %v: %w", cfg.CannonL2, err) return nil, fmt.Errorf("dial l2 client %v: %w", cfg.CannonL2, err)
...@@ -53,31 +49,26 @@ func RegisterGameTypes( ...@@ -53,31 +49,26 @@ func RegisterGameTypes(
l2Client = l2 l2Client = l2
closer = l2Client.Close closer = l2Client.Close
} }
if cfg.TraceTypeEnabled(config.TraceTypeOutputCannon) {
registerOutputCannon(registry, ctx, logger, m, cfg, rollupClient, txMgr, caller, l2Client)
}
if cfg.TraceTypeEnabled(config.TraceTypeOutputAlphabet) {
registerOutputAlphabet(registry, ctx, logger, m, rollupClient, txMgr, caller)
}
if cfg.TraceTypeEnabled(config.TraceTypeCannon) { if cfg.TraceTypeEnabled(config.TraceTypeCannon) {
registerCannon(registry, ctx, logger, m, cfg, txMgr, caller, l2Client) registerCannon(registry, ctx, logger, m, cfg, rollupClient, txMgr, caller, l2Client)
} }
if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) { if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) {
registerAlphabet(registry, ctx, logger, m, cfg.AlphabetTrace, txMgr, caller) registerAlphabet(registry, ctx, logger, m, rollupClient, txMgr, caller)
} }
return closer, nil return closer, nil
} }
func registerOutputAlphabet( func registerAlphabet(
registry Registry, registry Registry,
ctx context.Context, ctx context.Context,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
rollupClient outputs.OutputRollupClient, rollupClient outputs.OutputRollupClient,
txMgr txmgr.TxManager, txMgr txmgr.TxManager,
caller *batching.MultiCaller) { caller *batching.MultiCaller,
) {
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract, err := contracts.NewOutputBisectionGameContract(game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -101,10 +92,10 @@ func registerOutputAlphabet( ...@@ -101,10 +92,10 @@ func registerOutputAlphabet(
genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider) genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider)
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, contract, []Validator{prestateValidator, genesisValidator}, creator) return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, contract, []Validator{prestateValidator, genesisValidator}, creator)
} }
registry.RegisterGameType(outputAlphabetGameType, playerCreator) registry.RegisterGameType(alphabetGameType, playerCreator)
} }
func registerOutputCannon( func registerCannon(
registry Registry, registry Registry,
ctx context.Context, ctx context.Context,
logger log.Logger, logger log.Logger,
...@@ -113,9 +104,10 @@ func registerOutputCannon( ...@@ -113,9 +104,10 @@ func registerOutputCannon(
rollupClient outputs.OutputRollupClient, rollupClient outputs.OutputRollupClient,
txMgr txmgr.TxManager, txMgr txmgr.TxManager,
caller *batching.MultiCaller, caller *batching.MultiCaller,
l2Client cannon.L2HeaderSource) { l2Client cannon.L2HeaderSource,
) {
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract, err := contracts.NewOutputBisectionGameContract(game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -139,58 +131,5 @@ func registerOutputCannon( ...@@ -139,58 +131,5 @@ func registerOutputCannon(
genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider) genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider)
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, contract, []Validator{prestateValidator, genesisValidator}, creator) return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, contract, []Validator{prestateValidator, genesisValidator}, creator)
} }
registry.RegisterGameType(outputCannonGameType, playerCreator)
}
func registerCannon(
registry Registry,
ctx context.Context,
logger log.Logger,
m metrics.Metricer,
cfg *config.Config,
txMgr txmgr.TxManager,
caller *batching.MultiCaller,
l2Client cannon.L2HeaderSource) {
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller)
if err != nil {
return nil, err
}
prestateProvider := cannon.NewPrestateProvider(cfg.CannonAbsolutePreState)
creator := func(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (faultTypes.TraceAccessor, error) {
localInputs, err := cannon.FetchLocalInputs(ctx, contract, l2Client)
if err != nil {
return nil, fmt.Errorf("failed to fetch cannon local inputs: %w", err)
}
provider := cannon.NewTraceProvider(logger, m, cfg, faultTypes.NoLocalContext, localInputs, dir, gameDepth)
return trace.NewSimpleTraceAccessor(provider), nil
}
validator := NewPrestateValidator(contract.GetAbsolutePrestateHash, prestateProvider)
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, contract, []Validator{validator}, creator)
}
registry.RegisterGameType(cannonGameType, playerCreator) registry.RegisterGameType(cannonGameType, playerCreator)
} }
func registerAlphabet(
registry Registry,
ctx context.Context,
logger log.Logger,
m metrics.Metricer,
alphabetTrace string,
txMgr txmgr.TxManager,
caller *batching.MultiCaller) {
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller)
if err != nil {
return nil, err
}
prestateProvider := &alphabet.AlphabetPrestateProvider{}
creator := func(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (faultTypes.TraceAccessor, error) {
traceProvider := alphabet.NewTraceProvider(alphabetTrace, gameDepth)
return trace.NewSimpleTraceAccessor(traceProvider), nil
}
validator := NewPrestateValidator(contract.GetAbsolutePrestateHash, prestateProvider)
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, contract, []Validator{validator}, creator)
}
registry.RegisterGameType(alphabetGameType, playerCreator)
}
...@@ -54,31 +54,12 @@ func WithPrivKey(key *ecdsa.PrivateKey) Option { ...@@ -54,31 +54,12 @@ func WithPrivKey(key *ecdsa.PrivateKey) Option {
} }
} }
func WithAlphabet(alphabet string) Option {
return func(c *config.Config) {
c.TraceTypes = append(c.TraceTypes, config.TraceTypeAlphabet)
c.AlphabetTrace = alphabet
}
}
func WithPollInterval(pollInterval time.Duration) Option { func WithPollInterval(pollInterval time.Duration) Option {
return func(c *config.Config) { return func(c *config.Config) {
c.PollInterval = pollInterval c.PollInterval = pollInterval
} }
} }
func WithCannon(
t *testing.T,
rollupCfg *rollup.Config,
l2Genesis *core.Genesis,
l2Endpoint string,
) Option {
return func(c *config.Config) {
c.TraceTypes = append(c.TraceTypes, config.TraceTypeCannon)
applyCannonConfig(c, t, rollupCfg, l2Genesis, l2Endpoint)
}
}
func applyCannonConfig( func applyCannonConfig(
c *config.Config, c *config.Config,
t *testing.T, t *testing.T,
...@@ -96,34 +77,34 @@ func applyCannonConfig( ...@@ -96,34 +77,34 @@ func applyCannonConfig(
genesisBytes, err := json.Marshal(l2Genesis) genesisBytes, err := json.Marshal(l2Genesis)
require.NoError(err, "marshall l2 genesis config") require.NoError(err, "marshall l2 genesis config")
genesisFile := filepath.Join(c.Datadir, "l2-genesis.json") genesisFile := filepath.Join(c.Datadir, "l2-genesis.json")
require.NoError(os.WriteFile(genesisFile, genesisBytes, 0644)) require.NoError(os.WriteFile(genesisFile, genesisBytes, 0o644))
c.CannonL2GenesisPath = genesisFile c.CannonL2GenesisPath = genesisFile
rollupBytes, err := json.Marshal(rollupCfg) rollupBytes, err := json.Marshal(rollupCfg)
require.NoError(err, "marshall rollup config") require.NoError(err, "marshall rollup config")
rollupFile := filepath.Join(c.Datadir, "rollup.json") rollupFile := filepath.Join(c.Datadir, "rollup.json")
require.NoError(os.WriteFile(rollupFile, rollupBytes, 0644)) require.NoError(os.WriteFile(rollupFile, rollupBytes, 0o644))
c.CannonRollupConfigPath = rollupFile c.CannonRollupConfigPath = rollupFile
} }
func WithOutputCannon( func WithCannon(
t *testing.T, t *testing.T,
rollupCfg *rollup.Config, rollupCfg *rollup.Config,
l2Genesis *core.Genesis, l2Genesis *core.Genesis,
rollupEndpoint string, rollupEndpoint string,
l2Endpoint string) Option { l2Endpoint string,
) Option {
return func(c *config.Config) { return func(c *config.Config) {
c.TraceTypes = append(c.TraceTypes, config.TraceTypeOutputCannon) c.TraceTypes = append(c.TraceTypes, config.TraceTypeCannon)
c.RollupRpc = rollupEndpoint c.RollupRpc = rollupEndpoint
applyCannonConfig(c, t, rollupCfg, l2Genesis, l2Endpoint) applyCannonConfig(c, t, rollupCfg, l2Genesis, l2Endpoint)
} }
} }
func WithOutputAlphabet(alphabet string, rollupEndpoint string) Option { func WithAlphabet(rollupEndpoint string) Option {
return func(c *config.Config) { return func(c *config.Config) {
c.TraceTypes = append(c.TraceTypes, config.TraceTypeOutputAlphabet) c.TraceTypes = append(c.TraceTypes, config.TraceTypeAlphabet)
c.RollupRpc = rollupEndpoint c.RollupRpc = rollupEndpoint
c.AlphabetTrace = alphabet
} }
} }
......
...@@ -9,14 +9,13 @@ import ( ...@@ -9,14 +9,13 @@ import (
type AlphabetGameHelper struct { type AlphabetGameHelper struct {
FaultGameHelper FaultGameHelper
claimedAlphabet string
} }
func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint string, name string, options ...challenger.Option) *challenger.Helper { func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint string, name string, options ...challenger.Option) *challenger.Helper {
opts := []challenger.Option{ opts := []challenger.Option{
challenger.WithFactoryAddress(g.factoryAddr), challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr), challenger.WithGameAddress(g.addr),
challenger.WithAlphabet(g.claimedAlphabet), challenger.WithAlphabet(g.system.RollupEndpoint("sequencer")),
} }
opts = append(opts, options...) opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, l1Endpoint, name, opts...) c := challenger.NewChallenger(g.t, ctx, l1Endpoint, name, opts...)
......
...@@ -33,7 +33,7 @@ func (g *FaultGameHelper) Addr() common.Address { ...@@ -33,7 +33,7 @@ func (g *FaultGameHelper) Addr() common.Address {
} }
func (g *FaultGameHelper) GameDuration(ctx context.Context) time.Duration { func (g *FaultGameHelper) GameDuration(ctx context.Context) time.Duration {
duration, err := g.game.GAMEDURATION(&bind.CallOpts{Context: ctx}) duration, err := g.game.GameDuration(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to get game duration") g.require.NoError(err, "failed to get game duration")
return time.Duration(duration) * time.Second return time.Duration(duration) * time.Second
} }
...@@ -59,7 +59,7 @@ func (g *FaultGameHelper) WaitForClaimCount(ctx context.Context, count int64) { ...@@ -59,7 +59,7 @@ func (g *FaultGameHelper) WaitForClaimCount(ctx context.Context, count int64) {
} }
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")
return depth.Int64() return depth.Int64()
} }
...@@ -293,6 +293,7 @@ func (g *FaultGameHelper) ChallengeRootClaim(ctx context.Context, performMove fu ...@@ -293,6 +293,7 @@ func (g *FaultGameHelper) ChallengeRootClaim(ctx context.Context, performMove fu
func (g *FaultGameHelper) WaitForNewClaim(ctx context.Context, checkPoint int64) (int64, error) { func (g *FaultGameHelper) WaitForNewClaim(ctx context.Context, checkPoint int64) (int64, error) {
return g.waitForNewClaim(ctx, checkPoint, defaultTimeout) return g.waitForNewClaim(ctx, checkPoint, defaultTimeout)
} }
func (g *FaultGameHelper) waitForNewClaim(ctx context.Context, checkPoint int64, timeout time.Duration) (int64, error) { func (g *FaultGameHelper) waitForNewClaim(ctx context.Context, checkPoint int64, timeout time.Duration) (int64, error) {
timedCtx, cancel := context.WithTimeout(ctx, timeout) timedCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel() defer cancel()
......
...@@ -32,9 +32,8 @@ import ( ...@@ -32,9 +32,8 @@ import (
) )
const ( const (
cannonGameType uint8 = 0
alphabetGameType uint8 = 255 alphabetGameType uint8 = 255
outputCannonGameType uint8 = 1
outputAlphabetGameType uint8 = 254
alphabetGameDepth = 4 alphabetGameDepth = 4
) )
...@@ -61,8 +60,6 @@ func (s Status) String() string { ...@@ -61,8 +60,6 @@ func (s Status) String() string {
} }
} }
var CorrectAlphabet = "abcdefghijklmnop"
type DisputeSystem interface { type DisputeSystem interface {
NodeEndpoint(name string) string NodeEndpoint(name string) string
NodeClient(name string) *ethclient.Client NodeClient(name string) *ethclient.Client
...@@ -82,7 +79,6 @@ type FactoryHelper struct { ...@@ -82,7 +79,6 @@ type FactoryHelper struct {
opts *bind.TransactOpts opts *bind.TransactOpts
factoryAddr common.Address factoryAddr common.Address
factory *bindings.DisputeGameFactory factory *bindings.DisputeGameFactory
blockOracle *bindings.BlockOracle
l2ooHelper *l2oo.L2OOHelper l2ooHelper *l2oo.L2OOHelper
} }
...@@ -98,8 +94,6 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) * ...@@ -98,8 +94,6 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *
factoryAddr := l1Deployments.DisputeGameFactoryProxy factoryAddr := l1Deployments.DisputeGameFactoryProxy
factory, err := bindings.NewDisputeGameFactory(factoryAddr, client) factory, err := bindings.NewDisputeGameFactory(factoryAddr, client)
require.NoError(err) require.NoError(err)
blockOracle, err := bindings.NewBlockOracle(l1Deployments.BlockOracle, client)
require.NoError(err)
return &FactoryHelper{ return &FactoryHelper{
t: t, t: t,
...@@ -109,49 +103,10 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) * ...@@ -109,49 +103,10 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *
opts: opts, opts: opts,
factory: factory, factory: factory,
factoryAddr: factoryAddr, factoryAddr: factoryAddr,
blockOracle: blockOracle,
l2ooHelper: l2oo.NewL2OOHelperReadOnly(t, l1Deployments, client), l2ooHelper: l2oo.NewL2OOHelperReadOnly(t, l1Deployments, client),
} }
} }
func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet string) *AlphabetGameHelper {
extraData, _, _ := h.createDisputeGameExtraData(ctx)
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
trace := alphabet.NewTraceProvider(claimedAlphabet, alphabetGameDepth)
pos := faultTypes.NewPosition(alphabetGameDepth, lastAlphabetTraceIndex)
rootClaim, err := trace.Get(ctx, pos)
h.require.NoError(err, "get root claim")
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 fault dispute game")
h.opts.GasLimit = 0
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, 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 &AlphabetGameHelper{
FaultGameHelper: FaultGameHelper{
t: h.t,
require: h.require,
system: h.system,
client: h.client,
opts: h.opts,
game: game,
factoryAddr: h.factoryAddr,
addr: createdEvent.DisputeProxy,
},
claimedAlphabet: claimedAlphabet,
}
}
func (h *FactoryHelper) StartOutputCannonGameWithCorrectRoot(ctx context.Context, l2Node string, l2BlockNumber uint64) *OutputCannonGameHelper { func (h *FactoryHelper) StartOutputCannonGameWithCorrectRoot(ctx context.Context, l2Node string, l2BlockNumber uint64) *OutputCannonGameHelper {
h.waitForBlockToBeSafe(l2Node, l2BlockNumber) h.waitForBlockToBeSafe(l2Node, l2BlockNumber)
output, err := h.system.RollupClient(l2Node).OutputAtBlock(ctx, l2BlockNumber) output, err := h.system.RollupClient(l2Node).OutputAtBlock(ctx, l2BlockNumber)
...@@ -169,7 +124,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string ...@@ -169,7 +124,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string
defer cancel() defer cancel()
tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) { tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.factory.Create(opts, outputCannonGameType, rootClaim, extraData) return h.factory.Create(opts, cannonGameType, rootClaim, extraData)
}) })
h.require.NoError(err, "create fault dispute game") h.require.NoError(err, "create fault dispute game")
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash()) rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
...@@ -177,7 +132,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string ...@@ -177,7 +132,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string
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.NewOutputBisectionGame(createdEvent.DisputeProxy, h.client) game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err) h.require.NoError(err)
prestateBlock, err := game.GenesisBlockNumber(&bind.CallOpts{Context: ctx}) prestateBlock, err := game.GenesisBlockNumber(&bind.CallOpts{Context: ctx})
...@@ -218,7 +173,7 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri ...@@ -218,7 +173,7 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri
rootClaim, err := trace.Get(ctx, pos) rootClaim, err := trace.Get(ctx, pos)
h.require.NoError(err, "get root claim") h.require.NoError(err, "get root claim")
tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) { tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.factory.Create(opts, outputAlphabetGameType, rootClaim, extraData) return h.factory.Create(opts, alphabetGameType, rootClaim, extraData)
}) })
h.require.NoError(err, "create output bisection game") h.require.NoError(err, "create output bisection game")
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash()) rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
...@@ -226,7 +181,7 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri ...@@ -226,7 +181,7 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri
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.NewOutputBisectionGame(createdEvent.DisputeProxy, h.client) game, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.client)
h.require.NoError(err) h.require.NoError(err)
prestateBlock, err := game.GenesisBlockNumber(&bind.CallOpts{Context: ctx}) prestateBlock, err := game.GenesisBlockNumber(&bind.CallOpts{Context: ctx})
...@@ -250,7 +205,6 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri ...@@ -250,7 +205,6 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri
correctOutputProvider: provider, correctOutputProvider: provider,
system: h.system, system: h.system,
}, },
claimedAlphabet: claimedAlphabet,
} }
} }
...@@ -268,15 +222,6 @@ func (h *FactoryHelper) waitForBlockToBeSafe(l2Node string, l2BlockNumber uint64 ...@@ -268,15 +222,6 @@ func (h *FactoryHelper) waitForBlockToBeSafe(l2Node string, l2BlockNumber uint64
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) createDisputeGameExtraData(ctx context.Context) (extraData []byte, l1Head *big.Int, l2BlockNumber uint64) {
l2BlockNumber = h.waitForProposals(ctx)
l1Head = h.checkpointL1Block(ctx)
extraData = make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
binary.BigEndian.PutUint64(extraData[56:], l1Head.Uint64())
return
}
func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, options ...challenger.Option) *challenger.Helper { func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, options ...challenger.Option) *challenger.Helper {
opts := []challenger.Option{ opts := []challenger.Option{
challenger.WithFactoryAddress(h.factoryAddr), challenger.WithFactoryAddress(h.factoryAddr),
...@@ -288,26 +233,3 @@ func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, option ...@@ -288,26 +233,3 @@ func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, option
}) })
return c return c
} }
// waitForProposals waits until there are at least two proposals in the output oracle
// This is the minimum required for creating a game.
// Returns the l2 block number of the latest available proposal
func (h *FactoryHelper) waitForProposals(ctx context.Context) uint64 {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
latestOutputIdx := h.l2ooHelper.WaitForProposals(ctx, 2)
return h.l2ooHelper.GetL2Output(ctx, latestOutputIdx).L2BlockNumber.Uint64()
}
// checkpointL1Block stores the current L1 block in the oracle
// Returns the L1 block number that was stored as the checkpoint
func (h *FactoryHelper) checkpointL1Block(ctx context.Context) *big.Int {
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer cancel()
// Store the current block in the oracle
tx, err := h.blockOracle.Checkpoint(h.opts)
h.require.NoError(err)
r, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err, "failed to store block in block oracle")
return new(big.Int).Sub(r.BlockNumber, big.NewInt(1))
}
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
type OutputAlphabetGameHelper struct { type OutputAlphabetGameHelper struct {
OutputGameHelper OutputGameHelper
claimedAlphabet string
} }
func (g *OutputAlphabetGameHelper) StartChallenger( func (g *OutputAlphabetGameHelper) StartChallenger(
...@@ -18,7 +17,7 @@ func (g *OutputAlphabetGameHelper) StartChallenger( ...@@ -18,7 +17,7 @@ func (g *OutputAlphabetGameHelper) StartChallenger(
options ...challenger.Option, options ...challenger.Option,
) *challenger.Helper { ) *challenger.Helper {
opts := []challenger.Option{ opts := []challenger.Option{
challenger.WithOutputAlphabet(g.claimedAlphabet, g.system.RollupEndpoint(l2Node)), challenger.WithAlphabet(g.system.RollupEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr), challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr), challenger.WithGameAddress(g.addr),
} }
......
...@@ -26,7 +26,7 @@ func (g *OutputCannonGameHelper) StartChallenger( ...@@ -26,7 +26,7 @@ func (g *OutputCannonGameHelper) StartChallenger(
rollupEndpoint := g.system.RollupEndpoint(l2Node) rollupEndpoint := g.system.RollupEndpoint(l2Node)
l2Endpoint := g.system.NodeEndpoint(l2Node) l2Endpoint := g.system.NodeEndpoint(l2Node)
opts := []challenger.Option{ opts := []challenger.Option{
challenger.WithOutputCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), rollupEndpoint, l2Endpoint), challenger.WithCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), rollupEndpoint, l2Endpoint),
challenger.WithFactoryAddress(g.factoryAddr), challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr), challenger.WithGameAddress(g.addr),
} }
...@@ -40,7 +40,7 @@ func (g *OutputCannonGameHelper) StartChallenger( ...@@ -40,7 +40,7 @@ func (g *OutputCannonGameHelper) StartChallenger(
func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *OutputHonestHelper { func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *OutputHonestHelper {
opts := []challenger.Option{ opts := []challenger.Option{
challenger.WithOutputCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), g.system.RollupEndpoint(l2Node), g.system.NodeEndpoint(l2Node)), challenger.WithCannon(g.t, g.system.RollupCfg(), g.system.L2Genesis(), g.system.RollupEndpoint(l2Node), g.system.NodeEndpoint(l2Node)),
challenger.WithFactoryAddress(g.factoryAddr), challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr), challenger.WithGameAddress(g.addr),
} }
...@@ -50,7 +50,7 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s ...@@ -50,7 +50,7 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s
logger := testlog.Logger(g.t, log.LvlInfo).New("role", "HonestHelper", "game", g.addr) logger := testlog.Logger(g.t, log.LvlInfo).New("role", "HonestHelper", "game", g.addr)
l2Client := g.system.NodeClient(l2Node) l2Client := g.system.NodeClient(l2Node)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract, err := contracts.NewOutputBisectionGameContract(g.addr, caller) contract, err := contracts.NewFaultDisputeGameContract(g.addr, caller)
g.require.NoError(err, "Failed to create game contact") g.require.NoError(err, "Failed to create game contact")
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx) prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
......
...@@ -25,7 +25,7 @@ type OutputGameHelper struct { ...@@ -25,7 +25,7 @@ type OutputGameHelper struct {
require *require.Assertions require *require.Assertions
client *ethclient.Client client *ethclient.Client
opts *bind.TransactOpts opts *bind.TransactOpts
game *bindings.OutputBisectionGame game *bindings.FaultDisputeGame
factoryAddr common.Address factoryAddr common.Address
addr common.Address addr common.Address
correctOutputProvider *outputs.OutputTraceProvider correctOutputProvider *outputs.OutputTraceProvider
......
...@@ -14,7 +14,7 @@ type OutputHonestHelper struct { ...@@ -14,7 +14,7 @@ type OutputHonestHelper struct {
t *testing.T t *testing.T
require *require.Assertions require *require.Assertions
game *OutputGameHelper game *OutputGameHelper
contract *contracts.OutputBisectionGameContract contract *contracts.FaultDisputeGameContract
correctTrace types.TraceAccessor correctTrace types.TraceAccessor
} }
......
package faultproofs
import (
"context"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/stretchr/testify/require"
)
func TestChallengerCompleteDisputeGame(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UseExecutor(1))
tests := []struct {
name string
rootClaimAlphabet string
otherAlphabet string
expectedResult disputegame.Status
expectStep bool
}{
{
name: "ChallengerWins_DefenseStep",
rootClaimAlphabet: "abcdexyz",
otherAlphabet: disputegame.CorrectAlphabet,
expectedResult: disputegame.StatusChallengerWins,
expectStep: true,
},
{
name: "DefenderWins_DefenseStep",
rootClaimAlphabet: disputegame.CorrectAlphabet,
otherAlphabet: "abcdexyz",
expectedResult: disputegame.StatusDefenderWins,
expectStep: false,
},
{
name: "ChallengerWins_AttackStep",
rootClaimAlphabet: "abcdefghzyx",
otherAlphabet: disputegame.CorrectAlphabet,
expectedResult: disputegame.StatusChallengerWins,
expectStep: true,
},
{
name: "DefenderWins_AttackStep",
rootClaimAlphabet: disputegame.CorrectAlphabet,
otherAlphabet: "abcdexyz",
expectedResult: disputegame.StatusDefenderWins,
expectStep: false,
},
{
name: "DefenderIncorrectAtTraceZero",
rootClaimAlphabet: "zyxwvut",
otherAlphabet: disputegame.CorrectAlphabet,
expectedResult: disputegame.StatusChallengerWins,
expectStep: true,
},
{
name: "ChallengerIncorrectAtTraceZero",
rootClaimAlphabet: disputegame.CorrectAlphabet,
otherAlphabet: "zyxwvut",
expectedResult: disputegame.StatusDefenderWins,
expectStep: false,
},
{
name: "DefenderIncorrectAtLastTraceIndex",
rootClaimAlphabet: "abcdefghijklmnoz",
otherAlphabet: disputegame.CorrectAlphabet,
expectedResult: disputegame.StatusChallengerWins,
expectStep: true,
},
{
name: "ChallengerIncorrectAtLastTraceIndex",
rootClaimAlphabet: disputegame.CorrectAlphabet,
otherAlphabet: "abcdefghijklmnoz",
expectedResult: disputegame.StatusDefenderWins,
expectStep: false,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UseExecutor(1))
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartAlphabetGame(ctx, test.rootClaimAlphabet)
require.NotNil(t, game)
gameDuration := game.GameDuration(ctx)
game.StartChallenger(ctx, sys.NodeEndpoint("l1"), "Defender",
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory),
)
game.StartChallenger(ctx, sys.NodeEndpoint("l1"), "Challenger",
challenger.WithAlphabet(test.otherAlphabet),
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
)
// Wait for a claim at the maximum depth that has been countered to indicate we're ready to resolve the game
game.WaitForClaimAtMaxDepth(ctx, test.expectStep)
sys.TimeTravelClock.AdvanceTime(gameDuration)
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true)
game.LogGameData(ctx)
require.EqualValues(t, test.expectedResult, game.Status(ctx))
})
}
}
func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UseExecutor(1))
testCase := func(t *testing.T, isRootCorrect bool) {
ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
rootClaimedAlphabet := disputegame.CorrectAlphabet
if !isRootCorrect {
rootClaimedAlphabet = "abcdexyz"
}
game := disputeGameFactory.StartAlphabetGame(ctx, rootClaimedAlphabet)
require.NotNil(t, game)
gameDuration := game.GameDuration(ctx)
// Start honest challenger
game.StartChallenger(ctx, sys.NodeEndpoint("l1"), "Challenger",
challenger.WithAlphabet(disputegame.CorrectAlphabet),
challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
// Ensures the challenger responds to all claims before test timeout
challenger.WithPollInterval(time.Millisecond*400),
)
// Start dishonest challenger
dishonestHelper := game.CreateDishonestHelper(disputegame.CorrectAlphabet, 4, !isRootCorrect)
dishonestHelper.ExhaustDishonestClaims(ctx)
// Wait until we've reached max depth before checking for inactivity
game.WaitForClaimAtDepth(ctx, int(game.MaxDepth(ctx)))
// Wait for 4 blocks of no challenger responses. The challenger may still be stepping on invalid claims at max depth
game.WaitForInactivity(ctx, 4, false)
sys.TimeTravelClock.AdvanceTime(gameDuration)
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
expectedStatus := disputegame.StatusChallengerWins
if isRootCorrect {
expectedStatus = disputegame.StatusDefenderWins
}
game.WaitForInactivity(ctx, 10, true)
game.LogGameData(ctx)
require.EqualValues(t, expectedStatus, game.Status(ctx))
}
t.Run("RootCorrect", func(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UseExecutor(1))
testCase(t, true)
})
t.Run("RootIncorrect", func(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UseExecutor(1))
testCase(t, false)
})
}
...@@ -26,8 +26,8 @@ func TestMultipleGameTypes(t *testing.T) { ...@@ -26,8 +26,8 @@ func TestMultipleGameTypes(t *testing.T) {
// Start a challenger with both cannon and alphabet support // Start a challenger with both cannon and alphabet support
gameFactory.StartChallenger(ctx, "TowerDefense", gameFactory.StartChallenger(ctx, "TowerDefense",
challenger.WithOutputCannon(t, sys.RollupConfig, sys.L2GenesisCfg, sys.RollupEndpoint("sequencer"), sys.NodeEndpoint("sequencer")), challenger.WithCannon(t, sys.RollupConfig, sys.L2GenesisCfg, sys.RollupEndpoint("sequencer"), sys.NodeEndpoint("sequencer")),
challenger.WithOutputAlphabet(disputegame.CorrectAlphabet, sys.RollupEndpoint("sequencer")), challenger.WithAlphabet(sys.RollupEndpoint("sequencer")),
challenger.WithPrivKey(sys.Cfg.Secrets.Alice), challenger.WithPrivKey(sys.Cfg.Secrets.Alice),
) )
......
...@@ -49,9 +49,9 @@ ...@@ -49,9 +49,9 @@
"faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98", "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 44, "faultGameMaxDepth": 44,
"faultGameMaxDuration": 1200, "faultGameMaxDuration": 1200,
"outputBisectionGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"outputBisectionGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"outputBisectionGameSplitDepth": 14, "faultGameSplitDepth": 14,
"systemConfigStartBlock": 0, "systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000" "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000"
......
...@@ -30,10 +30,8 @@ import { ResourceMetering } from "src/L1/ResourceMetering.sol"; ...@@ -30,10 +30,8 @@ import { ResourceMetering } from "src/L1/ResourceMetering.sol";
import { Constants } from "src/libraries/Constants.sol"; import { Constants } from "src/libraries/Constants.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol"; import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
import { OutputBisectionGame } from "src/dispute/OutputBisectionGame.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol"; import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { MIPS } from "src/cannon/MIPS.sol"; import { MIPS } from "src/cannon/MIPS.sol";
import { BlockOracle } from "src/dispute/BlockOracle.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol"; import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
import { ProtocolVersions, ProtocolVersion } from "src/L1/ProtocolVersions.sol"; import { ProtocolVersions, ProtocolVersion } from "src/L1/ProtocolVersions.sol";
import { StorageSetter } from "src/universal/StorageSetter.sol"; import { StorageSetter } from "src/universal/StorageSetter.sol";
...@@ -43,7 +41,6 @@ import { Chains } from "scripts/Chains.sol"; ...@@ -43,7 +41,6 @@ import { Chains } from "scripts/Chains.sol";
import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol"; import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";
import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol";
import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; import { AlphabetVM } from "test/mocks/AlphabetVM.sol";
import { AlphabetVM2 } from "test/mocks/AlphabetVM2.sol";
import "src/libraries/DisputeTypes.sol"; import "src/libraries/DisputeTypes.sol";
import { ChainAssertions } from "scripts/ChainAssertions.sol"; import { ChainAssertions } from "scripts/ChainAssertions.sol";
import { Types } from "scripts/Types.sol"; import { Types } from "scripts/Types.sol";
...@@ -290,9 +287,6 @@ contract Deploy is Deployer { ...@@ -290,9 +287,6 @@ contract Deploy is Deployer {
deployImplementations(); deployImplementations();
initializeImplementations(); initializeImplementations();
setCannonOutputBisectionGameImplementation();
setAlphabetOutputBisectionGameImplementation();
setAlphabetFaultGameImplementation(); setAlphabetFaultGameImplementation();
setCannonFaultGameImplementation(); setCannonFaultGameImplementation();
...@@ -326,7 +320,6 @@ contract Deploy is Deployer { ...@@ -326,7 +320,6 @@ contract Deploy is Deployer {
deployL1StandardBridge(); deployL1StandardBridge();
deployL1ERC721Bridge(); deployL1ERC721Bridge();
deployDisputeGameFactory(); deployDisputeGameFactory();
deployBlockOracle();
deployPreimageOracle(); deployPreimageOracle();
deployMips(); deployMips();
} }
...@@ -569,16 +562,6 @@ contract Deploy is Deployer { ...@@ -569,16 +562,6 @@ contract Deploy is Deployer {
addr_ = address(factory); addr_ = address(factory);
} }
/// @notice Deploy the BlockOracle
function deployBlockOracle() public onlyDevnet broadcast returns (address addr_) {
console.log("Deploying BlockOracle implementation");
BlockOracle oracle = new BlockOracle{ salt: _implSalt() }();
save("BlockOracle", address(oracle));
console.log("BlockOracle deployed at %s", address(oracle));
addr_ = address(oracle);
}
/// @notice Deploy the ProtocolVersions /// @notice Deploy the ProtocolVersions
function deployProtocolVersions() public broadcast returns (address addr_) { function deployProtocolVersions() public broadcast returns (address addr_) {
console.log("Deploying ProtocolVersions implementation"); console.log("Deploying ProtocolVersions implementation");
...@@ -1019,35 +1002,6 @@ contract Deploy is Deployer { ...@@ -1019,35 +1002,6 @@ contract Deploy is Deployer {
_gameType: GameTypes.CANNON, _gameType: GameTypes.CANNON,
_absolutePrestate: loadMipsAbsolutePrestate(), _absolutePrestate: loadMipsAbsolutePrestate(),
_faultVm: IBigStepper(mustGetAddress("Mips")), _faultVm: IBigStepper(mustGetAddress("Mips")),
_maxGameDepth: 30 // Hard code depth for legacy game to keep e2e tests fast
});
}
/// @notice Sets the implementation for the `OUTPUT_CANNON` game type in the `DisputeGameFactory`
function setCannonOutputBisectionGameImplementation() public onlyDevnet broadcast {
console.log("Setting Cannon OutputBisectionGame implementation");
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
_setFaultGameImplementation({
_factory: factory,
_gameType: GameTypes.OUTPUT_CANNON,
_absolutePrestate: loadMipsAbsolutePrestate(),
_faultVm: IBigStepper(mustGetAddress("Mips")),
_maxGameDepth: cfg.faultGameMaxDepth()
});
}
/// @notice Sets the implementation for the `OUTPUT_ALPHABET` game type in the `DisputeGameFactory`
function setAlphabetOutputBisectionGameImplementation() public onlyDevnet broadcast {
console.log("Setting Alphabet OutputBisectionGame implementation");
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
Claim outputAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
_setFaultGameImplementation({
_factory: factory,
_gameType: GameTypes.OUTPUT_ALPHABET,
_absolutePrestate: outputAbsolutePrestate,
_faultVm: IBigStepper(new AlphabetVM2(outputAbsolutePrestate)),
_maxGameDepth: cfg.faultGameMaxDepth() _maxGameDepth: cfg.faultGameMaxDepth()
}); });
} }
...@@ -1057,14 +1011,13 @@ contract Deploy is Deployer { ...@@ -1057,14 +1011,13 @@ contract Deploy is Deployer {
console.log("Setting Alphabet FaultDisputeGame implementation"); console.log("Setting Alphabet FaultDisputeGame implementation");
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy")); DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
// Set the Alphabet FaultDisputeGame implementation in the factory. Claim outputAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
Claim alphabetAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
_setFaultGameImplementation({ _setFaultGameImplementation({
_factory: factory, _factory: factory,
_gameType: GameTypes.ALPHABET, _gameType: GameTypes.ALPHABET,
_absolutePrestate: alphabetAbsolutePrestate, _absolutePrestate: outputAbsolutePrestate,
_faultVm: IBigStepper(new AlphabetVM(alphabetAbsolutePrestate)), _faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate)),
_maxGameDepth: 4 // The max game depth of the alphabet game is always 4. _maxGameDepth: cfg.faultGameMaxDepth()
}); });
} }
...@@ -1086,49 +1039,24 @@ contract Deploy is Deployer { ...@@ -1086,49 +1039,24 @@ contract Deploy is Deployer {
return; return;
} }
string memory deployed;
if (
GameType.unwrap(_gameType) == GameType.unwrap(GameTypes.OUTPUT_ALPHABET)
|| GameType.unwrap(_gameType) == GameType.unwrap(GameTypes.OUTPUT_CANNON)
) {
deployed = "OutputBisectionGame";
_factory.setImplementation(
_gameType,
new OutputBisectionGame({
_gameType: _gameType,
_absolutePrestate: _absolutePrestate,
_genesisBlockNumber: cfg.outputBisectionGameGenesisBlock(),
_genesisOutputRoot: Hash.wrap(cfg.outputBisectionGameGenesisOutputRoot()),
_maxGameDepth: _maxGameDepth,
_splitDepth: cfg.outputBisectionGameSplitDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())),
_vm: _faultVm
})
);
} else {
deployed = "FaultDisputeGame";
_factory.setImplementation( _factory.setImplementation(
_gameType, _gameType,
new FaultDisputeGame({ new FaultDisputeGame({
_gameType: _gameType, _gameType: _gameType,
_absolutePrestate: _absolutePrestate, _absolutePrestate: _absolutePrestate,
_genesisBlockNumber: cfg.faultGameGenesisBlock(),
_genesisOutputRoot: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
_maxGameDepth: _maxGameDepth, _maxGameDepth: _maxGameDepth,
_splitDepth: cfg.faultGameSplitDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())), _gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())),
_vm: _faultVm, _vm: _faultVm
_l2oo: L2OutputOracle(mustGetAddress("L2OutputOracleProxy")),
_blockOracle: BlockOracle(mustGetAddress("BlockOracle"))
}) })
); );
}
uint8 rawGameType = GameType.unwrap(_gameType); uint8 rawGameType = GameType.unwrap(_gameType);
string memory gameTypeString; string memory gameTypeString;
if (rawGameType == GameType.unwrap(GameTypes.CANNON)) { if (rawGameType == GameType.unwrap(GameTypes.CANNON)) {
gameTypeString = "Cannon"; gameTypeString = "Cannon";
} else if (rawGameType == GameType.unwrap(GameTypes.OUTPUT_CANNON)) {
gameTypeString = "OutputBisectionCannon";
} else if (rawGameType == GameType.unwrap(GameTypes.OUTPUT_ALPHABET)) {
gameTypeString = "OutputBisectionAlphabet";
} else if (rawGameType == GameType.unwrap(GameTypes.ALPHABET)) { } else if (rawGameType == GameType.unwrap(GameTypes.ALPHABET)) {
gameTypeString = "Alphabet"; gameTypeString = "Alphabet";
} else { } else {
...@@ -1136,8 +1064,7 @@ contract Deploy is Deployer { ...@@ -1136,8 +1064,7 @@ contract Deploy is Deployer {
} }
console.log( console.log(
"DisputeGameFactoryProxy: set `%s` implementation (Backend: %s | GameType: %s)", "DisputeGameFactoryProxy: set `FaultDisputeGame` implementation (Backend: %s | GameType: %s)",
deployed,
gameTypeString, gameTypeString,
vm.toString(rawGameType) vm.toString(rawGameType)
); );
......
...@@ -48,11 +48,11 @@ contract DeployConfig is Script { ...@@ -48,11 +48,11 @@ contract DeployConfig is Script {
uint256 public eip1559Denominator; uint256 public eip1559Denominator;
uint256 public eip1559Elasticity; uint256 public eip1559Elasticity;
uint256 public faultGameAbsolutePrestate; uint256 public faultGameAbsolutePrestate;
uint256 public faultGameGenesisBlock;
bytes32 public faultGameGenesisOutputRoot;
uint256 public faultGameMaxDepth; uint256 public faultGameMaxDepth;
uint256 public faultGameSplitDepth;
uint256 public faultGameMaxDuration; uint256 public faultGameMaxDuration;
uint256 public outputBisectionGameGenesisBlock;
bytes32 public outputBisectionGameGenesisOutputRoot;
uint256 public outputBisectionGameSplitDepth;
uint256 public systemConfigStartBlock; uint256 public systemConfigStartBlock;
uint256 public requiredProtocolVersion; uint256 public requiredProtocolVersion;
uint256 public recommendedProtocolVersion; uint256 public recommendedProtocolVersion;
...@@ -106,10 +106,10 @@ contract DeployConfig is Script { ...@@ -106,10 +106,10 @@ contract DeployConfig is Script {
if (block.chainid == Chains.LocalDevnet || block.chainid == Chains.GethDevnet) { if (block.chainid == Chains.LocalDevnet || block.chainid == Chains.GethDevnet) {
faultGameAbsolutePrestate = stdJson.readUint(_json, "$.faultGameAbsolutePrestate"); faultGameAbsolutePrestate = stdJson.readUint(_json, "$.faultGameAbsolutePrestate");
faultGameMaxDepth = stdJson.readUint(_json, "$.faultGameMaxDepth"); faultGameMaxDepth = stdJson.readUint(_json, "$.faultGameMaxDepth");
faultGameSplitDepth = stdJson.readUint(_json, "$.faultGameSplitDepth");
faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration"); faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration");
outputBisectionGameGenesisBlock = stdJson.readUint(_json, "$.outputBisectionGameGenesisBlock"); faultGameGenesisBlock = stdJson.readUint(_json, "$.faultGameGenesisBlock");
outputBisectionGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.outputBisectionGameGenesisOutputRoot"); faultGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.faultGameGenesisOutputRoot");
outputBisectionGameSplitDepth = stdJson.readUint(_json, "$.outputBisectionGameSplitDepth");
} }
} }
......
...@@ -20,12 +20,19 @@ import { LibPosition } from "../src/dispute/lib/LibPosition.sol"; ...@@ -20,12 +20,19 @@ import { LibPosition } from "../src/dispute/lib/LibPosition.sol";
*/ */
contract FaultDisputeGameViz is Script, FaultDisputeGame_Init { contract FaultDisputeGameViz is Script, FaultDisputeGame_Init {
/// @dev The root claim of the game. /// @dev The root claim of the game.
Claim internal constant ROOT_CLAIM = Claim.wrap(bytes32(uint256(10))); Claim internal constant ROOT_CLAIM = Claim.wrap(bytes32(uint256(1)));
/// @dev The absolute prestate of the trace. /// @dev The absolute prestate of the trace.
Claim internal constant ABSOLUTE_PRESTATE = Claim.wrap(bytes32(uint256(0))); Claim internal constant ABSOLUTE_PRESTATE = Claim.wrap(bytes32((uint256(3) << 248) | uint256(0)));
function setUp() public override { function setUp() public override {
super.init(ROOT_CLAIM, ABSOLUTE_PRESTATE); super.setUp();
super.init({
rootClaim: ROOT_CLAIM,
absolutePrestate: ABSOLUTE_PRESTATE,
l2BlockNumber: 0x10,
genesisBlockNumber: 0,
genesisOutputRoot: Hash.wrap(bytes32(0))
});
} }
/** /**
......
...@@ -87,26 +87,26 @@ ...@@ -87,26 +87,26 @@
"initCodeHash": "0x0da844fb4dd22f252ff631524f01f45edf43bca7558fe45f71d711b79af01742", "initCodeHash": "0x0da844fb4dd22f252ff631524f01f45edf43bca7558fe45f71d711b79af01742",
"sourceCodeHash": "0x1afb1d392e8f6a58ff86ea7f648e0d1756d4ba8d0d964279d58a390deaa53b7e" "sourceCodeHash": "0x1afb1d392e8f6a58ff86ea7f648e0d1756d4ba8d0d964279d58a390deaa53b7e"
}, },
"src/dispute/BlockOracle.sol": {
"initCodeHash": "0x183ce41fb2842c9853f08955ddd91e345126028fad64e07ed14f593cbf9c88bc",
"sourceCodeHash": "0xabbfe0def64318b467e098bb518100a4cbf7ad4e803d13fbb187f25df35de8dd"
},
"src/dispute/DisputeGameFactory.sol": { "src/dispute/DisputeGameFactory.sol": {
"initCodeHash": "0x84a15994d275bea8a96af83a46849e74eb573aa579db86350b6fe358bd61ec57", "initCodeHash": "0x84a15994d275bea8a96af83a46849e74eb573aa579db86350b6fe358bd61ec57",
"sourceCodeHash": "0x64290a5d8138c46d2ecd308e3ef62ba04663049cce8a271b9a686ddd2e630391" "sourceCodeHash": "0x64290a5d8138c46d2ecd308e3ef62ba04663049cce8a271b9a686ddd2e630391"
}, },
"src/dispute/FaultDisputeGame.sol": { "src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0x77ae981180b9c2fc9cf33b7862551f74368e8889f68c2f535f46730d1272eba3", "initCodeHash": "0xbd89fd5227cf5c52309cbaa24175351491180f6ff5b7a40a542bfc0e80d6ec00",
"sourceCodeHash": "0xa995b54dce03ddf5c9c47451bd7181996b91398ad66b54ab0b8cbf582863a33e" "sourceCodeHash": "0xbf39a67d44f5bcdaf65b202c393c538a87903a172056f4fb548645120f38d88c"
}, },
"src/dispute/OutputBisectionGame.sol": { "src/legacy/BlockOracle.sol": {
"initCodeHash": "0x10596ff55c460324b6b442fe19d7f849e6dd8202c9b4514ca979ca02be339060", "initCodeHash": "0x183ce41fb2842c9853f08955ddd91e345126028fad64e07ed14f593cbf9c88bc",
"sourceCodeHash": "0xe0fada6499eb1a24a4e1ccce50568f0b10617dec0fc8af189bff2c9ab4c320ce" "sourceCodeHash": "0xabbfe0def64318b467e098bb518100a4cbf7ad4e803d13fbb187f25df35de8dd"
}, },
"src/legacy/DeployerWhitelist.sol": { "src/legacy/DeployerWhitelist.sol": {
"initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d", "initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d",
"sourceCodeHash": "0xb518a9f56136a910f2450098b4823c9982f93883fe4a9ef6f6b0a89355965d38" "sourceCodeHash": "0xb518a9f56136a910f2450098b4823c9982f93883fe4a9ef6f6b0a89355965d38"
}, },
"src/legacy/FaultDisputeGame.sol": {
"initCodeHash": "0xbd89fd5227cf5c52309cbaa24175351491180f6ff5b7a40a542bfc0e80d6ec00",
"sourceCodeHash": "0xdc119ac6d4766e6ee88fcaff31f7ef3b8f5ac79055bc426dd3c6872f3df0eb30"
},
"src/legacy/L1BlockNumber.sol": { "src/legacy/L1BlockNumber.sol": {
"initCodeHash": "0xd586c4f93caf1753e53fcdc05eb547c1f3a69afda2904ae9f9d851b73e1c9c1d", "initCodeHash": "0xd586c4f93caf1753e53fcdc05eb547c1f3a69afda2904ae9f9d851b73e1c9c1d",
"sourceCodeHash": "0x2a42b124a918a987da60934d9059a72d4fe13dba2609b9f80146f9c8a3fc8293" "sourceCodeHash": "0x2a42b124a918a987da60934d9059a72d4fe13dba2609b9f80146f9c8a3fc8293"
......
...@@ -11,11 +11,26 @@ ...@@ -11,11 +11,26 @@
"name": "_absolutePrestate", "name": "_absolutePrestate",
"type": "bytes32" "type": "bytes32"
}, },
{
"internalType": "uint256",
"name": "_genesisBlockNumber",
"type": "uint256"
},
{
"internalType": "Hash",
"name": "_genesisOutputRoot",
"type": "bytes32"
},
{ {
"internalType": "uint256", "internalType": "uint256",
"name": "_maxGameDepth", "name": "_maxGameDepth",
"type": "uint256" "type": "uint256"
}, },
{
"internalType": "uint256",
"name": "_splitDepth",
"type": "uint256"
},
{ {
"internalType": "Duration", "internalType": "Duration",
"name": "_gameDuration", "name": "_gameDuration",
...@@ -25,16 +40,6 @@ ...@@ -25,16 +40,6 @@
"internalType": "contract IBigStepper", "internalType": "contract IBigStepper",
"name": "_vm", "name": "_vm",
"type": "address" "type": "address"
},
{
"internalType": "contract L2OutputOracle",
"name": "_l2oo",
"type": "address"
},
{
"internalType": "contract BlockOracle",
"name": "_blockOracle",
"type": "address"
} }
], ],
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
...@@ -42,82 +47,17 @@ ...@@ -42,82 +47,17 @@
}, },
{ {
"inputs": [], "inputs": [],
"name": "ABSOLUTE_PRESTATE", "name": "absolutePrestate",
"outputs": [ "outputs": [
{ {
"internalType": "Claim", "internalType": "Claim",
"name": "", "name": "absolutePrestate_",
"type": "bytes32" "type": "bytes32"
} }
], ],
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "BLOCK_ORACLE",
"outputs": [
{
"internalType": "contract BlockOracle",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "GAME_DURATION",
"outputs": [
{
"internalType": "Duration",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "L2_OUTPUT_ORACLE",
"outputs": [
{
"internalType": "contract L2OutputOracle",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_GAME_DEPTH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "VM",
"outputs": [
{
"internalType": "contract IBigStepper",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -126,9 +66,9 @@ ...@@ -126,9 +66,9 @@
"type": "uint256" "type": "uint256"
}, },
{ {
"internalType": "bytes32", "internalType": "uint256",
"name": "_localContext", "name": "_execLeafIdx",
"type": "bytes32" "type": "uint256"
}, },
{ {
"internalType": "uint256", "internalType": "uint256",
...@@ -291,6 +231,19 @@ ...@@ -291,6 +231,19 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "gameDuration",
"outputs": [
{
"internalType": "Duration",
"name": "gameDuration_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "gameType", "name": "gameType",
...@@ -306,22 +259,35 @@ ...@@ -306,22 +259,35 @@
}, },
{ {
"inputs": [], "inputs": [],
"name": "initialize", "name": "genesisBlockNumber",
"outputs": [], "outputs": [
"stateMutability": "nonpayable", {
"internalType": "uint256",
"name": "genesisBlockNumber_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function" "type": "function"
}, },
{ {
"inputs": [], "inputs": [],
"name": "l1BlockNumber", "name": "genesisOutputRoot",
"outputs": [ "outputs": [
{ {
"internalType": "uint256", "internalType": "Hash",
"name": "l1BlockNumber_", "name": "genesisOutputRoot_",
"type": "uint256" "type": "bytes32"
} }
], ],
"stateMutability": "pure", "stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "initialize",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{ {
...@@ -350,6 +316,19 @@ ...@@ -350,6 +316,19 @@
"stateMutability": "pure", "stateMutability": "pure",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "maxGameDepth",
"outputs": [
{
"internalType": "uint256",
"name": "maxGameDepth_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -373,58 +352,6 @@ ...@@ -373,58 +352,6 @@
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "proposals",
"outputs": [
{
"components": [
{
"internalType": "uint128",
"name": "index",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "l2BlockNumber",
"type": "uint128"
},
{
"internalType": "Hash",
"name": "outputRoot",
"type": "bytes32"
}
],
"internalType": "struct IFaultDisputeGame.OutputProposal",
"name": "starting",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint128",
"name": "index",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "l2BlockNumber",
"type": "uint128"
},
{
"internalType": "Hash",
"name": "outputRoot",
"type": "bytes32"
}
],
"internalType": "struct IFaultDisputeGame.OutputProposal",
"name": "disputed",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "resolve", "name": "resolve",
...@@ -451,6 +378,19 @@ ...@@ -451,6 +378,19 @@
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "resolvedAt",
"outputs": [
{
"internalType": "Timestamp",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "rootClaim", "name": "rootClaim",
...@@ -464,6 +404,19 @@ ...@@ -464,6 +404,19 @@
"stateMutability": "pure", "stateMutability": "pure",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "splitDepth",
"outputs": [
{
"internalType": "uint256",
"name": "splitDepth_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "status", "name": "status",
...@@ -518,6 +471,19 @@ ...@@ -518,6 +471,19 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "vm",
"outputs": [
{
"internalType": "contract IBigStepper",
"name": "vm_",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"anonymous": false, "anonymous": false,
"inputs": [ "inputs": [
...@@ -561,6 +527,11 @@ ...@@ -561,6 +527,11 @@
"name": "CannotDefendRootClaim", "name": "CannotDefendRootClaim",
"type": "error" "type": "error"
}, },
{
"inputs": [],
"name": "ClaimAboveSplit",
"type": "error"
},
{ {
"inputs": [], "inputs": [],
"name": "ClaimAlreadyExists", "name": "ClaimAlreadyExists",
...@@ -591,6 +562,11 @@ ...@@ -591,6 +562,11 @@
"name": "GameNotInProgress", "name": "GameNotInProgress",
"type": "error" "type": "error"
}, },
{
"inputs": [],
"name": "InvalidLocalIdent",
"type": "error"
},
{ {
"inputs": [], "inputs": [],
"name": "InvalidParent", "name": "InvalidParent",
...@@ -603,7 +579,7 @@ ...@@ -603,7 +579,7 @@
}, },
{ {
"inputs": [], "inputs": [],
"name": "L1HeadTooOld", "name": "InvalidSplitDepth",
"type": "error" "type": "error"
}, },
{ {
......
...@@ -6,60 +6,60 @@ ...@@ -6,60 +6,60 @@
"slot": "0", "slot": "0",
"type": "Timestamp" "type": "Timestamp"
}, },
{
"bytes": "8",
"label": "resolvedAt",
"offset": 8,
"slot": "0",
"type": "Timestamp"
},
{ {
"bytes": "1", "bytes": "1",
"label": "status", "label": "status",
"offset": 8, "offset": 16,
"slot": "0", "slot": "0",
"type": "enum GameStatus" "type": "enum GameStatus"
}, },
{ {
"bytes": "20", "bytes": "20",
"label": "bondManager", "label": "bondManager",
"offset": 9, "offset": 0,
"slot": "0", "slot": "1",
"type": "contract IBondManager" "type": "contract IBondManager"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "l1Head", "label": "l1Head",
"offset": 0, "offset": 0,
"slot": "1", "slot": "2",
"type": "Hash" "type": "Hash"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "claimData", "label": "claimData",
"offset": 0, "offset": 0,
"slot": "2",
"type": "struct IFaultDisputeGame.ClaimData[]"
},
{
"bytes": "128",
"label": "proposals",
"offset": 0,
"slot": "3", "slot": "3",
"type": "struct IFaultDisputeGame.OutputProposals" "type": "struct IFaultDisputeGame.ClaimData[]"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "claims", "label": "claims",
"offset": 0, "offset": 0,
"slot": "7", "slot": "4",
"type": "mapping(ClaimHash => bool)" "type": "mapping(ClaimHash => bool)"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "subgames", "label": "subgames",
"offset": 0, "offset": 0,
"slot": "8", "slot": "5",
"type": "mapping(uint256 => uint256[])" "type": "mapping(uint256 => uint256[])"
}, },
{ {
"bytes": "1", "bytes": "1",
"label": "subgameAtRootResolved", "label": "subgameAtRootResolved",
"offset": 0, "offset": 0,
"slot": "9", "slot": "6",
"type": "bool" "type": "bool"
} }
] ]
\ No newline at end of file
...@@ -6,60 +6,60 @@ ...@@ -6,60 +6,60 @@
"slot": "0", "slot": "0",
"type": "Timestamp" "type": "Timestamp"
}, },
{
"bytes": "8",
"label": "resolvedAt",
"offset": 8,
"slot": "0",
"type": "Timestamp"
},
{ {
"bytes": "1", "bytes": "1",
"label": "status", "label": "status",
"offset": 16, "offset": 8,
"slot": "0", "slot": "0",
"type": "enum GameStatus" "type": "enum GameStatus"
}, },
{ {
"bytes": "20", "bytes": "20",
"label": "bondManager", "label": "bondManager",
"offset": 0, "offset": 9,
"slot": "1", "slot": "0",
"type": "contract IBondManager" "type": "contract IBondManager"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "l1Head", "label": "l1Head",
"offset": 0, "offset": 0,
"slot": "2", "slot": "1",
"type": "Hash" "type": "Hash"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "claimData", "label": "claimData",
"offset": 0, "offset": 0,
"slot": "2",
"type": "struct ILegacyFaultDisputeGame.ClaimData[]"
},
{
"bytes": "128",
"label": "proposals",
"offset": 0,
"slot": "3", "slot": "3",
"type": "struct IOutputBisectionGame.ClaimData[]" "type": "struct ILegacyFaultDisputeGame.OutputProposals"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "claims", "label": "claims",
"offset": 0, "offset": 0,
"slot": "4", "slot": "7",
"type": "mapping(ClaimHash => bool)" "type": "mapping(ClaimHash => bool)"
}, },
{ {
"bytes": "32", "bytes": "32",
"label": "subgames", "label": "subgames",
"offset": 0, "offset": 0,
"slot": "5", "slot": "8",
"type": "mapping(uint256 => uint256[])" "type": "mapping(uint256 => uint256[])"
}, },
{ {
"bytes": "1", "bytes": "1",
"label": "subgameAtRootResolved", "label": "subgameAtRootResolved",
"offset": 0, "offset": 0,
"slot": "6", "slot": "9",
"type": "bool" "type": "bool"
} }
] ]
\ No newline at end of file
...@@ -18,27 +18,6 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -18,27 +18,6 @@ interface IFaultDisputeGame is IDisputeGame {
Clock clock; Clock clock;
} }
/// @notice The `OutputProposal` struct contains information about an output proposal in
/// the `L2OutputOracle` at a given index.
struct OutputProposal {
uint128 index;
uint128 l2BlockNumber;
Hash outputRoot;
}
/// @notice A container for two consecutive `OutputProposal`s, used to store the starting
/// and disputed output proposals for a given dispute game. The starting output
/// proposal will be used to determine where the off chain agents should begin
/// running their fault proof program, and the disputed output proposal will be
/// fed into the program and treated as disputed state. The program's exit code
/// expresses its opinion on the validity of the state transition from the starting,
/// trusted output proposal to the disputed output proposal, and ultimately resolves
/// the dispute.
struct OutputProposals {
OutputProposal starting;
OutputProposal disputed;
}
/// @notice Emitted when a new claim is added to the DAG by `claimant` /// @notice Emitted when a new claim is added to the DAG by `claimant`
/// @param parentIndex The index within the `claimData` array of the parent claim /// @param parentIndex The index within the `claimData` array of the parent claim
/// @param claim The claim being added /// @param claim The claim being added
...@@ -70,9 +49,9 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -70,9 +49,9 @@ interface IFaultDisputeGame is IDisputeGame {
/// @notice Posts the requested local data to the VM's `PreimageOralce`. /// @notice Posts the requested local data to the VM's `PreimageOralce`.
/// @param _ident The local identifier of the data to post. /// @param _ident The local identifier of the data to post.
/// @param _localContext The local context for the `PreimageOracle` key. /// @param _execLeafIdx The index of the leaf claim in an execution subgame that requires the local data for a step.
/// @param _partOffset The offset of the data to post. /// @param _partOffset The offset of the data to post.
function addLocalData(uint256 _ident, bytes32 _localContext, uint256 _partOffset) external; function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external;
/// @notice Resolves the subgame rooted at the given claim index. /// @notice Resolves the subgame rooted at the given claim index.
/// @dev This function must be called bottom-up in the DAG /// @dev This function must be called bottom-up in the DAG
...@@ -82,15 +61,9 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -82,15 +61,9 @@ interface IFaultDisputeGame is IDisputeGame {
/// @param _claimIndex The index of the subgame root claim to resolve. /// @param _claimIndex The index of the subgame root claim to resolve.
function resolveClaim(uint256 _claimIndex) external payable; function resolveClaim(uint256 _claimIndex) external payable;
/// @notice An L1 block hash that contains the disputed output root, fetched from the /// @notice A block hash on the L1 that contains the disputed output root.
/// `BlockOracle` and verified by referencing the timestamp associated with the
/// first L2 Output Proposal in the `L2OutputOracle` that contains the disputed
/// L2 block number.
function l1Head() external view returns (Hash l1Head_); function l1Head() external view returns (Hash l1Head_);
/// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`. /// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`.
function l2BlockNumber() external view returns (uint256 l2BlockNumber_); function l2BlockNumber() external view returns (uint256 l2BlockNumber_);
/// @notice The l1BlockNumber that Cannon was ran from to generate the root claim.
function l1BlockNumber() external view returns (uint256 l1BlockNumber_);
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import { IDisputeGame } from "./IDisputeGame.sol"; import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import "src/libraries/DisputeTypes.sol"; import "src/libraries/DisputeTypes.sol";
/// @title IOutputBisectionGame /// @title ILegacyFaultDisputeGame
/// @notice The interface for a fault proof backed dispute game. /// @notice The interface for a fault proof backed dispute game.
interface IOutputBisectionGame is IDisputeGame { interface ILegacyFaultDisputeGame is IDisputeGame {
/// @notice The `ClaimData` struct represents the data associated with a Claim. /// @notice The `ClaimData` struct represents the data associated with a Claim.
/// @dev TODO(clabby): Add bond ID information. /// @dev TODO(clabby): Add bond ID information.
struct ClaimData { struct ClaimData {
...@@ -18,6 +18,27 @@ interface IOutputBisectionGame is IDisputeGame { ...@@ -18,6 +18,27 @@ interface IOutputBisectionGame is IDisputeGame {
Clock clock; Clock clock;
} }
/// @notice The `OutputProposal` struct contains information about an output proposal in
/// the `L2OutputOracle` at a given index.
struct OutputProposal {
uint128 index;
uint128 l2BlockNumber;
Hash outputRoot;
}
/// @notice A container for two consecutive `OutputProposal`s, used to store the starting
/// and disputed output proposals for a given dispute game. The starting output
/// proposal will be used to determine where the off chain agents should begin
/// running their fault proof program, and the disputed output proposal will be
/// fed into the program and treated as disputed state. The program's exit code
/// expresses its opinion on the validity of the state transition from the starting,
/// trusted output proposal to the disputed output proposal, and ultimately resolves
/// the dispute.
struct OutputProposals {
OutputProposal starting;
OutputProposal disputed;
}
/// @notice Emitted when a new claim is added to the DAG by `claimant` /// @notice Emitted when a new claim is added to the DAG by `claimant`
/// @param parentIndex The index within the `claimData` array of the parent claim /// @param parentIndex The index within the `claimData` array of the parent claim
/// @param claim The claim being added /// @param claim The claim being added
...@@ -49,9 +70,9 @@ interface IOutputBisectionGame is IDisputeGame { ...@@ -49,9 +70,9 @@ interface IOutputBisectionGame is IDisputeGame {
/// @notice Posts the requested local data to the VM's `PreimageOralce`. /// @notice Posts the requested local data to the VM's `PreimageOralce`.
/// @param _ident The local identifier of the data to post. /// @param _ident The local identifier of the data to post.
/// @param _execLeafIdx The index of the leaf claim in an execution subgame that requires the local data for a step. /// @param _localContext The local context for the `PreimageOracle` key.
/// @param _partOffset The offset of the data to post. /// @param _partOffset The offset of the data to post.
function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external; function addLocalData(uint256 _ident, bytes32 _localContext, uint256 _partOffset) external;
/// @notice Resolves the subgame rooted at the given claim index. /// @notice Resolves the subgame rooted at the given claim index.
/// @dev This function must be called bottom-up in the DAG /// @dev This function must be called bottom-up in the DAG
...@@ -61,9 +82,15 @@ interface IOutputBisectionGame is IDisputeGame { ...@@ -61,9 +82,15 @@ interface IOutputBisectionGame is IDisputeGame {
/// @param _claimIndex The index of the subgame root claim to resolve. /// @param _claimIndex The index of the subgame root claim to resolve.
function resolveClaim(uint256 _claimIndex) external payable; function resolveClaim(uint256 _claimIndex) external payable;
/// @notice A block hash on the L1 that contains the disputed output root. /// @notice An L1 block hash that contains the disputed output root, fetched from the
/// `BlockOracle` and verified by referencing the timestamp associated with the
/// first L2 Output Proposal in the `L2OutputOracle` that contains the disputed
/// L2 block number.
function l1Head() external view returns (Hash l1Head_); function l1Head() external view returns (Hash l1Head_);
/// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`. /// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`.
function l2BlockNumber() external view returns (uint256 l2BlockNumber_); function l2BlockNumber() external view returns (uint256 l2BlockNumber_);
/// @notice The l1BlockNumber that Cannon was ran from to generate the root claim.
function l1BlockNumber() external view returns (uint256 l1BlockNumber_);
} }
...@@ -84,26 +84,7 @@ error ClaimAboveSplit(); ...@@ -84,26 +84,7 @@ error ClaimAboveSplit();
error InvalidSplitDepth(); error InvalidSplitDepth();
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// `AttestationDisputeGame` Errors // // `BlockOracle` Errors (Legacy) //
////////////////////////////////////////////////////////////////
/// @notice Thrown when an invalid signature is submitted to `challenge`.
error InvalidSignature();
/// @notice Thrown when a signature that has already been used to support the
/// `rootClaim` is submitted to `challenge`.
error AlreadyChallenged();
////////////////////////////////////////////////////////////////
// `Ownable` Errors //
////////////////////////////////////////////////////////////////
/// @notice Thrown when a function that is protected by the `onlyOwner` modifier
/// is called from an account other than the owner.
error NotOwner();
////////////////////////////////////////////////////////////////
// `BlockOracle` Errors //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// @notice Thrown when a block that is out of the range of the `BLOCKHASH` opcode /// @notice Thrown when a block that is out of the range of the `BLOCKHASH` opcode
......
...@@ -82,13 +82,6 @@ library GameTypes { ...@@ -82,13 +82,6 @@ library GameTypes {
/// @dev A dispute game type the uses the cannon vm. /// @dev A dispute game type the uses the cannon vm.
GameType internal constant CANNON = GameType.wrap(0); GameType internal constant CANNON = GameType.wrap(0);
/// @dev A dispute game type that performs output bisection and then uses the cannon vm.
GameType internal constant OUTPUT_CANNON = GameType.wrap(1);
/// @notice A dispute game type that performs output bisection and then uses an alphabet vm.
/// Not intended for production use.
GameType internal constant OUTPUT_ALPHABET = GameType.wrap(254);
/// @notice A dispute game type that uses an alphabet vm. /// @notice A dispute game type that uses an alphabet vm.
/// Not intended for production use. /// Not intended for production use.
GameType internal constant ALPHABET = GameType.wrap(255); GameType internal constant ALPHABET = GameType.wrap(255);
......
This diff is collapsed.
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