Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOM: slot height #663

Merged
merged 7 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions cmd/monitoring/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,27 @@ func main() {
chainReader,
logger.With(log, "component", "source-node-balances"),
)
slotHeightSourceFactory := monitoring.NewSlotHeightSourceFactory(
chainReader,
logger.With(log, "component", "souce-slot-height"),
)
monitor.NetworkSourceFactories = append(monitor.NetworkSourceFactories,
nodeBalancesSourceFactory,
slotHeightSourceFactory,
)

// exporter names
promExporter := "solana-prom-exporter"
promMetrics := "solana-metrics"

// per-feed exporters
feedBalancesExporterFactory := exporter.NewFeedBalancesFactory(
logger.With(log, "component", "solana-prom-exporter"),
metrics.NewFeedBalances(logger.With(log, "component", "solana-metrics")),
logger.With(log, "component", promExporter),
metrics.NewFeedBalances(logger.With(log, "component", promMetrics)),
)
reportObservationsFactory := exporter.NewReportObservationsFactory(
logger.With(log, "component", "solana-prome-exporter"),
metrics.NewReportObservations(logger.With(log, "component", "solana-metrics")),
metrics.NewReportObservations(logger.With(log, "component", promMetrics)),
)
monitor.ExporterFactories = append(monitor.ExporterFactories,
feedBalancesExporterFactory,
Expand All @@ -96,11 +105,16 @@ func main() {

// network exporters
nodeBalancesExporterFactory := exporter.NewNodeBalancesFactory(
logger.With(log, "component", "solana-prom-exporter"),
logger.With(log, "component", promExporter),
metrics.NewNodeBalances,
)
slotHeightExporterFactory := exporter.NewSlotHeightFactory(
logger.With(log, "component", promExporter),
metrics.NewSlotHeight(logger.With(log, "component", promMetrics)),
)
monitor.NetworkExporterFactories = append(monitor.NetworkExporterFactories,
nodeBalancesExporterFactory,
slotHeightExporterFactory,
)

monitor.Run()
Expand Down
5 changes: 5 additions & 0 deletions pkg/monitoring/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type ChainReader interface {
GetBalance(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (out *rpc.GetBalanceResult, err error)
GetSignaturesForAddressWithOpts(ctx context.Context, account solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) (out []*rpc.TransactionSignature, err error)
GetTransaction(ctx context.Context, txSig solana.Signature, opts *rpc.GetTransactionOpts) (out *rpc.GetTransactionResult, err error)
GetSlot(ctx context.Context) (slot uint64, err error)
}

func NewChainReader(client *rpc.Client) ChainReader {
Expand Down Expand Up @@ -50,3 +51,7 @@ func (c *chainReader) GetSignaturesForAddressWithOpts(ctx context.Context, accou
func (c *chainReader) GetTransaction(ctx context.Context, txSig solana.Signature, opts *rpc.GetTransactionOpts) (out *rpc.GetTransactionResult, err error) {
return c.client.GetTransaction(ctx, txSig, opts)
}

func (c *chainReader) GetSlot(ctx context.Context) (uint64, error) {
return c.client.GetSlot(ctx, rpc.CommitmentProcessed) // get latest height
}
50 changes: 50 additions & 0 deletions pkg/monitoring/exporter/slotheight.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package exporter

import (
"context"

commonMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types"
)

func NewSlotHeightFactory(
_ commonMonitoring.Logger,
metrics metrics.SlotHeight,
) commonMonitoring.ExporterFactory {
return &slotHeightFactory{
metrics,
}
}

type slotHeightFactory struct {
metrics metrics.SlotHeight
}

func (p *slotHeightFactory) NewExporter(
params commonMonitoring.ExporterParams,
) (commonMonitoring.Exporter, error) {
return &slotHeight{
params.ChainConfig.GetNetworkName(),
params.ChainConfig.GetRPCEndpoint(),
p.metrics,
}, nil
}

type slotHeight struct {
chain, url string
metrics metrics.SlotHeight
}

func (p *slotHeight) Export(ctx context.Context, data interface{}) {
slot, ok := data.(types.SlotHeight)
if !ok {
return // skip if input could not be parsed
}

p.metrics.Set(slot, p.chain, p.url)
}

func (p *slotHeight) Cleanup(_ context.Context) {
p.metrics.Cleanup()
}
36 changes: 36 additions & 0 deletions pkg/monitoring/exporter/slotheight_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package exporter

import (
"testing"

"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
commonMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring"
"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics/mocks"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/testutils"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types"
)

func TestSlotHeight(t *testing.T) {
ctx := utils.Context(t)
m := mocks.NewSlotHeight(t)
m.On("Set", mock.Anything, mock.Anything, mock.Anything).Once()
m.On("Cleanup").Once()

factory := NewSlotHeightFactory(logger.Test(t), m)

chainConfig := testutils.GenerateChainConfig()
exporter, err := factory.NewExporter(commonMonitoring.ExporterParams{ChainConfig: chainConfig})
require.NoError(t, err)

// happy path
exporter.Export(ctx, types.SlotHeight(10))
exporter.Cleanup(ctx)

// test passing uint64 instead of SlotHeight - should not call mock
// SlotHeight alias of uint64
exporter.Export(ctx, uint64(10))
}
8 changes: 8 additions & 0 deletions pkg/monitoring/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ func init() {
},
feedLabels,
)

// init gauge for slot height
gauges[types.SlotHeightMetric] = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: types.SlotHeightMetric,
},
[]string{"chain", "url"},
)
}

type FeedInput struct {
Expand Down
38 changes: 38 additions & 0 deletions pkg/monitoring/metrics/mocks/SlotHeight.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions pkg/monitoring/metrics/slotheight.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package metrics

import (
"github.com/prometheus/client_golang/prometheus"
commonMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring"

"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types"
)

//go:generate mockery --name SlotHeight --output ./mocks/

type SlotHeight interface {
Set(slot types.SlotHeight, chain, url string)
Cleanup()
}

var _ SlotHeight = (*slotHeight)(nil)

type slotHeight struct {
simpleGauge
labels prometheus.Labels
}

func NewSlotHeight(log commonMonitoring.Logger) *slotHeight {
return &slotHeight{
simpleGauge: newSimpleGauge(log, types.SlotHeightMetric),
}
}

func (sh *slotHeight) Set(slot types.SlotHeight, chain, url string) {
sh.labels = prometheus.Labels{"chain": chain, "url": url}
sh.set(float64(slot), sh.labels)
}

func (sh *slotHeight) Cleanup() {
sh.delete(sh.labels)
}
38 changes: 38 additions & 0 deletions pkg/monitoring/metrics/slotheight_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package metrics

import (
"testing"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"

"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types"
)

func TestSlotHeight(t *testing.T) {
lgr := logger.Test(t)
m := NewSlotHeight(lgr)

// fetching gauges
g, ok := gauges[types.SlotHeightMetric]
require.True(t, ok)

v := 100

// set gauge
assert.NotPanics(t, func() { m.Set(types.SlotHeight(v), t.Name(), t.Name()+"_url") })
promBal := testutil.ToFloat64(g.With(prometheus.Labels{
"chain": t.Name(),
"url": t.Name() + "_url",
}))
assert.Equal(t, float64(v), promBal)

// cleanup gauges
assert.Equal(t, 1, testutil.CollectAndCount(g))
assert.NotPanics(t, func() { m.Cleanup() })
assert.Equal(t, 0, testutil.CollectAndCount(g))
}
24 changes: 24 additions & 0 deletions pkg/monitoring/mocks/ChainReader.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions pkg/monitoring/source_slotheight.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package monitoring

import (
"context"

commonMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring"

"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types"
)

func NewSlotHeightSourceFactory(
client ChainReader,
log commonMonitoring.Logger,
) commonMonitoring.NetworkSourceFactory {
return &slotHeightSourceFactory{
client,
log,
}
}

type slotHeightSourceFactory struct {
client ChainReader
log commonMonitoring.Logger
}

func (s *slotHeightSourceFactory) NewSource(
_ commonMonitoring.ChainConfig,
_ []commonMonitoring.NodeConfig,
) (commonMonitoring.Source, error) {
return &slotHeightSource{s.client}, nil
}

func (s *slotHeightSourceFactory) GetType() string {
return types.SlotHeightType
}

type slotHeightSource struct {
client ChainReader
}

func (t *slotHeightSource) Fetch(ctx context.Context) (interface{}, error) {
slot, err := t.client.GetSlot(ctx)
return types.SlotHeight(slot), err
}
34 changes: 34 additions & 0 deletions pkg/monitoring/source_slotheight_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package monitoring

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/mocks"
"github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types"
)

func TestSlotHeightSource(t *testing.T) {
cr := mocks.NewChainReader(t)
lgr := logger.Test(t)
ctx := utils.Context(t)

factory := NewSlotHeightSourceFactory(cr, lgr)
assert.Equal(t, types.SlotHeightType, factory.GetType())

// generate source
source, err := factory.NewSource(nil, nil)
cr.On("GetSlot", mock.Anything, mock.Anything, mock.Anything).Return(uint64(1), nil).Once()

// happy path
out, err := source.Fetch(ctx)
require.NoError(t, err)
slot, ok := out.(types.SlotHeight)
require.True(t, ok)
assert.Equal(t, types.SlotHeight(1), slot)
}
Loading
Loading