github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/consensus/ipbft/api.go (about)

     1  package ipbft
     2  
     3  import (
     4  	"errors"
     5  	"github.com/intfoundation/go-crypto"
     6  	"github.com/intfoundation/intchain/common"
     7  	"github.com/intfoundation/intchain/common/hexutil"
     8  	"github.com/intfoundation/intchain/consensus"
     9  	"github.com/intfoundation/intchain/consensus/ipbft/epoch"
    10  	tdmTypes "github.com/intfoundation/intchain/consensus/ipbft/types"
    11  	intCrypto "github.com/intfoundation/intchain/crypto"
    12  	"math/big"
    13  )
    14  
    15  // API is a user facing RPC API of Tendermint
    16  type API struct {
    17  	chain      consensus.ChainReader
    18  	tendermint *backend
    19  }
    20  
    21  // GetCurrentEpochNumber retrieves the current epoch number.
    22  func (api *API) GetCurrentEpochNumber() (hexutil.Uint64, error) {
    23  	return hexutil.Uint64(api.tendermint.core.consensusState.Epoch.Number), nil
    24  }
    25  
    26  // GetEpoch retrieves the Epoch Detail by Number
    27  func (api *API) GetEpoch(num hexutil.Uint64) (*tdmTypes.EpochApi, error) {
    28  
    29  	number := uint64(num)
    30  	var resultEpoch *epoch.Epoch
    31  	curEpoch := api.tendermint.core.consensusState.Epoch
    32  	if number < 0 || number > curEpoch.Number {
    33  		return nil, errors.New("epoch number out of range")
    34  	}
    35  
    36  	if number == curEpoch.Number {
    37  		resultEpoch = curEpoch
    38  	} else {
    39  		resultEpoch = epoch.LoadOneEpoch(curEpoch.GetDB(), number, nil)
    40  	}
    41  
    42  	validators := make([]*tdmTypes.EpochValidator, len(resultEpoch.Validators.Validators))
    43  	for i, val := range resultEpoch.Validators.Validators {
    44  		validators[i] = &tdmTypes.EpochValidator{
    45  			Address:        common.BytesToAddress(val.Address),
    46  			PubKey:         val.PubKey.KeyString(),
    47  			Amount:         (*hexutil.Big)(val.VotingPower),
    48  			RemainingEpoch: hexutil.Uint64(val.RemainingEpoch),
    49  		}
    50  	}
    51  
    52  	return &tdmTypes.EpochApi{
    53  		Number:         hexutil.Uint64(resultEpoch.Number),
    54  		RewardPerBlock: (*hexutil.Big)(resultEpoch.RewardPerBlock),
    55  		StartBlock:     hexutil.Uint64(resultEpoch.StartBlock),
    56  		EndBlock:       hexutil.Uint64(resultEpoch.EndBlock),
    57  		StartTime:      resultEpoch.StartTime,
    58  		EndTime:        resultEpoch.EndTime,
    59  		Validators:     validators,
    60  	}, nil
    61  }
    62  
    63  // GetEpochVote
    64  func (api *API) GetNextEpochVote() (*tdmTypes.EpochVotesApi, error) {
    65  
    66  	ep := api.tendermint.core.consensusState.Epoch
    67  	if ep.GetNextEpoch() != nil {
    68  
    69  		var votes []*epoch.EpochValidatorVote
    70  		if ep.GetNextEpoch().GetEpochValidatorVoteSet() != nil {
    71  			votes = ep.GetNextEpoch().GetEpochValidatorVoteSet().Votes
    72  		}
    73  		votesApi := make([]*tdmTypes.EpochValidatorVoteApi, 0, len(votes))
    74  		for _, v := range votes {
    75  			var pkstring string
    76  			if v.PubKey != nil {
    77  				pkstring = v.PubKey.KeyString()
    78  			}
    79  
    80  			votesApi = append(votesApi, &tdmTypes.EpochValidatorVoteApi{
    81  				EpochValidator: tdmTypes.EpochValidator{
    82  					Address: v.Address,
    83  					PubKey:  pkstring,
    84  					Amount:  (*hexutil.Big)(v.Amount),
    85  				},
    86  				Salt:     v.Salt,
    87  				VoteHash: v.VoteHash,
    88  				TxHash:   v.TxHash,
    89  			})
    90  		}
    91  
    92  		return &tdmTypes.EpochVotesApi{
    93  			EpochNumber: hexutil.Uint64(ep.GetNextEpoch().Number),
    94  			StartBlock:  hexutil.Uint64(ep.GetNextEpoch().StartBlock),
    95  			EndBlock:    hexutil.Uint64(ep.GetNextEpoch().EndBlock),
    96  			Votes:       votesApi,
    97  		}, nil
    98  	}
    99  	return nil, errors.New("next epoch has not been proposed")
   100  }
   101  
   102  func (api *API) GetNextEpochValidators() ([]*tdmTypes.EpochValidator, error) {
   103  
   104  	//height := api.chain.CurrentBlock().NumberU64()
   105  
   106  	ep := api.tendermint.core.consensusState.Epoch
   107  	nextEp := ep.GetNextEpoch()
   108  	if nextEp == nil {
   109  		return nil, errors.New("voting for next epoch has not started yet")
   110  	} else {
   111  		state, err := api.chain.State()
   112  		if err != nil {
   113  			return nil, err
   114  		}
   115  
   116  		nextValidators := ep.Validators.Copy()
   117  
   118  		err = epoch.DryRunUpdateEpochValidatorSet(state, nextValidators, nextEp.GetEpochValidatorVoteSet())
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  
   123  		validators := make([]*tdmTypes.EpochValidator, 0, len(nextValidators.Validators))
   124  		for _, val := range nextValidators.Validators {
   125  			var pkstring string
   126  			if val.PubKey != nil {
   127  				pkstring = val.PubKey.KeyString()
   128  			}
   129  			validators = append(validators, &tdmTypes.EpochValidator{
   130  				Address:        common.BytesToAddress(val.Address),
   131  				PubKey:         pkstring,
   132  				Amount:         (*hexutil.Big)(val.VotingPower),
   133  				RemainingEpoch: hexutil.Uint64(val.RemainingEpoch),
   134  			})
   135  		}
   136  
   137  		return validators, nil
   138  	}
   139  }
   140  
   141  // decode extra data
   142  func (api *API) DecodeExtraData(extra string) (extraApi *tdmTypes.TendermintExtraApi, err error) {
   143  	tdmExtra, err := tdmTypes.DecodeExtraData(extra)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	extraApi = &tdmTypes.TendermintExtraApi{
   148  		ChainID:         tdmExtra.ChainID,
   149  		Height:          hexutil.Uint64(tdmExtra.Height),
   150  		Time:            tdmExtra.Time,
   151  		NeedToSave:      tdmExtra.NeedToSave,
   152  		NeedToBroadcast: tdmExtra.NeedToBroadcast,
   153  		EpochNumber:     hexutil.Uint64(tdmExtra.EpochNumber),
   154  		SeenCommitHash:  hexutil.Encode(tdmExtra.SeenCommitHash),
   155  		ValidatorsHash:  hexutil.Encode(tdmExtra.ValidatorsHash),
   156  		SeenCommit: &tdmTypes.CommitApi{
   157  			BlockID: tdmTypes.BlockIDApi{
   158  				Hash: hexutil.Encode(tdmExtra.SeenCommit.BlockID.Hash),
   159  				PartsHeader: tdmTypes.PartSetHeaderApi{
   160  					Total: hexutil.Uint64(tdmExtra.SeenCommit.BlockID.PartsHeader.Total),
   161  					Hash:  hexutil.Encode(tdmExtra.SeenCommit.BlockID.PartsHeader.Hash),
   162  				},
   163  			},
   164  			Height:   hexutil.Uint64(tdmExtra.SeenCommit.Height),
   165  			Round:    tdmExtra.SeenCommit.Round,
   166  			SignAggr: tdmExtra.SeenCommit.SignAggr,
   167  			BitArray: tdmExtra.SeenCommit.BitArray,
   168  		},
   169  		EpochBytes: tdmExtra.EpochBytes,
   170  	}
   171  	return extraApi, nil
   172  }
   173  
   174  // get consensus publickey of the block
   175  func (api *API) GetConsensusPublicKey(extra string) ([]string, error) {
   176  	tdmExtra, err := tdmTypes.DecodeExtraData(extra)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	number := uint64(tdmExtra.EpochNumber)
   182  	var resultEpoch *epoch.Epoch
   183  	curEpoch := api.tendermint.core.consensusState.Epoch
   184  	if number < 0 || number > curEpoch.Number {
   185  		return nil, errors.New("epoch number out of range")
   186  	}
   187  
   188  	if number == curEpoch.Number {
   189  		resultEpoch = curEpoch
   190  	} else {
   191  		resultEpoch = epoch.LoadOneEpoch(curEpoch.GetDB(), number, nil)
   192  	}
   193  
   194  	validatorSet := resultEpoch.Validators
   195  
   196  	aggr, err := validatorSet.GetAggrPubKeyAndAddress(tdmExtra.SeenCommit.BitArray)
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  
   201  	var pubkeys []string
   202  	if len(aggr.PublicKeys) > 0 {
   203  		for _, v := range aggr.PublicKeys {
   204  			if v != "" {
   205  				pubkeys = append(pubkeys, v)
   206  			}
   207  		}
   208  	}
   209  
   210  	return pubkeys, nil
   211  }
   212  
   213  func (api *API) GetVoteHash(from common.Address, pubkey crypto.BLSPubKey, amount *hexutil.Big, salt string) common.Hash {
   214  	byteData := [][]byte{
   215  		from.Bytes(),
   216  		pubkey.Bytes(),
   217  		(*big.Int)(amount).Bytes(),
   218  		[]byte(salt),
   219  	}
   220  	return intCrypto.Keccak256Hash(ConcatCopyPreAllocate(byteData))
   221  }