Skip to content
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
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.24.2

require (
cosmossdk.io/api v0.9.2
cosmossdk.io/math v1.5.3
github.com/prometheus/client_golang v1.22.0
github.com/shirou/gopsutil/v4 v4.25.4
github.com/spf13/cobra v1.9.1
Expand All @@ -18,7 +19,6 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
github.com/cosmos/gogoproto v1.7.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
Expand All @@ -28,7 +28,6 @@ require (
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
Expand Down
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cosmossdk.io/api v0.9.2 h1:9i9ptOBdmoIEVEVWLtYYHjxZonlF/aOVODLFaxpmNtg=
cosmossdk.io/api v0.9.2/go.mod h1:CWt31nVohvoPMTlPv+mMNCtC0a7BqRdESjCsstHcTkU=
cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
Expand Down Expand Up @@ -63,8 +65,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
Expand Down Expand Up @@ -138,3 +140,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
resty.dev/v3 v3.0.0-beta.3 h1:3kEwzEgCnnS6Ob4Emlk94t+I/gClyoah7SnNi67lt+E=
resty.dev/v3 v3.0.0-beta.3/go.mod h1:OgkqiPvTDtOuV4MGZuUDhwOpkY8enjOsjjMzeOHefy4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
3 changes: 1 addition & 2 deletions pkg/collectors/autodetect/manifestd/denom_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ func NewDenomInfoCollector(client *client.GRPCClient, denom string) *DenomInfoCo
var initialError error
if client == nil {
initialError = status.Error(codes.Internal, "gRPC client is nil")
}
if client != nil && client.Conn == nil {
} else if client.Conn == nil {
initialError = status.Error(codes.Internal, "gRPC client connection is nil")
}
if denom == "" {
Expand Down
16 changes: 9 additions & 7 deletions pkg/collectors/autodetect/manifestd/excluded_supply.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ type ExcludedSupplyCollector struct {
initialError error
}

func NewExcludedSupplyCollector(c *client.GRPCClient, endpoint, denom string) *ExcludedSupplyCollector {
var err error
if c == nil || c.Conn == nil {
err = status.Error(codes.Internal, "gRPC client or connection is nil")
func NewExcludedSupplyCollector(client *client.GRPCClient, endpoint, denom string) *ExcludedSupplyCollector {
var initialError error
if client == nil {
initialError = status.Error(codes.Internal, "gRPC client is nil")
} else if client.Conn == nil {
initialError = status.Error(codes.Internal, "gRPC client connection is nil")
}

return &ExcludedSupplyCollector{
grpcClient: c,
grpcClient: client,
addrsEndpoint: endpoint,
restyClient: resty.New().SetHeader("Accept", "application/json").SetTimeout(pkg.ClientTimeout).SetRetryCount(pkg.ClientRetry),
initialError: err,
initialError: initialError,
denom: denom,
excludedSupplyDesc: prometheus.NewDesc(
prometheus.BuildFQName("manifest", "tokenomics", "excluded_supply"),
Expand Down Expand Up @@ -83,7 +85,7 @@ func (c *ExcludedSupplyCollector) Collect(ch chan<- prometheus.Metric) {
}

const rpcTimeout = 2 * time.Second
eg, egCtx := errgroup.WithContext(context.Background())
eg, egCtx := errgroup.WithContext(c.grpcClient.Ctx)
results := make(chan *big.Int, len(addrs))

bankClient := bankv1beta1.NewQueryClient(c.grpcClient.Conn)
Expand Down
160 changes: 160 additions & 0 deletions pkg/collectors/autodetect/manifestd/fees.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//go:build manifest_node_exporter
// +build manifest_node_exporter

package manifestd

import (
"context"
"log/slog"
"math/big"
"time"

distributionv1beta1 "cosmossdk.io/api/cosmos/distribution/v1beta1"
stakingv1beta1 "cosmossdk.io/api/cosmos/staking/v1beta1"
"cosmossdk.io/math"
"github.com/liftedinit/manifest-node-exporter/pkg/client"
"github.com/liftedinit/manifest-node-exporter/pkg/collectors"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type FeesCollector struct {
grpcClient *client.GRPCClient
feesDesc *prometheus.Desc
upDesc *prometheus.Desc
denom string
initialError error
}

func NewFeesCollector(client *client.GRPCClient, denom string) *FeesCollector {
var initialError error
if client == nil {
initialError = status.Error(codes.Internal, "gRPC client is nil")
} else if client.Conn == nil {
initialError = status.Error(codes.Internal, "gRPC client connection is nil")
}

return &FeesCollector{
grpcClient: client,
initialError: initialError,
denom: denom,
feesDesc: prometheus.NewDesc(
prometheus.BuildFQName("manifest", "tokenomics", "fees"),
"Transaction fees locked in validators.",
[]string{"amount", "denom"},
prometheus.Labels{"source": "grpc"},
),
upDesc: prometheus.NewDesc(
prometheus.BuildFQName("manifest", "tokenomics", "fees_grpc_up"),
"Whether the gRPC query was successful.",
nil,
prometheus.Labels{"source": "grpc", "queries": "Validators, ValidatorOutstandingRewards"},
),
}
}

func (c *FeesCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.feesDesc
ch <- c.upDesc
}

func (c *FeesCollector) Collect(ch chan<- prometheus.Metric) {
// Check for initialization or connection errors first.
if err := collectors.ValidateClient(c.grpcClient, c.initialError); err != nil {
collectors.ReportUpMetric(ch, c.upDesc, 0) // Report gRPC down
collectors.ReportInvalidMetric(ch, c.feesDesc, err)
return
}

stakingQueryClient := stakingv1beta1.NewQueryClient(c.grpcClient.Conn)
validatorsResp, validatorsErr := stakingQueryClient.Validators(c.grpcClient.Ctx, &stakingv1beta1.QueryValidatorsRequest{})
if validatorsErr != nil {
slog.Error("Failed to query via gRPC", "query", "Validators", "error", validatorsErr)
collectors.ReportUpMetric(ch, c.upDesc, 0)
collectors.ReportInvalidMetric(ch, c.feesDesc, validatorsErr)
return
}

if validatorsResp == nil || validatorsResp.Validators == nil || len(validatorsResp.Validators) == 0 {
collectors.ReportUpMetric(ch, c.upDesc, 0)
collectors.ReportInvalidMetric(ch, c.feesDesc, status.Error(codes.Internal, "Validators response is nil or empty"))
return
}

distributionQueryClient := distributionv1beta1.NewQueryClient(c.grpcClient.Conn)
const rpcTimeout = 2 * time.Second
eg, egCtx := errgroup.WithContext(c.grpcClient.Ctx)
results := make(chan math.Int, len(validatorsResp.Validators))
for _, val := range validatorsResp.Validators {
val := val
eg.Go(func() error {
callCtx, callCancel := context.WithTimeout(egCtx, rpcTimeout)
defer callCancel()

feesResp, feesErr := distributionQueryClient.ValidatorOutstandingRewards(callCtx, &distributionv1beta1.QueryValidatorOutstandingRewardsRequest{ValidatorAddress: val.OperatorAddress})
if feesErr != nil {
slog.Error("Failed to query via gRPC", "query", "ValidatorOutstandingRewards", "validator", val.OperatorAddress, "error", feesErr)
return feesErr
}
if feesResp == nil || feesResp.Rewards == nil {
slog.Error("ValidatorOutstandingRewards response is nil or empty", "validator", val.OperatorAddress)
return status.Error(codes.Internal, "ValidatorOutstandingRewards response is nil or empty")
}
if len(feesResp.Rewards.Rewards) != 1 {
slog.Warn("ValidatorOutstandingRewards response has no rewards or too many rewards", "validator", val.OperatorAddress)
return nil
}
denom := feesResp.Rewards.Rewards[0].Denom
if denom != c.denom {
slog.Warn("ValidatorOutstandingRewards response has different denom", "validator", val.OperatorAddress, "expected", c.denom, "got", denom)
return status.Error(codes.InvalidArgument, "denom mismatch for validator "+val.OperatorAddress+": expected "+c.denom+", got "+denom)
}

// Convert the amount to a big.Int
amount, ok := new(big.Int).SetString(feesResp.Rewards.Rewards[0].Amount, 10)
if !ok {
slog.Error("Failed to parse coin amount", "validator", val.OperatorAddress, "amount", feesResp.Rewards.Rewards[0].Amount)
return status.Error(codes.Internal, "invalid coin amount for validator "+val.OperatorAddress+": "+feesResp.Rewards.Rewards[0].Amount)
}

// And create a LegacyDec from it, using the LegacyPrecision
legacyAmount := math.LegacyNewDecFromBigIntWithPrec(amount, math.LegacyPrecision)

// And only keep the integer part
truncatedAmount := legacyAmount.TruncateInt()
results <- truncatedAmount

return nil
})
}

if err := eg.Wait(); err != nil {
collectors.ReportUpMetric(ch, c.upDesc, 0)
collectors.ReportInvalidMetric(ch, c.feesDesc, err)
close(results)
return
}
close(results)

total := math.ZeroInt()
for v := range results {
total = total.Add(v)
}

collectors.ReportUpMetric(ch, c.upDesc, 1)
m, err := prometheus.NewConstMetric(c.feesDesc, prometheus.GaugeValue, 1, total.String(), c.denom)
if err != nil {
slog.Error("Failed to create fees metric", "error", err)
collectors.ReportInvalidMetric(ch, c.feesDesc, err)
} else {
ch <- m
}
}

func init() {
RegisterCollectorFactory("fees", func(client *client.GRPCClient, extra ...interface{}) prometheus.Collector {
return NewFeesCollector(client, "umfx")
})
}
3 changes: 1 addition & 2 deletions pkg/collectors/autodetect/manifestd/token_count.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ func NewTokenCountCollector(client *client.GRPCClient) *TokenCountCollector {
var initialError error
if client == nil {
initialError = status.Error(codes.Internal, "gRPC client is nil")
}
if client != nil && client.Conn == nil {
} else if client.Conn == nil {
initialError = status.Error(codes.Internal, "gRPC client connection is nil")
}

Expand Down