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  } */