github.com/DxChainNetwork/dxc@v0.8.1-0.20220824085222-1162e304b6e7/consensus/clique/api.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package clique 18 19 import ( 20 "encoding/json" 21 "fmt" 22 23 "github.com/DxChainNetwork/dxc/common" 24 "github.com/DxChainNetwork/dxc/common/hexutil" 25 "github.com/DxChainNetwork/dxc/consensus" 26 "github.com/DxChainNetwork/dxc/core/types" 27 "github.com/DxChainNetwork/dxc/rlp" 28 "github.com/DxChainNetwork/dxc/rpc" 29 ) 30 31 // API is a user facing RPC API to allow controlling the signer and voting 32 // mechanisms of the proof-of-authority scheme. 33 type API struct { 34 chain consensus.ChainHeaderReader 35 clique *Clique 36 } 37 38 // GetSnapshot retrieves the state snapshot at a given block. 39 func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { 40 // Retrieve the requested block number (or current if none requested) 41 var header *types.Header 42 if number == nil || *number == rpc.LatestBlockNumber { 43 header = api.chain.CurrentHeader() 44 } else { 45 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 46 } 47 // Ensure we have an actually valid block and return its snapshot 48 if header == nil { 49 return nil, errUnknownBlock 50 } 51 return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 52 } 53 54 // GetSnapshotAtHash retrieves the state snapshot at a given block. 55 func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { 56 header := api.chain.GetHeaderByHash(hash) 57 if header == nil { 58 return nil, errUnknownBlock 59 } 60 return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 61 } 62 63 // GetSigners retrieves the list of authorized signers at the specified block. 64 func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) { 65 // Retrieve the requested block number (or current if none requested) 66 var header *types.Header 67 if number == nil || *number == rpc.LatestBlockNumber { 68 header = api.chain.CurrentHeader() 69 } else { 70 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 71 } 72 // Ensure we have an actually valid block and return the signers from its snapshot 73 if header == nil { 74 return nil, errUnknownBlock 75 } 76 snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 77 if err != nil { 78 return nil, err 79 } 80 return snap.signers(), nil 81 } 82 83 // GetSignersAtHash retrieves the list of authorized signers at the specified block. 84 func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { 85 header := api.chain.GetHeaderByHash(hash) 86 if header == nil { 87 return nil, errUnknownBlock 88 } 89 snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 90 if err != nil { 91 return nil, err 92 } 93 return snap.signers(), nil 94 } 95 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) 124 } 125 126 type status struct { 127 InturnPercent float64 `json:"inturnPercent"` 128 SigningStatus map[common.Address]int `json:"sealerActivity"` 129 NumBlocks uint64 `json:"numBlocks"` 130 } 131 132 // Status returns the status of the last N blocks, 133 // - the number of active signers, 134 // - the number of signers, 135 // - the percentage of in-turn blocks 136 func (api *API) Status() (*status, error) { 137 var ( 138 numBlocks = uint64(64) 139 header = api.chain.CurrentHeader() 140 diff = uint64(0) 141 optimals = 0 142 ) 143 snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 144 if err != nil { 145 return nil, err 146 } 147 var ( 148 signers = snap.signers() 149 end = header.Number.Uint64() 150 start = end - numBlocks 151 ) 152 if numBlocks > end { 153 start = 1 154 numBlocks = end - start 155 } 156 signStatus := make(map[common.Address]int) 157 for _, s := range signers { 158 signStatus[s] = 0 159 } 160 for n := start; n < end; n++ { 161 h := api.chain.GetHeaderByNumber(n) 162 if h == nil { 163 return nil, fmt.Errorf("missing block %d", n) 164 } 165 if h.Difficulty.Cmp(diffInTurn) == 0 { 166 optimals++ 167 } 168 diff += h.Difficulty.Uint64() 169 sealer, err := api.clique.Author(h) 170 if err != nil { 171 return nil, err 172 } 173 signStatus[sealer]++ 174 } 175 return &status{ 176 InturnPercent: float64(100*optimals) / float64(numBlocks), 177 SigningStatus: signStatus, 178 NumBlocks: numBlocks, 179 }, nil 180 } 181 182 type blockNumberOrHashOrRLP struct { 183 *rpc.BlockNumberOrHash 184 RLP hexutil.Bytes `json:"rlp,omitempty"` 185 } 186 187 func (sb *blockNumberOrHashOrRLP) UnmarshalJSON(data []byte) error { 188 bnOrHash := new(rpc.BlockNumberOrHash) 189 // Try to unmarshal bNrOrHash 190 if err := bnOrHash.UnmarshalJSON(data); err == nil { 191 sb.BlockNumberOrHash = bnOrHash 192 return nil 193 } 194 // Try to unmarshal RLP 195 var input string 196 if err := json.Unmarshal(data, &input); err != nil { 197 return err 198 } 199 sb.RLP = hexutil.MustDecode(input) 200 return nil 201 } 202 203 // GetSigner returns the signer for a specific clique block. 204 // Can be called with either a blocknumber, blockhash or an rlp encoded blob. 205 // The RLP encoded blob can either be a block or a header. 206 func (api *API) GetSigner(rlpOrBlockNr *blockNumberOrHashOrRLP) (common.Address, error) { 207 if len(rlpOrBlockNr.RLP) == 0 { 208 blockNrOrHash := rlpOrBlockNr.BlockNumberOrHash 209 var header *types.Header 210 if blockNrOrHash == nil { 211 header = api.chain.CurrentHeader() 212 } else if hash, ok := blockNrOrHash.Hash(); ok { 213 header = api.chain.GetHeaderByHash(hash) 214 } else if number, ok := blockNrOrHash.Number(); ok { 215 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 216 } 217 return api.clique.Author(header) 218 } 219 block := new(types.Block) 220 if err := rlp.DecodeBytes(rlpOrBlockNr.RLP, block); err == nil { 221 return api.clique.Author(block.Header()) 222 } 223 header := new(types.Header) 224 if err := rlp.DecodeBytes(rlpOrBlockNr.RLP, header); err != nil { 225 return common.Address{}, err 226 } 227 return api.clique.Author(header) 228 }