Commit 4af4a302 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Add timer metrics for acting on games and attempting to resolve claims (#9934)

* op-challenger: Add timer metrics for acting on games and attempting to resolve claims.

* op-challenger: Add metrics for contract interactions
parent af9aa336
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/flags" "github.com/ethereum-optimism/optimism/op-challenger/flags"
"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/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
opservice "github.com/ethereum-optimism/optimism/op-service" opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/dial"
...@@ -47,7 +48,7 @@ func ListClaims(ctx *cli.Context) error { ...@@ -47,7 +48,7 @@ func ListClaims(ctx *cli.Context) error {
defer l1Client.Close() defer l1Client.Close()
caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize)
contract, err := contracts.NewFaultDisputeGameContract(gameAddr, caller) contract, err := contracts.NewFaultDisputeGameContract(metrics.NoopContractMetrics, gameAddr, caller)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/flags" "github.com/ethereum-optimism/optimism/op-challenger/flags"
"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/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/dial" "github.com/ethereum-optimism/optimism/op-service/dial"
...@@ -39,7 +40,7 @@ func ListGames(ctx *cli.Context) error { ...@@ -39,7 +40,7 @@ func ListGames(ctx *cli.Context) error {
defer l1Client.Close() defer l1Client.Close()
caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize)
contract, err := contracts.NewDisputeGameFactoryContract(factoryAddr, caller) contract, err := contracts.NewDisputeGameFactoryContract(metrics.NoopContractMetrics, factoryAddr, caller)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
...@@ -68,7 +69,7 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr ...@@ -68,7 +69,7 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr
infos := make([]*gameInfo, len(games)) infos := make([]*gameInfo, len(games))
var wg sync.WaitGroup var wg sync.WaitGroup
for idx, game := range games { for idx, game := range games {
gameContract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller) gameContract, err := contracts.NewFaultDisputeGameContract(metrics.NoopContractMetrics, game.Proxy, caller)
if err != nil { if err != nil {
return fmt.Errorf("failed to bind game contract at %v: %w", game.Proxy, err) return fmt.Errorf("failed to bind game contract at %v: %w", game.Proxy, err)
} }
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/op-challenger/flags" "github.com/ethereum-optimism/optimism/op-challenger/flags"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
opservice "github.com/ethereum-optimism/optimism/op-service" opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/dial"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
...@@ -13,7 +14,7 @@ import ( ...@@ -13,7 +14,7 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
type ContractCreator[T any] func(common.Address, *batching.MultiCaller) (T, error) type ContractCreator[T any] func(contractMetrics.ContractMetricer, common.Address, *batching.MultiCaller) (T, error)
// NewContractWithTxMgr creates a new contract and a transaction manager. // NewContractWithTxMgr creates a new contract and a transaction manager.
func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator ContractCreator[T]) (T, txmgr.TxManager, error) { func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator ContractCreator[T]) (T, txmgr.TxManager, error) {
...@@ -39,7 +40,7 @@ func newContractFromCLI[T any](ctx *cli.Context, flagName string, caller *batchi ...@@ -39,7 +40,7 @@ func newContractFromCLI[T any](ctx *cli.Context, flagName string, caller *batchi
return contract, err return contract, err
} }
created, err := creator(gameAddr, caller) created, err := creator(contractMetrics.NoopContractMetrics, gameAddr, caller)
if err != nil { if err != nil {
return contract, fmt.Errorf("failed to create dispute game bindings: %w", err) return contract, fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -32,6 +33,7 @@ type ClaimLoader interface { ...@@ -32,6 +33,7 @@ type ClaimLoader interface {
type Agent struct { type Agent struct {
metrics metrics.Metricer metrics metrics.Metricer
cl clock.Clock
solver *solver.GameSolver solver *solver.GameSolver
loader ClaimLoader loader ClaimLoader
responder Responder responder Responder
...@@ -43,6 +45,7 @@ type Agent struct { ...@@ -43,6 +45,7 @@ type Agent struct {
func NewAgent( func NewAgent(
m metrics.Metricer, m metrics.Metricer,
cl clock.Clock,
loader ClaimLoader, loader ClaimLoader,
maxDepth types.Depth, maxDepth types.Depth,
trace types.TraceAccessor, trace types.TraceAccessor,
...@@ -53,6 +56,7 @@ func NewAgent( ...@@ -53,6 +56,7 @@ func NewAgent(
) *Agent { ) *Agent {
return &Agent{ return &Agent{
metrics: m, metrics: m,
cl: cl,
solver: solver.NewGameSolver(maxDepth, trace), solver: solver.NewGameSolver(maxDepth, trace),
loader: loader, loader: loader,
responder: responder, responder: responder,
...@@ -69,6 +73,10 @@ func (a *Agent) Act(ctx context.Context) error { ...@@ -69,6 +73,10 @@ func (a *Agent) Act(ctx context.Context) error {
return nil return nil
} }
start := a.cl.Now()
defer func() {
a.metrics.RecordGameActTime(a.cl.Since(start).Seconds())
}()
game, err := a.newGameFromContracts(ctx) game, err := a.newGameFromContracts(ctx)
if err != nil { if err != nil {
return fmt.Errorf("create game from contracts: %w", err) return fmt.Errorf("create game from contracts: %w", err)
...@@ -188,6 +196,10 @@ func (a *Agent) tryResolveClaims(ctx context.Context) error { ...@@ -188,6 +196,10 @@ func (a *Agent) tryResolveClaims(ctx context.Context) error {
} }
func (a *Agent) resolveClaims(ctx context.Context) error { func (a *Agent) resolveClaims(ctx context.Context) error {
start := a.cl.Now()
defer func() {
a.metrics.RecordClaimResolutionTime(a.cl.Since(start).Seconds())
}()
for { for {
err := a.tryResolveClaims(ctx) err := a.tryResolveClaims(ctx)
switch err { switch err {
......
...@@ -6,8 +6,10 @@ import ( ...@@ -6,8 +6,10 @@ import (
"math/big" "math/big"
"sync" "sync"
"testing" "testing"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -154,7 +156,8 @@ func setupTestAgent(t *testing.T) (*Agent, *stubClaimLoader, *stubResponder) { ...@@ -154,7 +156,8 @@ func setupTestAgent(t *testing.T) (*Agent, *stubClaimLoader, *stubResponder) {
depth := types.Depth(4) depth := types.Depth(4)
provider := alphabet.NewTraceProvider(big.NewInt(0), depth) provider := alphabet.NewTraceProvider(big.NewInt(0), depth)
responder := &stubResponder{} responder := &stubResponder{}
agent := NewAgent(metrics.NoopMetrics, claimLoader, depth, trace.NewSimpleTraceAccessor(provider), responder, logger, false, []common.Address{}) cl := clock.NewDeterministicClock(time.UnixMilli(0))
agent := NewAgent(metrics.NoopMetrics, cl, claimLoader, depth, trace.NewSimpleTraceAccessor(provider), responder, logger, false, []common.Address{})
return agent, claimLoader, responder return agent, claimLoader, responder
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/types" "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
...@@ -441,7 +442,7 @@ func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultD ...@@ -441,7 +442,7 @@ func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultD
stubRpc.AddContract(vmAddr, vmAbi) stubRpc.AddContract(vmAddr, vmAbi)
stubRpc.AddContract(oracleAddr, oracleAbi) stubRpc.AddContract(oracleAddr, oracleAbi)
caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize) caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize)
game, err := NewFaultDisputeGameContract(fdgAddr, caller) game, err := NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, fdgAddr, caller)
require.NoError(t, err) require.NoError(t, err)
return stubRpc, game return stubRpc, game
} }
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"math/big" "math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"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"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
...@@ -23,22 +24,25 @@ const ( ...@@ -23,22 +24,25 @@ const (
) )
type DisputeGameFactoryContract struct { type DisputeGameFactoryContract struct {
metrics metrics.ContractMetricer
multiCaller *batching.MultiCaller multiCaller *batching.MultiCaller
contract *batching.BoundContract contract *batching.BoundContract
} }
func NewDisputeGameFactoryContract(addr common.Address, caller *batching.MultiCaller) (*DisputeGameFactoryContract, error) { func NewDisputeGameFactoryContract(m metrics.ContractMetricer, addr common.Address, caller *batching.MultiCaller) (*DisputeGameFactoryContract, error) {
factoryAbi, err := bindings.DisputeGameFactoryMetaData.GetAbi() factoryAbi, err := bindings.DisputeGameFactoryMetaData.GetAbi()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load dispute game factory ABI: %w", err) return nil, fmt.Errorf("failed to load dispute game factory ABI: %w", err)
} }
return &DisputeGameFactoryContract{ return &DisputeGameFactoryContract{
metrics: m,
multiCaller: caller, multiCaller: caller,
contract: batching.NewBoundContract(factoryAbi, addr), contract: batching.NewBoundContract(factoryAbi, addr),
}, nil }, nil
} }
func (f *DisputeGameFactoryContract) GetGameFromParameters(ctx context.Context, traceType uint32, outputRoot common.Hash, l2BlockNum uint64) (common.Address, error) { func (f *DisputeGameFactoryContract) GetGameFromParameters(ctx context.Context, traceType uint32, outputRoot common.Hash, l2BlockNum uint64) (common.Address, error) {
defer f.metrics.StartContractRequest("GetGameFromParameters")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGames, traceType, outputRoot, common.BigToHash(big.NewInt(int64(l2BlockNum))).Bytes())) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGames, traceType, outputRoot, common.BigToHash(big.NewInt(int64(l2BlockNum))).Bytes()))
if err != nil { if err != nil {
return common.Address{}, fmt.Errorf("failed to fetch game from parameters: %w", err) return common.Address{}, fmt.Errorf("failed to fetch game from parameters: %w", err)
...@@ -47,6 +51,7 @@ func (f *DisputeGameFactoryContract) GetGameFromParameters(ctx context.Context, ...@@ -47,6 +51,7 @@ func (f *DisputeGameFactoryContract) GetGameFromParameters(ctx context.Context,
} }
func (f *DisputeGameFactoryContract) GetGameCount(ctx context.Context, blockHash common.Hash) (uint64, error) { func (f *DisputeGameFactoryContract) GetGameCount(ctx context.Context, blockHash common.Hash) (uint64, error) {
defer f.metrics.StartContractRequest("GetGameCount")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.ByHash(blockHash), f.contract.Call(methodGameCount)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.ByHash(blockHash), f.contract.Call(methodGameCount))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to load game count: %w", err) return 0, fmt.Errorf("failed to load game count: %w", err)
...@@ -55,6 +60,7 @@ func (f *DisputeGameFactoryContract) GetGameCount(ctx context.Context, blockHash ...@@ -55,6 +60,7 @@ func (f *DisputeGameFactoryContract) GetGameCount(ctx context.Context, blockHash
} }
func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, blockHash common.Hash) (types.GameMetadata, error) { func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, blockHash common.Hash) (types.GameMetadata, error) {
defer f.metrics.StartContractRequest("GetGame")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.ByHash(blockHash), f.contract.Call(methodGameAtIndex, new(big.Int).SetUint64(idx))) result, err := f.multiCaller.SingleCall(ctx, rpcblock.ByHash(blockHash), f.contract.Call(methodGameAtIndex, new(big.Int).SetUint64(idx)))
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)
...@@ -63,6 +69,7 @@ func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, bl ...@@ -63,6 +69,7 @@ func (f *DisputeGameFactoryContract) GetGame(ctx context.Context, idx uint64, bl
} }
func (f *DisputeGameFactoryContract) GetGameImpl(ctx context.Context, gameType uint32) (common.Address, error) { func (f *DisputeGameFactoryContract) GetGameImpl(ctx context.Context, gameType uint32) (common.Address, error) {
defer f.metrics.StartContractRequest("GetGameImpl")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGameImpls, gameType)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGameImpls, gameType))
if err != nil { if err != nil {
return common.Address{}, fmt.Errorf("failed to load game impl for type %v: %w", gameType, err) return common.Address{}, fmt.Errorf("failed to load game impl for type %v: %w", gameType, err)
...@@ -71,6 +78,7 @@ func (f *DisputeGameFactoryContract) GetGameImpl(ctx context.Context, gameType u ...@@ -71,6 +78,7 @@ func (f *DisputeGameFactoryContract) GetGameImpl(ctx context.Context, gameType u
} }
func (f *DisputeGameFactoryContract) GetGamesAtOrAfter(ctx context.Context, blockHash common.Hash, earliestTimestamp uint64) ([]types.GameMetadata, error) { func (f *DisputeGameFactoryContract) GetGamesAtOrAfter(ctx context.Context, blockHash common.Hash, earliestTimestamp uint64) ([]types.GameMetadata, error) {
defer f.metrics.StartContractRequest("GetGamesAtOrAfter")()
count, err := f.GetGameCount(ctx, blockHash) count, err := f.GetGameCount(ctx, blockHash)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -114,6 +122,7 @@ func (f *DisputeGameFactoryContract) GetGamesAtOrAfter(ctx context.Context, bloc ...@@ -114,6 +122,7 @@ func (f *DisputeGameFactoryContract) GetGamesAtOrAfter(ctx context.Context, bloc
} }
func (f *DisputeGameFactoryContract) GetAllGames(ctx context.Context, blockHash common.Hash) ([]types.GameMetadata, error) { func (f *DisputeGameFactoryContract) GetAllGames(ctx context.Context, blockHash common.Hash) ([]types.GameMetadata, error) {
defer f.metrics.StartContractRequest("GetAllGames")()
count, err := f.GetGameCount(ctx, blockHash) count, err := f.GetGameCount(ctx, blockHash)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"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"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
...@@ -228,7 +229,7 @@ func setupDisputeGameFactoryTest(t *testing.T) (*batchingTest.AbiBasedRpc, *Disp ...@@ -228,7 +229,7 @@ func setupDisputeGameFactoryTest(t *testing.T) (*batchingTest.AbiBasedRpc, *Disp
stubRpc := batchingTest.NewAbiBasedRpc(t, factoryAddr, fdgAbi) stubRpc := batchingTest.NewAbiBasedRpc(t, factoryAddr, fdgAbi)
caller := batching.NewMultiCaller(stubRpc, batchSize) caller := batching.NewMultiCaller(stubRpc, batchSize)
factory, err := NewDisputeGameFactoryContract(factoryAddr, caller) factory, err := NewDisputeGameFactoryContract(metrics.NoopContractMetrics, factoryAddr, caller)
require.NoError(t, err) require.NoError(t, err)
return stubRpc, factory return stubRpc, factory
} }
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
)
const ConstractSubsystem = "contracts"
type EndTimer func()
type Factory interface {
NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec
NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec
}
type ContractMetricer interface {
StartContractRequest(name string) EndTimer
}
type ContractMetrics struct {
ContractRequestsTotal *prometheus.CounterVec
ContractRequestDurationSeconds *prometheus.HistogramVec
}
var _ ContractMetricer = (*ContractMetrics)(nil)
func MakeContractMetrics(ns string, factory Factory) *ContractMetrics {
return &ContractMetrics{
ContractRequestsTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns,
Subsystem: ConstractSubsystem,
Name: "requests_total",
Help: "Total requests to the contracts",
}, []string{
"method",
}),
ContractRequestDurationSeconds: factory.NewHistogramVec(prometheus.HistogramOpts{
Namespace: ns,
Subsystem: ConstractSubsystem,
Name: "requests_duration_seconds",
Help: "Histogram of contract request durations",
}, []string{
"method",
}),
}
}
func (m *ContractMetrics) StartContractRequest(method string) EndTimer {
m.ContractRequestsTotal.WithLabelValues(method).Inc()
timer := prometheus.NewTimer(m.ContractRequestDurationSeconds.WithLabelValues(method))
return func() {
timer.ObserveDuration()
}
}
package metrics
type NoopMetrics struct {
}
func (n *NoopMetrics) StartContractRequest(_ string) EndTimer {
return func() {}
}
var _ ContractMetricer = (*NoopMetrics)(nil)
var NoopContractMetrics = &NoopMetrics{}
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types" gethTypes "github.com/ethereum/go-ethereum/core/types"
...@@ -59,7 +60,8 @@ type resourceCreator func(ctx context.Context, logger log.Logger, gameDepth type ...@@ -59,7 +60,8 @@ type resourceCreator func(ctx context.Context, logger log.Logger, gameDepth type
func NewGamePlayer( func NewGamePlayer(
ctx context.Context, ctx context.Context,
cl types.ClockReader, systemClock clock.Clock,
l1Clock types.ClockReader,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
dir string, dir string,
...@@ -124,14 +126,14 @@ func NewGamePlayer( ...@@ -124,14 +126,14 @@ func NewGamePlayer(
return nil, fmt.Errorf("failed to load min large preimage size: %w", err) return nil, fmt.Errorf("failed to load min large preimage size: %w", err)
} }
direct := preimages.NewDirectPreimageUploader(logger, txSender, loader) direct := preimages.NewDirectPreimageUploader(logger, txSender, loader)
large := preimages.NewLargePreimageUploader(logger, cl, txSender, oracle) large := preimages.NewLargePreimageUploader(logger, l1Clock, txSender, oracle)
uploader := preimages.NewSplitPreimageUploader(direct, large, minLargePreimageSize) uploader := preimages.NewSplitPreimageUploader(direct, large, minLargePreimageSize)
responder, err := responder.NewFaultResponder(logger, txSender, loader, uploader, oracle) responder, err := responder.NewFaultResponder(logger, txSender, loader, uploader, oracle)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create the responder: %w", err) return nil, fmt.Errorf("failed to create the responder: %w", err)
} }
agent := NewAgent(m, loader, gameDepth, accessor, responder, logger, selective, claimants) agent := NewAgent(m, systemClock, loader, gameDepth, accessor, responder, logger, selective, claimants)
return &GamePlayer{ return &GamePlayer{
act: agent.Act, act: agent.Act,
loader: loader, loader: loader,
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/scheduler" "github.com/ethereum-optimism/optimism/op-challenger/game/scheduler"
"github.com/ethereum-optimism/optimism/op-challenger/game/types" "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -40,7 +41,8 @@ type RollupClient interface { ...@@ -40,7 +41,8 @@ type RollupClient interface {
func RegisterGameTypes( func RegisterGameTypes(
ctx context.Context, ctx context.Context,
cl faultTypes.ClockReader, systemClock clock.Clock,
l1Clock faultTypes.ClockReader,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
cfg *config.Config, cfg *config.Config,
...@@ -67,17 +69,17 @@ func RegisterGameTypes( ...@@ -67,17 +69,17 @@ func RegisterGameTypes(
syncValidator := newSyncStatusValidator(rollupClient) syncValidator := newSyncStatusValidator(rollupClient)
if cfg.TraceTypeEnabled(config.TraceTypeCannon) { if cfg.TraceTypeEnabled(config.TraceTypeCannon) {
if err := registerCannon(faultTypes.CannonGameType, registry, oracles, ctx, cl, logger, m, cfg, syncValidator, rollupClient, txSender, gameFactory, caller, l2Client, l1HeaderSource, selective, claimants); err != nil { if err := registerCannon(faultTypes.CannonGameType, registry, oracles, ctx, systemClock, l1Clock, logger, m, cfg, syncValidator, rollupClient, txSender, gameFactory, caller, l2Client, l1HeaderSource, selective, claimants); err != nil {
return nil, fmt.Errorf("failed to register cannon game type: %w", err) return nil, fmt.Errorf("failed to register cannon game type: %w", err)
} }
} }
if cfg.TraceTypeEnabled(config.TraceTypePermissioned) { if cfg.TraceTypeEnabled(config.TraceTypePermissioned) {
if err := registerCannon(faultTypes.PermissionedGameType, registry, oracles, ctx, cl, logger, m, cfg, syncValidator, rollupClient, txSender, gameFactory, caller, l2Client, l1HeaderSource, selective, claimants); err != nil { if err := registerCannon(faultTypes.PermissionedGameType, registry, oracles, ctx, systemClock, l1Clock, logger, m, cfg, syncValidator, rollupClient, txSender, gameFactory, caller, l2Client, l1HeaderSource, selective, claimants); err != nil {
return nil, fmt.Errorf("failed to register permissioned cannon game type: %w", err) return nil, fmt.Errorf("failed to register permissioned cannon game type: %w", err)
} }
} }
if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) { if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) {
if err := registerAlphabet(registry, oracles, ctx, cl, logger, m, syncValidator, rollupClient, txSender, gameFactory, caller, l1HeaderSource, selective, claimants); err != nil { if err := registerAlphabet(registry, oracles, ctx, systemClock, l1Clock, logger, m, syncValidator, rollupClient, txSender, gameFactory, caller, l1HeaderSource, selective, claimants); err != nil {
return nil, fmt.Errorf("failed to register alphabet game type: %w", err) return nil, fmt.Errorf("failed to register alphabet game type: %w", err)
} }
} }
...@@ -88,7 +90,8 @@ func registerAlphabet( ...@@ -88,7 +90,8 @@ func registerAlphabet(
registry Registry, registry Registry,
oracles OracleRegistry, oracles OracleRegistry,
ctx context.Context, ctx context.Context,
cl faultTypes.ClockReader, systemClock clock.Clock,
l1Clock faultTypes.ClockReader,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
syncValidator SyncValidator, syncValidator SyncValidator,
...@@ -101,7 +104,7 @@ func registerAlphabet( ...@@ -101,7 +104,7 @@ func registerAlphabet(
claimants []common.Address, claimants []common.Address,
) error { ) error {
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(m, game.Proxy, caller)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -132,27 +135,27 @@ func registerAlphabet( ...@@ -132,27 +135,27 @@ func registerAlphabet(
} }
prestateValidator := NewPrestateValidator("alphabet", contract.GetAbsolutePrestateHash, alphabet.PrestateProvider) prestateValidator := NewPrestateValidator("alphabet", contract.GetAbsolutePrestateHash, alphabet.PrestateProvider)
startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider) startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider)
return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants) return NewGamePlayer(ctx, systemClock, l1Clock, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants)
} }
err := registerOracle(ctx, oracles, gameFactory, caller, faultTypes.AlphabetGameType) err := registerOracle(ctx, m, oracles, gameFactory, caller, faultTypes.AlphabetGameType)
if err != nil { if err != nil {
return err return err
} }
registry.RegisterGameType(faultTypes.AlphabetGameType, playerCreator) registry.RegisterGameType(faultTypes.AlphabetGameType, playerCreator)
contractCreator := func(game types.GameMetadata) (claims.BondContract, error) { contractCreator := func(game types.GameMetadata) (claims.BondContract, error) {
return contracts.NewFaultDisputeGameContract(game.Proxy, caller) return contracts.NewFaultDisputeGameContract(m, game.Proxy, caller)
} }
registry.RegisterBondContract(faultTypes.AlphabetGameType, contractCreator) registry.RegisterBondContract(faultTypes.AlphabetGameType, contractCreator)
return nil return nil
} }
func registerOracle(ctx context.Context, oracles OracleRegistry, gameFactory *contracts.DisputeGameFactoryContract, caller *batching.MultiCaller, gameType uint32) error { func registerOracle(ctx context.Context, m metrics.Metricer, oracles OracleRegistry, gameFactory *contracts.DisputeGameFactoryContract, caller *batching.MultiCaller, gameType uint32) error {
implAddr, err := gameFactory.GetGameImpl(ctx, gameType) implAddr, err := gameFactory.GetGameImpl(ctx, gameType)
if err != nil { if err != nil {
return fmt.Errorf("failed to load implementation for game type %v: %w", gameType, err) return fmt.Errorf("failed to load implementation for game type %v: %w", gameType, err)
} }
contract, err := contracts.NewFaultDisputeGameContract(implAddr, caller) contract, err := contracts.NewFaultDisputeGameContract(m, implAddr, caller)
if err != nil { if err != nil {
return err return err
} }
...@@ -169,7 +172,8 @@ func registerCannon( ...@@ -169,7 +172,8 @@ func registerCannon(
registry Registry, registry Registry,
oracles OracleRegistry, oracles OracleRegistry,
ctx context.Context, ctx context.Context,
cl faultTypes.ClockReader, systemClock clock.Clock,
l1Clock faultTypes.ClockReader,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
cfg *config.Config, cfg *config.Config,
...@@ -185,7 +189,7 @@ func registerCannon( ...@@ -185,7 +189,7 @@ func registerCannon(
) error { ) error {
cannonPrestateProvider := cannon.NewPrestateProvider(cfg.CannonAbsolutePreState) cannonPrestateProvider := cannon.NewPrestateProvider(cfg.CannonAbsolutePreState)
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract, err := contracts.NewFaultDisputeGameContract(game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(m, game.Proxy, caller)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -216,16 +220,16 @@ func registerCannon( ...@@ -216,16 +220,16 @@ func registerCannon(
} }
prestateValidator := NewPrestateValidator("cannon", contract.GetAbsolutePrestateHash, cannonPrestateProvider) prestateValidator := NewPrestateValidator("cannon", contract.GetAbsolutePrestateHash, cannonPrestateProvider)
startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider) startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider)
return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants) return NewGamePlayer(ctx, systemClock, l1Clock, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants)
} }
err := registerOracle(ctx, oracles, gameFactory, caller, gameType) err := registerOracle(ctx, m, oracles, gameFactory, caller, gameType)
if err != nil { if err != nil {
return err return err
} }
registry.RegisterGameType(gameType, playerCreator) registry.RegisterGameType(gameType, playerCreator)
contractCreator := func(game types.GameMetadata) (claims.BondContract, error) { contractCreator := func(game types.GameMetadata) (claims.BondContract, error) {
return contracts.NewFaultDisputeGameContract(game.Proxy, caller) return contracts.NewFaultDisputeGameContract(m, game.Proxy, caller)
} }
registry.RegisterBondContract(gameType, contractCreator) registry.RegisterBondContract(gameType, contractCreator)
return nil return nil
......
...@@ -46,7 +46,8 @@ type Service struct { ...@@ -46,7 +46,8 @@ type Service struct {
txMgr *txmgr.SimpleTxManager txMgr *txmgr.SimpleTxManager
txSender *sender.TxSender txSender *sender.TxSender
cl *clock.SimpleClock systemClock clock.Clock
l1Clock *clock.SimpleClock
claimants []common.Address claimants []common.Address
claimer *claims.BondClaimScheduler claimer *claims.BondClaimScheduler
...@@ -70,9 +71,10 @@ type Service struct { ...@@ -70,9 +71,10 @@ type Service struct {
// NewService creates a new Service. // NewService creates a new Service.
func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*Service, error) { func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*Service, error) {
s := &Service{ s := &Service{
cl: clock.NewSimpleClock(), systemClock: clock.SystemClock,
logger: logger, l1Clock: clock.NewSimpleClock(),
metrics: metrics.NewMetrics(), logger: logger,
metrics: metrics.NewMetrics(),
} }
if err := s.initFromConfig(ctx, cfg); err != nil { if err := s.initFromConfig(ctx, cfg); err != nil {
...@@ -196,7 +198,7 @@ func (s *Service) initMetricsServer(cfg *opmetrics.CLIConfig) error { ...@@ -196,7 +198,7 @@ func (s *Service) initMetricsServer(cfg *opmetrics.CLIConfig) error {
} }
func (s *Service) initFactoryContract(cfg *config.Config) error { func (s *Service) initFactoryContract(cfg *config.Config) error {
factoryContract, err := contracts.NewDisputeGameFactoryContract(cfg.GameFactoryAddress, factoryContract, err := contracts.NewDisputeGameFactoryContract(s.metrics, cfg.GameFactoryAddress,
batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize)) batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize))
if err != nil { if err != nil {
return fmt.Errorf("failed to bind the fault dispute game factory contract: %w", err) return fmt.Errorf("failed to bind the fault dispute game factory contract: %w", err)
...@@ -227,7 +229,7 @@ func (s *Service) registerGameTypes(ctx context.Context, cfg *config.Config) err ...@@ -227,7 +229,7 @@ func (s *Service) registerGameTypes(ctx context.Context, cfg *config.Config) err
gameTypeRegistry := registry.NewGameTypeRegistry() gameTypeRegistry := registry.NewGameTypeRegistry()
oracles := registry.NewOracleRegistry() oracles := registry.NewOracleRegistry()
caller := batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize)
closer, err := fault.RegisterGameTypes(ctx, s.cl, s.logger, s.metrics, cfg, gameTypeRegistry, oracles, s.rollupClient, s.txSender, s.factoryContract, caller, s.l1Client, cfg.SelectiveClaimResolution, s.claimants) closer, err := fault.RegisterGameTypes(ctx, s.systemClock, s.l1Clock, s.logger, s.metrics, cfg, gameTypeRegistry, oracles, s.rollupClient, s.txSender, s.factoryContract, caller, s.l1Client, cfg.SelectiveClaimResolution, s.claimants)
if err != nil { if err != nil {
return err return err
} }
...@@ -247,12 +249,12 @@ func (s *Service) initLargePreimages() error { ...@@ -247,12 +249,12 @@ func (s *Service) initLargePreimages() error {
fetcher := fetcher.NewPreimageFetcher(s.logger, s.l1Client) fetcher := fetcher.NewPreimageFetcher(s.logger, s.l1Client)
verifier := keccak.NewPreimageVerifier(s.logger, fetcher) verifier := keccak.NewPreimageVerifier(s.logger, fetcher)
challenger := keccak.NewPreimageChallenger(s.logger, s.metrics, verifier, s.txSender) challenger := keccak.NewPreimageChallenger(s.logger, s.metrics, verifier, s.txSender)
s.preimages = keccak.NewLargePreimageScheduler(s.logger, s.cl, s.oracles, challenger) s.preimages = keccak.NewLargePreimageScheduler(s.logger, s.l1Clock, s.oracles, challenger)
return nil return nil
} }
func (s *Service) initMonitor(cfg *config.Config) { func (s *Service) initMonitor(cfg *config.Config) {
s.monitor = newGameMonitor(s.logger, s.cl, s.factoryContract, s.sched, s.preimages, cfg.GameWindow, s.claimer, s.l1Client.BlockNumber, cfg.GameAllowlist, s.pollClient) s.monitor = newGameMonitor(s.logger, s.l1Clock, s.factoryContract, s.sched, s.preimages, cfg.GameWindow, s.claimer, s.l1Client.BlockNumber, cfg.GameAllowlist, s.pollClient)
} }
func (s *Service) Start(ctx context.Context) error { func (s *Service) Start(ctx context.Context) error {
......
...@@ -3,13 +3,14 @@ package metrics ...@@ -3,13 +3,14 @@ package metrics
import ( import (
"io" "io"
"github.com/ethereum-optimism/optimism/op-service/httputil"
"github.com/ethereum-optimism/optimism/op-service/sources/caching" "github.com/ethereum-optimism/optimism/op-service/sources/caching"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/ethereum-optimism/optimism/op-service/httputil" contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics"
) )
...@@ -28,11 +29,16 @@ type Metricer interface { ...@@ -28,11 +29,16 @@ type Metricer interface {
// Record cache metrics // Record cache metrics
caching.Metrics caching.Metrics
// Record contract metrics
contractMetrics.ContractMetricer
RecordActedL1Block(n uint64) RecordActedL1Block(n uint64)
RecordGameStep() RecordGameStep()
RecordGameMove() RecordGameMove()
RecordCannonExecutionTime(t float64) RecordCannonExecutionTime(t float64)
RecordClaimResolutionTime(t float64)
RecordGameActTime(t float64)
RecordPreimageChallenged() RecordPreimageChallenged()
RecordPreimageChallengeFailed() RecordPreimageChallengeFailed()
...@@ -60,8 +66,8 @@ type Metrics struct { ...@@ -60,8 +66,8 @@ type Metrics struct {
factory opmetrics.Factory factory opmetrics.Factory
txmetrics.TxMetrics txmetrics.TxMetrics
*opmetrics.CacheMetrics *opmetrics.CacheMetrics
*contractMetrics.ContractMetrics
info prometheus.GaugeVec info prometheus.GaugeVec
up prometheus.Gauge up prometheus.Gauge
...@@ -80,6 +86,8 @@ type Metrics struct { ...@@ -80,6 +86,8 @@ type Metrics struct {
steps prometheus.Counter steps prometheus.Counter
cannonExecutionTime prometheus.Histogram cannonExecutionTime prometheus.Histogram
claimResolutionTime prometheus.Histogram
gameActTime prometheus.Histogram
trackedGames prometheus.GaugeVec trackedGames prometheus.GaugeVec
inflightGames prometheus.Gauge inflightGames prometheus.Gauge
...@@ -104,6 +112,8 @@ func NewMetrics() *Metrics { ...@@ -104,6 +112,8 @@ func NewMetrics() *Metrics {
CacheMetrics: opmetrics.NewCacheMetrics(factory, Namespace, "provider_cache", "Provider cache"), CacheMetrics: opmetrics.NewCacheMetrics(factory, Namespace, "provider_cache", "Provider cache"),
ContractMetrics: contractMetrics.MakeContractMetrics(Namespace, factory),
info: *factory.NewGaugeVec(prometheus.GaugeOpts{ info: *factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace, Namespace: Namespace,
Name: "info", Name: "info",
...@@ -141,6 +151,20 @@ func NewMetrics() *Metrics { ...@@ -141,6 +151,20 @@ func NewMetrics() *Metrics {
[]float64{1.0, 10.0}, []float64{1.0, 10.0},
prometheus.ExponentialBuckets(30.0, 2.0, 14)...), prometheus.ExponentialBuckets(30.0, 2.0, 14)...),
}), }),
claimResolutionTime: factory.NewHistogram(prometheus.HistogramOpts{
Namespace: Namespace,
Name: "claim_resolution_time",
Help: "Time (in seconds) spent trying to resolve claims",
Buckets: []float64{.05, .1, .25, .5, 1, 2.5, 5, 7.5, 10},
}),
gameActTime: factory.NewHistogram(prometheus.HistogramOpts{
Namespace: Namespace,
Name: "game_act_time",
Help: "Time (in seconds) spent acting on a game",
Buckets: append(
[]float64{1.0, 2.0, 5.0, 10.0},
prometheus.ExponentialBuckets(30.0, 2.0, 14)...),
}),
bondClaimFailures: factory.NewCounter(prometheus.CounterOpts{ bondClaimFailures: factory.NewCounter(prometheus.CounterOpts{
Namespace: Namespace, Namespace: Namespace,
Name: "claim_failures", Name: "claim_failures",
...@@ -237,6 +261,14 @@ func (m *Metrics) RecordCannonExecutionTime(t float64) { ...@@ -237,6 +261,14 @@ func (m *Metrics) RecordCannonExecutionTime(t float64) {
m.cannonExecutionTime.Observe(t) m.cannonExecutionTime.Observe(t)
} }
func (m *Metrics) RecordClaimResolutionTime(t float64) {
m.claimResolutionTime.Observe(t)
}
func (m *Metrics) RecordGameActTime(t float64) {
m.gameActTime.Observe(t)
}
func (m *Metrics) IncActiveExecutors() { func (m *Metrics) IncActiveExecutors() {
m.executors.WithLabelValues("active").Inc() m.executors.WithLabelValues("active").Inc()
} }
......
...@@ -3,6 +3,7 @@ package metrics ...@@ -3,6 +3,7 @@ package metrics
import ( import (
"io" "io"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -12,6 +13,7 @@ import ( ...@@ -12,6 +13,7 @@ import (
type NoopMetricsImpl struct { type NoopMetricsImpl struct {
txmetrics.NoopTxMetrics txmetrics.NoopTxMetrics
contractMetrics.NoopMetrics
} }
func (i *NoopMetricsImpl) StartBalanceMetrics(l log.Logger, client *ethclient.Client, account common.Address) io.Closer { func (i *NoopMetricsImpl) StartBalanceMetrics(l log.Logger, client *ethclient.Client, account common.Address) io.Closer {
...@@ -35,6 +37,8 @@ func (*NoopMetricsImpl) RecordBondClaimFailed() {} ...@@ -35,6 +37,8 @@ func (*NoopMetricsImpl) RecordBondClaimFailed() {}
func (*NoopMetricsImpl) RecordBondClaimed(uint64) {} func (*NoopMetricsImpl) RecordBondClaimed(uint64) {}
func (*NoopMetricsImpl) RecordCannonExecutionTime(t float64) {} func (*NoopMetricsImpl) RecordCannonExecutionTime(t float64) {}
func (*NoopMetricsImpl) RecordClaimResolutionTime(t float64) {}
func (*NoopMetricsImpl) RecordGameActTime(t float64) {}
func (*NoopMetricsImpl) RecordGamesStatus(inProgress, defenderWon, challengerWon int) {} func (*NoopMetricsImpl) RecordGamesStatus(inProgress, defenderWon, challengerWon int) {}
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"io" "io"
"math/big" "math/big"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-service/sources/caching" "github.com/ethereum-optimism/optimism/op-service/sources/caching"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
...@@ -47,6 +48,7 @@ type Metricer interface { ...@@ -47,6 +48,7 @@ type Metricer interface {
RecordBondCollateral(addr common.Address, required *big.Int, available *big.Int) RecordBondCollateral(addr common.Address, required *big.Int, available *big.Int)
caching.Metrics caching.Metrics
contractMetrics.ContractMetricer
} }
// Metrics implementation must implement RegistryMetricer to allow the metrics server to work. // Metrics implementation must implement RegistryMetricer to allow the metrics server to work.
...@@ -58,6 +60,7 @@ type Metrics struct { ...@@ -58,6 +60,7 @@ type Metrics struct {
factory opmetrics.Factory factory opmetrics.Factory
*opmetrics.CacheMetrics *opmetrics.CacheMetrics
*contractMetrics.ContractMetrics
info prometheus.GaugeVec info prometheus.GaugeVec
up prometheus.Gauge up prometheus.Gauge
...@@ -87,7 +90,8 @@ func NewMetrics() *Metrics { ...@@ -87,7 +90,8 @@ func NewMetrics() *Metrics {
registry: registry, registry: registry,
factory: factory, factory: factory,
CacheMetrics: opmetrics.NewCacheMetrics(factory, Namespace, "provider_cache", "Provider cache"), CacheMetrics: opmetrics.NewCacheMetrics(factory, Namespace, "provider_cache", "Provider cache"),
ContractMetrics: contractMetrics.MakeContractMetrics(Namespace, factory),
info: *factory.NewGaugeVec(prometheus.GaugeOpts{ info: *factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace, Namespace: Namespace,
......
...@@ -3,10 +3,13 @@ package metrics ...@@ -3,10 +3,13 @@ package metrics
import ( import (
"math/big" "math/big"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type NoopMetricsImpl struct{} type NoopMetricsImpl struct {
contractMetrics.NoopMetrics
}
var NoopMetrics Metricer = new(NoopMetricsImpl) var NoopMetrics Metricer = new(NoopMetricsImpl)
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -16,6 +17,10 @@ import ( ...@@ -16,6 +17,10 @@ import (
const metricsLabel = "game_caller_creator" const metricsLabel = "game_caller_creator"
type GameCallerMetrics interface {
caching.Metrics
contractMetrics.ContractMetricer
}
type GameCaller interface { type GameCaller interface {
GetGameMetadata(context.Context, rpcblock.Block) (common.Hash, uint64, common.Hash, types.GameStatus, uint64, error) GetGameMetadata(context.Context, rpcblock.Block) (common.Hash, uint64, common.Hash, types.GameStatus, uint64, error)
GetAllClaims(context.Context, rpcblock.Block) ([]faultTypes.Claim, error) GetAllClaims(context.Context, rpcblock.Block) ([]faultTypes.Claim, error)
...@@ -24,12 +29,14 @@ type GameCaller interface { ...@@ -24,12 +29,14 @@ type GameCaller interface {
} }
type GameCallerCreator struct { type GameCallerCreator struct {
m GameCallerMetrics
cache *caching.LRUCache[common.Address, *contracts.FaultDisputeGameContract] cache *caching.LRUCache[common.Address, *contracts.FaultDisputeGameContract]
caller *batching.MultiCaller caller *batching.MultiCaller
} }
func NewGameCallerCreator(m caching.Metrics, caller *batching.MultiCaller) *GameCallerCreator { func NewGameCallerCreator(m GameCallerMetrics, caller *batching.MultiCaller) *GameCallerCreator {
return &GameCallerCreator{ return &GameCallerCreator{
m: m,
caller: caller, caller: caller,
cache: caching.NewLRUCache[common.Address, *contracts.FaultDisputeGameContract](m, metricsLabel, 100), cache: caching.NewLRUCache[common.Address, *contracts.FaultDisputeGameContract](m, metricsLabel, 100),
} }
...@@ -41,7 +48,7 @@ func (g *GameCallerCreator) CreateContract(game types.GameMetadata) (GameCaller, ...@@ -41,7 +48,7 @@ func (g *GameCallerCreator) CreateContract(game types.GameMetadata) (GameCaller,
} }
switch game.GameType { switch game.GameType {
case faultTypes.CannonGameType, faultTypes.AlphabetGameType: case faultTypes.CannonGameType, faultTypes.AlphabetGameType:
fdg, err := contracts.NewFaultDisputeGameContract(game.Proxy, g.caller) fdg, err := contracts.NewFaultDisputeGameContract(g.m, game.Proxy, g.caller)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create FaultDisputeGameContract: %w", err) return nil, fmt.Errorf("failed to create FaultDisputeGameContract: %w", err)
} }
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"testing" "testing"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
...@@ -71,6 +72,7 @@ func setupMetadataLoaderTest(t *testing.T) (*batching.MultiCaller, *mockCacheMet ...@@ -71,6 +72,7 @@ func setupMetadataLoaderTest(t *testing.T) (*batching.MultiCaller, *mockCacheMet
type mockCacheMetrics struct { type mockCacheMetrics struct {
cacheAddCalls int cacheAddCalls int
cacheGetCalls int cacheGetCalls int
*contractMetrics.NoopMetrics
} }
func (m *mockCacheMetrics) CacheAdd(_ string, _ int, _ bool) { func (m *mockCacheMetrics) CacheAdd(_ string, _ int, _ bool) {
......
...@@ -184,7 +184,7 @@ func (s *Service) initMetricsServer(cfg *opmetrics.CLIConfig) error { ...@@ -184,7 +184,7 @@ func (s *Service) initMetricsServer(cfg *opmetrics.CLIConfig) error {
} }
func (s *Service) initFactoryContract(cfg *config.Config) error { func (s *Service) initFactoryContract(cfg *config.Config) error {
factoryContract, err := contracts.NewDisputeGameFactoryContract(cfg.GameFactoryAddress, factoryContract, err := contracts.NewDisputeGameFactoryContract(s.metrics, cfg.GameFactoryAddress,
batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize)) batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize))
if err != nil { if err != nil {
return fmt.Errorf("failed to bind the fault dispute game factory contract: %w", err) return fmt.Errorf("failed to bind the fault dispute game factory contract: %w", err)
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
...@@ -38,7 +39,7 @@ func (g *OutputAlphabetGameHelper) StartChallenger( ...@@ -38,7 +39,7 @@ func (g *OutputAlphabetGameHelper) StartChallenger(
func (g *OutputAlphabetGameHelper) CreateHonestActor(ctx context.Context, l2Node string) *OutputHonestHelper { func (g *OutputAlphabetGameHelper) CreateHonestActor(ctx context.Context, l2Node string) *OutputHonestHelper {
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "HonestHelper", "game", g.addr) logger := testlog.Logger(g.t, log.LevelInfo).New("role", "HonestHelper", "game", g.addr)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract, err := contracts.NewFaultDisputeGameContract(g.addr, caller) contract, err := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, 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)
g.require.NoError(err, "Get block range") g.require.NoError(err, "Get block range")
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer" "github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"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"
...@@ -62,7 +63,7 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s ...@@ -62,7 +63,7 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "HonestHelper", "game", g.addr) logger := testlog.Logger(g.t, log.LevelInfo).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.NewFaultDisputeGameContract(g.addr, caller) contract, err := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, 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)
...@@ -294,7 +295,7 @@ func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context, ...@@ -294,7 +295,7 @@ func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context,
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
l2Client := g.system.NodeClient(l2Node) l2Client := g.system.NodeClient(l2Node)
contract, err := contracts.NewFaultDisputeGameContract(g.addr, caller) contract, err := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, 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)
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/preimages" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/preimages"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
...@@ -701,7 +702,7 @@ func (g *OutputGameHelper) uploadPreimage(ctx context.Context, data *types.Preim ...@@ -701,7 +702,7 @@ func (g *OutputGameHelper) uploadPreimage(ctx context.Context, data *types.Preim
func (g *OutputGameHelper) oracle(ctx context.Context) *contracts.PreimageOracleContract { func (g *OutputGameHelper) oracle(ctx context.Context) *contracts.PreimageOracleContract {
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract, err := contracts.NewFaultDisputeGameContract(g.addr, caller) contract, err := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.addr, caller)
g.require.NoError(err, "Failed to create game contract") g.require.NoError(err, "Failed to create game contract")
oracle, err := contract.GetOracle(ctx) oracle, err := contract.GetOracle(ctx)
g.require.NoError(err, "Failed to create oracle contract") g.require.NoError(err, "Failed to create oracle contract")
......
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