Commit 918459c4 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

Merge pull request #8364 from ethereum-optimism/refcell/output-alphabet

feat(op-challenger): alphabet output bisection game
parents 69bdcd56 73668c11
......@@ -468,6 +468,8 @@ func requiredArgs(traceType config.TraceType) map[string]string {
addRequiredCannonArgs(args)
case config.TraceTypeOutputCannon:
addRequiredOutputCannonArgs(args)
case config.TraceTypeOutputAlphabet:
addRequiredOutputAlphabetArgs(args)
}
return args
}
......@@ -476,8 +478,16 @@ 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
}
......
......@@ -43,6 +43,7 @@ const (
TraceTypeAlphabet TraceType = "alphabet"
TraceTypeCannon TraceType = "cannon"
TraceTypeOutputCannon TraceType = "output_cannon"
TraceTypeOutputAlphabet TraceType = "output_alphabet"
// Mainnet games
CannonFaultGameID = 0
......@@ -51,7 +52,7 @@ const (
AlphabetFaultGameID = 255
)
var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon, TraceTypeOutputCannon}
var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon, TraceTypeOutputCannon, TraceTypeOutputAlphabet}
// GameIdToString maps game IDs to their string representation.
var GameIdToString = map[uint8]string{
......@@ -179,10 +180,13 @@ func (c Config) Check() error {
if c.MaxConcurrency == 0 {
return ErrMaxConcurrencyZero
}
if c.TraceTypeEnabled(TraceTypeOutputCannon) {
if c.TraceTypeEnabled(TraceTypeOutputCannon) || c.TraceTypeEnabled(TraceTypeOutputAlphabet) {
if c.RollupRpc == "" {
return ErrMissingRollupRpc
}
if c.TraceTypeEnabled(TraceTypeCannon) && (c.TraceTypeEnabled(TraceTypeOutputCannon) || c.TraceTypeEnabled(TraceTypeOutputAlphabet)) {
return ErrCannonAndOutputCannonConflict
}
}
if c.TraceTypeEnabled(TraceTypeCannon) && c.TraceTypeEnabled(TraceTypeOutputCannon) {
return ErrCannonAndOutputCannonConflict
......
......@@ -35,7 +35,7 @@ func validConfig(traceType TraceType) Config {
cfg.CannonL2 = validCannonL2
cfg.CannonNetwork = validCannonNetwork
}
if traceType == TraceTypeOutputCannon {
if traceType == TraceTypeOutputCannon || traceType == TraceTypeOutputAlphabet {
cfg.RollupRpc = validRollupRpc
}
return cfg
......@@ -84,6 +84,12 @@ func TestAlphabetTraceRequired(t *testing.T) {
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) {
config := validConfig(TraceTypeCannon)
config.CannonBin = ""
......@@ -128,12 +134,18 @@ func TestHttpPollInterval(t *testing.T) {
})
}
func TestRollupRpcRequired(t *testing.T) {
func TestRollupRpcRequired_OutputCannon(t *testing.T) {
config := validConfig(TraceTypeOutputCannon)
config.RollupRpc = ""
require.ErrorIs(t, config.Check(), ErrMissingRollupRpc)
}
func TestRollupRpcRequired_OutputAlphabet(t *testing.T) {
config := validConfig(TraceTypeOutputAlphabet)
config.RollupRpc = ""
require.ErrorIs(t, config.Check(), ErrMissingRollupRpc)
}
func TestCannotEnableBothCannonAndOutputCannonTraceTypes(t *testing.T) {
config := validConfig(TraceTypeOutputCannon)
config.TraceTypes = append(config.TraceTypes, TraceTypeCannon)
......
......@@ -224,6 +224,10 @@ func CheckRequired(ctx *cli.Context, traceTypes []config.TraceType) error {
if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
}
case config.TraceTypeOutputAlphabet:
if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
}
default:
return fmt.Errorf("invalid trace type. must be one of %v", config.TraceTypes)
}
......
......@@ -23,7 +23,8 @@ import (
var (
cannonGameType = uint8(0)
outputCannonGameType = uint8(0) // TODO(client-pod#43): This should be a unique game type
outputCannonGameType = uint8(0) // TODO(client-pod#260): Switch the output cannon game type to 1
outputAlphabetGameType = uint8(254)
alphabetGameType = uint8(255)
)
......@@ -55,6 +56,9 @@ func RegisterGameTypes(
if cfg.TraceTypeEnabled(config.TraceTypeOutputCannon) {
registerOutputCannon(registry, ctx, logger, m, cfg, txMgr, caller, l2Client)
}
if cfg.TraceTypeEnabled(config.TraceTypeOutputAlphabet) {
registerOutputAlphabet(registry, ctx, logger, m, cfg, txMgr, caller, l2Client)
}
if cfg.TraceTypeEnabled(config.TraceTypeCannon) {
registerCannon(registry, ctx, logger, m, cfg, txMgr, caller, l2Client)
}
......@@ -64,6 +68,61 @@ func RegisterGameTypes(
return closer, nil
}
func registerOutputAlphabet(
registry Registry,
ctx context.Context,
logger log.Logger,
m metrics.Metricer,
cfg *config.Config,
txMgr txmgr.TxManager,
caller *batching.MultiCaller,
l2Client cannon.L2HeaderSource) {
resourceCreator := func(addr common.Address) (gameTypeResources, error) {
contract, err := contracts.NewOutputBisectionGameContract(addr, caller)
if err != nil {
return nil, err
}
return &outputAlphabetResources{
m: m,
cfg: cfg,
l2Client: l2Client,
contract: contract,
}, nil
}
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txMgr, resourceCreator)
}
registry.RegisterGameType(outputAlphabetGameType, playerCreator)
}
type outputAlphabetResources struct {
m metrics.Metricer
cfg *config.Config
l2Client cannon.L2HeaderSource
contract *contracts.OutputBisectionGameContract
}
func (r *outputAlphabetResources) Contract() GameContract {
return r.contract
}
func (r *outputAlphabetResources) CreateAccessor(ctx context.Context, logger log.Logger, gameDepth uint64, dir string) (faultTypes.TraceAccessor, error) {
// TODO(client-pod#44): Validate absolute pre-state for split games
prestateBlock, poststateBlock, err := r.contract.GetBlockRange(ctx)
if err != nil {
return nil, err
}
splitDepth, err := r.contract.GetSplitDepth(ctx)
if err != nil {
return nil, err
}
accessor, err := outputs.NewOutputAlphabetTraceAccessor(ctx, logger, r.m, r.cfg, gameDepth, splitDepth, prestateBlock, poststateBlock)
if err != nil {
return nil, err
}
return accessor, nil
}
func registerOutputCannon(
registry Registry,
ctx context.Context,
......@@ -97,7 +156,7 @@ type outputCannonResources struct {
m metrics.Metricer
cfg *config.Config
l2Client cannon.L2HeaderSource
contract *contracts.FaultDisputeGameContract
contract *contracts.FaultDisputeGameContract // TODO(client-pod#260): Use the OutputBisectionGame Contract
}
func (r *outputCannonResources) Contract() GameContract {
......
package outputs
import (
"context"
"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/trace"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/split"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
func NewOutputAlphabetTraceAccessor(
ctx context.Context,
logger log.Logger,
m metrics.Metricer,
cfg *config.Config,
gameDepth uint64,
splitDepth uint64,
prestateBlock uint64,
poststateBlock uint64,
) (*trace.Accessor, error) {
bottomDepth := gameDepth - splitDepth
outputProvider, err := NewTraceProvider(ctx, logger, cfg.RollupRpc, splitDepth, prestateBlock, poststateBlock)
if err != nil {
return nil, err
}
alphabetCreator := func(ctx context.Context, localContext common.Hash, agreed contracts.Proposal, claimed contracts.Proposal) (types.TraceProvider, error) {
provider := alphabet.NewTraceProvider(localContext.Hex(), bottomDepth)
return provider, nil
}
cache := NewProviderCache(m, "output_alphabet_provider", alphabetCreator)
selector := split.NewSplitProviderSelector(outputProvider, int(splitDepth), OutputRootSplitAdapter(outputProvider, cache.GetOrCreate))
return trace.NewAccessor(selector), nil
}
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