github.com/Night-mk/quorum@v21.1.0+incompatible/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  	"errors"
    21  	"fmt"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/consensus"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/rpc"
    27  )
    28  
    29  // API is a user facing RPC API to allow controlling the signer and voting
    30  // mechanisms of the proof-of-authority scheme.
    31  type API struct {
    32  	chain  consensus.ChainReader
    33  	clique *Clique
    34  }
    35  
    36  // GetSnapshot retrieves the state snapshot at a given block.
    37  func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
    38  	// Retrieve the requested block number (or current if none requested)
    39  	var header *types.Header
    40  	if number == nil || *number == rpc.LatestBlockNumber {
    41  		header = api.chain.CurrentHeader()
    42  	} else {
    43  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    44  	}
    45  	// Ensure we have an actually valid block and return its snapshot
    46  	if header == nil {
    47  		return nil, errUnknownBlock
    48  	}
    49  	return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    50  }
    51  
    52  // GetSnapshotAtHash retrieves the state snapshot at a given block.
    53  func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
    54  	header := api.chain.GetHeaderByHash(hash)
    55  	if header == nil {
    56  		return nil, errUnknownBlock
    57  	}
    58  	return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    59  }
    60  
    61  // GetSigners retrieves the list of authorized signers at the specified block.
    62  func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
    63  	// Retrieve the requested block number (or current if none requested)
    64  	var header *types.Header
    65  	if number == nil || *number == rpc.LatestBlockNumber {
    66  		header = api.chain.CurrentHeader()
    67  	} else {
    68  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    69  	}
    70  	// Ensure we have an actually valid block and return the signers from its snapshot
    71  	if header == nil {
    72  		return nil, errUnknownBlock
    73  	}
    74  	snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return snap.signers(), nil
    79  }
    80  
    81  // GetSignersAtHash retrieves the list of authorized signers at the specified block.
    82  func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
    83  	header := api.chain.GetHeaderByHash(hash)
    84  	if header == nil {
    85  		return nil, errUnknownBlock
    86  	}
    87  	snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	return snap.signers(), nil
    92  }
    93  
    94  // Proposals returns the current proposals the node tries to uphold and vote on.
    95  func (api *API) Proposals() map[common.Address]bool {
    96  	api.clique.lock.RLock()
    97  	defer api.clique.lock.RUnlock()
    98  
    99  	proposals := make(map[common.Address]bool)
   100  	for address, auth := range api.clique.proposals {
   101  		proposals[address] = auth
   102  	}
   103  	return proposals
   104  }
   105  
   106  // Propose injects a new authorization proposal that the signer will attempt to
   107  // push through.
   108  func (api *API) Propose(address common.Address, auth bool) {
   109  	api.clique.lock.Lock()
   110  	defer api.clique.lock.Unlock()
   111  
   112  	api.clique.proposals[address] = auth
   113  }
   114  
   115  // Discard drops a currently running proposal, stopping the signer from casting
   116  // further votes (either for or against).
   117  func (api *API) Discard(address common.Address) {
   118  	api.clique.lock.Lock()
   119  	defer api.clique.lock.Unlock()
   120  
   121  	delete(api.clique.proposals, address)
   122  }
   123  
   124  type Status struct {
   125  	InturnPercent float64                `json:"inturnPercent"`
   126  	SigningStatus map[common.Address]int `json:"sealerActivity"`
   127  	NumBlocks     uint64                 `json:"numBlocks"`
   128  }
   129  
   130  // Status returns the status of the last N blocks,
   131  // - the number of active signers,
   132  // - the number of signers,
   133  // - the percentage of in-turn blocks
   134  func (api *API) Status(startBlockNum *rpc.BlockNumber, endBlockNum *rpc.BlockNumber) (*Status, error) {
   135  	var (
   136  		numBlocks uint64
   137  		header    *types.Header
   138  		diff      = uint64(0)
   139  		optimals  = 0
   140  
   141  		start uint64
   142  		end   uint64
   143  	)
   144  	if startBlockNum != nil && endBlockNum == nil {
   145  		return nil, errors.New("pass the end block number")
   146  	}
   147  
   148  	if startBlockNum == nil && endBlockNum != nil {
   149  		return nil, errors.New("pass the start block number")
   150  	}
   151  
   152  	if startBlockNum == nil && endBlockNum == nil {
   153  		numBlocks = uint64(64)
   154  		header = api.chain.CurrentHeader()
   155  		end = header.Number.Uint64()
   156  		start = end - numBlocks
   157  	} else {
   158  		end = uint64(*endBlockNum)
   159  		start = uint64(*startBlockNum)
   160  		if start > end {
   161  			return nil, errors.New("start block number should be less than end block number")
   162  		}
   163  
   164  		if end > api.chain.CurrentHeader().Number.Uint64() {
   165  			return nil, errors.New("end block number should be less than or equal to current block height")
   166  		}
   167  
   168  		numBlocks = end - start
   169  		header = api.chain.GetHeaderByNumber(end)
   170  	}
   171  
   172  	snap, err := api.clique.snapshot(api.chain, end, header.Hash(), nil)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	var (
   177  		signers = snap.signers()
   178  	)
   179  	if numBlocks > end {
   180  		start = 1
   181  		numBlocks = end - start
   182  	}
   183  	signStatus := make(map[common.Address]int)
   184  	for _, s := range signers {
   185  		signStatus[s] = 0
   186  	}
   187  	for n := start; n < end; n++ {
   188  		h := api.chain.GetHeaderByNumber(n)
   189  		if h == nil {
   190  			return nil, fmt.Errorf("missing block %d", n)
   191  		}
   192  		if h.Difficulty.Cmp(diffInTurn) == 0 {
   193  			optimals++
   194  		}
   195  		diff += h.Difficulty.Uint64()
   196  		sealer, err := api.clique.Author(h)
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		signStatus[sealer]++
   201  	}
   202  	return &Status{
   203  		InturnPercent: float64((100 * optimals)) / float64(numBlocks),
   204  		SigningStatus: signStatus,
   205  		NumBlocks:     numBlocks,
   206  	}, nil
   207  }