github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/backend/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 backend 18 19 import ( 20 "errors" 21 22 "github.com/kisexp/xdchain/common" 23 "github.com/kisexp/xdchain/consensus" 24 istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common" 25 "github.com/kisexp/xdchain/core/types" 26 "github.com/kisexp/xdchain/rpc" 27 ) 28 29 // API is a user facing RPC API to dump Istanbul state 30 type API struct { 31 chain consensus.ChainHeaderReader 32 backend *Backend 33 } 34 35 // BlockSigners is contains who created and who signed a particular block, denoted by its number and hash 36 type BlockSigners struct { 37 Number uint64 38 Hash common.Hash 39 Author common.Address 40 Committers []common.Address 41 } 42 43 type Status struct { 44 SigningStatus map[common.Address]int `json:"sealerActivity"` 45 NumBlocks uint64 `json:"numBlocks"` 46 } 47 48 // NodeAddress returns the public address that is used to sign block headers in IBFT 49 func (api *API) NodeAddress() common.Address { 50 return api.backend.Address() 51 } 52 53 // GetSignersFromBlock returns the signers and minter for a given block number, or the 54 // latest block available if none is specified 55 func (api *API) GetSignersFromBlock(number *rpc.BlockNumber) (*BlockSigners, error) { 56 // Retrieve the requested block number (or current if none requested) 57 var header *types.Header 58 if number == nil || *number == rpc.LatestBlockNumber { 59 header = api.chain.CurrentHeader() 60 } else { 61 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 62 } 63 64 if header == nil { 65 return nil, istanbulcommon.ErrUnknownBlock 66 } 67 68 return api.signers(header) 69 } 70 71 // GetSignersFromBlockByHash returns the signers and minter for a given block hash 72 func (api *API) GetSignersFromBlockByHash(hash common.Hash) (*BlockSigners, error) { 73 header := api.chain.GetHeaderByHash(hash) 74 if header == nil { 75 return nil, istanbulcommon.ErrUnknownBlock 76 } 77 78 return api.signers(header) 79 } 80 81 func (api *API) signers(header *types.Header) (*BlockSigners, error) { 82 author, err := api.backend.Author(header) 83 if err != nil { 84 return nil, err 85 } 86 87 committers, err := api.backend.Signers(header) 88 if err != nil { 89 return nil, err 90 } 91 92 return &BlockSigners{ 93 Number: header.Number.Uint64(), 94 Hash: header.Hash(), 95 Author: author, 96 Committers: committers, 97 }, nil 98 } 99 100 // GetSnapshot retrieves the state snapshot at a given block. 101 func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { 102 // Retrieve the requested block number (or current if none requested) 103 var header *types.Header 104 if number == nil || *number == rpc.LatestBlockNumber { 105 header = api.chain.CurrentHeader() 106 } else { 107 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 108 } 109 // Ensure we have an actually valid block and return its snapshot 110 if header == nil { 111 return nil, istanbulcommon.ErrUnknownBlock 112 } 113 return api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 114 } 115 116 // GetSnapshotAtHash retrieves the state snapshot at a given block. 117 func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { 118 header := api.chain.GetHeaderByHash(hash) 119 if header == nil { 120 return nil, istanbulcommon.ErrUnknownBlock 121 } 122 return api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 123 } 124 125 // GetValidators retrieves the list of authorized validators at the specified block. 126 func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) { 127 // Retrieve the requested block number (or current if none requested) 128 var header *types.Header 129 if number == nil || *number == rpc.LatestBlockNumber { 130 header = api.chain.CurrentHeader() 131 } else { 132 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 133 } 134 // Ensure we have an actually valid block and return the validators from its snapshot 135 if header == nil { 136 return nil, istanbulcommon.ErrUnknownBlock 137 } 138 snap, err := api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 139 if err != nil { 140 return nil, err 141 } 142 return snap.validators(), nil 143 } 144 145 // GetValidatorsAtHash retrieves the state snapshot at a given block. 146 func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error) { 147 header := api.chain.GetHeaderByHash(hash) 148 if header == nil { 149 return nil, istanbulcommon.ErrUnknownBlock 150 } 151 snap, err := api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 152 if err != nil { 153 return nil, err 154 } 155 return snap.validators(), nil 156 } 157 158 // Candidates returns the current candidates the node tries to uphold and vote on. 159 func (api *API) Candidates() map[common.Address]bool { 160 api.backend.candidatesLock.RLock() 161 defer api.backend.candidatesLock.RUnlock() 162 163 proposals := make(map[common.Address]bool) 164 for address, auth := range api.backend.candidates { 165 proposals[address] = auth 166 } 167 return proposals 168 } 169 170 // Propose injects a new authorization candidate that the validator will attempt to 171 // push through. 172 func (api *API) Propose(address common.Address, auth bool) { 173 api.backend.candidatesLock.Lock() 174 defer api.backend.candidatesLock.Unlock() 175 176 api.backend.candidates[address] = auth 177 } 178 179 // Discard drops a currently running candidate, stopping the validator from casting 180 // further votes (either for or against). 181 func (api *API) Discard(address common.Address) { 182 api.backend.candidatesLock.Lock() 183 defer api.backend.candidatesLock.Unlock() 184 185 delete(api.backend.candidates, address) 186 } 187 188 func (api *API) Status(startBlockNum *rpc.BlockNumber, endBlockNum *rpc.BlockNumber) (*Status, error) { 189 var ( 190 numBlocks uint64 191 header = api.chain.CurrentHeader() 192 start uint64 193 end uint64 194 blockNumber rpc.BlockNumber 195 ) 196 if startBlockNum != nil && endBlockNum == nil { 197 return nil, errors.New("pass the end block number") 198 } 199 200 if startBlockNum == nil && endBlockNum != nil { 201 return nil, errors.New("pass the start block number") 202 } 203 204 if startBlockNum == nil && endBlockNum == nil { 205 numBlocks = uint64(64) 206 header = api.chain.CurrentHeader() 207 end = header.Number.Uint64() 208 start = end - numBlocks 209 blockNumber = rpc.BlockNumber(header.Number.Int64()) 210 } else { 211 end = uint64(*endBlockNum) 212 start = uint64(*startBlockNum) 213 if start > end { 214 return nil, errors.New("start block number should be less than end block number") 215 } 216 217 if end > api.chain.CurrentHeader().Number.Uint64() { 218 return nil, errors.New("end block number should be less than or equal to current block height") 219 } 220 221 numBlocks = end - start 222 header = api.chain.GetHeaderByNumber(end) 223 blockNumber = rpc.BlockNumber(end) 224 } 225 226 signers, err := api.GetValidators(&blockNumber) 227 228 if err != nil { 229 return nil, err 230 } 231 232 if numBlocks >= end { 233 start = 1 234 if end > start { 235 numBlocks = end - start 236 } else { 237 numBlocks = 0 238 } 239 } 240 signStatus := make(map[common.Address]int) 241 for _, s := range signers { 242 signStatus[s] = 0 243 } 244 245 for n := start; n < end; n++ { 246 blockNum := rpc.BlockNumber(int64(n)) 247 s, _ := api.GetSignersFromBlock(&blockNum) 248 signStatus[s.Author]++ 249 250 } 251 return &Status{ 252 SigningStatus: signStatus, 253 NumBlocks: numBlocks, 254 }, nil 255 } 256 257 func (api *API) IsValidator(blockNum *rpc.BlockNumber) (bool, error) { 258 var blockNumber rpc.BlockNumber 259 if blockNum != nil { 260 blockNumber = *blockNum 261 } else { 262 header := api.chain.CurrentHeader() 263 blockNumber = rpc.BlockNumber(header.Number.Int64()) 264 } 265 s, _ := api.GetValidators(&blockNumber) 266 267 for _, v := range s { 268 if v == api.backend.address { 269 return true, nil 270 } 271 } 272 return false, nil 273 }