|
17 | 17 | package clique
|
18 | 18 |
|
19 | 19 | import (
|
| 20 | + "bytes" |
20 | 21 | "encoding/json"
|
21 | 22 | "fmt"
|
22 | 23 |
|
@@ -93,40 +94,18 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
|
93 | 94 | return snap.signers(), nil
|
94 | 95 | }
|
95 | 96 |
|
96 |
| -// Proposals returns the current proposals the node tries to uphold and vote on. |
97 |
| -func (api *API) Proposals() map[common.Address]bool { |
98 |
| - api.clique.lock.RLock() |
99 |
| - defer api.clique.lock.RUnlock() |
100 |
| - |
101 |
| - proposals := make(map[common.Address]bool) |
102 |
| - for address, auth := range api.clique.proposals { |
103 |
| - proposals[address] = auth |
104 |
| - } |
105 |
| - return proposals |
106 |
| -} |
107 |
| - |
108 |
| -// Propose injects a new authorization proposal that the signer will attempt to |
109 |
| -// push through. |
110 |
| -func (api *API) Propose(address common.Address, auth bool) { |
111 |
| - api.clique.lock.Lock() |
112 |
| - defer api.clique.lock.Unlock() |
113 |
| - |
114 |
| - api.clique.proposals[address] = auth |
115 |
| -} |
116 |
| - |
117 |
| -// Discard drops a currently running proposal, stopping the signer from casting |
118 |
| -// further votes (either for or against). |
119 |
| -func (api *API) Discard(address common.Address) { |
120 |
| - api.clique.lock.Lock() |
121 |
| - defer api.clique.lock.Unlock() |
122 |
| - |
123 |
| - delete(api.clique.proposals, address) |
| 97 | +type status struct { |
| 98 | + InturnPercent float64 `json:"inturnPercent"` |
| 99 | + SigningStatus map[common.Address]int `json:"sealerActivity"` |
| 100 | + NumBlocks uint64 `json:"numBlocks"` |
124 | 101 | }
|
125 | 102 |
|
126 |
| -type status struct { |
| 103 | +type epochPerformance struct { |
127 | 104 | InturnPercent float64 `json:"inturnPercent"`
|
128 | 105 | SigningStatus map[common.Address]int `json:"sealerActivity"`
|
129 | 106 | NumBlocks uint64 `json:"numBlocks"`
|
| 107 | + NextEpoch uint64 `json:"nextEpoch"` |
| 108 | + StartBlock uint64 `json:"startBlock"` |
130 | 109 | }
|
131 | 110 |
|
132 | 111 | // Status returns the status of the last N blocks,
|
@@ -179,6 +158,70 @@ func (api *API) Status() (*status, error) {
|
179 | 158 | }, nil
|
180 | 159 | }
|
181 | 160 |
|
| 161 | +// EpochPerformance returns the performance of all the validators in an epoch, |
| 162 | +// - the signer activity, |
| 163 | +// - the number of blocks in epoch, |
| 164 | +// - start of epoch block, |
| 165 | +// - next epoch number if available else 0, |
| 166 | +// - the percentage of in-turn blocks |
| 167 | +func (api *API) EpochPerformance(epochNumber, epochBlockNumber uint64) (*epochPerformance, error) { |
| 168 | + var ( |
| 169 | + numBlocks = uint64(0) |
| 170 | + header = api.chain.CurrentHeader() |
| 171 | + optimals = 0 |
| 172 | + ) |
| 173 | + epochBlock := api.chain.GetHeaderByNumber(epochBlockNumber) |
| 174 | + if epochBlock == nil { |
| 175 | + return nil, fmt.Errorf("missing epoch block %d", epochBlockNumber) |
| 176 | + } |
| 177 | + snap, err := api.clique.snapshot(api.chain, epochBlockNumber, epochBlock.Hash(), nil) |
| 178 | + if err != nil { |
| 179 | + return nil, err |
| 180 | + } |
| 181 | + if snap.EpochNumber != epochNumber { |
| 182 | + return nil, fmt.Errorf("epoch number mismatch, expected=%v got=%v", epochNumber, snap.EpochNumber) |
| 183 | + } |
| 184 | + var ( |
| 185 | + signers = snap.signers() |
| 186 | + end = header.Number.Uint64() |
| 187 | + start = snap.Number + 1 |
| 188 | + ) |
| 189 | + signStatus := make(map[common.Address]int) |
| 190 | + for _, s := range signers { |
| 191 | + signStatus[s] = 0 |
| 192 | + } |
| 193 | + nextEpoch := uint64(0) |
| 194 | + n := start |
| 195 | + for ; n <= end; n++ { |
| 196 | + h := api.chain.GetHeaderByNumber(n) |
| 197 | + if h == nil { |
| 198 | + return nil, fmt.Errorf("missing block %d", n) |
| 199 | + } |
| 200 | + numBlocks++ |
| 201 | + |
| 202 | + if h.Difficulty.Cmp(diffInTurn) == 0 { |
| 203 | + optimals++ |
| 204 | + } |
| 205 | + sealer, err := api.clique.Author(h) |
| 206 | + if err != nil { |
| 207 | + return nil, err |
| 208 | + } |
| 209 | + signStatus[sealer]++ |
| 210 | + |
| 211 | + if !bytes.Equal(h.Nonce[:], nonceDropVote) { |
| 212 | + nextEpoch = h.Nonce.Uint64() |
| 213 | + break |
| 214 | + } |
| 215 | + } |
| 216 | + return &epochPerformance{ |
| 217 | + InturnPercent: float64(100*optimals) / float64(numBlocks), |
| 218 | + SigningStatus: signStatus, |
| 219 | + NumBlocks: numBlocks, |
| 220 | + NextEpoch: nextEpoch, |
| 221 | + StartBlock: start, |
| 222 | + }, nil |
| 223 | +} |
| 224 | + |
182 | 225 | type blockNumberOrHashOrRLP struct {
|
183 | 226 | *rpc.BlockNumberOrHash
|
184 | 227 | RLP hexutil.Bytes `json:"rlp,omitempty"`
|
|
0 commit comments