diff --git a/consensus/clique/api.go b/consensus/clique/api.go index 6bcf987af5..fdb7b7a079 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 +}