Commit 25c1249b authored by refcell.eth's avatar refcell.eth Committed by GitHub

Switch game address parameter to an allowlist. (#6926)

parent dbed8eed
......@@ -105,20 +105,20 @@ func TestGameFactoryAddress(t *testing.T) {
})
}
func TestGameAddress(t *testing.T) {
func TestGameAllowlist(t *testing.T) {
t.Run("Optional", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address"))
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist"))
require.NoError(t, cfg.Check())
})
t.Run("Valid", func(t *testing.T) {
addr := common.Address{0xbb, 0xcc, 0xdd}
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address", "--game-address="+addr.Hex()))
require.Equal(t, addr, cfg.GameAddress)
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist", "--game-allowlist="+addr.Hex()))
require.Contains(t, cfg.GameAllowlist, addr)
})
t.Run("Invalid", func(t *testing.T) {
verifyArgsInvalid(t, "invalid address: foo", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address", "--game-address=foo"))
verifyArgsInvalid(t, "invalid address: foo", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist", "--game-allowlist=foo"))
})
}
......
......@@ -4,11 +4,12 @@ import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
)
var (
......@@ -78,10 +79,10 @@ const DefaultCannonSnapshotFreq = uint(1_000_000_000)
// This also contains config options for auxiliary services.
// It is used to initialize the challenger.
type Config struct {
L1EthRpc string // L1 RPC Url
GameFactoryAddress common.Address // Address of the dispute game factory
GameAddress common.Address // Address of the fault game
AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output
L1EthRpc string // L1 RPC Url
GameFactoryAddress common.Address // Address of the dispute game factory
GameAllowlist []common.Address // Allowlist of fault game addresses
AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output
TraceType TraceType // Type of trace
......
......@@ -3,9 +3,10 @@ package config
import (
"testing"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
)
var (
......@@ -68,9 +69,9 @@ func TestGameFactoryAddressRequired(t *testing.T) {
require.ErrorIs(t, config.Check(), ErrMissingGameFactoryAddress)
}
func TestGameAddressNotRequired(t *testing.T) {
func TestGameAllowlistNotRequired(t *testing.T) {
config := validConfig(TraceTypeCannon)
config.GameAddress = common.Address{}
config.GameAllowlist = []common.Address{}
require.NoError(t, config.Check())
}
......
......@@ -29,22 +29,34 @@ type gameMonitor struct {
source gameSource
createPlayer playerCreator
fetchBlockNumber blockNumberFetcher
allowedGame common.Address
allowedGames []common.Address
players map[common.Address]gamePlayer
}
func newGameMonitor(logger log.Logger, cl clock.Clock, fetchBlockNumber blockNumberFetcher, allowedGame common.Address, source gameSource, createGame playerCreator) *gameMonitor {
func newGameMonitor(logger log.Logger, cl clock.Clock, fetchBlockNumber blockNumberFetcher, allowedGames []common.Address, source gameSource, createGame playerCreator) *gameMonitor {
return &gameMonitor{
logger: logger,
clock: cl,
source: source,
createPlayer: createGame,
fetchBlockNumber: fetchBlockNumber,
allowedGame: allowedGame,
allowedGames: allowedGames,
players: make(map[common.Address]gamePlayer),
}
}
func (m *gameMonitor) allowedGame(game common.Address) bool {
if len(m.allowedGames) == 0 {
return true
}
for _, allowed := range m.allowedGames {
if allowed == game {
return true
}
}
return false
}
func (m *gameMonitor) progressGames(ctx context.Context) error {
blockNum, err := m.fetchBlockNumber(ctx)
if err != nil {
......@@ -55,7 +67,7 @@ func (m *gameMonitor) progressGames(ctx context.Context) error {
return fmt.Errorf("failed to load games: %w", err)
}
for _, game := range games {
if m.allowedGame != (common.Address{}) && m.allowedGame != game.Proxy {
if !m.allowedGame(game.Proxy) {
m.logger.Debug("Skipping game not on allow list", "game", game.Proxy)
continue
}
......
......@@ -14,7 +14,7 @@ import (
)
func TestMonitorExitsWhenContextDone(t *testing.T) {
monitor, _, _ := setupMonitorTest(t, common.Address{})
monitor, _, _ := setupMonitorTest(t, []common.Address{common.Address{}})
ctx, cancel := context.WithCancel(context.Background())
cancel()
err := monitor.MonitorGames(ctx)
......@@ -22,7 +22,7 @@ func TestMonitorExitsWhenContextDone(t *testing.T) {
}
func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
monitor, source, games := setupMonitorTest(t, common.Address{})
monitor, source, games := setupMonitorTest(t, []common.Address{})
addr1 := common.Address{0xaa}
addr2 := common.Address{0xbb}
......@@ -55,7 +55,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
addr1 := common.Address{0xaa}
addr2 := common.Address{0xbb}
monitor, source, games := setupMonitorTest(t, addr2)
monitor, source, games := setupMonitorTest(t, []common.Address{addr2})
source.games = []FaultDisputeGame{
{
......@@ -77,7 +77,7 @@ func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
require.Equal(t, 1, games.created[addr2].progressCount)
}
func setupMonitorTest(t *testing.T, allowedGame common.Address) (*gameMonitor, *stubGameSource, *createdGames) {
func setupMonitorTest(t *testing.T, allowedGames []common.Address) (*gameMonitor, *stubGameSource, *createdGames) {
logger := testlog.Logger(t, log.LvlDebug)
source := &stubGameSource{}
games := &createdGames{
......@@ -87,7 +87,7 @@ func setupMonitorTest(t *testing.T, allowedGame common.Address) (*gameMonitor, *
fetchBlockNum := func(ctx context.Context) (uint64, error) {
return 1234, nil
}
monitor := newGameMonitor(logger, clock.SystemClock, fetchBlockNum, allowedGame, source, games.CreateGame)
monitor := newGameMonitor(logger, clock.SystemClock, fetchBlockNum, allowedGames, source, games.CreateGame)
return monitor, source, games
}
......
......@@ -73,7 +73,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se
}
loader := NewGameLoader(factory)
monitor := newGameMonitor(logger, cl, client.BlockNumber, cfg.GameAddress, loader, func(addr common.Address) (gamePlayer, error) {
monitor := newGameMonitor(logger, cl, client.BlockNumber, cfg.GameAllowlist, loader, func(addr common.Address) (gamePlayer, error) {
return NewGamePlayer(ctx, logger, cfg, addr, txMgr, client)
})
......
......@@ -4,6 +4,9 @@ import (
"fmt"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
opservice "github.com/ethereum-optimism/optimism/op-service"
......@@ -12,9 +15,6 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
)
const (
......@@ -37,10 +37,11 @@ var (
Usage: "Address of the fault game factory contract.",
EnvVars: prefixEnvVars("GAME_FACTORY_ADDRESS"),
}
GameAddressFlag = &cli.StringFlag{
Name: "game-address",
Usage: "Address of the Fault Game contract.",
EnvVars: prefixEnvVars("GAME_ADDRESS"),
GameAllowlistFlag = &cli.StringSliceFlag{
Name: "game-allowlist",
Usage: "List of Fault Game contract addresses the challenger is allowed to play. " +
"If empty, the challenger will play all games.",
EnvVars: prefixEnvVars("GAME_ALLOWLIST"),
}
TraceTypeFlag = &cli.GenericFlag{
Name: "trace-type",
......@@ -121,7 +122,7 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{
AlphabetFlag,
GameAddressFlag,
GameAllowlistFlag,
CannonNetworkFlag,
CannonRollupConfigFlag,
CannonL2GenesisFlag,
......@@ -154,11 +155,13 @@ func CheckRequired(ctx *cli.Context) error {
gameType := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name)))
switch gameType {
case config.TraceTypeCannon:
if !ctx.IsSet(CannonNetworkFlag.Name) && !(ctx.IsSet(CannonRollupConfigFlag.Name) && ctx.IsSet(CannonL2GenesisFlag.Name)) {
if !ctx.IsSet(CannonNetworkFlag.Name) &&
!(ctx.IsSet(CannonRollupConfigFlag.Name) && ctx.IsSet(CannonL2GenesisFlag.Name)) {
return fmt.Errorf("flag %v or %v and %v is required",
CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name)
}
if ctx.IsSet(CannonNetworkFlag.Name) && (ctx.IsSet(CannonRollupConfigFlag.Name) || ctx.IsSet(CannonL2GenesisFlag.Name)) {
if ctx.IsSet(CannonNetworkFlag.Name) &&
(ctx.IsSet(CannonRollupConfigFlag.Name) || ctx.IsSet(CannonL2GenesisFlag.Name)) {
return fmt.Errorf("flag %v can not be used with %v and %v",
CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name)
}
......@@ -196,11 +199,14 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
if err != nil {
return nil, err
}
var gameAddress common.Address
if ctx.IsSet(GameAddressFlag.Name) {
gameAddress, err = opservice.ParseAddress(ctx.String(GameAddressFlag.Name))
if err != nil {
return nil, err
var allowedGames []common.Address
if ctx.StringSlice(GameAllowlistFlag.Name) != nil {
for _, addr := range ctx.StringSlice(GameAllowlistFlag.Name) {
gameAddress, err := opservice.ParseAddress(addr)
if err != nil {
return nil, err
}
allowedGames = append(allowedGames, gameAddress)
}
}
......@@ -215,7 +221,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
L1EthRpc: ctx.String(L1EthRpcFlag.Name),
TraceType: traceTypeFlag,
GameFactoryAddress: gameFactoryAddress,
GameAddress: gameAddress,
GameAllowlist: allowedGames,
AlphabetTrace: ctx.String(AlphabetFlag.Name),
CannonNetwork: ctx.String(CannonNetworkFlag.Name),
CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name),
......
......@@ -38,7 +38,10 @@ func WithFactoryAddress(addr common.Address) Option {
func WithGameAddress(addr common.Address) Option {
return func(c *config.Config) {
c.GameAddress = addr
if c.GameAllowlist == nil {
c.GameAllowlist = make([]common.Address, 0)
}
c.GameAllowlist = append(c.GameAllowlist, addr)
}
}
......
......@@ -5,6 +5,8 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum/go-ethereum/common"
)
type AlphabetGameHelper struct {
......@@ -16,7 +18,7 @@ func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint str
opts := []challenger.Option{
func(c *config.Config) {
c.GameFactoryAddress = g.factoryAddr
c.GameAddress = g.addr
c.GameAllowlist = []common.Address{g.addr}
c.TraceType = config.TraceTypeAlphabet
// By default the challenger agrees with the root claim (thus disagrees with the proposed output)
// This can be overridden by passing in options
......
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