github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/backend/api.go (about)

     1  package backend
     2  
     3  import (
     4  	"math/big"
     5  	"sort"
     6  
     7  	"github.com/quickchainproject/quickchain/common"
     8  	"github.com/quickchainproject/quickchain/consensus"
     9  	"github.com/quickchainproject/quickchain/core/types"
    10  	"github.com/quickchainproject/quickchain/rpc"
    11  )
    12  
    13  // API is a user facing RPC API to dump BFT state
    14  type API struct {
    15  	chain consensus.ChainReader
    16  	bft   *backend
    17  }
    18  
    19  // GetSnapshot retrieves the state snapshot at a given block.
    20  func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
    21  	// Retrieve the requested block number (or current if none requested)
    22  	var header *types.Header
    23  	if number == nil || *number == rpc.LatestBlockNumber {
    24  		header = api.chain.CurrentHeader()
    25  	} else {
    26  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    27  	}
    28  	// Ensure we have an actually valid block and return its snapshot
    29  	if header == nil {
    30  		return nil, errUnknownBlock
    31  	}
    32  	return api.bft.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    33  }
    34  
    35  // GetSnapshotAtHash retrieves the state snapshot at a given block.
    36  func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
    37  	header := api.chain.GetHeaderByHash(hash)
    38  	if header == nil {
    39  		return nil, errUnknownBlock
    40  	}
    41  	return api.bft.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    42  }
    43  
    44  // GetValidators retrieves the list of authorized validators at the specified block.
    45  func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
    46  	// Retrieve the requested block number (or current if none requested)
    47  	var header *types.Header
    48  	if number == nil || *number == rpc.LatestBlockNumber {
    49  		header = api.chain.CurrentHeader()
    50  	} else {
    51  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    52  	}
    53  	// Ensure we have an actually valid block and return the validators from its snapshot
    54  	if header == nil {
    55  		return nil, errUnknownBlock
    56  	}
    57  	snap, err := api.bft.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	return snap.validators(), nil
    62  }
    63  
    64  // GetValidatorsAtHash retrieves the state snapshot at a given block.
    65  func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error) {
    66  	header := api.chain.GetHeaderByHash(hash)
    67  	if header == nil {
    68  		return nil, errUnknownBlock
    69  	}
    70  	snap, err := api.bft.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	return snap.validators(), nil
    75  }
    76  
    77  // Candidates returns the current candidates the node tries to uphold and vote on.
    78  func (api *API) Candidates() map[common.Address]bool {
    79  	api.bft.candidatesLock.RLock()
    80  	defer api.bft.candidatesLock.RUnlock()
    81  
    82  	proposals := make(map[common.Address]bool)
    83  	for address, auth := range api.bft.candidates {
    84  		proposals[address] = auth
    85  	}
    86  	return proposals
    87  }
    88  
    89  // Propose injects a new authorization candidate that the validator will attempt to
    90  // push through.
    91  func (api *API) Propose(address common.Address, auth bool) {
    92  	api.bft.candidatesLock.Lock()
    93  	defer api.bft.candidatesLock.Unlock()
    94  
    95  	api.bft.candidates[address] = auth
    96  }
    97  
    98  // Discard drops a currently running candidate, stopping the validator from casting
    99  // further votes (either for or against).
   100  func (api *API) Discard(address common.Address) {
   101  	api.bft.candidatesLock.Lock()
   102  	defer api.bft.candidatesLock.Unlock()
   103  
   104  	delete(api.bft.candidates, address)
   105  }
   106  
   107  //copy from dpos.api
   108  // GetDposValidators retrieves the list of the validators at specified block
   109  func (api *API) GetDposValidators(number *rpc.BlockNumber) ([]common.Address, error) {
   110  	var header *types.Header
   111  	if number == nil || *number == rpc.LatestBlockNumber {
   112  		header = api.chain.CurrentHeader()
   113  	} else {
   114  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   115  	}
   116  	if header == nil {
   117  		return nil, errUnknownBlock
   118  	}
   119  
   120  	dposContext, err := types.NewDposContextFromProto(api.bft.db, header.DposContext)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	validators, err := dposContext.GetValidators()
   125   	if err != nil {
   126  		return nil, err
   127  	}
   128  	return validators, nil
   129  }
   130  
   131  // GetCandidates retrieves maxcnt result of the list of the candidates at specified block
   132  func (api *API) GetDposCandidates(maxcnt, number *rpc.BlockNumber) ([]types.CandidateContext, error) {
   133  	var header *types.Header
   134  	if number == nil || *number == rpc.LatestBlockNumber {
   135  		header = api.chain.CurrentHeader()
   136  	} else {
   137  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   138  	}
   139  	if header == nil {
   140  		return nil, errUnknownBlock
   141  	}
   142  
   143  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	candidates, err := dposContext.GetCandidates()
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	sort.Sort(types.SortCandidateContexts(candidates))
   152  	if maxcnt == nil {
   153  		return candidates, nil
   154  	}
   155  	index := int(maxcnt.Int64())
   156  	if int(maxcnt.Int64()) > len(candidates) {
   157  		index = len(candidates)
   158  	}
   159  	return candidates[:index], nil
   160  }
   161  
   162  // GetDposCandidates retrieves the list of the candidates at specified block
   163  func (api *API) GetDposCandidate(addr common.Address, number *rpc.BlockNumber) (types.CandidateContext, error) {
   164  	var header *types.Header
   165  	var cc types.CandidateContext
   166  	if number == nil || *number == rpc.LatestBlockNumber {
   167  		header = api.chain.CurrentHeader()
   168  	} else {
   169  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   170  	}
   171  	if header == nil {
   172  		return cc, errUnknownBlock
   173  	}
   174  
   175  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   176  	if err != nil {
   177  		return cc, err
   178  	}
   179  	candidatecontext, err := dposContext.GetCandidateContext(addr)
   180  	if err != nil {
   181  		return cc, err
   182  	}
   183  	return candidatecontext, nil
   184  }
   185  
   186  func (api *API) GetSortableAddresses(number *rpc.BlockNumber) (types.SortableAddresses, error) {
   187  	var header *types.Header
   188  	if number == nil || *number == rpc.LatestBlockNumber {
   189  		header = api.chain.CurrentHeader()
   190  	} else {
   191  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   192  	}
   193  	if header == nil {
   194  		return nil, errUnknownBlock
   195  	}
   196  
   197  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	sa, err := dposContext.GetSortableAddresses()
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	return sa, nil
   206  }
   207  
   208  // GetMintCnt retrieves the mint cnt of the validator at specified block
   209  func (api *API) GetMintCnt(addr common.Address, number *rpc.BlockNumber) (int64, error) {
   210  	var header *types.Header
   211  	cnt := int64(0)
   212  	if number == nil || *number == rpc.LatestBlockNumber {
   213  		header = api.chain.CurrentHeader()
   214  	} else {
   215  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   216  	}
   217  	if header == nil {
   218  		return cnt, errUnknownBlock
   219  	}
   220  
   221  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   222  	if err != nil {
   223  		return cnt, err
   224  	}
   225  	cnt = dposContext.GetMintCnt(addr)
   226  	return cnt, nil
   227  }
   228  
   229  // GetMintCnt retrieves maxcnt result of the mint cnt of all validators at specified block
   230  func (api *API) GetMintCnts(maxcnt, number *rpc.BlockNumber) ([]types.MintCntAddress, error) {
   231  	var header *types.Header
   232  	ma := make([]types.MintCntAddress, 0)
   233  	if number == nil || *number == rpc.LatestBlockNumber {
   234  		header = api.chain.CurrentHeader()
   235  	} else {
   236  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   237  	}
   238  	if header == nil {
   239  		return ma, errUnknownBlock
   240  	}
   241  
   242  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   243  	if err != nil {
   244  		return ma, err
   245  	}
   246  	ma, err = dposContext.GetMintCnts()
   247  	sort.Sort(types.SortableMintCntAddresses(ma))
   248  	if maxcnt == nil {
   249  		return ma, err
   250  	}
   251  	index := int(maxcnt.Int64())
   252  	if int(maxcnt.Int64()) > len(ma) {
   253  		index = len(ma)
   254  	}
   255  	return ma[:index], nil
   256  }
   257  
   258  // GetVote retrieves delegator to candidate at specified block
   259  func (api *API) GetVote(addr common.Address, number *rpc.BlockNumber) (map[string]types.VoteContext, error) {
   260  	var header *types.Header
   261  	vote := make(map[string]types.VoteContext)
   262  	if number == nil || *number == rpc.LatestBlockNumber {
   263  		header = api.chain.CurrentHeader()
   264  	} else {
   265  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   266  	}
   267  	if header == nil {
   268  		return vote, errUnknownBlock
   269  	}
   270  
   271  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   272  	if err != nil {
   273  		return vote, err
   274  	}
   275  	return dposContext.GetVote(addr)
   276  }
   277  
   278  // GetVotes retrieves all delegator to their candidate at specified block
   279  func (api *API) GetVotes(number *rpc.BlockNumber) (map[string]types.VoteContext, error) {
   280  	var header *types.Header
   281  	votes := make(map[string]types.VoteContext)
   282  
   283  	if number == nil || *number == rpc.LatestBlockNumber {
   284  		header = api.chain.CurrentHeader()
   285  	} else {
   286  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   287  	}
   288  	if header == nil {
   289  		return votes, errUnknownBlock
   290  	}
   291  
   292  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   293  	if err != nil {
   294  		return votes, err
   295  	}
   296  	return dposContext.GetVotes()
   297  }
   298  
   299  // GetCFDs retrieves all candidates from their delegates at specified block
   300  func (api *API) GetCFDs(number *rpc.BlockNumber) (map[string]map[string]*big.Int, error) {
   301  	var header *types.Header
   302  	cfd := make(map[string]map[string]*big.Int)
   303  
   304  	if number == nil || *number == rpc.LatestBlockNumber {
   305  		header = api.chain.CurrentHeader()
   306  	} else {
   307  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   308  	}
   309  	if header == nil {
   310  		return cfd, errUnknownBlock
   311  	}
   312  
   313  	dposContext, err := types.NewDposContextFromProto(api.bft.DB(), header.DposContext)
   314  	if err != nil {
   315  		return cfd, err
   316  	}
   317  	return dposContext.GetCFDs()
   318  }