Commit 5a829ce7 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Apply game window to list-games (#10336)

Avoids it getting increasingly slower over time.
parent 98afa5b4
...@@ -3,6 +3,7 @@ package main ...@@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"slices"
"sync" "sync"
"time" "time"
...@@ -11,6 +12,7 @@ import ( ...@@ -11,6 +12,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/game/types" "github.com/ethereum-optimism/optimism/op-challenger/game/types"
opservice "github.com/ethereum-optimism/optimism/op-service" opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/dial"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
...@@ -33,6 +35,8 @@ func ListGames(ctx *cli.Context) error { ...@@ -33,6 +35,8 @@ func ListGames(ctx *cli.Context) error {
return err return err
} }
gameWindow := ctx.Duration(flags.GameWindowFlag.Name)
l1Client, err := dial.DialEthClientWithTimeout(ctx.Context, dial.DefaultDialTimeout, logger, rpcUrl) l1Client, err := dial.DialEthClientWithTimeout(ctx.Context, dial.DefaultDialTimeout, logger, rpcUrl)
if err != nil { if err != nil {
return fmt.Errorf("failed to dial L1: %w", err) return fmt.Errorf("failed to dial L1: %w", err)
...@@ -45,7 +49,7 @@ func ListGames(ctx *cli.Context) error { ...@@ -45,7 +49,7 @@ func ListGames(ctx *cli.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve current head block: %w", err) return fmt.Errorf("failed to retrieve current head block: %w", err)
} }
return listGames(ctx.Context, caller, contract, head.Hash()) return listGames(ctx.Context, caller, contract, head.Hash(), gameWindow)
} }
type gameInfo struct { type gameInfo struct {
...@@ -57,11 +61,13 @@ type gameInfo struct { ...@@ -57,11 +61,13 @@ type gameInfo struct {
err error err error
} }
func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contracts.DisputeGameFactoryContract, block common.Hash) error { func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contracts.DisputeGameFactoryContract, block common.Hash, gameWindow time.Duration) error {
games, err := factory.GetAllGames(ctx, block) earliestTimestamp := clock.MinCheckedTimestamp(clock.SystemClock, gameWindow)
games, err := factory.GetGamesAtOrAfter(ctx, block, earliestTimestamp)
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve games: %w", err) return fmt.Errorf("failed to retrieve games: %w", err)
} }
slices.Reverse(games)
infos := make([]*gameInfo, len(games)) infos := make([]*gameInfo, len(games))
var wg sync.WaitGroup var wg sync.WaitGroup
...@@ -95,13 +101,13 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr ...@@ -95,13 +101,13 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr
wg.Wait() wg.Wait()
lineFormat := "%3v %-42v %4v %-21v %14v %-66v %6v %-14v\n" lineFormat := "%3v %-42v %4v %-21v %14v %-66v %6v %-14v\n"
fmt.Printf(lineFormat, "Idx", "Game", "Type", "Created (Local)", "L2 Block", "Output Root", "Claims", "Status") fmt.Printf(lineFormat, "Idx", "Game", "Type", "Created (Local)", "L2 Block", "Output Root", "Claims", "Status")
for idx, game := range infos { for _, game := range infos {
if game.err != nil { if game.err != nil {
return game.err return game.err
} }
created := time.Unix(int64(game.Timestamp), 0).Format(time.DateTime) created := time.Unix(int64(game.Timestamp), 0).Format(time.DateTime)
fmt.Printf(lineFormat, fmt.Printf(lineFormat,
idx, game.Proxy, game.GameType, created, game.l2BlockNum, game.rootClaim, game.claimCount, game.status) game.Index, game.Proxy, game.GameType, created, game.l2BlockNum, game.rootClaim, game.claimCount, game.status)
} }
return nil return nil
} }
...@@ -110,6 +116,7 @@ func listGamesFlags() []cli.Flag { ...@@ -110,6 +116,7 @@ func listGamesFlags() []cli.Flag {
cliFlags := []cli.Flag{ cliFlags := []cli.Flag{
flags.L1EthRpcFlag, flags.L1EthRpcFlag,
flags.FactoryAddressFlag, flags.FactoryAddressFlag,
flags.GameWindowFlag,
} }
cliFlags = append(cliFlags, oplog.CLIFlags("OP_CHALLENGER")...) cliFlags = append(cliFlags, oplog.CLIFlags("OP_CHALLENGER")...)
return cliFlags return cliFlags
......
...@@ -73,7 +73,7 @@ func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, bl ...@@ -73,7 +73,7 @@ func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, bl
if err != nil { if err != nil {
return types.GameMetadata{}, fmt.Errorf("failed to load game %v: %w", idx, err) return types.GameMetadata{}, fmt.Errorf("failed to load game %v: %w", idx, err)
} }
return f.decodeGame(result), nil return f.decodeGame(idx, result), nil
} }
func (f *DisputeGameFactoryContract) GetGameImpl(ctx context.Context, gameType uint32) (common.Address, error) { func (f *DisputeGameFactoryContract) GetGameImpl(ctx context.Context, gameType uint32) (common.Address, error) {
...@@ -118,8 +118,9 @@ func (f *DisputeGameFactoryContract) GetGamesAtOrAfter(ctx context.Context, bloc ...@@ -118,8 +118,9 @@ func (f *DisputeGameFactoryContract) GetGamesAtOrAfter(ctx context.Context, bloc
return nil, fmt.Errorf("failed to fetch games: %w", err) return nil, fmt.Errorf("failed to fetch games: %w", err)
} }
for _, result := range results { for i, result := range results {
game := f.decodeGame(result) idx := rangeEnd - uint64(i) - 1
game := f.decodeGame(idx, result)
if game.Timestamp < earliestTimestamp { if game.Timestamp < earliestTimestamp {
return games, nil return games, nil
} }
...@@ -147,8 +148,8 @@ func (f *DisputeGameFactoryContract) GetAllGames(ctx context.Context, blockHash ...@@ -147,8 +148,8 @@ func (f *DisputeGameFactoryContract) GetAllGames(ctx context.Context, blockHash
} }
var games []types.GameMetadata var games []types.GameMetadata
for _, result := range results { for i, result := range results {
games = append(games, f.decodeGame(result)) games = append(games, f.decodeGame(uint64(i), result))
} }
return games, nil return games, nil
} }
...@@ -189,11 +190,12 @@ func (f *DisputeGameFactoryContract) DecodeDisputeGameCreatedLog(rcpt *ethTypes. ...@@ -189,11 +190,12 @@ func (f *DisputeGameFactoryContract) DecodeDisputeGameCreatedLog(rcpt *ethTypes.
return common.Address{}, 0, common.Hash{}, fmt.Errorf("%w: %v", ErrEventNotFound, eventDisputeGameCreated) return common.Address{}, 0, common.Hash{}, fmt.Errorf("%w: %v", ErrEventNotFound, eventDisputeGameCreated)
} }
func (f *DisputeGameFactoryContract) decodeGame(result *batching.CallResult) types.GameMetadata { func (f *DisputeGameFactoryContract) decodeGame(idx uint64, result *batching.CallResult) types.GameMetadata {
gameType := result.GetUint32(0) gameType := result.GetUint32(0)
timestamp := result.GetUint64(1) timestamp := result.GetUint64(1)
proxy := result.GetAddress(2) proxy := result.GetAddress(2)
return types.GameMetadata{ return types.GameMetadata{
Index: idx,
GameType: gameType, GameType: gameType,
Timestamp: timestamp, Timestamp: timestamp,
Proxy: proxy, Proxy: proxy,
......
...@@ -61,16 +61,19 @@ func TestLoadGame(t *testing.T) { ...@@ -61,16 +61,19 @@ func TestLoadGame(t *testing.T) {
blockHash := common.Hash{0xbb, 0xce} blockHash := common.Hash{0xbb, 0xce}
stubRpc, factory := setupDisputeGameFactoryTest(t) stubRpc, factory := setupDisputeGameFactoryTest(t)
game0 := types.GameMetadata{ game0 := types.GameMetadata{
Index: 0,
GameType: 0, GameType: 0,
Timestamp: 1234, Timestamp: 1234,
Proxy: common.Address{0xaa}, Proxy: common.Address{0xaa},
} }
game1 := types.GameMetadata{ game1 := types.GameMetadata{
Index: 1,
GameType: 1, GameType: 1,
Timestamp: 5678, Timestamp: 5678,
Proxy: common.Address{0xbb}, Proxy: common.Address{0xbb},
} }
game2 := types.GameMetadata{ game2 := types.GameMetadata{
Index: 2,
GameType: 99, GameType: 99,
Timestamp: 9988, Timestamp: 9988,
Proxy: common.Address{0xcc}, Proxy: common.Address{0xcc},
...@@ -88,16 +91,19 @@ func TestGetAllGames(t *testing.T) { ...@@ -88,16 +91,19 @@ func TestGetAllGames(t *testing.T) {
blockHash := common.Hash{0xbb, 0xce} blockHash := common.Hash{0xbb, 0xce}
stubRpc, factory := setupDisputeGameFactoryTest(t) stubRpc, factory := setupDisputeGameFactoryTest(t)
game0 := types.GameMetadata{ game0 := types.GameMetadata{
Index: 0,
GameType: 0, GameType: 0,
Timestamp: 1234, Timestamp: 1234,
Proxy: common.Address{0xaa}, Proxy: common.Address{0xaa},
} }
game1 := types.GameMetadata{ game1 := types.GameMetadata{
Index: 1,
GameType: 1, GameType: 1,
Timestamp: 5678, Timestamp: 5678,
Proxy: common.Address{0xbb}, Proxy: common.Address{0xbb},
} }
game2 := types.GameMetadata{ game2 := types.GameMetadata{
Index: 2,
GameType: 99, GameType: 99,
Timestamp: 9988, Timestamp: 9988,
Proxy: common.Address{0xcc}, Proxy: common.Address{0xcc},
...@@ -135,6 +141,7 @@ func TestGetAllGamesAtOrAfter(t *testing.T) { ...@@ -135,6 +141,7 @@ func TestGetAllGamesAtOrAfter(t *testing.T) {
var allGames []types.GameMetadata var allGames []types.GameMetadata
for i := 0; i < test.gameCount; i++ { for i := 0; i < test.gameCount; i++ {
allGames = append(allGames, types.GameMetadata{ allGames = append(allGames, types.GameMetadata{
Index: uint64(i),
GameType: uint32(i), GameType: uint32(i),
Timestamp: uint64(i), Timestamp: uint64(i),
Proxy: common.Address{byte(i)}, Proxy: common.Address{byte(i)},
......
...@@ -40,6 +40,7 @@ func GameStatusFromUint8(i uint8) (GameStatus, error) { ...@@ -40,6 +40,7 @@ func GameStatusFromUint8(i uint8) (GameStatus, error) {
} }
type GameMetadata struct { type GameMetadata struct {
Index uint64
GameType uint32 GameType uint32
Timestamp uint64 Timestamp uint64
Proxy common.Address Proxy common.Address
......
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