Commit a5e34735 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-dispute-mon: Add metric to report timestamp of last invalid proposal (#10373)

parent 8ed6612b
......@@ -92,6 +92,8 @@ type Metricer interface {
RecordGameAgreement(status GameAgreementStatus, count int)
RecordLatestInvalidProposal(timestamp uint64)
RecordIgnoredGames(count int)
RecordBondCollateral(addr common.Address, required *big.Int, available *big.Int)
......@@ -127,8 +129,9 @@ type Metrics struct {
lastOutputFetch prometheus.Gauge
gamesAgreement prometheus.GaugeVec
ignoredGames prometheus.Gauge
gamesAgreement prometheus.GaugeVec
latestInvalidProposal prometheus.Gauge
ignoredGames prometheus.Gauge
requiredCollateral prometheus.GaugeVec
availableCollateral prometheus.GaugeVec
......@@ -228,6 +231,11 @@ func NewMetrics() *Metrics {
"result_correctness",
"root_agreement",
}),
latestInvalidProposal: factory.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "latest_invalid_proposal",
Help: "Timestamp of the most recent game with an invalid root claim in unix seconds",
}),
ignoredGames: factory.NewGauge(prometheus.GaugeOpts{
Namespace: Namespace,
Name: "ignored_games",
......@@ -370,6 +378,10 @@ func (m *Metrics) RecordGameAgreement(status GameAgreementStatus, count int) {
m.gamesAgreement.WithLabelValues(labelValuesFor(status)...).Set(float64(count))
}
func (m *Metrics) RecordLatestInvalidProposal(timestamp uint64) {
m.latestInvalidProposal.Set(float64(timestamp))
}
func (m *Metrics) RecordIgnoredGames(count int) {
m.ignoredGames.Set(float64(count))
}
......
......@@ -33,6 +33,8 @@ func (*NoopMetricsImpl) RecordOutputFetchTime(_ float64) {}
func (*NoopMetricsImpl) RecordGameAgreement(_ GameAgreementStatus, _ int) {}
func (*NoopMetricsImpl) RecordLatestInvalidProposal(_ uint64) {}
func (*NoopMetricsImpl) RecordIgnoredGames(_ int) {}
func (i *NoopMetricsImpl) RecordBondCollateral(_ common.Address, _ *big.Int, _ *big.Int) {}
......@@ -24,9 +24,24 @@ type OutputValidator interface {
type ForecastMetrics interface {
RecordGameAgreement(status metrics.GameAgreementStatus, count int)
RecordLatestInvalidProposal(timestamp uint64)
RecordIgnoredGames(count int)
}
type forecastBatch struct {
AgreeDefenderAhead int
DisagreeDefenderAhead int
AgreeChallengerAhead int
DisagreeChallengerAhead int
AgreeDefenderWins int
DisagreeDefenderWins int
AgreeChallengerWins int
DisagreeChallengerWins int
LatestInvalidProposal uint64
}
type forecast struct {
logger log.Logger
metrics ForecastMetrics
......@@ -42,7 +57,7 @@ func newForecast(logger log.Logger, metrics ForecastMetrics, validator OutputVal
}
func (f *forecast) Forecast(ctx context.Context, games []*monTypes.EnrichedGameData, ignoredCount int) {
batch := monTypes.ForecastBatch{}
batch := forecastBatch{}
for _, game := range games {
if err := f.forecastGame(ctx, game, &batch); err != nil {
f.logger.Error("Failed to forecast game", "err", err)
......@@ -51,7 +66,7 @@ func (f *forecast) Forecast(ctx context.Context, games []*monTypes.EnrichedGameD
f.recordBatch(batch, ignoredCount)
}
func (f *forecast) recordBatch(batch monTypes.ForecastBatch, ignoredCount int) {
func (f *forecast) recordBatch(batch forecastBatch, ignoredCount int) {
f.metrics.RecordGameAgreement(metrics.AgreeDefenderWins, batch.AgreeDefenderWins)
f.metrics.RecordGameAgreement(metrics.DisagreeDefenderWins, batch.DisagreeDefenderWins)
f.metrics.RecordGameAgreement(metrics.AgreeChallengerWins, batch.AgreeChallengerWins)
......@@ -62,10 +77,12 @@ func (f *forecast) recordBatch(batch monTypes.ForecastBatch, ignoredCount int) {
f.metrics.RecordGameAgreement(metrics.AgreeDefenderAhead, batch.AgreeDefenderAhead)
f.metrics.RecordGameAgreement(metrics.DisagreeDefenderAhead, batch.DisagreeDefenderAhead)
f.metrics.RecordLatestInvalidProposal(batch.LatestInvalidProposal)
f.metrics.RecordIgnoredGames(ignoredCount)
}
func (f *forecast) forecastGame(ctx context.Context, game *monTypes.EnrichedGameData, metrics *monTypes.ForecastBatch) error {
func (f *forecast) forecastGame(ctx context.Context, game *monTypes.EnrichedGameData, metrics *forecastBatch) error {
// Check the root agreement.
agreement, expected, err := f.validator.CheckRootAgreement(ctx, game.L1HeadNum, game.L2BlockNumber, game.RootClaim)
if err != nil {
......@@ -75,6 +92,9 @@ func (f *forecast) forecastGame(ctx context.Context, game *monTypes.EnrichedGame
expectedResult := types.GameStatusDefenderWon
if !agreement {
expectedResult = types.GameStatusChallengerWon
if metrics.LatestInvalidProposal < game.Timestamp {
metrics.LatestInvalidProposal = game.Timestamp
}
}
if game.Status != types.GameStatusInProgress {
......
......@@ -236,8 +236,8 @@ func TestForecast_Forecast_MultipleGames(t *testing.T) {
{},
mockRootClaim,
{},
{},
{},
{}, // Expected latest invalid proposal (will have timestamp 7)
mockRootClaim,
}
games := make([]*monTypes.EnrichedGameData, 9)
for i := range games {
......@@ -245,6 +245,9 @@ func TestForecast_Forecast_MultipleGames(t *testing.T) {
Status: gameStatus[i],
Claims: claims[i],
RootClaim: rootClaims[i],
GameMetadata: types.GameMetadata{
Timestamp: uint64(i),
},
}
}
forecast.Forecast(context.Background(), games, 3)
......@@ -255,10 +258,12 @@ func TestForecast_Forecast_MultipleGames(t *testing.T) {
expectedMetrics[metrics.DisagreeChallengerAhead] = 1
expectedMetrics[metrics.AgreeDefenderAhead] = 1
expectedMetrics[metrics.DisagreeDefenderAhead] = 1
expectedMetrics[metrics.AgreeChallengerWins] = 1
expectedMetrics[metrics.DisagreeDefenderWins] = 2
expectedMetrics[metrics.DisagreeChallengerWins] = 3
expectedMetrics[metrics.DisagreeChallengerWins] = 2
require.Equal(t, expectedMetrics, m.gameAgreement)
require.Equal(t, 3, m.ignoredGames)
require.EqualValues(t, 7, m.latestInvalidProposal)
}
func setupForecastTest(t *testing.T) (*forecast, *mockForecastMetrics, *stubOutputValidator, *testlog.CapturingHandler) {
......@@ -284,14 +289,19 @@ func zeroGameAgreement() map[metrics.GameAgreementStatus]int {
}
type mockForecastMetrics struct {
gameAgreement map[metrics.GameAgreementStatus]int
ignoredGames int
gameAgreement map[metrics.GameAgreementStatus]int
ignoredGames int
latestInvalidProposal uint64
}
func (m *mockForecastMetrics) RecordGameAgreement(status metrics.GameAgreementStatus, count int) {
m.gameAgreement[status] = count
}
func (m *mockForecastMetrics) RecordLatestInvalidProposal(timestamp uint64) {
m.latestInvalidProposal = timestamp
}
func (m *mockForecastMetrics) RecordIgnoredGames(count int) {
m.ignoredGames = count
}
......
......@@ -54,15 +54,3 @@ type BidirectionalClaim struct {
Claim *faultTypes.Claim
Children []*BidirectionalClaim
}
type ForecastBatch struct {
AgreeDefenderAhead int
DisagreeDefenderAhead int
AgreeChallengerAhead int
DisagreeChallengerAhead int
AgreeDefenderWins int
DisagreeDefenderWins int
AgreeChallengerWins int
DisagreeChallengerWins int
}
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