Skip to content

Commit

Permalink
chore: add node config generator
Browse files Browse the repository at this point in the history
  • Loading branch information
freak12techno committed Sep 9, 2024
1 parent 98df3cc commit 7626663
Show file tree
Hide file tree
Showing 8 changed files with 311 additions and 169 deletions.
1 change: 1 addition & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (

FetcherNameNodeStatus FetcherName = "node_status"
FetcherNameCosmovisorVersion FetcherName = "cosmovisor_version"
FetcherNameNodeConfig FetcherName = "node_config"
)

var (
Expand Down
2 changes: 2 additions & 0 deletions pkg/fetchers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ func (c *Controller) Fetch(ctx context.Context) (

c.Logger.Trace().Str("name", string(fetcher.Name())).Msg("Processing fetcher...")

mutex.Lock()
fetchersStatus[fetcher.Name()] = FetcherProcessStatusProcessing
mutex.Unlock()

fetcherData, fetcherQueries := fetcher.Get(ctx)

Expand Down
62 changes: 62 additions & 0 deletions pkg/fetchers/node_config_fetcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package fetchers

import (
"context"
grpcPkg "main/pkg/clients/grpc"
"main/pkg/constants"
"main/pkg/query_info"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"

"github.com/rs/zerolog"
)

type NodeConfigFetcher struct {
gRPC *grpcPkg.Client
Logger zerolog.Logger
Tracer trace.Tracer
}

func NewNodeConfigFetcher(logger zerolog.Logger, grpc *grpcPkg.Client, tracer trace.Tracer) *NodeConfigFetcher {
return &NodeConfigFetcher{
Logger: logger.With().Str("component", "node_config_fetcher").Logger(),
gRPC: grpc,
Tracer: tracer,
}
}

func (n *NodeConfigFetcher) Enabled() bool {
return n.gRPC != nil
}

func (n *NodeConfigFetcher) Name() constants.FetcherName {
return constants.FetcherNameNodeConfig
}

func (n *NodeConfigFetcher) Dependencies() []constants.FetcherName {
return []constants.FetcherName{}
}

func (n *NodeConfigFetcher) Get(ctx context.Context) (interface{}, []query_info.QueryInfo) {
childCtx, span := n.Tracer.Start(
ctx,
"NodeConfigFetcher "+string(n.Name()),
trace.WithAttributes(attribute.String("node", string(n.Name()))),
)
defer span.End()

config, queryInfo, err := n.gRPC.GetNodeConfig(childCtx)
if err != nil {
n.Logger.Error().Err(err).Msg("Could not fetch node config")
return nil, []query_info.QueryInfo{queryInfo}
}

if config == nil {
n.Logger.Debug().
Msg("Node config is nil, probably chain does not implement the node config endpoint.")
return nil, []query_info.QueryInfo{queryInfo}
}

return config, []query_info.QueryInfo{queryInfo}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package node_stats
package fetchers

import (
"context"
grpcPkg "main/pkg/clients/grpc"
configPkg "main/pkg/config"
"main/pkg/constants"
loggerPkg "main/pkg/logger"
"main/pkg/tracing"
"testing"
Expand All @@ -19,7 +20,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestNodeConfigQuerierBase(t *testing.T) {
func TestNodeConfigFetcherBase(t *testing.T) {
t.Parallel()

config := configPkg.GrpcConfig{
Expand All @@ -28,11 +29,12 @@ func TestNodeConfigQuerierBase(t *testing.T) {
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := grpcPkg.NewClient(config, *logger, tracer)
querier := NewQuerier(*logger, client, tracer)
assert.True(t, querier.Enabled())
assert.Equal(t, "node-config-querier", querier.Name())
fetcher := NewNodeConfigFetcher(*logger, client, tracer)
assert.True(t, fetcher.Enabled())
assert.Equal(t, constants.FetcherNameNodeConfig, fetcher.Name())
assert.Empty(t, fetcher.Dependencies())
}
func TestNodeConfigQuerierFail(t *testing.T) {
func TestNodeConfigFetcherFail(t *testing.T) {
t.Parallel()

_, d := grpcmock.MockServerWithBufConn()(t)
Expand All @@ -51,14 +53,14 @@ func TestNodeConfigQuerierFail(t *testing.T) {
Tracer: tracer,
}

querier := NewQuerier(*logger, client, tracer)
metrics, queryInfos := querier.Get(context.Background())
fetcher := NewNodeConfigFetcher(*logger, client, tracer)
data, queryInfos := fetcher.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.False(t, queryInfos[0].Success)
assert.Empty(t, metrics)
assert.Nil(t, data)
}

func TestNodeConfigQuerierError(t *testing.T) {
func TestNodeConfigFetcherError(t *testing.T) {
t.Parallel()

_, d := grpcmock.MockServerWithBufConn()(t)
Expand All @@ -77,14 +79,14 @@ func TestNodeConfigQuerierError(t *testing.T) {
Tracer: tracer,
}

querier := NewQuerier(*logger, client, tracer)
metrics, queryInfos := querier.Get(context.Background())
fetcher := NewNodeConfigFetcher(*logger, client, tracer)
data, queryInfos := fetcher.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.False(t, queryInfos[0].Success)
assert.Empty(t, metrics)
assert.Nil(t, data)
}

func TestNodeConfigQuerierNotImplemented(t *testing.T) {
func TestNodeConfigFetcherNotImplemented(t *testing.T) {
t.Parallel()

_, d := grpcmock.MockServerWithBufConn()(t)
Expand All @@ -103,52 +105,14 @@ func TestNodeConfigQuerierNotImplemented(t *testing.T) {
Tracer: tracer,
}

querier := NewQuerier(*logger, client, tracer)
metrics, queryInfos := querier.Get(context.Background())
fetcher := NewNodeConfigFetcher(*logger, client, tracer)
data, queryInfos := fetcher.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.True(t, queryInfos[0].Success)
assert.Empty(t, metrics)
assert.Nil(t, data)
}

func TestNodeConfigQuerierInvalidResponse(t *testing.T) {
t.Parallel()

_, d := grpcmock.MockServerWithBufConn(
grpcmock.RegisterServiceFromMethods(service.Method{
ServiceName: "cosmos.base.node.v1beta1.Service",
MethodName: "Config",
MethodType: service.TypeUnary,
Input: &nodeTypes.ConfigRequest{},
Output: &nodeTypes.ConfigResponse{},
}),
func(s *grpcmock.Server) {
s.ExpectUnary("cosmos.base.node.v1beta1.Service/Config").
Return(&nodeTypes.ConfigResponse{MinimumGasPrice: "test"})
},
)(t)

logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
grpcConn, err := grpc.NewClient(
"localhost:9090",
grpc.WithContextDialer(d),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
require.NoError(t, err)
client := &grpcPkg.Client{
Logger: *logger,
Client: grpcConn,
Tracer: tracer,
}

querier := NewQuerier(*logger, client, tracer)
metrics, queryInfos := querier.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.True(t, queryInfos[0].Success)
assert.Empty(t, metrics)
}

func TestNodeConfigQuerierOk(t *testing.T) {
func TestNodeConfigFetcherOk(t *testing.T) {
t.Parallel()

_, d := grpcmock.MockServerWithBufConn(
Expand Down Expand Up @@ -179,29 +143,9 @@ func TestNodeConfigQuerierOk(t *testing.T) {
Tracer: tracer,
}

querier := NewQuerier(*logger, client, tracer)
metrics, queryInfos := querier.Get(context.Background())
fetcher := NewNodeConfigFetcher(*logger, client, tracer)
data, queryInfos := fetcher.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.True(t, queryInfos[0].Success)
assert.Len(t, metrics, 4)

pricesCount := metrics[0]
assert.Empty(t, pricesCount.Labels)
assert.InDelta(t, 2, pricesCount.Value, 0.01)

firstPrice := metrics[1]
assert.Equal(t, map[string]string{
"denom": "uatom",
}, firstPrice.Labels)
assert.InDelta(t, 0.1, firstPrice.Value, 0.01)

secondPrice := metrics[2]
assert.Equal(t, map[string]string{
"denom": "ustake",
}, secondPrice.Labels)
assert.InDelta(t, 0.2, secondPrice.Value, 0.01)

haltHeight := metrics[3]
assert.Equal(t, map[string]string{}, haltHeight.Labels)
assert.InDelta(t, 123, haltHeight.Value, 0.01)
assert.NotNil(t, data)
}
58 changes: 58 additions & 0 deletions pkg/generators/node_config_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package generators

import (
"main/pkg/constants"
"main/pkg/fetchers"
metricsPkg "main/pkg/metrics"

"github.com/cosmos/cosmos-sdk/client/grpc/node"
cosmosTypes "github.com/cosmos/cosmos-sdk/types"
)

type NodeConfigGenerator struct{}

func NewNodeConfigGenerator() *NodeConfigGenerator {
return &NodeConfigGenerator{}
}

func (g *NodeConfigGenerator) Get(state fetchers.State) []metricsPkg.MetricInfo {
statusRaw, ok := state[constants.FetcherNameNodeConfig]
if !ok || statusRaw == nil {
return []metricsPkg.MetricInfo{}
}

config, ok := statusRaw.(*node.ConfigResponse)
if !ok {
panic("expected the state entry to be *node.ConfigResponse")
}

coinsParsed, err := cosmosTypes.ParseDecCoins(config.MinimumGasPrice)
if err != nil {
panic(err)
}

metrics := []metricsPkg.MetricInfo{}
metrics = append(metrics, metricsPkg.MetricInfo{
MetricName: metricsPkg.MetricNameMinimumGasPricesCount,
Labels: map[string]string{},
Value: float64(len(coinsParsed)),
})

for _, amount := range coinsParsed {
metrics = append(metrics, metricsPkg.MetricInfo{
MetricName: metricsPkg.MetricNameMinimumGasPrice,
Labels: map[string]string{"denom": amount.Denom},
Value: amount.Amount.MustFloat64(),
})
}

if config.HaltHeight > 0 {
metrics = append(metrics, metricsPkg.MetricInfo{
MetricName: metricsPkg.MetricNameHaltHeight,
Labels: map[string]string{},
Value: float64(config.HaltHeight),
})
}

return metrics
}
Loading

0 comments on commit 7626663

Please sign in to comment.