github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/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 "fmt" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/consensus" 25 "github.com/ethereum/go-ethereum/consensus/istanbul" 26 vet "github.com/ethereum/go-ethereum/consensus/istanbul/backend/internal/enodes" 27 "github.com/ethereum/go-ethereum/consensus/istanbul/core" 28 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/p2p/enode" 31 "github.com/ethereum/go-ethereum/rpc" 32 ) 33 34 // API is a user facing RPC API to dump Istanbul state 35 type API struct { 36 chain consensus.ChainReader 37 istanbul *Backend 38 } 39 40 // getHeaderByNumber retrieves the header requested block or current if unspecified. 41 func (api *API) getParentHeaderByNumber(number *rpc.BlockNumber) (*types.Header, error) { 42 var parent uint64 43 if number == nil || *number == rpc.LatestBlockNumber || *number == rpc.PendingBlockNumber { 44 head := api.chain.CurrentHeader() 45 if head == nil { 46 return nil, errUnknownBlock 47 } 48 if number == nil || *number == rpc.LatestBlockNumber { 49 parent = head.Number.Uint64() - 1 50 } else { 51 parent = head.Number.Uint64() 52 } 53 } else if *number == rpc.EarliestBlockNumber { 54 return nil, errUnknownBlock 55 } else { 56 parent = uint64(*number - 1) 57 } 58 59 header := api.chain.GetHeaderByNumber(parent) 60 if header == nil { 61 return nil, errUnknownBlock 62 } 63 return header, nil 64 } 65 66 // GetSnapshot retrieves the state snapshot at a given block. 67 func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { 68 // Retrieve the requested block number (or current if none requested) 69 var header *types.Header 70 if number == nil || *number == rpc.LatestBlockNumber { 71 header = api.chain.CurrentHeader() 72 } else { 73 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 74 } 75 // Ensure we have an actually valid block and return its snapshot 76 if header == nil { 77 return nil, errUnknownBlock 78 } 79 return api.istanbul.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 80 } 81 82 // GetValidators retrieves the list validators that must sign a given block. 83 func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) { 84 header, err := api.getParentHeaderByNumber(number) 85 if err != nil { 86 return nil, err 87 } 88 validators := api.istanbul.GetValidators(header.Number, header.Hash()) 89 return istanbul.MapValidatorsToAddresses(validators), nil 90 } 91 92 // GetProposer retrieves the proposer for a given block number (i.e. sequence) and round. 93 func (api *API) GetProposer(sequence *rpc.BlockNumber, round *uint64) (common.Address, error) { 94 header, err := api.getParentHeaderByNumber(sequence) 95 if err != nil { 96 return common.Address{}, err 97 } 98 99 valSet := api.istanbul.getOrderedValidators(header.Number.Uint64(), header.Hash()) 100 if valSet == nil { 101 return common.Address{}, err 102 } 103 previousProposer, err := api.istanbul.Author(header) 104 if err != nil { 105 return common.Address{}, err 106 } 107 if round == nil { 108 round = new(uint64) 109 } 110 proposer := validator.GetProposerSelector(api.istanbul.config.ProposerPolicy)(valSet, previousProposer, *round) 111 return proposer.Address(), nil 112 } 113 114 // AddProxy peers with a remote node that acts as a proxy, even if slots are full 115 func (api *API) AddProxy(url, externalUrl string) (bool, error) { 116 if !api.istanbul.config.Proxied { 117 api.istanbul.logger.Error("Add proxy node failed: this node is not configured to be proxied") 118 return false, errors.New("Can't add proxy for node that is not configured to be proxied") 119 } 120 121 node, err := enode.ParseV4(url) 122 if err != nil { 123 return false, fmt.Errorf("invalid enode: %v", err) 124 } 125 126 externalNode, err := enode.ParseV4(externalUrl) 127 if err != nil { 128 return false, fmt.Errorf("invalid external enode: %v", err) 129 } 130 131 err = api.istanbul.addProxy(node, externalNode) 132 return true, err 133 } 134 135 // RemoveProxy removes a node from acting as a proxy 136 func (api *API) RemoveProxy(url string) (bool, error) { 137 // Try to remove the url as a proxy and return 138 node, err := enode.ParseV4(url) 139 if err != nil { 140 return false, fmt.Errorf("invalid enode: %v", err) 141 } 142 api.istanbul.removeProxy(node) 143 return true, nil 144 } 145 146 // Retrieve the Validator Enode Table 147 func (api *API) GetValEnodeTable() (map[string]*vet.ValEnodeEntryInfo, error) { 148 return api.istanbul.valEnodeTable.ValEnodeTableInfo() 149 } 150 151 // GetCurrentRoundState retrieves the current IBFT RoundState 152 func (api *API) GetCurrentRoundState() (*core.RoundStateSummary, error) { 153 if !api.istanbul.coreStarted { 154 return nil, istanbul.ErrStoppedEngine 155 } 156 return api.istanbul.core.CurrentRoundState().Summary(), nil 157 } 158 159 // GetCurrentRoundState retrieves the current IBFT RoundState 160 func (api *API) ForceRoundChange() (bool, error) { 161 if !api.istanbul.coreStarted { 162 return false, istanbul.ErrStoppedEngine 163 } 164 api.istanbul.core.ForceRoundChange() 165 return true, nil 166 } 167 168 // TODO(kevjue) - implement this 169 // ProxyInfo retrieves all the information we know about each individual proxy node 170 /* func (api *PublicAdminAPI) ProxyInfo() ([]*p2p.PeerInfo, error) { 171 server := api.node.Server() 172 if server == nil { 173 return nil, ErrNodeStopped 174 } 175 return server.ProxyInfo(), nil 176 } */