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  }