From 1ec20cc001ad69f6f3764455236f9e2390df8f7c Mon Sep 17 00:00:00 2001 From: Matt Ketmo Date: Thu, 6 Jun 2024 16:08:15 +0200 Subject: [PATCH] feat: count proposed blocks by validators (#72) Close #6 --- README.md | 1 + pkg/metrics/metrics.go | 10 ++++++++++ pkg/watcher/block.go | 24 +++++++++++++++--------- pkg/watcher/block_test.go | 27 +++++++++++++++++++++++---- pkg/watcher/block_types.go | 2 ++ 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b13cfd8..046db87 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ Metrics (without prefix) | Description `node_block_height` | Latest fetched block height for each node `node_synced` | Set to 1 is the node is synced (ie. not catching-up) `proposal_end_time` | Timestamp of the voting end time of a proposal +`proposed_blocks` | Number of proposed blocks per validator (for a bonded validator) `rank` | Rank of the validator `seat_price` | Min seat price to be in the active set (ie. bonded tokens of the latest validator) `skipped_blocks` | Number of blocks skipped (ie. not tracked) since start diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index f49e065..bed1aec 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -20,6 +20,7 @@ type Metrics struct { // Validator metrics Rank *prometheus.GaugeVec + ProposedBlocks *prometheus.CounterVec ValidatedBlocks *prometheus.CounterVec MissedBlocks *prometheus.CounterVec SoloMissedBlocks *prometheus.CounterVec @@ -69,6 +70,14 @@ func New(namespace string) *Metrics { }, []string{"chain_id", "address", "name"}, ), + ProposedBlocks: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: namespace, + Name: "proposed_blocks", + Help: "Number of proposed blocks per validator (for a bonded validator)", + }, + []string{"chain_id", "address", "name"}, + ), ValidatedBlocks: prometheus.NewCounterVec( prometheus.CounterOpts{ Namespace: namespace, @@ -202,6 +211,7 @@ func (m *Metrics) Register() { m.Registry.MustRegister(m.ActiveSet) m.Registry.MustRegister(m.SeatPrice) m.Registry.MustRegister(m.Rank) + m.Registry.MustRegister(m.ProposedBlocks) m.Registry.MustRegister(m.ValidatedBlocks) m.Registry.MustRegister(m.MissedBlocks) m.Registry.MustRegister(m.SoloMissedBlocks) diff --git a/pkg/watcher/block.go b/pkg/watcher/block.go index 6f7c1eb..40ebfeb 100644 --- a/pkg/watcher/block.go +++ b/pkg/watcher/block.go @@ -18,12 +18,13 @@ import ( ) type BlockWatcher struct { - trackedValidators []TrackedValidator - metrics *metrics.Metrics - writer io.Writer - blockChan chan *BlockInfo - validatorSet atomic.Value // []*types.Validator - latestBlockHeight int64 + trackedValidators []TrackedValidator + metrics *metrics.Metrics + writer io.Writer + blockChan chan *BlockInfo + validatorSet atomic.Value // []*types.Validator + latestBlockHeight int64 + latestBlockProposer string } func NewBlockWatcher(validators []TrackedValidator, metrics *metrics.Metrics, writer io.Writer) *BlockWatcher { @@ -32,7 +33,6 @@ func NewBlockWatcher(validators []TrackedValidator, metrics *metrics.Metrics, wr metrics: metrics, writer: writer, blockChan: make(chan *BlockInfo), - latestBlockHeight: 0, } } @@ -181,7 +181,6 @@ func (w *BlockWatcher) handleBlockInfo(block *BlockInfo) { w.metrics.SkippedBlocks.WithLabelValues(chainId).Add(float64(blockDiff)) } - w.latestBlockHeight = block.Height w.metrics.BlockHeight.WithLabelValues(chainId).Set(float64(block.Height)) w.metrics.ActiveSet.WithLabelValues(chainId).Set(float64(block.TotalValidators)) w.metrics.TrackedBlocks.WithLabelValues(chainId).Inc() @@ -191,7 +190,11 @@ func (w *BlockWatcher) handleBlockInfo(block *BlockInfo) { validatorStatus := []string{} for _, res := range block.ValidatorStatus { icon := "⚪️" - if res.Signed { + if w.latestBlockProposer == res.Address { + icon = "👑" + w.metrics.ProposedBlocks.WithLabelValues(block.ChainID, res.Address, res.Label).Inc() + w.metrics.ValidatedBlocks.WithLabelValues(block.ChainID, res.Address, res.Label).Inc() + } else if res.Signed { icon = "✅" w.metrics.ValidatedBlocks.WithLabelValues(block.ChainID, res.Address, res.Label).Inc() } else if res.Bonded { @@ -212,6 +215,9 @@ func (w *BlockWatcher) handleBlockInfo(block *BlockInfo) { color.CyanString(fmt.Sprintf("%3d/%d validators", block.SignedValidators, block.TotalValidators)), strings.Join(validatorStatus, " "), ) + + w.latestBlockHeight = block.Height + w.latestBlockProposer = block.ProposerAddress } func (w *BlockWatcher) computeValidatorStatus(block *types.Block) []ValidatorStatus { diff --git a/pkg/watcher/block_test.go b/pkg/watcher/block_test.go index 4ba655b..629b4e2 100644 --- a/pkg/watcher/block_test.go +++ b/pkg/watcher/block_test.go @@ -84,6 +84,23 @@ func TestBlockWatcher(t *testing.T) { Transactions: 7, TotalValidators: 2, SignedValidators: 2, + ProposerAddress: kilnAddress, + ValidatorStatus: []ValidatorStatus{ + { + Address: kilnAddress, + Label: kilnName, + Bonded: true, + Signed: true, + Rank: 2, + }, + }, + }, + { + ChainID: chainID, + Height: 44, + Transactions: 7, + TotalValidators: 2, + SignedValidators: 2, ValidatorStatus: []ValidatorStatus{ { Address: kilnAddress, @@ -106,20 +123,22 @@ func TestBlockWatcher(t *testing.T) { `#40 0/1 validators ❌ Kiln`, `#41 1/2 validators ✅ Kiln`, `#42 2/2 validators ✅ Kiln`, + `#43 2/2 validators 👑 Kiln`, }, "\n")+"\n", blockWatcher.writer.(*bytes.Buffer).String(), ) - assert.Equal(t, float64(43), testutil.ToFloat64(blockWatcher.metrics.BlockHeight.WithLabelValues(chainID))) - assert.Equal(t, float64(22), testutil.ToFloat64(blockWatcher.metrics.Transactions.WithLabelValues(chainID))) + assert.Equal(t, float64(44), testutil.ToFloat64(blockWatcher.metrics.BlockHeight.WithLabelValues(chainID))) + assert.Equal(t, float64(29), testutil.ToFloat64(blockWatcher.metrics.Transactions.WithLabelValues(chainID))) assert.Equal(t, float64(2), testutil.ToFloat64(blockWatcher.metrics.ActiveSet.WithLabelValues(chainID))) - assert.Equal(t, float64(4), testutil.ToFloat64(blockWatcher.metrics.TrackedBlocks.WithLabelValues(chainID))) + assert.Equal(t, float64(5), testutil.ToFloat64(blockWatcher.metrics.TrackedBlocks.WithLabelValues(chainID))) assert.Equal(t, float64(5), testutil.ToFloat64(blockWatcher.metrics.SkippedBlocks.WithLabelValues(chainID))) assert.Equal(t, 1, testutil.CollectAndCount(blockWatcher.metrics.ValidatedBlocks)) assert.Equal(t, 1, testutil.CollectAndCount(blockWatcher.metrics.MissedBlocks)) assert.Equal(t, 1, testutil.CollectAndCount(blockWatcher.metrics.SoloMissedBlocks)) - assert.Equal(t, float64(2), testutil.ToFloat64(blockWatcher.metrics.ValidatedBlocks.WithLabelValues(chainID, kilnAddress, kilnName))) + assert.Equal(t, float64(1), testutil.ToFloat64(blockWatcher.metrics.ProposedBlocks.WithLabelValues(chainID, kilnAddress, kilnName))) + assert.Equal(t, float64(3), testutil.ToFloat64(blockWatcher.metrics.ValidatedBlocks.WithLabelValues(chainID, kilnAddress, kilnName))) assert.Equal(t, float64(1), testutil.ToFloat64(blockWatcher.metrics.MissedBlocks.WithLabelValues(chainID, kilnAddress, kilnName))) assert.Equal(t, float64(0), testutil.ToFloat64(blockWatcher.metrics.SoloMissedBlocks.WithLabelValues(chainID, kilnAddress, kilnName))) }) diff --git a/pkg/watcher/block_types.go b/pkg/watcher/block_types.go index 9d1ff21..d3577c8 100644 --- a/pkg/watcher/block_types.go +++ b/pkg/watcher/block_types.go @@ -11,6 +11,7 @@ type BlockInfo struct { Transactions int TotalValidators int SignedValidators int + ProposerAddress string ValidatorStatus []ValidatorStatus } @@ -30,6 +31,7 @@ func NewBlockInfo(block *types.Block, validatorStatus []ValidatorStatus) *BlockI TotalValidators: len(block.LastCommit.Signatures), SignedValidators: signedValidators, ValidatorStatus: validatorStatus, + ProposerAddress: block.Header.ProposerAddress.String(), } }