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 }