github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/cmd/bc/bc.go (about) 1 // Copyright (c) 2022 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package bc 7 8 import ( 9 "context" 10 "strconv" 11 12 "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" 13 "github.com/iotexproject/iotex-proto/golang/iotexapi" 14 "github.com/iotexproject/iotex-proto/golang/iotextypes" 15 "github.com/spf13/cobra" 16 "google.golang.org/grpc/codes" 17 "google.golang.org/grpc/status" 18 "google.golang.org/protobuf/proto" 19 20 "github.com/iotexproject/iotex-core/ioctl/config" 21 "github.com/iotexproject/iotex-core/ioctl/output" 22 "github.com/iotexproject/iotex-core/ioctl/util" 23 ) 24 25 // Multi-language support 26 var ( 27 _bcCmdShorts = map[config.Language]string{ 28 config.English: "Deal with block chain of IoTeX blockchain", 29 config.Chinese: "处理IoTeX区块链上的区块", 30 } 31 _flagEndpointUsages = map[config.Language]string{ 32 config.English: "set endpoint for once", 33 config.Chinese: "一次设置端点", 34 } 35 _flagInsecureUsages = map[config.Language]string{ 36 config.English: "insecure connection for once", 37 config.Chinese: "一次不安全的连接", 38 } 39 ) 40 41 // BCCmd represents the bc(block chain) command 42 var BCCmd = &cobra.Command{ 43 Use: "bc", 44 Short: config.TranslateInLang(_bcCmdShorts, config.UILanguage), 45 } 46 47 func init() { 48 BCCmd.AddCommand(_bcBlockCmd) 49 BCCmd.AddCommand(_bcInfoCmd) 50 BCCmd.AddCommand(_bcBucketListCmd) 51 BCCmd.AddCommand(_bcBucketCmd) 52 BCCmd.AddCommand(_bcDelegateCmd) 53 BCCmd.AddCommand(_bcVersionCmd) 54 BCCmd.PersistentFlags().StringVar(&config.ReadConfig.Endpoint, "endpoint", 55 config.ReadConfig.Endpoint, config.TranslateInLang(_flagEndpointUsages, config.UILanguage)) 56 BCCmd.PersistentFlags().BoolVar(&config.Insecure, "insecure", config.Insecure, 57 config.TranslateInLang(_flagInsecureUsages, config.UILanguage)) 58 } 59 60 // GetChainMeta gets block chain metadata 61 func GetChainMeta() (*iotextypes.ChainMeta, error) { 62 conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) 63 if err != nil { 64 return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err) 65 } 66 defer conn.Close() 67 cli := iotexapi.NewAPIServiceClient(conn) 68 request := iotexapi.GetChainMetaRequest{} 69 ctx := context.Background() 70 71 jwtMD, err := util.JwtAuth() 72 if err == nil { 73 ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) 74 } 75 76 response, err := cli.GetChainMeta(ctx, &request) 77 if err != nil { 78 sta, ok := status.FromError(err) 79 if ok { 80 return nil, output.NewError(output.APIError, sta.Message(), nil) 81 } 82 return nil, output.NewError(output.NetworkError, "failed to invoke GetChainMeta api", err) 83 } 84 return response.ChainMeta, nil 85 } 86 87 // GetEpochMeta gets blockchain epoch meta 88 func GetEpochMeta(epochNum uint64) (*iotexapi.GetEpochMetaResponse, error) { 89 conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) 90 if err != nil { 91 return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err) 92 } 93 defer conn.Close() 94 cli := iotexapi.NewAPIServiceClient(conn) 95 request := &iotexapi.GetEpochMetaRequest{EpochNumber: epochNum} 96 ctx := context.Background() 97 98 jwtMD, err := util.JwtAuth() 99 if err == nil { 100 ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) 101 } 102 103 response, err := cli.GetEpochMeta(ctx, request) 104 if err != nil { 105 sta, ok := status.FromError(err) 106 if ok { 107 return nil, output.NewError(output.APIError, sta.Message(), nil) 108 } 109 return nil, output.NewError(output.NetworkError, "failed to invoke GetEpochMeta api", err) 110 } 111 return response, nil 112 } 113 114 // GetProbationList gets probation list 115 func GetProbationList(epochNum uint64, epochStartHeight uint64) (*iotexapi.ReadStateResponse, error) { 116 conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) 117 if err != nil { 118 return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err) 119 } 120 defer conn.Close() 121 cli := iotexapi.NewAPIServiceClient(conn) 122 123 request := &iotexapi.ReadStateRequest{ 124 ProtocolID: []byte("poll"), 125 MethodName: []byte("ProbationListByEpoch"), 126 Arguments: [][]byte{[]byte(strconv.FormatUint(epochNum, 10))}, 127 Height: strconv.FormatUint(epochStartHeight, 10), 128 } 129 ctx := context.Background() 130 131 jwtMD, err := util.JwtAuth() 132 if err == nil { 133 ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) 134 } 135 136 response, err := cli.ReadState(ctx, request) 137 if err != nil { 138 sta, ok := status.FromError(err) 139 if ok && sta.Code() == codes.NotFound { 140 return nil, nil 141 } else if ok { 142 return nil, output.NewError(output.APIError, sta.Message(), nil) 143 } 144 return nil, output.NewError(output.NetworkError, "failed to invoke ReadState api", err) 145 } 146 return response, nil 147 } 148 149 // GetBucketList get bucket list 150 func GetBucketList( 151 methodName iotexapi.ReadStakingDataMethod_Name, 152 readStakingDataRequest *iotexapi.ReadStakingDataRequest, 153 ) (*iotextypes.VoteBucketList, error) { 154 conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) 155 if err != nil { 156 return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err) 157 } 158 defer conn.Close() 159 cli := iotexapi.NewAPIServiceClient(conn) 160 method := &iotexapi.ReadStakingDataMethod{Method: methodName} 161 methodData, err := proto.Marshal(method) 162 if err != nil { 163 return nil, output.NewError(output.SerializationError, "failed to marshal read staking data method", err) 164 } 165 requestData, err := proto.Marshal(readStakingDataRequest) 166 if err != nil { 167 return nil, output.NewError(output.SerializationError, "failed to marshal read staking data request", err) 168 } 169 170 request := &iotexapi.ReadStateRequest{ 171 ProtocolID: []byte("staking"), 172 MethodName: methodData, 173 Arguments: [][]byte{requestData}, 174 } 175 176 ctx := context.Background() 177 jwtMD, err := util.JwtAuth() 178 if err == nil { 179 ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) 180 } 181 182 response, err := cli.ReadState(ctx, request) 183 if err != nil { 184 sta, ok := status.FromError(err) 185 if ok { 186 return nil, output.NewError(output.APIError, sta.Message(), nil) 187 } 188 return nil, output.NewError(output.NetworkError, "failed to invoke ReadState api", err) 189 } 190 bucketlist := iotextypes.VoteBucketList{} 191 if err := proto.Unmarshal(response.Data, &bucketlist); err != nil { 192 return nil, output.NewError(output.SerializationError, "failed to unmarshal response", err) 193 } 194 return &bucketlist, nil 195 }