github.com/core-coin/go-core/v2@v2.1.9/consensus/clique/api.go (about) 1 // Copyright 2017 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package clique 18 19 import ( 20 "fmt" 21 22 "github.com/core-coin/go-core/v2/common" 23 "github.com/core-coin/go-core/v2/consensus" 24 "github.com/core-coin/go-core/v2/core/types" 25 "github.com/core-coin/go-core/v2/rpc" 26 ) 27 28 // API is a user facing RPC API to allow controlling the signer and voting 29 // mechanisms of the proof-of-authority scheme. 30 type API struct { 31 chain consensus.ChainHeaderReader 32 clique *Clique 33 } 34 35 // GetSnapshot retrieves the state snapshot at a given block. 36 func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { 37 // Retrieve the requested block number (or current if none requested) 38 var header *types.Header 39 if number == nil || *number == rpc.LatestBlockNumber { 40 header = api.chain.CurrentHeader() 41 } else { 42 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 43 } 44 // Ensure we have an actually valid block and return its snapshot 45 if header == nil { 46 return nil, errUnknownBlock 47 } 48 return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 49 } 50 51 // GetSnapshotAtHash retrieves the state snapshot at a given block. 52 func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { 53 header := api.chain.GetHeaderByHash(hash) 54 if header == nil { 55 return nil, errUnknownBlock 56 } 57 return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 58 } 59 60 // GetSigners retrieves the list of authorized signers at the specified block. 61 func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) { 62 // Retrieve the requested block number (or current if none requested) 63 var header *types.Header 64 if number == nil || *number == rpc.LatestBlockNumber { 65 header = api.chain.CurrentHeader() 66 } else { 67 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 68 } 69 // Ensure we have an actually valid block and return the signers from its snapshot 70 if header == nil { 71 return nil, errUnknownBlock 72 } 73 snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 74 if err != nil { 75 return nil, err 76 } 77 return snap.signers(), nil 78 } 79 80 // GetSignersAtHash retrieves the list of authorized signers at the specified block. 81 func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { 82 header := api.chain.GetHeaderByHash(hash) 83 if header == nil { 84 return nil, errUnknownBlock 85 } 86 snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 87 if err != nil { 88 return nil, err 89 } 90 return snap.signers(), nil 91 } 92 93 // Proposals returns the current proposals the node tries to uphold and vote on. 94 func (api *API) Proposals() map[common.Address]bool { 95 api.clique.lock.RLock() 96 defer api.clique.lock.RUnlock() 97 98 proposals := make(map[common.Address]bool) 99 for address, auth := range api.clique.proposals { 100 proposals[address] = auth 101 } 102 return proposals 103 } 104 105 // Propose injects a new authorization proposal that the signer will attempt to 106 // push through. 107 func (api *API) Propose(address common.Address, auth bool) { 108 api.clique.lock.Lock() 109 defer api.clique.lock.Unlock() 110 111 api.clique.proposals[address] = auth 112 } 113 114 // Discard drops a currently running proposal, stopping the signer from casting 115 // further votes (either for or against). 116 func (api *API) Discard(address common.Address) { 117 api.clique.lock.Lock() 118 defer api.clique.lock.Unlock() 119 120 delete(api.clique.proposals, address) 121 } 122 123 type status struct { 124 InturnPercent float64 `json:"inturnPercent"` 125 SigningStatus map[common.Address]int `json:"sealerActivity"` 126 NumBlocks uint64 `json:"numBlocks"` 127 } 128 129 // Status returns the status of the last N blocks, 130 // - the number of active signers, 131 // - the number of signers, 132 // - the percentage of in-turn blocks 133 func (api *API) Status() (*status, error) { 134 var ( 135 numBlocks = uint64(64) 136 header = api.chain.CurrentHeader() 137 diff = uint64(0) 138 optimals = 0 139 ) 140 snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 141 if err != nil { 142 return nil, err 143 } 144 var ( 145 signers = snap.signers() 146 end = header.Number.Uint64() 147 start = end - numBlocks 148 ) 149 if numBlocks > end { 150 start = 1 151 numBlocks = end - start 152 } 153 signStatus := make(map[common.Address]int) 154 for _, s := range signers { 155 signStatus[s] = 0 156 } 157 for n := start; n < end; n++ { 158 h := api.chain.GetHeaderByNumber(n) 159 if h == nil { 160 return nil, fmt.Errorf("missing block %d", n) 161 } 162 if h.Difficulty.Cmp(diffInTurn) == 0 { 163 optimals++ 164 } 165 diff += h.Difficulty.Uint64() 166 sealer, err := api.clique.Author(h) 167 if err != nil { 168 return nil, err 169 } 170 signStatus[sealer]++ 171 } 172 return &status{ 173 InturnPercent: float64(100*optimals) / float64(numBlocks), 174 SigningStatus: signStatus, 175 NumBlocks: numBlocks, 176 }, nil 177 }