From 3f4a875bf6a74defd6e5e5a9cf121a5adc6e6c86 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 18 Nov 2019 17:03:57 +0100 Subject: [PATCH] consensus/clique: add clique_status API method (#20103) 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? --- consensus/clique/api.go | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/consensus/clique/api.go b/consensus/clique/api.go index 6bcf987af..fdb7b7a07 100644 --- a/consensus/clique/api.go +++ b/consensus/clique/api.go @@ -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" @@ -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 +}