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?
This commit is contained in:
		
							parent
							
								
									a3d263dd3a
								
							
						
					
					
						commit
						3f4a875bf6
					
				| @ -17,6 +17,8 @@ | |||||||
| package clique | package clique | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/consensus" | 	"github.com/ethereum/go-ethereum/consensus" | ||||||
| 	"github.com/ethereum/go-ethereum/core/types" | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| @ -117,3 +119,59 @@ func (api *API) Discard(address common.Address) { | |||||||
| 
 | 
 | ||||||
| 	delete(api.clique.proposals, 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 | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user