From 94f2275c9cbe0590a65351b031d17fae5d532a16 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 12:44:58 +0100 Subject: [PATCH 01/15] PoC --- .../capabilities/ccip/oraclecreator/plugin.go | 9 + core/services/ocr3/promwrapper/factory.go | 35 ++++ core/services/ocr3/promwrapper/plugin.go | 175 ++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 core/services/ocr3/promwrapper/factory.go create mode 100644 core/services/ocr3/promwrapper/plugin.go diff --git a/core/capabilities/ccip/oraclecreator/plugin.go b/core/capabilities/ccip/oraclecreator/plugin.go index 6b63491f8e6..fb1ab310615 100644 --- a/core/capabilities/ccip/oraclecreator/plugin.go +++ b/core/capabilities/ccip/oraclecreator/plugin.go @@ -22,6 +22,7 @@ import ( cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr3/promwrapper" "github.com/smartcontractkit/libocr/commontypes" libocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus" @@ -229,6 +230,12 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( ) (ocr3types.ReportingPluginFactory[[]byte], ocr3types.ContractTransmitter[[]byte], error) { var factory ocr3types.ReportingPluginFactory[[]byte] var transmitter ocr3types.ContractTransmitter[[]byte] + + chainID, err := chainsel.GetChainIDFromSelector(uint64(config.Config.ChainSelector)) + if err != nil { + return nil, nil, fmt.Errorf("unsupported chain selector %d %v", config.Config.ChainSelector, err) + } + if config.Config.PluginType == uint8(cctypes.PluginTypeCCIPCommit) { if !i.peerWrapper.IsStarted() { return nil, nil, fmt.Errorf("peer wrapper is not started") @@ -263,6 +270,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( rmnPeerClient, rmnCrypto, ) + factory = promwrapper.NewReportingPluginFactory[[]byte](factory, chainID, "commit") transmitter = ocrimpls.NewCommitContractTransmitter[[]byte](destChainWriter, ocrtypes.Account(destFromAccounts[0]), hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm? @@ -283,6 +291,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( contractReaders, chainWriters, ) + factory = promwrapper.NewReportingPluginFactory[[]byte](factory, chainID, "exec") transmitter = ocrimpls.NewExecContractTransmitter[[]byte](destChainWriter, ocrtypes.Account(destFromAccounts[0]), hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm? diff --git a/core/services/ocr3/promwrapper/factory.go b/core/services/ocr3/promwrapper/factory.go new file mode 100644 index 00000000000..71a5f7b9340 --- /dev/null +++ b/core/services/ocr3/promwrapper/factory.go @@ -0,0 +1,35 @@ +package promwrapper + +import ( + "context" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" +) + +var _ ocr3types.ReportingPluginFactory[any] = &ReportingPluginFactory[any]{} + +type ReportingPluginFactory[RI any] struct { + origin ocr3types.ReportingPluginFactory[RI] + chainID string + plugin string +} + +func NewReportingPluginFactory[RI any]( + origin ocr3types.ReportingPluginFactory[RI], + chainID string, + plugin string, +) *ReportingPluginFactory[RI] { + return &ReportingPluginFactory[RI]{ + origin: origin, + chainID: chainID, + plugin: plugin, + } +} + +func (r ReportingPluginFactory[RI]) NewReportingPlugin(ctx context.Context, config ocr3types.ReportingPluginConfig) (ocr3types.ReportingPlugin[RI], ocr3types.ReportingPluginInfo, error) { + plugin, info, err := r.origin.NewReportingPlugin(ctx, config) + if err != nil { + return nil, ocr3types.ReportingPluginInfo{}, err + } + wrapped := NewReportingPlugin(plugin, r.chainID, r.plugin, config.ConfigDigest) + return wrapped, info, err +} diff --git a/core/services/ocr3/promwrapper/plugin.go b/core/services/ocr3/promwrapper/plugin.go new file mode 100644 index 00000000000..a64233205ef --- /dev/null +++ b/core/services/ocr3/promwrapper/plugin.go @@ -0,0 +1,175 @@ +package promwrapper + +import ( + "context" + "strconv" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +type functionType string + +const ( + query functionType = "query" + observation functionType = "observation" + validateObservation functionType = "validateObservation" + outcome functionType = "outcome" + reports functionType = "reports" + shouldAccept functionType = "shouldAccept" + shouldTransmit functionType = "shouldTransmit" +) + +var ( + buckets = []float64{ + float64(1 * time.Millisecond), + float64(5 * time.Millisecond), + float64(10 * time.Millisecond), + float64(50 * time.Millisecond), + float64(100 * time.Millisecond), + float64(500 * time.Millisecond), + float64(time.Second), + float64(5 * time.Second), + float64(10 * time.Second), + } + + reportsGenerated = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "ocr3_reports_generated", + Help: "Tracks number of reports generated withing a single OCR3's Reports step", + }, + []string{"chainID", "plugin"}, + ) + sequenceNumbers = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "ocr3_sequence_numbers", + Help: "Tracks OCR3 sequence numbers", + }, + []string{"chainID", "plugin"}, + ) + phaseDurationBucket = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "ocr3_phase_duration", + Help: "The amount of time elapsed during the OCR3 plugin's function", + Buckets: buckets, + }, + []string{"chainID", "plugin", "function"}, + ) +) + +var ( + _ ocr3types.ReportingPlugin[any] = &ReportingPlugin[any]{} +) + +type ReportingPlugin[RI any] struct { + ocr3types.ReportingPlugin[RI] + + // Mandatory labels + chainID string + plugin string + configDigest string + + // Prom + reportsGenerated *prometheus.GaugeVec + sequenceNumbers *prometheus.GaugeVec + durations *prometheus.HistogramVec +} + +func NewReportingPlugin[RI any]( + origin ocr3types.ReportingPlugin[RI], + chainID string, + plugin string, + configDigest types.ConfigDigest, +) *ReportingPlugin[RI] { + return &ReportingPlugin[RI]{ + ReportingPlugin: origin, + + chainID: chainID, + plugin: plugin, + configDigest: configDigest.Hex(), + + reportsGenerated: reportsGenerated, + sequenceNumbers: sequenceNumbers, + durations: phaseDurationBucket, + } +} + +func (p *ReportingPlugin[RI]) Query(ctx context.Context, outctx ocr3types.OutcomeContext) (ocrtypes.Query, error) { + return withObservedExecution(p, query, func() (ocrtypes.Query, error) { + return p.ReportingPlugin.Query(ctx, outctx) + }) +} + +func (p *ReportingPlugin[RI]) Observation(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query) (ocrtypes.Observation, error) { + return withObservedExecution(p, observation, func() (ocrtypes.Observation, error) { + return p.ReportingPlugin.Observation(ctx, outctx, query) + }) +} + +func (p *ReportingPlugin[RI]) ValidateObservation(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query, ao ocrtypes.AttributedObservation) error { + _, err := withObservedExecution(p, validateObservation, func() (any, error) { + err := p.ReportingPlugin.ValidateObservation(ctx, outctx, query, ao) + return nil, err + }) + return err +} + +func (p *ReportingPlugin[RI]) Outcome(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query, aos []ocrtypes.AttributedObservation) (ocr3types.Outcome, error) { + return withObservedExecution(p, outcome, func() (ocr3types.Outcome, error) { + return p.ReportingPlugin.Outcome(ctx, outctx, query, aos) + }) +} + +func (p *ReportingPlugin[RI]) Reports(ctx context.Context, seqNr uint64, outcome ocr3types.Outcome) ([]ocr3types.ReportPlus[RI], error) { + result, err := withObservedExecution(p, reports, func() ([]ocr3types.ReportPlus[RI], error) { + return p.ReportingPlugin.Reports(ctx, seqNr, outcome) + }) + p.trackReportSizes(result) + return result, err +} + +func (p *ReportingPlugin[RI]) ShouldAcceptAttestedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { + return withObservedExecution(p, shouldAccept, func() (bool, error) { + return p.ReportingPlugin.ShouldAcceptAttestedReport(ctx, seqNr, reportWithInfo) + }) +} + +func (p *ReportingPlugin[RI]) ShouldTransmitAcceptedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { + return withObservedExecution(p, shouldTransmit, func() (bool, error) { + return p.ReportingPlugin.ShouldTransmitAcceptedReport(ctx, seqNr, reportWithInfo) + }) +} + +func (p *ReportingPlugin[RI]) Close() error { + return p.ReportingPlugin.Close() +} + +func (p *ReportingPlugin[RI]) trackReportSizes( + reports []ocr3types.ReportPlus[RI], +) { + p.reportsGenerated. + WithLabelValues(p.chainID, p.plugin, p.configDigest). + Set(float64(len(reports))) +} + +func withObservedExecution[RI, R any]( + p *ReportingPlugin[RI], + function functionType, + exec func() (R, error), +) (R, error) { + start := time.Now() + result, err := exec() + + success := err == nil + + p.durations. + WithLabelValues(p.chainID, p.plugin, p.configDigest, string(function), strconv.FormatBool(success)). + Observe(float64(time.Since(start))) + + return result, err +} From 92eecd5dd7ab48a448558186fd65347381e56463 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 13:24:38 +0100 Subject: [PATCH 02/15] Basic implementation --- core/services/ocr3/promwrapper/factory.go | 9 +- core/services/ocr3/promwrapper/plugin.go | 85 ++-------- core/services/ocr3/promwrapper/plugin_test.go | 156 ++++++++++++++++++ core/services/ocr3/promwrapper/types.go | 54 ++++++ 4 files changed, 230 insertions(+), 74 deletions(-) create mode 100644 core/services/ocr3/promwrapper/plugin_test.go create mode 100644 core/services/ocr3/promwrapper/types.go diff --git a/core/services/ocr3/promwrapper/factory.go b/core/services/ocr3/promwrapper/factory.go index 71a5f7b9340..5a8a5940048 100644 --- a/core/services/ocr3/promwrapper/factory.go +++ b/core/services/ocr3/promwrapper/factory.go @@ -2,6 +2,7 @@ package promwrapper import ( "context" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ) @@ -30,6 +31,12 @@ func (r ReportingPluginFactory[RI]) NewReportingPlugin(ctx context.Context, conf if err != nil { return nil, ocr3types.ReportingPluginInfo{}, err } - wrapped := NewReportingPlugin(plugin, r.chainID, r.plugin, config.ConfigDigest) + wrapped := NewReportingPlugin( + plugin, + r.chainID, + r.plugin, + promOCR3ReportsGenerated, + promOCR3Durations, + ) return wrapped, info, err } diff --git a/core/services/ocr3/promwrapper/plugin.go b/core/services/ocr3/promwrapper/plugin.go index a64233205ef..885853691af 100644 --- a/core/services/ocr3/promwrapper/plugin.go +++ b/core/services/ocr3/promwrapper/plugin.go @@ -6,77 +6,19 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - - "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) -type functionType string - -const ( - query functionType = "query" - observation functionType = "observation" - validateObservation functionType = "validateObservation" - outcome functionType = "outcome" - reports functionType = "reports" - shouldAccept functionType = "shouldAccept" - shouldTransmit functionType = "shouldTransmit" -) - -var ( - buckets = []float64{ - float64(1 * time.Millisecond), - float64(5 * time.Millisecond), - float64(10 * time.Millisecond), - float64(50 * time.Millisecond), - float64(100 * time.Millisecond), - float64(500 * time.Millisecond), - float64(time.Second), - float64(5 * time.Second), - float64(10 * time.Second), - } - - reportsGenerated = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "ocr3_reports_generated", - Help: "Tracks number of reports generated withing a single OCR3's Reports step", - }, - []string{"chainID", "plugin"}, - ) - sequenceNumbers = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "ocr3_sequence_numbers", - Help: "Tracks OCR3 sequence numbers", - }, - []string{"chainID", "plugin"}, - ) - phaseDurationBucket = promauto.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "ocr3_phase_duration", - Help: "The amount of time elapsed during the OCR3 plugin's function", - Buckets: buckets, - }, - []string{"chainID", "plugin", "function"}, - ) -) - -var ( - _ ocr3types.ReportingPlugin[any] = &ReportingPlugin[any]{} -) +var _ ocr3types.ReportingPlugin[any] = &ReportingPlugin[any]{} type ReportingPlugin[RI any] struct { ocr3types.ReportingPlugin[RI] + chainID string + plugin string - // Mandatory labels - chainID string - plugin string - configDigest string - - // Prom + // Prometheus components for tracking metrics reportsGenerated *prometheus.GaugeVec - sequenceNumbers *prometheus.GaugeVec durations *prometheus.HistogramVec } @@ -84,18 +26,15 @@ func NewReportingPlugin[RI any]( origin ocr3types.ReportingPlugin[RI], chainID string, plugin string, - configDigest types.ConfigDigest, + reportsGenerated *prometheus.GaugeVec, + durations *prometheus.HistogramVec, ) *ReportingPlugin[RI] { return &ReportingPlugin[RI]{ - ReportingPlugin: origin, - - chainID: chainID, - plugin: plugin, - configDigest: configDigest.Hex(), - + ReportingPlugin: origin, + chainID: chainID, + plugin: plugin, reportsGenerated: reportsGenerated, - sequenceNumbers: sequenceNumbers, - durations: phaseDurationBucket, + durations: durations, } } @@ -153,7 +92,7 @@ func (p *ReportingPlugin[RI]) trackReportSizes( reports []ocr3types.ReportPlus[RI], ) { p.reportsGenerated. - WithLabelValues(p.chainID, p.plugin, p.configDigest). + WithLabelValues(p.chainID, p.plugin). Set(float64(len(reports))) } @@ -168,7 +107,7 @@ func withObservedExecution[RI, R any]( success := err == nil p.durations. - WithLabelValues(p.chainID, p.plugin, p.configDigest, string(function), strconv.FormatBool(success)). + WithLabelValues(p.chainID, p.plugin, string(function), strconv.FormatBool(success)). Observe(float64(time.Since(start))) return result, err diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go new file mode 100644 index 00000000000..0879d66c7d5 --- /dev/null +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -0,0 +1,156 @@ +package promwrapper + +import ( + "context" + "fmt" + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + io_prometheus_client "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +func Test_ReportsGeneratedGauge(t *testing.T) { + plugin1 := NewReportingPlugin( + fakePlugin[uint]{reports: make([]ocr3types.ReportPlus[uint], 2)}, + "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, + ) + plugin2 := NewReportingPlugin( + fakePlugin[bool]{reports: make([]ocr3types.ReportPlus[bool], 10)}, + "solana", "different_plugin", promOCR3ReportsGenerated, promOCR3Durations, + ) + plugin3 := NewReportingPlugin( + fakePlugin[string]{err: fmt.Errorf("error")}, + "1234", "empty", promOCR3ReportsGenerated, promOCR3Durations, + ) + + r1, err := plugin1.Reports(nil, 1, nil) + require.NoError(t, err) + require.Len(t, r1, 2) + + for i := 0; i < 10; i++ { + r2, err := plugin2.Reports(nil, 1, nil) + require.NoError(t, err) + require.Len(t, r2, 10) + } + + _, err = plugin3.Reports(nil, 1, nil) + require.Error(t, err) + + g1 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("123", "empty")) + require.Equal(t, float64(2), g1) + + g2 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin")) + require.Equal(t, float64(10), g2) + + g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty")) + require.Equal(t, float64(0), g3) +} + +func Test_DurationHistograms(t *testing.T) { + plugin1 := NewReportingPlugin( + fakePlugin[uint]{}, + "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, + ) + plugin2 := NewReportingPlugin( + fakePlugin[uint]{err: fmt.Errorf("error")}, + "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, + ) + plugin3 := NewReportingPlugin( + fakePlugin[uint]{}, + "solana", "commit", promOCR3ReportsGenerated, promOCR3Durations, + ) + + for _, p := range []*ReportingPlugin[uint]{plugin1, plugin2, plugin3} { + _, _ = p.Query(nil, ocr3types.OutcomeContext{}) + for i := 0; i < 2; i++ { + _, _ = p.Observation(nil, ocr3types.OutcomeContext{}, nil) + } + _ = p.ValidateObservation(nil, ocr3types.OutcomeContext{}, nil, ocrtypes.AttributedObservation{}) + _, _ = p.Outcome(nil, ocr3types.OutcomeContext{}, nil, nil) + _, _ = p.Reports(nil, 0, nil) + _, _ = p.ShouldAcceptAttestedReport(nil, 0, ocr3types.ReportWithInfo[uint]{}) + _, _ = p.ShouldTransmitAcceptedReport(nil, 0, ocr3types.ReportWithInfo[uint]{}) + } + + require.Equal(t, 1, counterFromHistogramByLabels(t, promOCR3Durations, "123", "empty", "query", "true")) + require.Equal(t, 1, counterFromHistogramByLabels(t, promOCR3Durations, "123", "empty", "query", "false")) + require.Equal(t, 1, counterFromHistogramByLabels(t, promOCR3Durations, "solana", "commit", "query", "true")) + + require.Equal(t, 2, counterFromHistogramByLabels(t, promOCR3Durations, "123", "empty", "observation", "true")) + require.Equal(t, 2, counterFromHistogramByLabels(t, promOCR3Durations, "123", "empty", "observation", "false")) + require.Equal(t, 2, counterFromHistogramByLabels(t, promOCR3Durations, "solana", "commit", "observation", "true")) +} + +type fakePlugin[RI any] struct { + reports []ocr3types.ReportPlus[RI] + err error +} + +func (f fakePlugin[RI]) Query(context.Context, ocr3types.OutcomeContext) (ocrtypes.Query, error) { + if f.err != nil { + return nil, f.err + } + return ocrtypes.Query{}, nil +} + +func (f fakePlugin[RI]) Observation(context.Context, ocr3types.OutcomeContext, ocrtypes.Query) (ocrtypes.Observation, error) { + if f.err != nil { + return nil, f.err + } + return ocrtypes.Observation{}, nil +} + +func (f fakePlugin[RI]) ValidateObservation(context.Context, ocr3types.OutcomeContext, ocrtypes.Query, ocrtypes.AttributedObservation) error { + return f.err +} + +func (f fakePlugin[RI]) ObservationQuorum(context.Context, ocr3types.OutcomeContext, ocrtypes.Query, []ocrtypes.AttributedObservation) (quorumReached bool, err error) { + return false, f.err +} + +func (f fakePlugin[RI]) Outcome(context.Context, ocr3types.OutcomeContext, ocrtypes.Query, []ocrtypes.AttributedObservation) (ocr3types.Outcome, error) { + if f.err != nil { + return nil, f.err + } + return ocr3types.Outcome{}, nil +} + +func (f fakePlugin[RI]) Reports(context.Context, uint64, ocr3types.Outcome) ([]ocr3types.ReportPlus[RI], error) { + if f.err != nil { + return nil, f.err + } + return f.reports, nil +} + +func (f fakePlugin[RI]) ShouldAcceptAttestedReport(context.Context, uint64, ocr3types.ReportWithInfo[RI]) (bool, error) { + return false, f.err +} + +func (f fakePlugin[RI]) ShouldTransmitAcceptedReport(context.Context, uint64, ocr3types.ReportWithInfo[RI]) (bool, error) { + return false, f.err +} + +func (f fakePlugin[RI]) Close() error { + return f.err +} + +func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.HistogramVec, labels ...string) int { + observer, err := histogramVec.GetMetricWithLabelValues(labels...) + require.NoError(t, err) + + metricCh := make(chan prometheus.Metric, 1) + observer.(prometheus.Histogram).Collect(metricCh) + close(metricCh) + + metric := <-metricCh + pb := &io_prometheus_client.Metric{} + err = metric.Write(pb) + require.NoError(t, err) + + return int(pb.GetHistogram().GetSampleCount()) +} diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go new file mode 100644 index 00000000000..8e58eac8e49 --- /dev/null +++ b/core/services/ocr3/promwrapper/types.go @@ -0,0 +1,54 @@ +package promwrapper + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "time" +) + +type functionType string + +const ( + query functionType = "query" + observation functionType = "observation" + validateObservation functionType = "validateObservation" + outcome functionType = "outcome" + reports functionType = "reports" + shouldAccept functionType = "shouldAccept" + shouldTransmit functionType = "shouldTransmit" +) + +var ( + buckets = []float64{ + float64(1 * time.Millisecond), + float64(5 * time.Millisecond), + float64(10 * time.Millisecond), + float64(25 * time.Millisecond), + float64(50 * time.Millisecond), + float64(75 * time.Millisecond), + float64(100 * time.Millisecond), + float64(200 * time.Millisecond), + float64(500 * time.Millisecond), + float64(700 * time.Millisecond), + float64(time.Second), + float64(2 * time.Second), + float64(5 * time.Second), + float64(10 * time.Second), + } + + promOCR3ReportsGenerated = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "ocr3_reports_generated", + Help: "Tracks number of reports generated withing a single OCR3's Reports step", + }, + []string{"chainID", "plugin"}, + ) + promOCR3Durations = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "ocr3_phase_duration", + Help: "The amount of time elapsed during the OCR3 plugin's function", + Buckets: buckets, + }, + []string{"chainID", "plugin", "function", "success"}, + ) +) From a511ee9d4cb2db15f7697bb66670464cb08e038d Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 13:25:55 +0100 Subject: [PATCH 03/15] Basic implementation --- .changeset/fuzzy-hairs-appear.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fuzzy-hairs-appear.md diff --git a/.changeset/fuzzy-hairs-appear.md b/.changeset/fuzzy-hairs-appear.md new file mode 100644 index 00000000000..a4797462546 --- /dev/null +++ b/.changeset/fuzzy-hairs-appear.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Prometheus observability layer added to OCR3 Reporting Plugins #internal From f51a9eaf026490b471fc2354ab544fb5700b2117 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 13:31:19 +0100 Subject: [PATCH 04/15] Basic implementation --- core/capabilities/ccip/oraclecreator/plugin.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/capabilities/ccip/oraclecreator/plugin.go b/core/capabilities/ccip/oraclecreator/plugin.go index fb1ab310615..be2321ab133 100644 --- a/core/capabilities/ccip/oraclecreator/plugin.go +++ b/core/capabilities/ccip/oraclecreator/plugin.go @@ -270,7 +270,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( rmnPeerClient, rmnCrypto, ) - factory = promwrapper.NewReportingPluginFactory[[]byte](factory, chainID, "commit") + factory = promwrapper.NewReportingPluginFactory[[]byte](factory, chainID, "CCIPCommit") transmitter = ocrimpls.NewCommitContractTransmitter[[]byte](destChainWriter, ocrtypes.Account(destFromAccounts[0]), hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm? @@ -291,7 +291,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( contractReaders, chainWriters, ) - factory = promwrapper.NewReportingPluginFactory[[]byte](factory, chainID, "exec") + factory = promwrapper.NewReportingPluginFactory[[]byte](factory, chainID, "CCIPExec") transmitter = ocrimpls.NewExecContractTransmitter[[]byte](destChainWriter, ocrtypes.Account(destFromAccounts[0]), hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm? From a680a9c78aaadbc6062a9af71ca94e864198f708 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 13:53:42 +0100 Subject: [PATCH 05/15] fixes --- .../services/ocr3/promwrapper/factory_test.go | 40 +++++++++++++++++++ core/services/ocr3/promwrapper/plugin.go | 6 +-- core/services/ocr3/promwrapper/plugin_test.go | 23 ++++++----- core/services/ocr3/promwrapper/types.go | 4 +- 4 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 core/services/ocr3/promwrapper/factory_test.go diff --git a/core/services/ocr3/promwrapper/factory_test.go b/core/services/ocr3/promwrapper/factory_test.go new file mode 100644 index 00000000000..9236c62925f --- /dev/null +++ b/core/services/ocr3/promwrapper/factory_test.go @@ -0,0 +1,40 @@ +package promwrapper + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" +) + +func Test_WrapperFactory(t *testing.T) { + validFactory := NewReportingPluginFactory(fakeFactory[uint]{}, "solana", "plugin") + failingFactory := NewReportingPluginFactory(fakeFactory[uint]{err: fmt.Errorf("error")}, "123", "plugin") + + plugin, _, err := validFactory.NewReportingPlugin(tests.Context(t), ocr3types.ReportingPluginConfig{}) + require.NoError(t, err) + + _, err = plugin.Outcome(tests.Context(t), ocr3types.OutcomeContext{}, nil, nil) + require.NoError(t, err) + + require.Equal(t, 1, counterFromHistogramByLabels(t, promOCR3Durations, "solana", "plugin", "outcome", "true")) + require.Equal(t, 0, counterFromHistogramByLabels(t, promOCR3Durations, "solana", "plugin", "outcome", "false")) + + _, _, err = failingFactory.NewReportingPlugin(tests.Context(t), ocr3types.ReportingPluginConfig{}) + require.Error(t, err) +} + +type fakeFactory[RI any] struct { + err error +} + +func (f fakeFactory[RI]) NewReportingPlugin(context.Context, ocr3types.ReportingPluginConfig) (ocr3types.ReportingPlugin[RI], ocr3types.ReportingPluginInfo, error) { + if f.err != nil { + return nil, ocr3types.ReportingPluginInfo{}, f.err + } + return fakePlugin[RI]{}, ocr3types.ReportingPluginInfo{}, nil +} diff --git a/core/services/ocr3/promwrapper/plugin.go b/core/services/ocr3/promwrapper/plugin.go index 885853691af..dba45b4a9c3 100644 --- a/core/services/ocr3/promwrapper/plugin.go +++ b/core/services/ocr3/promwrapper/plugin.go @@ -18,7 +18,7 @@ type ReportingPlugin[RI any] struct { plugin string // Prometheus components for tracking metrics - reportsGenerated *prometheus.GaugeVec + reportsGenerated *prometheus.CounterVec durations *prometheus.HistogramVec } @@ -26,7 +26,7 @@ func NewReportingPlugin[RI any]( origin ocr3types.ReportingPlugin[RI], chainID string, plugin string, - reportsGenerated *prometheus.GaugeVec, + reportsGenerated *prometheus.CounterVec, durations *prometheus.HistogramVec, ) *ReportingPlugin[RI] { return &ReportingPlugin[RI]{ @@ -93,7 +93,7 @@ func (p *ReportingPlugin[RI]) trackReportSizes( ) { p.reportsGenerated. WithLabelValues(p.chainID, p.plugin). - Set(float64(len(reports))) + Add(float64(len(reports))) } func withObservedExecution[RI, R any]( diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go index 0879d66c7d5..1e68c987fc9 100644 --- a/core/services/ocr3/promwrapper/plugin_test.go +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -10,6 +10,7 @@ import ( io_prometheus_client "github.com/prometheus/client_model/go" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -28,24 +29,24 @@ func Test_ReportsGeneratedGauge(t *testing.T) { "1234", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) - r1, err := plugin1.Reports(nil, 1, nil) + r1, err := plugin1.Reports(tests.Context(t), 1, nil) require.NoError(t, err) require.Len(t, r1, 2) for i := 0; i < 10; i++ { - r2, err := plugin2.Reports(nil, 1, nil) + r2, err := plugin2.Reports(tests.Context(t), 1, nil) require.NoError(t, err) require.Len(t, r2, 10) } - _, err = plugin3.Reports(nil, 1, nil) + _, err = plugin3.Reports(tests.Context(t), 1, nil) require.Error(t, err) g1 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("123", "empty")) require.Equal(t, float64(2), g1) g2 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin")) - require.Equal(t, float64(10), g2) + require.Equal(t, float64(100), g2) g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty")) require.Equal(t, float64(0), g3) @@ -66,15 +67,15 @@ func Test_DurationHistograms(t *testing.T) { ) for _, p := range []*ReportingPlugin[uint]{plugin1, plugin2, plugin3} { - _, _ = p.Query(nil, ocr3types.OutcomeContext{}) + _, _ = p.Query(tests.Context(t), ocr3types.OutcomeContext{}) for i := 0; i < 2; i++ { - _, _ = p.Observation(nil, ocr3types.OutcomeContext{}, nil) + _, _ = p.Observation(tests.Context(t), ocr3types.OutcomeContext{}, nil) } - _ = p.ValidateObservation(nil, ocr3types.OutcomeContext{}, nil, ocrtypes.AttributedObservation{}) - _, _ = p.Outcome(nil, ocr3types.OutcomeContext{}, nil, nil) - _, _ = p.Reports(nil, 0, nil) - _, _ = p.ShouldAcceptAttestedReport(nil, 0, ocr3types.ReportWithInfo[uint]{}) - _, _ = p.ShouldTransmitAcceptedReport(nil, 0, ocr3types.ReportWithInfo[uint]{}) + _ = p.ValidateObservation(tests.Context(t), ocr3types.OutcomeContext{}, nil, ocrtypes.AttributedObservation{}) + _, _ = p.Outcome(tests.Context(t), ocr3types.OutcomeContext{}, nil, nil) + _, _ = p.Reports(tests.Context(t), 0, nil) + _, _ = p.ShouldAcceptAttestedReport(tests.Context(t), 0, ocr3types.ReportWithInfo[uint]{}) + _, _ = p.ShouldTransmitAcceptedReport(tests.Context(t), 0, ocr3types.ReportWithInfo[uint]{}) } require.Equal(t, 1, counterFromHistogramByLabels(t, promOCR3Durations, "123", "empty", "query", "true")) diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 8e58eac8e49..3758e84f9a2 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -36,8 +36,8 @@ var ( float64(10 * time.Second), } - promOCR3ReportsGenerated = promauto.NewGaugeVec( - prometheus.GaugeOpts{ + promOCR3ReportsGenerated = promauto.NewCounterVec( + prometheus.CounterOpts{ Name: "ocr3_reports_generated", Help: "Tracks number of reports generated withing a single OCR3's Reports step", }, From 1d185622cbec884ba16e9a67e44a0f125ea237c0 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:04:04 +0100 Subject: [PATCH 06/15] fixes --- core/services/ocr3/promwrapper/plugin.go | 26 ++++++++++++++----- core/services/ocr3/promwrapper/plugin_test.go | 6 ++--- core/services/ocr3/promwrapper/types.go | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/core/services/ocr3/promwrapper/plugin.go b/core/services/ocr3/promwrapper/plugin.go index dba45b4a9c3..e921b1b69d5 100644 --- a/core/services/ocr3/promwrapper/plugin.go +++ b/core/services/ocr3/promwrapper/plugin.go @@ -68,32 +68,44 @@ func (p *ReportingPlugin[RI]) Reports(ctx context.Context, seqNr uint64, outcome result, err := withObservedExecution(p, reports, func() ([]ocr3types.ReportPlus[RI], error) { return p.ReportingPlugin.Reports(ctx, seqNr, outcome) }) - p.trackReportSizes(result) + p.trackReports(reports, len(result)) return result, err } func (p *ReportingPlugin[RI]) ShouldAcceptAttestedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { - return withObservedExecution(p, shouldAccept, func() (bool, error) { + result, err := withObservedExecution(p, shouldAccept, func() (bool, error) { return p.ReportingPlugin.ShouldAcceptAttestedReport(ctx, seqNr, reportWithInfo) }) + p.trackReports(shouldAccept, boolToInt(result)) + return result, err } func (p *ReportingPlugin[RI]) ShouldTransmitAcceptedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { - return withObservedExecution(p, shouldTransmit, func() (bool, error) { + result, err := withObservedExecution(p, shouldTransmit, func() (bool, error) { return p.ReportingPlugin.ShouldTransmitAcceptedReport(ctx, seqNr, reportWithInfo) }) + p.trackReports(shouldTransmit, boolToInt(result)) + return result, err } func (p *ReportingPlugin[RI]) Close() error { return p.ReportingPlugin.Close() } -func (p *ReportingPlugin[RI]) trackReportSizes( - reports []ocr3types.ReportPlus[RI], +func (p *ReportingPlugin[RI]) trackReports( + function functionType, + count int, ) { p.reportsGenerated. - WithLabelValues(p.chainID, p.plugin). - Add(float64(len(reports))) + WithLabelValues(p.chainID, p.plugin, string(function)). + Add(float64(count)) +} + +func boolToInt(arg bool) int { + if arg { + return 1 + } + return 0 } func withObservedExecution[RI, R any]( diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go index 1e68c987fc9..e107f53d53d 100644 --- a/core/services/ocr3/promwrapper/plugin_test.go +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -42,13 +42,13 @@ func Test_ReportsGeneratedGauge(t *testing.T) { _, err = plugin3.Reports(tests.Context(t), 1, nil) require.Error(t, err) - g1 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("123", "empty")) + g1 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("123", "empty", "reports")) require.Equal(t, float64(2), g1) - g2 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin")) + g2 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin", "reports")) require.Equal(t, float64(100), g2) - g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty")) + g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty", "reports")) require.Equal(t, float64(0), g3) } diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 3758e84f9a2..5fda9d312a4 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -41,7 +41,7 @@ var ( Name: "ocr3_reports_generated", Help: "Tracks number of reports generated withing a single OCR3's Reports step", }, - []string{"chainID", "plugin"}, + []string{"chainID", "plugin", "function"}, ) promOCR3Durations = promauto.NewHistogramVec( prometheus.HistogramOpts{ From 54de082afc13030e078b942be21fd6747842b272 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:10:33 +0100 Subject: [PATCH 07/15] fixes --- core/services/ocr3/promwrapper/types.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 5fda9d312a4..961806657d4 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -20,8 +20,6 @@ const ( var ( buckets = []float64{ - float64(1 * time.Millisecond), - float64(5 * time.Millisecond), float64(10 * time.Millisecond), float64(25 * time.Millisecond), float64(50 * time.Millisecond), @@ -39,7 +37,7 @@ var ( promOCR3ReportsGenerated = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "ocr3_reports_generated", - Help: "Tracks number of reports generated withing a single OCR3's Reports step", + Help: "Tracks number of reports generated within by different OCR3 functions", }, []string{"chainID", "plugin", "function"}, ) From 98185b356ddc4553dd5cfea4cad0fd5b1aab49c3 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:14:18 +0100 Subject: [PATCH 08/15] fixes --- core/services/ocr3/promwrapper/plugin_test.go | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go index e107f53d53d..9e469c3f41b 100644 --- a/core/services/ocr3/promwrapper/plugin_test.go +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -39,6 +39,9 @@ func Test_ReportsGeneratedGauge(t *testing.T) { require.Len(t, r2, 10) } + _, err = plugin2.ShouldAcceptAttestedReport(tests.Context(t), 1, ocr3types.ReportWithInfo[bool]{}) + require.NoError(t, err) + _, err = plugin3.Reports(tests.Context(t), 1, nil) require.Error(t, err) @@ -48,8 +51,11 @@ func Test_ReportsGeneratedGauge(t *testing.T) { g2 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin", "reports")) require.Equal(t, float64(100), g2) - g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty", "reports")) - require.Equal(t, float64(0), g3) + g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin", "shouldAccept")) + require.Equal(t, float64(1), g3) + + g4 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty", "reports")) + require.Equal(t, float64(0), g4) } func Test_DurationHistograms(t *testing.T) { @@ -129,11 +135,17 @@ func (f fakePlugin[RI]) Reports(context.Context, uint64, ocr3types.Outcome) ([]o } func (f fakePlugin[RI]) ShouldAcceptAttestedReport(context.Context, uint64, ocr3types.ReportWithInfo[RI]) (bool, error) { - return false, f.err + if f.err != nil { + return false, f.err + } + return true, nil } func (f fakePlugin[RI]) ShouldTransmitAcceptedReport(context.Context, uint64, ocr3types.ReportWithInfo[RI]) (bool, error) { - return false, f.err + if f.err != nil { + return false, f.err + } + return true, nil } func (f fakePlugin[RI]) Close() error { From 85a44367c1b071981bce67153476a4c97c0b3536 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:15:18 +0100 Subject: [PATCH 09/15] fixes --- core/services/ocr3/promwrapper/types.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 961806657d4..7add9e77496 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -21,9 +21,7 @@ const ( var ( buckets = []float64{ float64(10 * time.Millisecond), - float64(25 * time.Millisecond), float64(50 * time.Millisecond), - float64(75 * time.Millisecond), float64(100 * time.Millisecond), float64(200 * time.Millisecond), float64(500 * time.Millisecond), From 97d657f6f655d633282e4c48030097ff787631c2 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:15:55 +0100 Subject: [PATCH 10/15] fixes --- core/services/ocr3/promwrapper/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 7add9e77496..779488cdb63 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -34,8 +34,8 @@ var ( promOCR3ReportsGenerated = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "ocr3_reports_generated", - Help: "Tracks number of reports generated within by different OCR3 functions", + Name: "ocr3_reports_processed", + Help: "Tracks number of reports processed/generated within by different OCR3 functions", }, []string{"chainID", "plugin", "function"}, ) From 357f5df2bc12a246fdedb2373e362bf8cb49e5a9 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:16:14 +0100 Subject: [PATCH 11/15] fixes --- core/services/ocr3/promwrapper/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 779488cdb63..46bfa1df20a 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -41,7 +41,7 @@ var ( ) promOCR3Durations = promauto.NewHistogramVec( prometheus.HistogramOpts{ - Name: "ocr3_phase_duration", + Name: "ocr3_function_duration", Help: "The amount of time elapsed during the OCR3 plugin's function", Buckets: buckets, }, From 89ef5c73a3b126cccd23e050fe6ead18961e993b Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:26:48 +0100 Subject: [PATCH 12/15] fixes --- core/services/ocr3/promwrapper/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index 46bfa1df20a..a53d65aecef 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -34,14 +34,14 @@ var ( promOCR3ReportsGenerated = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "ocr3_reports_processed", + Name: "ocr3_reporting_plugin_reports_processed", Help: "Tracks number of reports processed/generated within by different OCR3 functions", }, []string{"chainID", "plugin", "function"}, ) promOCR3Durations = promauto.NewHistogramVec( prometheus.HistogramOpts{ - Name: "ocr3_function_duration", + Name: "ocr3_reporting_plugin_duration", Help: "The amount of time elapsed during the OCR3 plugin's function", Buckets: buckets, }, From c46179a05432eef47a2bb1f4e570f6cfb176bc1d Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:39:09 +0100 Subject: [PATCH 13/15] fixes --- .../capabilities/ccip/oraclecreator/plugin.go | 2 +- .../services/ocr3/promwrapper/factory_test.go | 4 ++-- core/services/ocr3/promwrapper/plugin_test.go | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/core/capabilities/ccip/oraclecreator/plugin.go b/core/capabilities/ccip/oraclecreator/plugin.go index be2321ab133..556ed4cb233 100644 --- a/core/capabilities/ccip/oraclecreator/plugin.go +++ b/core/capabilities/ccip/oraclecreator/plugin.go @@ -233,7 +233,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( chainID, err := chainsel.GetChainIDFromSelector(uint64(config.Config.ChainSelector)) if err != nil { - return nil, nil, fmt.Errorf("unsupported chain selector %d %v", config.Config.ChainSelector, err) + return nil, nil, fmt.Errorf("unsupported chain selector %d %w", config.Config.ChainSelector, err) } if config.Config.PluginType == uint8(cctypes.PluginTypeCCIPCommit) { diff --git a/core/services/ocr3/promwrapper/factory_test.go b/core/services/ocr3/promwrapper/factory_test.go index 9236c62925f..19ab6bd5bce 100644 --- a/core/services/ocr3/promwrapper/factory_test.go +++ b/core/services/ocr3/promwrapper/factory_test.go @@ -2,7 +2,7 @@ package promwrapper import ( "context" - "fmt" + "errors" "testing" "github.com/stretchr/testify/require" @@ -13,7 +13,7 @@ import ( func Test_WrapperFactory(t *testing.T) { validFactory := NewReportingPluginFactory(fakeFactory[uint]{}, "solana", "plugin") - failingFactory := NewReportingPluginFactory(fakeFactory[uint]{err: fmt.Errorf("error")}, "123", "plugin") + failingFactory := NewReportingPluginFactory(fakeFactory[uint]{err: errors.New("error")}, "123", "plugin") plugin, _, err := validFactory.NewReportingPlugin(tests.Context(t), ocr3types.ReportingPluginConfig{}) require.NoError(t, err) diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go index 9e469c3f41b..37425baf076 100644 --- a/core/services/ocr3/promwrapper/plugin_test.go +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -2,7 +2,7 @@ package promwrapper import ( "context" - "fmt" + "errors" "testing" "github.com/prometheus/client_golang/prometheus" @@ -25,7 +25,7 @@ func Test_ReportsGeneratedGauge(t *testing.T) { "solana", "different_plugin", promOCR3ReportsGenerated, promOCR3Durations, ) plugin3 := NewReportingPlugin( - fakePlugin[string]{err: fmt.Errorf("error")}, + fakePlugin[string]{err: errors.New("error")}, "1234", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) @@ -34,8 +34,8 @@ func Test_ReportsGeneratedGauge(t *testing.T) { require.Len(t, r1, 2) for i := 0; i < 10; i++ { - r2, err := plugin2.Reports(tests.Context(t), 1, nil) - require.NoError(t, err) + r2, err1 := plugin2.Reports(tests.Context(t), 1, nil) + require.NoError(t, err1) require.Len(t, r2, 10) } @@ -46,16 +46,16 @@ func Test_ReportsGeneratedGauge(t *testing.T) { require.Error(t, err) g1 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("123", "empty", "reports")) - require.Equal(t, float64(2), g1) + require.Equal(t, 2, int(g1)) g2 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin", "reports")) - require.Equal(t, float64(100), g2) + require.Equal(t, 100, int(g2)) g3 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("solana", "different_plugin", "shouldAccept")) - require.Equal(t, float64(1), g3) + require.Equal(t, 1, int(g3)) g4 := testutil.ToFloat64(promOCR3ReportsGenerated.WithLabelValues("1234", "empty", "reports")) - require.Equal(t, float64(0), g4) + require.Equal(t, 0, int(g4)) } func Test_DurationHistograms(t *testing.T) { @@ -64,7 +64,7 @@ func Test_DurationHistograms(t *testing.T) { "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) plugin2 := NewReportingPlugin( - fakePlugin[uint]{err: fmt.Errorf("error")}, + fakePlugin[uint]{err: errors.New("error")}, "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) plugin3 := NewReportingPlugin( @@ -165,5 +165,6 @@ func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.Histogr err = metric.Write(pb) require.NoError(t, err) + // nolint:gosec return int(pb.GetHistogram().GetSampleCount()) } From 7853a038c6bd4be4098779c9e6968e58efba9a9b Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 14:50:44 +0100 Subject: [PATCH 14/15] fixes --- core/services/ocr3/promwrapper/factory.go | 2 +- .../services/ocr3/promwrapper/factory_test.go | 3 +- core/services/ocr3/promwrapper/plugin.go | 32 ++++++++----------- core/services/ocr3/promwrapper/plugin_test.go | 16 +++++----- core/services/ocr3/promwrapper/types.go | 3 +- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/core/services/ocr3/promwrapper/factory.go b/core/services/ocr3/promwrapper/factory.go index 5a8a5940048..0dabd346112 100644 --- a/core/services/ocr3/promwrapper/factory.go +++ b/core/services/ocr3/promwrapper/factory.go @@ -31,7 +31,7 @@ func (r ReportingPluginFactory[RI]) NewReportingPlugin(ctx context.Context, conf if err != nil { return nil, ocr3types.ReportingPluginInfo{}, err } - wrapped := NewReportingPlugin( + wrapped := newReportingPlugin( plugin, r.chainID, r.plugin, diff --git a/core/services/ocr3/promwrapper/factory_test.go b/core/services/ocr3/promwrapper/factory_test.go index 19ab6bd5bce..72f35aad172 100644 --- a/core/services/ocr3/promwrapper/factory_test.go +++ b/core/services/ocr3/promwrapper/factory_test.go @@ -7,8 +7,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" ) func Test_WrapperFactory(t *testing.T) { diff --git a/core/services/ocr3/promwrapper/plugin.go b/core/services/ocr3/promwrapper/plugin.go index e921b1b69d5..e4e0c3d35d5 100644 --- a/core/services/ocr3/promwrapper/plugin.go +++ b/core/services/ocr3/promwrapper/plugin.go @@ -10,9 +10,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) -var _ ocr3types.ReportingPlugin[any] = &ReportingPlugin[any]{} +var _ ocr3types.ReportingPlugin[any] = &reportingPlugin[any]{} -type ReportingPlugin[RI any] struct { +type reportingPlugin[RI any] struct { ocr3types.ReportingPlugin[RI] chainID string plugin string @@ -22,14 +22,14 @@ type ReportingPlugin[RI any] struct { durations *prometheus.HistogramVec } -func NewReportingPlugin[RI any]( +func newReportingPlugin[RI any]( origin ocr3types.ReportingPlugin[RI], chainID string, plugin string, reportsGenerated *prometheus.CounterVec, durations *prometheus.HistogramVec, -) *ReportingPlugin[RI] { - return &ReportingPlugin[RI]{ +) *reportingPlugin[RI] { + return &reportingPlugin[RI]{ ReportingPlugin: origin, chainID: chainID, plugin: plugin, @@ -38,19 +38,19 @@ func NewReportingPlugin[RI any]( } } -func (p *ReportingPlugin[RI]) Query(ctx context.Context, outctx ocr3types.OutcomeContext) (ocrtypes.Query, error) { +func (p *reportingPlugin[RI]) Query(ctx context.Context, outctx ocr3types.OutcomeContext) (ocrtypes.Query, error) { return withObservedExecution(p, query, func() (ocrtypes.Query, error) { return p.ReportingPlugin.Query(ctx, outctx) }) } -func (p *ReportingPlugin[RI]) Observation(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query) (ocrtypes.Observation, error) { +func (p *reportingPlugin[RI]) Observation(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query) (ocrtypes.Observation, error) { return withObservedExecution(p, observation, func() (ocrtypes.Observation, error) { return p.ReportingPlugin.Observation(ctx, outctx, query) }) } -func (p *ReportingPlugin[RI]) ValidateObservation(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query, ao ocrtypes.AttributedObservation) error { +func (p *reportingPlugin[RI]) ValidateObservation(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query, ao ocrtypes.AttributedObservation) error { _, err := withObservedExecution(p, validateObservation, func() (any, error) { err := p.ReportingPlugin.ValidateObservation(ctx, outctx, query, ao) return nil, err @@ -58,13 +58,13 @@ func (p *ReportingPlugin[RI]) ValidateObservation(ctx context.Context, outctx oc return err } -func (p *ReportingPlugin[RI]) Outcome(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query, aos []ocrtypes.AttributedObservation) (ocr3types.Outcome, error) { +func (p *reportingPlugin[RI]) Outcome(ctx context.Context, outctx ocr3types.OutcomeContext, query ocrtypes.Query, aos []ocrtypes.AttributedObservation) (ocr3types.Outcome, error) { return withObservedExecution(p, outcome, func() (ocr3types.Outcome, error) { return p.ReportingPlugin.Outcome(ctx, outctx, query, aos) }) } -func (p *ReportingPlugin[RI]) Reports(ctx context.Context, seqNr uint64, outcome ocr3types.Outcome) ([]ocr3types.ReportPlus[RI], error) { +func (p *reportingPlugin[RI]) Reports(ctx context.Context, seqNr uint64, outcome ocr3types.Outcome) ([]ocr3types.ReportPlus[RI], error) { result, err := withObservedExecution(p, reports, func() ([]ocr3types.ReportPlus[RI], error) { return p.ReportingPlugin.Reports(ctx, seqNr, outcome) }) @@ -72,7 +72,7 @@ func (p *ReportingPlugin[RI]) Reports(ctx context.Context, seqNr uint64, outcome return result, err } -func (p *ReportingPlugin[RI]) ShouldAcceptAttestedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { +func (p *reportingPlugin[RI]) ShouldAcceptAttestedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { result, err := withObservedExecution(p, shouldAccept, func() (bool, error) { return p.ReportingPlugin.ShouldAcceptAttestedReport(ctx, seqNr, reportWithInfo) }) @@ -80,7 +80,7 @@ func (p *ReportingPlugin[RI]) ShouldAcceptAttestedReport(ctx context.Context, se return result, err } -func (p *ReportingPlugin[RI]) ShouldTransmitAcceptedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { +func (p *reportingPlugin[RI]) ShouldTransmitAcceptedReport(ctx context.Context, seqNr uint64, reportWithInfo ocr3types.ReportWithInfo[RI]) (bool, error) { result, err := withObservedExecution(p, shouldTransmit, func() (bool, error) { return p.ReportingPlugin.ShouldTransmitAcceptedReport(ctx, seqNr, reportWithInfo) }) @@ -88,11 +88,7 @@ func (p *ReportingPlugin[RI]) ShouldTransmitAcceptedReport(ctx context.Context, return result, err } -func (p *ReportingPlugin[RI]) Close() error { - return p.ReportingPlugin.Close() -} - -func (p *ReportingPlugin[RI]) trackReports( +func (p *reportingPlugin[RI]) trackReports( function functionType, count int, ) { @@ -109,7 +105,7 @@ func boolToInt(arg bool) int { } func withObservedExecution[RI, R any]( - p *ReportingPlugin[RI], + p *reportingPlugin[RI], function functionType, exec func() (R, error), ) (R, error) { diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go index 37425baf076..76b274ff7ec 100644 --- a/core/services/ocr3/promwrapper/plugin_test.go +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -16,15 +16,15 @@ import ( ) func Test_ReportsGeneratedGauge(t *testing.T) { - plugin1 := NewReportingPlugin( + plugin1 := newReportingPlugin( fakePlugin[uint]{reports: make([]ocr3types.ReportPlus[uint], 2)}, "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) - plugin2 := NewReportingPlugin( + plugin2 := newReportingPlugin( fakePlugin[bool]{reports: make([]ocr3types.ReportPlus[bool], 10)}, "solana", "different_plugin", promOCR3ReportsGenerated, promOCR3Durations, ) - plugin3 := NewReportingPlugin( + plugin3 := newReportingPlugin( fakePlugin[string]{err: errors.New("error")}, "1234", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) @@ -59,20 +59,20 @@ func Test_ReportsGeneratedGauge(t *testing.T) { } func Test_DurationHistograms(t *testing.T) { - plugin1 := NewReportingPlugin( + plugin1 := newReportingPlugin( fakePlugin[uint]{}, "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) - plugin2 := NewReportingPlugin( + plugin2 := newReportingPlugin( fakePlugin[uint]{err: errors.New("error")}, "123", "empty", promOCR3ReportsGenerated, promOCR3Durations, ) - plugin3 := NewReportingPlugin( + plugin3 := newReportingPlugin( fakePlugin[uint]{}, "solana", "commit", promOCR3ReportsGenerated, promOCR3Durations, ) - for _, p := range []*ReportingPlugin[uint]{plugin1, plugin2, plugin3} { + for _, p := range []*reportingPlugin[uint]{plugin1, plugin2, plugin3} { _, _ = p.Query(tests.Context(t), ocr3types.OutcomeContext{}) for i := 0; i < 2; i++ { _, _ = p.Observation(tests.Context(t), ocr3types.OutcomeContext{}, nil) @@ -165,6 +165,6 @@ func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.Histogr err = metric.Write(pb) require.NoError(t, err) - // nolint:gosec + //nolint:gosec return int(pb.GetHistogram().GetSampleCount()) } diff --git a/core/services/ocr3/promwrapper/types.go b/core/services/ocr3/promwrapper/types.go index a53d65aecef..bf6a1b2a39c 100644 --- a/core/services/ocr3/promwrapper/types.go +++ b/core/services/ocr3/promwrapper/types.go @@ -1,9 +1,10 @@ package promwrapper import ( + "time" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "time" ) type functionType string From f663df838c420d2849b6815ad0d952e55a0eb17b Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 5 Dec 2024 15:01:12 +0100 Subject: [PATCH 15/15] fixes --- core/services/ocr3/promwrapper/plugin_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/services/ocr3/promwrapper/plugin_test.go b/core/services/ocr3/promwrapper/plugin_test.go index 76b274ff7ec..35a97d109aa 100644 --- a/core/services/ocr3/promwrapper/plugin_test.go +++ b/core/services/ocr3/promwrapper/plugin_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -165,6 +166,6 @@ func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.Histogr err = metric.Write(pb) require.NoError(t, err) - //nolint:gosec + //nolint:gosec // we don't care about that in tests return int(pb.GetHistogram().GetSampleCount()) }