github.com/ConsenSys/Quorum@v20.10.0+incompatible/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  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/consensus"
    22  	"github.com/ethereum/go-ethereum/core/types"
    23  	"github.com/ethereum/go-ethereum/rpc"
    24  )
    25  
    26  // API is a user facing RPC API to dump Istanbul state
    27  type API struct {
    28  	chain    consensus.ChainReader
    29  	istanbul *backend
    30  }
    31  
    32  // BlockSigners is contains who created and who signed a particular block, denoted by its number and hash
    33  type BlockSigners struct {
    34  	Number     uint64
    35  	Hash       common.Hash
    36  	Author     common.Address
    37  	Committers []common.Address
    38  }
    39  
    40  // NodeAddress returns the public address that is used to sign block headers in IBFT
    41  func (api *API) NodeAddress() common.Address {
    42  	return api.istanbul.Address()
    43  }
    44  
    45  // GetSignersFromBlock returns the signers and minter for a given block number, or the
    46  // latest block available if none is specified
    47  func (api *API) GetSignersFromBlock(number *rpc.BlockNumber) (*BlockSigners, error) {
    48  	// Retrieve the requested block number (or current if none requested)
    49  	var header *types.Header
    50  	if number == nil || *number == rpc.LatestBlockNumber {
    51  		header = api.chain.CurrentHeader()
    52  	} else {
    53  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    54  	}
    55  
    56  	if header == nil {
    57  		return nil, errUnknownBlock
    58  	}
    59  
    60  	return api.signers(header)
    61  }
    62  
    63  // GetSignersFromBlockByHash returns the signers and minter for a given block hash
    64  func (api *API) GetSignersFromBlockByHash(hash common.Hash) (*BlockSigners, error) {
    65  	header := api.chain.GetHeaderByHash(hash)
    66  	if header == nil {
    67  		return nil, errUnknownBlock
    68  	}
    69  
    70  	return api.signers(header)
    71  }
    72  
    73  func (api *API) signers(header *types.Header) (*BlockSigners, error) {
    74  	author, err := api.istanbul.Author(header)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	committers, err := api.istanbul.Signers(header)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	return &BlockSigners{
    85  		Number:     header.Number.Uint64(),
    86  		Hash:       header.Hash(),
    87  		Author:     author,
    88  		Committers: committers,
    89  	}, nil
    90  }
    91  
    92  // GetSnapshot retrieves the state snapshot at a given block.
    93  func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
    94  	// Retrieve the requested block number (or current if none requested)
    95  	var header *types.Header
    96  	if number == nil || *number == rpc.LatestBlockNumber {
    97  		header = api.chain.CurrentHeader()
    98  	} else {
    99  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   100  	}
   101  	// Ensure we have an actually valid block and return its snapshot
   102  	if header == nil {
   103  		return nil, errUnknownBlock
   104  	}
   105  	return api.istanbul.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   106  }
   107  
   108  // GetSnapshotAtHash retrieves the state snapshot at a given block.
   109  func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
   110  	header := api.chain.GetHeaderByHash(hash)
   111  	if header == nil {
   112  		return nil, errUnknownBlock
   113  	}
   114  	return api.istanbul.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   115  }
   116  
   117  // GetValidators retrieves the list of authorized validators at the specified block.
   118  func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
   119  	// Retrieve the requested block number (or current if none requested)
   120  	var header *types.Header
   121  	if number == nil || *number == rpc.LatestBlockNumber {
   122  		header = api.chain.CurrentHeader()
   123  	} else {
   124  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   125  	}
   126  	// Ensure we have an actually valid block and return the validators from its snapshot
   127  	if header == nil {
   128  		return nil, errUnknownBlock
   129  	}
   130  	snap, err := api.istanbul.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	return snap.validators(), nil
   135  }
   136  
   137  // GetValidatorsAtHash retrieves the state snapshot at a given block.
   138  func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error) {
   139  	header := api.chain.GetHeaderByHash(hash)
   140  	if header == nil {
   141  		return nil, errUnknownBlock
   142  	}
   143  	snap, err := api.istanbul.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	return snap.validators(), nil
   148  }
   149  
   150  // Candidates returns the current candidates the node tries to uphold and vote on.
   151  func (api *API) Candidates() map[common.Address]bool {
   152  	api.istanbul.candidatesLock.RLock()
   153  	defer api.istanbul.candidatesLock.RUnlock()
   154  
   155  	proposals := make(map[common.Address]bool)
   156  	for address, auth := range api.istanbul.candidates {
   157  		proposals[address] = auth
   158  	}
   159  	return proposals
   160  }
   161  
   162  // Propose injects a new authorization candidate that the validator will attempt to
   163  // push through.
   164  func (api *API) Propose(address common.Address, auth bool) {
   165  	api.istanbul.candidatesLock.Lock()
   166  	defer api.istanbul.candidatesLock.Unlock()
   167  
   168  	api.istanbul.candidates[address] = auth
   169  }
   170  
   171  // Discard drops a currently running candidate, stopping the validator from casting
   172  // further votes (either for or against).
   173  func (api *API) Discard(address common.Address) {
   174  	api.istanbul.candidatesLock.Lock()
   175  	defer api.istanbul.candidatesLock.Unlock()
   176  
   177  	delete(api.istanbul.candidates, address)
   178  }