Commit 7c34ab27 authored by refcell's avatar refcell Committed by GitHub

feat(op-dispute-mon): Claim Monitor (#10012)

* feat(op-dispute-mon): claim monitor

* fix(op-dispute-mon): lints
parent 75320b37
...@@ -35,10 +35,28 @@ const ( ...@@ -35,10 +35,28 @@ const (
DisagreeChallengerWins DisagreeChallengerWins
) )
type ClaimStatus uint8
const (
// Claims where the game is in the first half
FirstHalfExpiredResolved ClaimStatus = iota
FirstHalfExpiredUnresolved
FirstHalfNotExpiredResolved
FirstHalfNotExpiredUnresolved
// Claims where the game is in the second half
SecondHalfExpiredResolved
SecondHalfExpiredUnresolved
SecondHalfNotExpiredResolved
SecondHalfNotExpiredUnresolved
)
type Metricer interface { type Metricer interface {
RecordInfo(version string) RecordInfo(version string)
RecordUp() RecordUp()
RecordClaims(status ClaimStatus, count int)
RecordWithdrawalRequests(delayedWeth common.Address, matches bool, count int) RecordWithdrawalRequests(delayedWeth common.Address, matches bool, count int)
RecordClaimResolutionDelayMax(delay float64) RecordClaimResolutionDelayMax(delay float64)
...@@ -64,6 +82,8 @@ type Metrics struct { ...@@ -64,6 +82,8 @@ type Metrics struct {
*opmetrics.CacheMetrics *opmetrics.CacheMetrics
*contractMetrics.ContractMetrics *contractMetrics.ContractMetrics
claims prometheus.GaugeVec
withdrawalRequests prometheus.GaugeVec withdrawalRequests prometheus.GaugeVec
info prometheus.GaugeVec info prometheus.GaugeVec
...@@ -119,6 +139,15 @@ func NewMetrics() *Metrics { ...@@ -119,6 +139,15 @@ func NewMetrics() *Metrics {
Name: "claim_resolution_delay_max", Name: "claim_resolution_delay_max",
Help: "Maximum claim resolution delay in seconds", Help: "Maximum claim resolution delay in seconds",
}), }),
claims: *factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "claims",
Help: "Claims broken down by whether they were resolved, whether the clock expired, and the game time period",
}, []string{
"resolved",
"clock",
"game_time_period",
}),
withdrawalRequests: *factory.NewGaugeVec(prometheus.GaugeOpts{ withdrawalRequests: *factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: Namespace, Namespace: Namespace,
Name: "withdrawal_requests", Name: "withdrawal_requests",
...@@ -184,6 +213,32 @@ func (m *Metrics) RecordUp() { ...@@ -184,6 +213,32 @@ func (m *Metrics) RecordUp() {
m.up.Set(1) m.up.Set(1)
} }
func (m *Metrics) RecordClaims(status ClaimStatus, count int) {
asLabels := func(status ClaimStatus) []string {
switch status {
case FirstHalfExpiredResolved:
return []string{"resolved", "expired", "first_half"}
case FirstHalfExpiredUnresolved:
return []string{"unresolved", "expired", "first_half"}
case FirstHalfNotExpiredResolved:
return []string{"resolved", "not_expired", "first_half"}
case FirstHalfNotExpiredUnresolved:
return []string{"unresolved", "not_expired", "first_half"}
case SecondHalfExpiredResolved:
return []string{"resolved", "expired", "second_half"}
case SecondHalfExpiredUnresolved:
return []string{"unresolved", "expired", "second_half"}
case SecondHalfNotExpiredResolved:
return []string{"resolved", "not_expired", "second_half"}
case SecondHalfNotExpiredUnresolved:
return []string{"unresolved", "not_expired", "second_half"}
default:
panic(fmt.Errorf("unknown claim status: %v", status))
}
}
m.claims.WithLabelValues(asLabels(status)...).Set(float64(count))
}
func (m *Metrics) RecordWithdrawalRequests(delayedWeth common.Address, matches bool, count int) { func (m *Metrics) RecordWithdrawalRequests(delayedWeth common.Address, matches bool, count int) {
credits := "matching" credits := "matching"
if !matches { if !matches {
......
...@@ -13,17 +13,20 @@ type NoopMetricsImpl struct { ...@@ -13,17 +13,20 @@ type NoopMetricsImpl struct {
var NoopMetrics Metricer = new(NoopMetricsImpl) var NoopMetrics Metricer = new(NoopMetricsImpl)
func (*NoopMetricsImpl) RecordInfo(version string) {} func (*NoopMetricsImpl) RecordInfo(_ string) {}
func (*NoopMetricsImpl) RecordUp() {} func (*NoopMetricsImpl) RecordUp() {}
func (*NoopMetricsImpl) CacheAdd(_ string, _ int, _ bool) {} func (*NoopMetricsImpl) CacheAdd(_ string, _ int, _ bool) {}
func (*NoopMetricsImpl) CacheGet(_ string, _ bool) {} func (*NoopMetricsImpl) CacheGet(_ string, _ bool) {}
func (*NoopMetricsImpl) RecordClaims(_ ClaimStatus, _ int) {}
func (*NoopMetricsImpl) RecordWithdrawalRequests(_ common.Address, _ bool, _ int) {} func (*NoopMetricsImpl) RecordWithdrawalRequests(_ common.Address, _ bool, _ int) {}
func (*NoopMetricsImpl) RecordClaimResolutionDelayMax(delay float64) {}
func (*NoopMetricsImpl) RecordOutputFetchTime(timestamp float64) {} func (*NoopMetricsImpl) RecordClaimResolutionDelayMax(_ float64) {}
func (*NoopMetricsImpl) RecordOutputFetchTime(_ float64) {}
func (*NoopMetricsImpl) RecordGameAgreement(status GameAgreementStatus, count int) {} func (*NoopMetricsImpl) RecordGameAgreement(_ GameAgreementStatus, _ int) {}
func (i *NoopMetricsImpl) RecordBondCollateral(_ common.Address, _ *big.Int, _ *big.Int) {} func (i *NoopMetricsImpl) RecordBondCollateral(_ common.Address, _ *big.Int, _ *big.Int) {}
package mon
import (
"time"
"github.com/ethereum-optimism/optimism/op-dispute-mon/metrics"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum/go-ethereum/log"
)
type RClock interface {
Now() time.Time
}
type ClaimMetrics interface {
RecordClaims(status metrics.ClaimStatus, count int)
}
type ClaimMonitor struct {
logger log.Logger
clock RClock
metrics ClaimMetrics
}
func NewClaimMonitor(logger log.Logger, clock RClock, metrics ClaimMetrics) *ClaimMonitor {
return &ClaimMonitor{logger, clock, metrics}
}
func (c *ClaimMonitor) CheckClaims(games []*types.EnrichedGameData) {
claimStatus := make(map[metrics.ClaimStatus]int)
for _, game := range games {
c.checkGameClaims(game, claimStatus)
}
for status, count := range claimStatus {
c.metrics.RecordClaims(status, count)
}
}
func (c *ClaimMonitor) checkGameClaims(game *types.EnrichedGameData, claimStatus map[metrics.ClaimStatus]int) {
// Check if the game is in the first half
duration := uint64(c.clock.Now().Unix()) - game.Timestamp
firstHalf := duration <= (game.Duration / 2)
// Iterate over the game's claims
for _, claim := range game.Claims {
// Check if the clock has expired
if firstHalf && claim.Resolved {
c.logger.Error("Claim resolved in the first half of the game duration", "game", game.Proxy, "claimContractIndex", claim.ContractIndex)
}
maxChessTime := time.Duration(game.Duration/2) * time.Second
accumulatedTime := claim.ChessTime(c.clock.Now())
clockExpired := accumulatedTime >= maxChessTime
if claim.Resolved {
if clockExpired {
if firstHalf {
claimStatus[metrics.FirstHalfExpiredResolved]++
} else {
claimStatus[metrics.SecondHalfExpiredResolved]++
}
} else {
if firstHalf {
claimStatus[metrics.FirstHalfNotExpiredResolved]++
} else {
claimStatus[metrics.SecondHalfNotExpiredResolved]++
}
}
} else {
if clockExpired {
c.logger.Warn("Claim unresolved after clock expiration", "game", game.Proxy, "claimContractIndex", claim.ContractIndex)
if firstHalf {
claimStatus[metrics.FirstHalfExpiredUnresolved]++
} else {
claimStatus[metrics.SecondHalfExpiredUnresolved]++
}
} else {
if firstHalf {
claimStatus[metrics.FirstHalfNotExpiredUnresolved]++
} else {
claimStatus[metrics.SecondHalfNotExpiredUnresolved]++
}
}
}
}
}
package mon
import (
"testing"
"time"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-dispute-mon/metrics"
"github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
var frozen = time.Unix(int64(time.Hour.Seconds()), 0)
func TestClaimMonitor_CheckClaims(t *testing.T) {
cm, cl, cMetrics := newTestClaimMonitor(t)
games := makeMultipleTestGames(uint64(cl.Now().Unix()))
cm.CheckClaims(games)
require.Equal(t, 1, cMetrics.calls[metrics.FirstHalfExpiredResolved])
require.Equal(t, 1, cMetrics.calls[metrics.FirstHalfExpiredUnresolved])
require.Equal(t, 1, cMetrics.calls[metrics.FirstHalfNotExpiredResolved])
require.Equal(t, 1, cMetrics.calls[metrics.FirstHalfNotExpiredUnresolved])
require.Equal(t, 1, cMetrics.calls[metrics.SecondHalfExpiredResolved])
require.Equal(t, 1, cMetrics.calls[metrics.SecondHalfExpiredUnresolved])
require.Equal(t, 1, cMetrics.calls[metrics.SecondHalfNotExpiredResolved])
require.Equal(t, 1, cMetrics.calls[metrics.SecondHalfNotExpiredUnresolved])
}
func newTestClaimMonitor(t *testing.T) (*ClaimMonitor, *clock.DeterministicClock, *stubClaimMetrics) {
logger := testlog.Logger(t, log.LvlInfo)
cl := clock.NewDeterministicClock(frozen)
metrics := &stubClaimMetrics{}
return NewClaimMonitor(logger, cl, metrics), cl, metrics
}
type stubClaimMetrics struct {
calls map[metrics.ClaimStatus]int
}
func (s *stubClaimMetrics) RecordClaims(status metrics.ClaimStatus, count int) {
if s.calls == nil {
s.calls = make(map[metrics.ClaimStatus]int)
}
s.calls[status] += count
}
func makeMultipleTestGames(duration uint64) []*types.EnrichedGameData {
return []*types.EnrichedGameData{
makeTestGame(duration), // first half
makeTestGame(duration * 10), // second half
}
}
func makeTestGame(duration uint64) *types.EnrichedGameData {
return &types.EnrichedGameData{
Duration: duration,
Recipients: map[common.Address]bool{
common.Address{0x02}: true,
common.Address{0x03}: true,
common.Address{0x04}: true,
},
Claims: []types.EnrichedClaim{
{
Claim: faultTypes.Claim{
Clock: faultTypes.NewClock(time.Duration(0), frozen),
},
Resolved: true,
},
{
Claim: faultTypes.Claim{},
Resolved: true,
},
{
Claim: faultTypes.Claim{
Clock: faultTypes.NewClock(time.Duration(0), frozen),
},
},
{
Claim: faultTypes.Claim{},
},
},
}
}
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
type Forecast func(ctx context.Context, games []*types.EnrichedGameData) type Forecast func(ctx context.Context, games []*types.EnrichedGameData)
type Bonds func(games []*types.EnrichedGameData) type Bonds func(games []*types.EnrichedGameData)
type MonitorClaims func(games []*types.EnrichedGameData)
type MonitorWithdrawals func(games []*types.EnrichedGameData) type MonitorWithdrawals func(games []*types.EnrichedGameData)
type BlockHashFetcher func(ctx context.Context, number *big.Int) (common.Hash, error) type BlockHashFetcher func(ctx context.Context, number *big.Int) (common.Hash, error)
type BlockNumberFetcher func(ctx context.Context) (uint64, error) type BlockNumberFetcher func(ctx context.Context) (uint64, error)
...@@ -35,6 +36,7 @@ type gameMonitor struct { ...@@ -35,6 +36,7 @@ type gameMonitor struct {
delays RecordClaimResolutionDelayMax delays RecordClaimResolutionDelayMax
forecast Forecast forecast Forecast
bonds Bonds bonds Bonds
claims MonitorClaims
withdrawals MonitorWithdrawals withdrawals MonitorWithdrawals
extract Extract extract Extract
fetchBlockHash BlockHashFetcher fetchBlockHash BlockHashFetcher
...@@ -50,6 +52,7 @@ func newGameMonitor( ...@@ -50,6 +52,7 @@ func newGameMonitor(
delays RecordClaimResolutionDelayMax, delays RecordClaimResolutionDelayMax,
forecast Forecast, forecast Forecast,
bonds Bonds, bonds Bonds,
claims MonitorClaims,
withdrawals MonitorWithdrawals, withdrawals MonitorWithdrawals,
extract Extract, extract Extract,
fetchBlockNumber BlockNumberFetcher, fetchBlockNumber BlockNumberFetcher,
...@@ -65,6 +68,7 @@ func newGameMonitor( ...@@ -65,6 +68,7 @@ func newGameMonitor(
delays: delays, delays: delays,
forecast: forecast, forecast: forecast,
bonds: bonds, bonds: bonds,
claims: claims,
withdrawals: withdrawals, withdrawals: withdrawals,
extract: extract, extract: extract,
fetchBlockNumber: fetchBlockNumber, fetchBlockNumber: fetchBlockNumber,
...@@ -90,6 +94,7 @@ func (m *gameMonitor) monitorGames() error { ...@@ -90,6 +94,7 @@ func (m *gameMonitor) monitorGames() error {
m.delays(enrichedGames) m.delays(enrichedGames)
m.forecast(m.ctx, enrichedGames) m.forecast(m.ctx, enrichedGames)
m.bonds(enrichedGames) m.bonds(enrichedGames)
m.claims(enrichedGames)
m.withdrawals(enrichedGames) m.withdrawals(enrichedGames)
return nil return nil
} }
......
...@@ -24,7 +24,7 @@ func TestMonitor_MonitorGames(t *testing.T) { ...@@ -24,7 +24,7 @@ func TestMonitor_MonitorGames(t *testing.T) {
t.Parallel() t.Parallel()
t.Run("FailedFetchBlocknumber", func(t *testing.T) { t.Run("FailedFetchBlocknumber", func(t *testing.T) {
monitor, _, _, _, _, _ := setupMonitorTest(t) monitor, _, _, _, _, _, _ := setupMonitorTest(t)
boom := errors.New("boom") boom := errors.New("boom")
monitor.fetchBlockNumber = func(ctx context.Context) (uint64, error) { monitor.fetchBlockNumber = func(ctx context.Context) (uint64, error) {
return 0, boom return 0, boom
...@@ -34,7 +34,7 @@ func TestMonitor_MonitorGames(t *testing.T) { ...@@ -34,7 +34,7 @@ func TestMonitor_MonitorGames(t *testing.T) {
}) })
t.Run("FailedFetchBlockHash", func(t *testing.T) { t.Run("FailedFetchBlockHash", func(t *testing.T) {
monitor, _, _, _, _, _ := setupMonitorTest(t) monitor, _, _, _, _, _, _ := setupMonitorTest(t)
boom := errors.New("boom") boom := errors.New("boom")
monitor.fetchBlockHash = func(ctx context.Context, number *big.Int) (common.Hash, error) { monitor.fetchBlockHash = func(ctx context.Context, number *big.Int) (common.Hash, error) {
return common.Hash{}, boom return common.Hash{}, boom
...@@ -44,24 +44,26 @@ func TestMonitor_MonitorGames(t *testing.T) { ...@@ -44,24 +44,26 @@ func TestMonitor_MonitorGames(t *testing.T) {
}) })
t.Run("MonitorsWithNoGames", func(t *testing.T) { t.Run("MonitorsWithNoGames", func(t *testing.T) {
monitor, factory, forecast, delays, bonds, withdrawals := setupMonitorTest(t) monitor, factory, forecast, delays, bonds, withdrawals, claims := setupMonitorTest(t)
factory.games = []*monTypes.EnrichedGameData{} factory.games = []*monTypes.EnrichedGameData{}
err := monitor.monitorGames() err := monitor.monitorGames()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, forecast.calls) require.Equal(t, 1, forecast.calls)
require.Equal(t, 1, delays.calls) require.Equal(t, 1, delays.calls)
require.Equal(t, 1, bonds.calls) require.Equal(t, 1, bonds.calls)
require.Equal(t, 1, claims.calls)
require.Equal(t, 1, withdrawals.calls) require.Equal(t, 1, withdrawals.calls)
}) })
t.Run("MonitorsMultipleGames", func(t *testing.T) { t.Run("MonitorsMultipleGames", func(t *testing.T) {
monitor, factory, forecast, delays, bonds, withdrawals := setupMonitorTest(t) monitor, factory, forecast, delays, bonds, withdrawals, claims := setupMonitorTest(t)
factory.games = []*monTypes.EnrichedGameData{{}, {}, {}} factory.games = []*monTypes.EnrichedGameData{{}, {}, {}}
err := monitor.monitorGames() err := monitor.monitorGames()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, forecast.calls) require.Equal(t, 1, forecast.calls)
require.Equal(t, 1, delays.calls) require.Equal(t, 1, delays.calls)
require.Equal(t, 1, bonds.calls) require.Equal(t, 1, bonds.calls)
require.Equal(t, 1, claims.calls)
require.Equal(t, 1, withdrawals.calls) require.Equal(t, 1, withdrawals.calls)
}) })
} }
...@@ -70,7 +72,7 @@ func TestMonitor_StartMonitoring(t *testing.T) { ...@@ -70,7 +72,7 @@ func TestMonitor_StartMonitoring(t *testing.T) {
t.Run("MonitorsGames", func(t *testing.T) { t.Run("MonitorsGames", func(t *testing.T) {
addr1 := common.Address{0xaa} addr1 := common.Address{0xaa}
addr2 := common.Address{0xbb} addr2 := common.Address{0xbb}
monitor, factory, forecaster, _, _, _ := setupMonitorTest(t) monitor, factory, forecaster, _, _, _, _ := setupMonitorTest(t)
factory.games = []*monTypes.EnrichedGameData{newEnrichedGameData(addr1, 9999), newEnrichedGameData(addr2, 9999)} factory.games = []*monTypes.EnrichedGameData{newEnrichedGameData(addr1, 9999), newEnrichedGameData(addr2, 9999)}
factory.maxSuccess = len(factory.games) // Only allow two successful fetches factory.maxSuccess = len(factory.games) // Only allow two successful fetches
...@@ -83,7 +85,7 @@ func TestMonitor_StartMonitoring(t *testing.T) { ...@@ -83,7 +85,7 @@ func TestMonitor_StartMonitoring(t *testing.T) {
}) })
t.Run("FailsToFetchGames", func(t *testing.T) { t.Run("FailsToFetchGames", func(t *testing.T) {
monitor, factory, forecaster, _, _, _ := setupMonitorTest(t) monitor, factory, forecaster, _, _, _, _ := setupMonitorTest(t)
factory.fetchErr = errors.New("boom") factory.fetchErr = errors.New("boom")
monitor.StartMonitoring() monitor.StartMonitoring()
...@@ -105,7 +107,7 @@ func newEnrichedGameData(proxy common.Address, timestamp uint64) *monTypes.Enric ...@@ -105,7 +107,7 @@ func newEnrichedGameData(proxy common.Address, timestamp uint64) *monTypes.Enric
} }
} }
func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast, *mockDelayCalculator, *mockBonds, *mockWithdrawalMonitor) { func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast, *mockDelayCalculator, *mockBonds, *mockWithdrawalMonitor, *mockClaimMonitor) {
logger := testlog.Logger(t, log.LvlDebug) logger := testlog.Logger(t, log.LvlDebug)
fetchBlockNum := func(ctx context.Context) (uint64, error) { fetchBlockNum := func(ctx context.Context) (uint64, error) {
return 1, nil return 1, nil
...@@ -119,6 +121,7 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast ...@@ -119,6 +121,7 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast
extractor := &mockExtractor{} extractor := &mockExtractor{}
forecast := &mockForecast{} forecast := &mockForecast{}
bonds := &mockBonds{} bonds := &mockBonds{}
claims := &mockClaimMonitor{}
withdrawals := &mockWithdrawalMonitor{} withdrawals := &mockWithdrawalMonitor{}
delays := &mockDelayCalculator{} delays := &mockDelayCalculator{}
monitor := newGameMonitor( monitor := newGameMonitor(
...@@ -130,12 +133,21 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast ...@@ -130,12 +133,21 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast
delays.RecordClaimResolutionDelayMax, delays.RecordClaimResolutionDelayMax,
forecast.Forecast, forecast.Forecast,
bonds.CheckBonds, bonds.CheckBonds,
claims.CheckClaims,
withdrawals.CheckWithdrawals, withdrawals.CheckWithdrawals,
extractor.Extract, extractor.Extract,
fetchBlockNum, fetchBlockNum,
fetchBlockHash, fetchBlockHash,
) )
return monitor, extractor, forecast, delays, bonds, withdrawals return monitor, extractor, forecast, delays, bonds, withdrawals, claims
}
type mockClaimMonitor struct {
calls int
}
func (m *mockClaimMonitor) CheckClaims(games []*monTypes.EnrichedGameData) {
m.calls++
} }
type mockWithdrawalMonitor struct { type mockWithdrawalMonitor struct {
......
...@@ -42,6 +42,7 @@ type Service struct { ...@@ -42,6 +42,7 @@ type Service struct {
forecast *forecast forecast *forecast
bonds *bonds.Bonds bonds *bonds.Bonds
game *extract.GameCallerCreator game *extract.GameCallerCreator
claims *ClaimMonitor
withdrawals *WithdrawalMonitor withdrawals *WithdrawalMonitor
rollupClient *sources.RollupClient rollupClient *sources.RollupClient
validator *outputValidator validator *outputValidator
...@@ -86,6 +87,7 @@ func (s *Service) initFromConfig(ctx context.Context, cfg *config.Config) error ...@@ -86,6 +87,7 @@ func (s *Service) initFromConfig(ctx context.Context, cfg *config.Config) error
return fmt.Errorf("failed to init rollup client: %w", err) return fmt.Errorf("failed to init rollup client: %w", err)
} }
s.initClaimMonitor()
s.initWithdrawalMonitor() s.initWithdrawalMonitor()
s.initOutputValidator() // Must be called before initForecast s.initOutputValidator() // Must be called before initForecast
...@@ -105,6 +107,10 @@ func (s *Service) initFromConfig(ctx context.Context, cfg *config.Config) error ...@@ -105,6 +107,10 @@ func (s *Service) initFromConfig(ctx context.Context, cfg *config.Config) error
return nil return nil
} }
func (s *Service) initClaimMonitor() {
s.claims = NewClaimMonitor(s.logger, s.cl, s.metrics)
}
func (s *Service) initWithdrawalMonitor() { func (s *Service) initWithdrawalMonitor() {
s.withdrawals = NewWithdrawalMonitor(s.logger, s.metrics) s.withdrawals = NewWithdrawalMonitor(s.logger, s.metrics)
} }
...@@ -223,6 +229,7 @@ func (s *Service) initMonitor(ctx context.Context, cfg *config.Config) { ...@@ -223,6 +229,7 @@ func (s *Service) initMonitor(ctx context.Context, cfg *config.Config) {
s.delays.RecordClaimResolutionDelayMax, s.delays.RecordClaimResolutionDelayMax,
s.forecast.Forecast, s.forecast.Forecast,
s.bonds.CheckBonds, s.bonds.CheckBonds,
s.claims.CheckClaims,
s.withdrawals.CheckWithdrawals, s.withdrawals.CheckWithdrawals,
s.extractor.Extract, s.extractor.Extract,
s.l1Client.BlockNumber, s.l1Client.BlockNumber,
......
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