diff --git a/grpc.go b/grpc.go index 3757b7b..7377de2 100644 --- a/grpc.go +++ b/grpc.go @@ -20,7 +20,11 @@ type TendermintGRPC struct { Registry codectypes.InterfaceRegistry } -func NewTendermintGRPC(nodeConfig NodeConfig, registry codectypes.InterfaceRegistry, logger *zerolog.Logger) *TendermintGRPC { +func NewTendermintGRPC( + nodeConfig NodeConfig, + registry codectypes.InterfaceRegistry, + logger *zerolog.Logger, +) *TendermintGRPC { grpcConn, err := grpc.Dial( nodeConfig.GrpcAddress, grpc.WithInsecure(), @@ -68,7 +72,7 @@ func (grpc *TendermintGRPC) GetSlashingParams() SlashingParams { } } -func (grpc *TendermintGRPC) GetSigningInfos() ([]slashingtypes.ValidatorSigningInfo, error) { +func (grpc *TendermintGRPC) GetValidatorsState() (ValidatorsState, error) { slashingClient := slashingtypes.NewQueryClient(grpc.Client) signingInfos, err := slashingClient.SigningInfos( context.Background(), @@ -83,10 +87,6 @@ func (grpc *TendermintGRPC) GetSigningInfos() ([]slashingtypes.ValidatorSigningI return nil, err } - return signingInfos.Info, nil -} - -func (grpc *TendermintGRPC) GetValidators() ([]stakingtypes.Validator, error) { stakingClient := stakingtypes.NewQueryClient(grpc.Client) validatorsResult, err := stakingClient.Validators( context.Background(), @@ -101,7 +101,36 @@ func (grpc *TendermintGRPC) GetValidators() ([]stakingtypes.Validator, error) { return nil, err } - return validatorsResult.Validators, nil + validatorsMap := make(map[string]stakingtypes.Validator, len(validatorsResult.Validators)) + for _, validator := range validatorsResult.Validators { + err := validator.UnpackInterfaces(grpc.Registry) + if err != nil { + grpc.Logger.Error().Err(err).Msg("Could not unpack interface") + return nil, err + } + + pubKey, err := validator.GetConsAddr() + if err != nil { + grpc.Logger.Error().Err(err).Msg("Could not get cons addr") + return nil, err + } + + validatorsMap[pubKey.String()] = validator + } + + newState := make(ValidatorsState, len(signingInfos.Info)) + + for _, info := range signingInfos.Info { + validator, ok := validatorsMap[info.Address] + if !ok { + grpc.Logger.Warn().Str("address", info.Address).Msg("Could not find validator by pubkey") + continue + } + + newState[info.Address] = NewValidatorState(validator, info) + } + + return newState, nil } func (grpc *TendermintGRPC) GetValidator(address string) (stakingtypes.Validator, error) { @@ -118,16 +147,27 @@ func (grpc *TendermintGRPC) GetValidator(address string) (stakingtypes.Validator return validatorResponse.Validator, nil } -func (grpc *TendermintGRPC) GetSigningInfo(validator stakingtypes.Validator) (slashingtypes.ValidatorSigningInfo, error) { +func (grpc *TendermintGRPC) GetValidatorState(address string) (ValidatorState, error) { + stakingClient := stakingtypes.NewQueryClient(grpc.Client) + + validatorResponse, err := stakingClient.Validator( + context.Background(), + &stakingtypes.QueryValidatorRequest{ValidatorAddr: address}, + ) + if err != nil { + return ValidatorState{}, err + } + + validator := validatorResponse.Validator slashingClient := slashingtypes.NewQueryClient(grpc.Client) - err := validator.UnpackInterfaces(grpc.Registry) // Unpack interfaces, to populate the Anys' cached values + err = validator.UnpackInterfaces(grpc.Registry) // Unpack interfaces, to populate the Anys' cached values if err != nil { grpc.Logger.Error(). Str("address", validator.OperatorAddress). Err(err). Msg("Could not get unpack validator inferfaces") - return slashingtypes.ValidatorSigningInfo{}, err + return ValidatorState{}, err } pubKey, err := validator.GetConsAddr() @@ -136,7 +176,7 @@ func (grpc *TendermintGRPC) GetSigningInfo(validator stakingtypes.Validator) (sl Str("address", validator.OperatorAddress). Err(err). Msg("Could not get validator pubkey") - return slashingtypes.ValidatorSigningInfo{}, err + return ValidatorState{}, err } signingInfosResponse, err := slashingClient.SigningInfo( @@ -148,8 +188,8 @@ func (grpc *TendermintGRPC) GetSigningInfo(validator stakingtypes.Validator) (sl Str("address", validator.OperatorAddress). Err(err). Msg("Could not get signing info") - return slashingtypes.ValidatorSigningInfo{}, err + return ValidatorState{}, err } - return signingInfosResponse.ValSigningInfo, nil + return NewValidatorState(validator, signingInfosResponse.ValSigningInfo), nil } diff --git a/report_generator.go b/report_generator.go index e6d4384..6070e85 100644 --- a/report_generator.go +++ b/report_generator.go @@ -4,7 +4,6 @@ import ( "fmt" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/rs/zerolog" ) @@ -36,60 +35,15 @@ func NewReportGenerator( func (g *ReportGenerator) GetNewState() (ValidatorsState, error) { g.Logger.Debug().Msg("Querying for signing infos...") - signingInfos, err := g.gRPC.GetSigningInfos() + state, err := g.gRPC.GetValidatorsState() if err != nil { g.Logger.Error().Err(err).Msg("Could not query for signing infos") return nil, err } - validators, err := g.gRPC.GetValidators() - if err != nil { - g.Logger.Error().Err(err).Msg("Could not query for validators") - return nil, err - } - - validatorsMap := make(map[string]stakingtypes.Validator, len(validators)) - for _, validator := range validators { - err := validator.UnpackInterfaces(g.Registry) - if err != nil { - g.Logger.Error().Err(err).Msg("Could not unpack interface") - return nil, err - } - - pubKey, err := validator.GetConsAddr() - if err != nil { - g.Logger.Error().Err(err).Msg("Could not get cons addr") - return nil, err - } - - validatorsMap[pubKey.String()] = validator - } - - newState := make(ValidatorsState, len(signingInfos)) - - for _, info := range signingInfos { - validator, ok := validatorsMap[info.Address] - if !ok { - g.Logger.Warn().Str("address", info.Address).Msg("Could not find validator by pubkey") - continue - } - - if !g.Config.IsValidatorMonitored(validator.OperatorAddress) { - g.Logger.Trace().Str("address", info.Address).Msg("Not monitoring this validator, skipping.") - continue - } - - newState[info.Address] = ValidatorState{ - Address: validator.OperatorAddress, - Moniker: validator.Description.Moniker, - ConsensusAddress: info.Address, - MissedBlocks: info.MissedBlocksCounter, - Jailed: validator.Jailed, - Tombstoned: info.Tombstoned, - } - } - - return newState, nil + return FilterMap(state, func(v ValidatorState) bool { + return g.Config.IsValidatorMonitored(v.Address) + }), nil } func (g *ReportGenerator) GetValidatorReportEntry(oldState, newState ValidatorState) (*ReportEntry, bool) { diff --git a/telegram.go b/telegram.go index 0345de6..3c2d1ca 100644 --- a/telegram.go +++ b/telegram.go @@ -9,8 +9,6 @@ import ( "time" "github.com/BurntSushi/toml" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/rs/zerolog" tb "gopkg.in/tucnak/telebot.v2" ) @@ -256,7 +254,7 @@ func (r *TelegramReporter) getValidatorStatus(message *tb.Message) { address := args[1] r.Logger.Debug().Str("address", address).Msg("getValidatorStatus: address") - validator, err := r.Client.GetValidator(address) + state, err := r.Client.GetValidatorState(address) if err != nil { r.Logger.Error(). Str("address", address). @@ -266,13 +264,7 @@ func (r *TelegramReporter) getValidatorStatus(message *tb.Message) { return } - signingInfo, err := r.Client.GetSigningInfo(validator) - if err != nil { - r.sendMessage(message, "Could not get missed blocks info") - return - } - - r.sendMessage(message, r.getValidatorWithMissedBlocksSerialized(validator, signingInfo)) + r.sendMessage(message, r.getValidatorWithMissedBlocksSerialized(state)) r.Logger.Info(). Str("user", message.Sender.Username). Str("address", address). @@ -291,7 +283,7 @@ func (r *TelegramReporter) getSubscribedValidatorsStatuses(message *tb.Message) var sb strings.Builder for _, address := range subscribedValidators { - validator, err := r.Client.GetValidator(address) + state, err := r.Client.GetValidatorState(address) if err != nil { r.Logger.Error(). Str("address", address). @@ -301,13 +293,7 @@ func (r *TelegramReporter) getSubscribedValidatorsStatuses(message *tb.Message) return } - signingInfo, err := r.Client.GetSigningInfo(validator) - if err != nil { - r.sendMessage(message, "Could not get missed blocks info") - return - } - - sb.WriteString(r.getValidatorWithMissedBlocksSerialized(validator, signingInfo)) + sb.WriteString(r.getValidatorWithMissedBlocksSerialized(state)) sb.WriteString("\n") } @@ -317,22 +303,19 @@ func (r *TelegramReporter) getSubscribedValidatorsStatuses(message *tb.Message) Msg("Successfully returned subscribed validator statuses") } -func (r *TelegramReporter) getValidatorWithMissedBlocksSerialized( - validator stakingtypes.Validator, - signingInfo slashingtypes.ValidatorSigningInfo, -) string { +func (r *TelegramReporter) getValidatorWithMissedBlocksSerialized(state ValidatorState) string { var sb strings.Builder - sb.WriteString(fmt.Sprintf("%s\n", validator.Description.Moniker)) + sb.WriteString(fmt.Sprintf("%s\n", state.Moniker)) sb.WriteString(fmt.Sprintf( "Missed blocks: %d/%d (%.2f%%)\n", - signingInfo.MissedBlocksCounter, + state.MissedBlocks, r.Params.SignedBlocksWindow, - float64(signingInfo.MissedBlocksCounter)/float64(r.Params.SignedBlocksWindow)*100, + float64(state.MissedBlocks)/float64(r.Params.SignedBlocksWindow)*100, )) sb.WriteString(fmt.Sprintf( "Mintscan\n", r.ChainInfoConfig.MintscanPrefix, - validator.OperatorAddress, + state.Address, )) return sb.String() diff --git a/types.go b/types.go index 6cd45f5..fcd171e 100644 --- a/types.go +++ b/types.go @@ -2,6 +2,9 @@ package main import ( "time" + + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) type Direction int @@ -35,6 +38,20 @@ type ValidatorState struct { Tombstoned bool } +func NewValidatorState( + validator stakingtypes.Validator, + info slashingtypes.ValidatorSigningInfo, +) ValidatorState { + return ValidatorState{ + Address: validator.OperatorAddress, + Moniker: validator.Description.Moniker, + ConsensusAddress: info.Address, + MissedBlocks: info.MissedBlocksCounter, + Jailed: validator.Jailed, + Tombstoned: info.Tombstoned, + } +} + type ValidatorsState map[string]ValidatorState type ReportEntry struct { diff --git a/utils.go b/utils.go index 6292610..ae3e541 100644 --- a/utils.go +++ b/utils.go @@ -17,3 +17,13 @@ func removeFromSlice(slice []string, r string) []string { } return slice } + +func FilterMap[T any](source map[string]T, f func(T) bool) map[string]T { + var n map[string]T + for key, value := range source { + if f(value) { + n[key] = value + } + } + return n +}