Skip to content

Commit 3e33d8f

Browse files
authored
fix: better handle reset of vote metrics (#68)
1 parent be2c27d commit 3e33d8f

File tree

4 files changed

+68
-36
lines changed

4 files changed

+68
-36
lines changed

pkg/watcher/block.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ func (w *BlockWatcher) OnNodeStart(ctx context.Context, node *rpc.Node) error {
5454

5555
blockResp, err := node.Client.Block(ctx, nil)
5656
if err != nil {
57-
log.Warn().Err(err).Msg("failed to get latest block")
57+
log.Warn().Err(err).
58+
Str("node", node.Redacted()).
59+
Msg("failed to get latest block")
5860
} else {
59-
w.handleNodeBlock(ctx, node, blockResp.Block)
61+
w.handleNodeBlock(node, blockResp.Block)
6062
}
6163

6264
// Ticker to sync validator set
@@ -70,7 +72,7 @@ func (w *BlockWatcher) OnNodeStart(ctx context.Context, node *rpc.Node) error {
7072
return
7173
case <-ticker.C:
7274
if err := w.syncValidatorSet(ctx, node); err != nil {
73-
log.Error().Err(err).Msg("failed to sync validator set")
75+
log.Error().Err(err).Str("node", node.Redacted()).Msg("failed to sync validator set")
7476
}
7577
}
7678
}
@@ -88,7 +90,7 @@ func (w *BlockWatcher) OnNewBlock(ctx context.Context, node *rpc.Node, evt *ctyp
8890
blockEvent := evt.Data.(types.EventDataNewBlock)
8991
block := blockEvent.Block
9092

91-
w.handleNodeBlock(ctx, node, block)
93+
w.handleNodeBlock(node, block)
9294

9395
return nil
9496
}
@@ -104,7 +106,7 @@ func (w *BlockWatcher) OnValidatorSetUpdates(ctx context.Context, node *rpc.Node
104106
return nil
105107
}
106108

107-
func (w *BlockWatcher) handleNodeBlock(ctx context.Context, node *rpc.Node, block *types.Block) {
109+
func (w *BlockWatcher) handleNodeBlock(node *rpc.Node, block *types.Block) {
108110
validatorSet := w.getValidatorSet()
109111

110112
if len(validatorSet) != block.LastCommit.Size() {

pkg/watcher/upgrade.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ func (w *UpgradeWatcher) Start(ctx context.Context) error {
5353
if node == nil {
5454
log.Warn().Msg("no node available to fetch upgrade plan")
5555
} else if err := w.fetchUpgrade(ctx, node); err != nil {
56-
log.Error().Err(err).Msg("failed to fetch upgrade plan")
56+
log.Error().Err(err).
57+
Str("node", node.Redacted()).
58+
Msg("failed to fetch upgrade plan")
5759
}
5860

5961
select {

pkg/watcher/validators.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ func (w *ValidatorsWatcher) Start(ctx context.Context) error {
4545
if node == nil {
4646
log.Warn().Msg("no node available to fetch validators")
4747
} else if err := w.fetchValidators(ctx, node); err != nil {
48-
log.Error().Err(err).Msg("failed to fetch staking validators")
48+
log.Error().Err(err).
49+
Str("node", node.Redacted()).
50+
Msg("failed to fetch staking validators")
4951
}
5052

5153
select {

pkg/watcher/votes.go

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ func (w *VotesWatcher) Start(ctx context.Context) error {
4343
if node == nil {
4444
log.Warn().Msg("no node available to fetch proposals")
4545
} else if err := w.fetchProposals(ctx, node); err != nil {
46-
log.Error().Err(err).Msg("failed to fetch pending proposals")
46+
log.Error().Err(err).
47+
Str("node", node.Redacted()).
48+
Msg("failed to fetch pending proposals")
4749
}
4850

4951
select {
@@ -55,17 +57,37 @@ func (w *VotesWatcher) Start(ctx context.Context) error {
5557
}
5658

5759
func (w *VotesWatcher) fetchProposals(ctx context.Context, node *rpc.Node) error {
58-
w.metrics.Vote.Reset()
60+
var (
61+
votes map[uint64]map[TrackedValidator]bool
62+
err error
63+
)
5964

6065
switch w.options.GovModuleVersion {
6166
case "v1beta1":
62-
return w.fetchProposalsV1Beta1(ctx, node)
67+
votes, err = w.fetchProposalsV1Beta1(ctx, node)
6368
default: // v1
64-
return w.fetchProposalsV1(ctx, node)
69+
votes, err = w.fetchProposalsV1(ctx, node)
70+
}
71+
72+
if err != nil {
73+
return err
74+
}
75+
76+
w.metrics.Vote.Reset()
77+
for proposalId, votes := range votes {
78+
for validator, voted := range votes {
79+
w.metrics.Vote.
80+
WithLabelValues(node.ChainID(), validator.Address, validator.Name, fmt.Sprintf("%d", proposalId)).
81+
Set(metrics.BoolToFloat64(voted))
82+
}
6583
}
84+
85+
return nil
6686
}
6787

68-
func (w *VotesWatcher) fetchProposalsV1(ctx context.Context, node *rpc.Node) error {
88+
func (w *VotesWatcher) fetchProposalsV1(ctx context.Context, node *rpc.Node) (map[uint64]map[TrackedValidator]bool, error) {
89+
votes := make(map[uint64]map[TrackedValidator]bool)
90+
6991
clientCtx := (client.Context{}).WithClient(node.Client)
7092
queryClient := gov.NewQueryClient(clientCtx)
7193

@@ -74,13 +96,14 @@ func (w *VotesWatcher) fetchProposalsV1(ctx context.Context, node *rpc.Node) err
7496
ProposalStatus: gov.StatusVotingPeriod,
7597
})
7698
if err != nil {
77-
return fmt.Errorf("failed to get proposals: %w", err)
99+
return votes, fmt.Errorf("failed to fetch proposals in voting period: %w", err)
78100
}
79101

80102
chainID := node.ChainID()
81103

82104
// For each proposal, fetch validators vote
83105
for _, proposal := range proposalsResp.GetProposals() {
106+
votes[proposal.Id] = make(map[TrackedValidator]bool)
84107
w.metrics.ProposalEndTime.WithLabelValues(chainID, fmt.Sprintf("%d", proposal.Id)).Set(float64(proposal.VotingEndTime.Unix()))
85108

86109
for _, validator := range w.validators {
@@ -95,34 +118,29 @@ func (w *VotesWatcher) fetchProposalsV1(ctx context.Context, node *rpc.Node) err
95118
})
96119

97120
if isInvalidArgumentError(err) {
98-
w.handleVoteV1(chainID, validator, proposal.Id, nil)
121+
votes[proposal.Id][validator] = false
99122
} else if err != nil {
100-
return fmt.Errorf("failed to get validator vote for proposal %d: %w", proposal.Id, err)
123+
return votes, fmt.Errorf("failed to get validator vote for proposal %d: %w", proposal.Id, err)
101124
} else {
102125
vote := voteResp.GetVote()
103-
w.handleVoteV1(chainID, validator, proposal.Id, vote.Options)
126+
voted := false
127+
for _, option := range vote.Options {
128+
if option.Option != gov.OptionEmpty {
129+
voted = true
130+
break
131+
}
132+
}
133+
votes[proposal.Id][validator] = voted
104134
}
105135
}
106136
}
107137

108-
return nil
138+
return votes, nil
109139
}
110140

111-
func (w *VotesWatcher) handleVoteV1(chainID string, validator TrackedValidator, proposalId uint64, votes []*gov.WeightedVoteOption) {
112-
voted := false
113-
for _, option := range votes {
114-
if option.Option != gov.OptionEmpty {
115-
voted = true
116-
break
117-
}
118-
}
141+
func (w *VotesWatcher) fetchProposalsV1Beta1(ctx context.Context, node *rpc.Node) (map[uint64]map[TrackedValidator]bool, error) {
142+
votes := make(map[uint64]map[TrackedValidator]bool)
119143

120-
w.metrics.Vote.
121-
WithLabelValues(chainID, validator.Address, validator.Name, fmt.Sprintf("%d", proposalId)).
122-
Set(metrics.BoolToFloat64(voted))
123-
}
124-
125-
func (w *VotesWatcher) fetchProposalsV1Beta1(ctx context.Context, node *rpc.Node) error {
126144
clientCtx := (client.Context{}).WithClient(node.Client)
127145
queryClient := govbeta.NewQueryClient(clientCtx)
128146

@@ -131,13 +149,14 @@ func (w *VotesWatcher) fetchProposalsV1Beta1(ctx context.Context, node *rpc.Node
131149
ProposalStatus: govbeta.StatusVotingPeriod,
132150
})
133151
if err != nil {
134-
return fmt.Errorf("failed to get proposals: %w", err)
152+
return votes, fmt.Errorf("failed to fetch proposals in voting period: %w", err)
135153
}
136154

137155
chainID := node.ChainID()
138156

139157
// For each proposal, fetch validators vote
140158
for _, proposal := range proposalsResp.GetProposals() {
159+
votes[proposal.ProposalId] = make(map[TrackedValidator]bool)
141160
w.metrics.ProposalEndTime.WithLabelValues(chainID, fmt.Sprintf("%d", proposal.ProposalId)).Set(float64(proposal.VotingEndTime.Unix()))
142161

143162
for _, validator := range w.validators {
@@ -152,17 +171,24 @@ func (w *VotesWatcher) fetchProposalsV1Beta1(ctx context.Context, node *rpc.Node
152171
})
153172

154173
if isInvalidArgumentError(err) {
155-
w.handleVoteV1Beta1(chainID, validator, proposal.ProposalId, nil)
174+
votes[proposal.ProposalId][validator] = false
156175
} else if err != nil {
157-
return fmt.Errorf("failed to get validator vote for proposal %d: %w", proposal.ProposalId, err)
176+
return votes, fmt.Errorf("failed to get validator vote for proposal %d: %w", proposal.ProposalId, err)
158177
} else {
159178
vote := voteResp.GetVote()
160-
w.handleVoteV1Beta1(chainID, validator, proposal.ProposalId, vote.Options)
179+
voted := false
180+
for _, option := range vote.Options {
181+
if option.Option != govbeta.OptionEmpty {
182+
voted = true
183+
break
184+
}
185+
}
186+
votes[proposal.ProposalId][validator] = voted
161187
}
162188
}
163189
}
164190

165-
return nil
191+
return votes, nil
166192
}
167193

168194
func (w *VotesWatcher) handleVoteV1Beta1(chainID string, validator TrackedValidator, proposalId uint64, votes []govbeta.WeightedVoteOption) {

0 commit comments

Comments
 (0)