Skip to content

Commit

Permalink
feat(op-challenger): sort the games listing subcommand (ethereum-opti…
Browse files Browse the repository at this point in the history
  • Loading branch information
refcell authored May 8, 2024
1 parent 7e2bb8a commit 700a1db
Showing 1 changed file with 63 additions and 8 deletions.
71 changes: 63 additions & 8 deletions op-challenger/cmd/list_games.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"cmp"
"context"
"fmt"
"slices"
Expand All @@ -14,13 +15,30 @@ import (
opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/dial"
openum "github.com/ethereum-optimism/optimism/op-service/enum"
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/rpcblock"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
)

var ColumnTypes = []string{"time", "claimCount", "l2BlockNum"}

var (
SortByFlag = &cli.StringFlag{
Name: "sort-by",
Usage: "Sort games by column. Valid options: " + openum.EnumString(ColumnTypes),
EnvVars: opservice.PrefixEnvVar(flags.EnvVarPrefix, "SORT_BY"),
}
SortOrderFlag = &cli.StringFlag{
Name: "sort-order",
Usage: "Sort order for games. Valid options: 'asc' or 'desc'.",
Value: "asc",
EnvVars: opservice.PrefixEnvVar(flags.EnvVarPrefix, "SORT_ORDER"),
}
)

func ListGames(ctx *cli.Context) error {
logger, err := setupLogging(ctx)
if err != nil {
Expand All @@ -34,6 +52,14 @@ func ListGames(ctx *cli.Context) error {
if err != nil {
return err
}
sortBy := ctx.String(SortByFlag.Name)
if !slices.Contains(ColumnTypes, sortBy) {
return fmt.Errorf("invalid sort-by value: %v", sortBy)
}
sortOrder := ctx.String(SortOrderFlag.Name)
if sortOrder != "" && sortOrder != "asc" && sortOrder != "desc" {
return fmt.Errorf("invalid sort-order value: %v", sortOrder)
}

gameWindow := ctx.Duration(flags.GameWindowFlag.Name)

Expand All @@ -49,7 +75,7 @@ func ListGames(ctx *cli.Context) error {
if err != nil {
return fmt.Errorf("failed to retrieve current head block: %w", err)
}
return listGames(ctx.Context, caller, contract, head.Hash(), gameWindow)
return listGames(ctx.Context, caller, contract, head.Hash(), gameWindow, sortBy, sortOrder)
}

type gameInfo struct {
Expand All @@ -61,24 +87,25 @@ type gameInfo struct {
err error
}

func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contracts.DisputeGameFactoryContract, block common.Hash, gameWindow time.Duration) error {
func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contracts.DisputeGameFactoryContract, block common.Hash, gameWindow time.Duration, sortBy, sortOrder string) error {
earliestTimestamp := clock.MinCheckedTimestamp(clock.SystemClock, gameWindow)
games, err := factory.GetGamesAtOrAfter(ctx, block, earliestTimestamp)
if err != nil {
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
for idx, game := range games {
gameContract, err := contracts.NewFaultDisputeGameContract(ctx, metrics.NoopContractMetrics, game.Proxy, caller)
if err != nil {
return fmt.Errorf("failed to create dispute game contract: %w", err)
}
info := gameInfo{GameMetadata: game}
infos[idx] = &info
infos[idx] = info
gameProxy := game.Proxy
currIndex := idx
wg.Add(1)
go func() {
defer wg.Done()
Expand All @@ -87,20 +114,46 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr
info.err = fmt.Errorf("failed to retrieve metadata for game %v: %w", gameProxy, err)
return
}
info.status = status
info.l2BlockNum = l2BlockNum
info.rootClaim = rootClaim
infos[currIndex].status = status
infos[currIndex].l2BlockNum = l2BlockNum
infos[currIndex].rootClaim = rootClaim
claimCount, err := gameContract.GetClaimCount(ctx)
if err != nil {
info.err = fmt.Errorf("failed to retrieve claim count for game %v: %w", gameProxy, err)
return
}
info.claimCount = claimCount
infos[currIndex].claimCount = claimCount
}()
}
wg.Wait()
lineFormat := "%3v %-42v %4v %-21v %14v %-66v %6v %-14v\n"
fmt.Printf(lineFormat, "Idx", "Game", "Type", "Created (Local)", "L2 Block", "Output Root", "Claims", "Status")

// Sort infos by the specified column
switch sortBy {
case "time":
slices.SortFunc(infos, func(i, j gameInfo) int {
if sortOrder == "desc" {
return cmp.Compare(j.Timestamp, i.Timestamp)
}
return cmp.Compare(i.Timestamp, j.Timestamp)
})
case "claimCount":
slices.SortFunc(infos, func(i, j gameInfo) int {
if sortOrder == "desc" {
return cmp.Compare(j.claimCount, i.claimCount)
}
return cmp.Compare(i.claimCount, j.claimCount)
})
case "l2BlockNum":
slices.SortFunc(infos, func(i, j gameInfo) int {
if sortOrder == "desc" {
return cmp.Compare(j.l2BlockNum, i.l2BlockNum)
}
return cmp.Compare(i.l2BlockNum, j.l2BlockNum)
})
}

for _, game := range infos {
if game.err != nil {
return game.err
Expand All @@ -114,6 +167,8 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr

func listGamesFlags() []cli.Flag {
cliFlags := []cli.Flag{
SortByFlag,
SortOrderFlag,
flags.L1EthRpcFlag,
flags.FactoryAddressFlag,
flags.GameWindowFlag,
Expand Down

0 comments on commit 700a1db

Please sign in to comment.