Skip to content

Commit

Permalink
consensus/clique: add clique_status API method (ethereum#20103)
Browse files Browse the repository at this point in the history
This PR introduces clique_status which gives info about the health of
the clique network.

It's currently a bit PITA to find out how a clique network is
performing, and it can easily happen that sealers drop off -- and
everything is 'fine' until one more signer drops off, and the network
suddenly halts.

The new method provides the following stats:

- Which signers are currently active, and have signed blocks in the last
  N (set to 64) blocks?
- How many blocks has each signer signed?
- What is the difficulty in the last N blocks, compared to the
  theoretical maximum?
  • Loading branch information
holiman authored and enriquefynn committed Feb 15, 2021
1 parent 8e32619 commit 8d4e8dd
Showing 1 changed file with 58 additions and 0 deletions.
58 changes: 58 additions & 0 deletions consensus/clique/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package clique

import (
"fmt"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -117,3 +119,59 @@ func (api *API) Discard(address common.Address) {

delete(api.clique.proposals, address)
}

type Status struct {
InturnPercent float64 `json:"inturnPercent"`
SigningStatus map[common.Address]int `json:"sealerActivity""`
NumBlocks uint64 `json:"numBlocks"`
}

// Status returns the status of the last N blocks,
// - the number of active signers,
// - the number of signers,
// - the percentage of in-turn blocks
func (api *API) Status() (*Status, error) {
var (
numBlocks = uint64(64)
header = api.chain.CurrentHeader()
diff = uint64(0)
optimals = 0
)
snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return nil, err
}
var (
signers = snap.signers()
end = header.Number.Uint64()
start = end - numBlocks
)
if numBlocks > end {
start = 1
numBlocks = end - start
}
signStatus := make(map[common.Address]int)
for _, s := range signers {
signStatus[s] = 0
}
for n := start; n < end; n++ {
h := api.chain.GetHeaderByNumber(n)
if h == nil {
return nil, fmt.Errorf("missing block %d", n)
}
if h.Difficulty.Cmp(diffInTurn) == 0 {
optimals++
}
diff += h.Difficulty.Uint64()
sealer, err := api.clique.Author(h)
if err != nil {
return nil, err
}
signStatus[sealer]++
}
return &Status{
InturnPercent: float64((100 * optimals)) / float64(numBlocks),
SigningStatus: signStatus,
NumBlocks: numBlocks,
}, nil
}

0 comments on commit 8d4e8dd

Please sign in to comment.