github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/cmd/bc/bcbucketlist.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  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/iotexproject/iotex-proto/golang/iotexapi"
    14  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    15  	"github.com/spf13/cobra"
    16  
    17  	"github.com/iotexproject/iotex-core/ioctl/config"
    18  	"github.com/iotexproject/iotex-core/ioctl/output"
    19  	"github.com/iotexproject/iotex-core/ioctl/util"
    20  )
    21  
    22  const (
    23  	_bucketlistMethodByVoter     = "voter"
    24  	_bucketlistMethodByCandidate = "cand"
    25  )
    26  
    27  var (
    28  	_validMethods = []string{
    29  		_bucketlistMethodByVoter,
    30  		_bucketlistMethodByCandidate,
    31  	}
    32  )
    33  
    34  // Multi-language support
    35  var (
    36  	_bcBucketListCmdShorts = map[config.Language]string{
    37  		config.English: "Get bucket list with method and arg(s) on IoTeX blockchain",
    38  		config.Chinese: "根据方法和参数在IoTeX区块链上读取投票列表",
    39  	}
    40  	_bcBucketListCmdUses = map[config.Language]string{
    41  		config.English: "bucketlist <method> [arguments]",
    42  		config.Chinese: "bucketlist <方法> [参数]",
    43  	}
    44  	_bcBucketListCmdLongs = map[config.Language]string{
    45  		config.English: "Read bucket list\nValid methods: [" +
    46  			strings.Join(_validMethods, ", ") + "]",
    47  		config.Chinese: "根据方法和参数在IoTeX区块链上读取投票列表\n可用方法有:" +
    48  			strings.Join(_validMethods, ","),
    49  	}
    50  )
    51  
    52  // _bcBucketListCmd represents the bc bucketlist command
    53  var _bcBucketListCmd = &cobra.Command{
    54  	Use:   config.TranslateInLang(_bcBucketListCmdUses, config.UILanguage),
    55  	Short: config.TranslateInLang(_bcBucketListCmdShorts, config.UILanguage),
    56  	Long:  config.TranslateInLang(_bcBucketListCmdLongs, config.UILanguage),
    57  	Args:  cobra.MinimumNArgs(2),
    58  	Example: `ioctl bc bucketlist voter [VOTER_ADDRESS] [OFFSET] [LIMIT]
    59  ioctl bc bucketlist cand [CANDIDATE_NAME] [OFFSET] [LIMIT]`,
    60  	RunE: func(cmd *cobra.Command, args []string) error {
    61  		cmd.SilenceUsage = true
    62  		err := getBucketList(args[0], args[1], args[2:]...)
    63  		return output.PrintError(err)
    64  	},
    65  }
    66  
    67  type bucketlistMessage struct {
    68  	Node       string    `json:"node"`
    69  	Bucketlist []*bucket `json:"bucketlist"`
    70  }
    71  
    72  func (m *bucketlistMessage) String() string {
    73  	if output.Format == "" {
    74  		var lines []string
    75  		if len(m.Bucketlist) == 0 {
    76  			lines = append(lines, "Empty bucketlist with given address")
    77  		} else {
    78  			for _, bucket := range m.Bucketlist {
    79  				lines = append(lines, bucket.String())
    80  			}
    81  		}
    82  		return strings.Join(lines, "\n")
    83  	}
    84  	return output.FormatString(output.Result, m)
    85  }
    86  
    87  // getBucketList get bucket list from chain
    88  func getBucketList(method, addr string, args ...string) (err error) {
    89  	offset, limit := uint32(0), uint32(1000)
    90  	if len(args) > 0 {
    91  		val, err := strconv.ParseUint(args[0], 10, 32)
    92  		if err != nil {
    93  			return output.NewError(output.ValidationError, "invalid offset", err)
    94  		}
    95  		offset = uint32(val)
    96  	}
    97  	if len(args) > 1 {
    98  		val, err := strconv.ParseUint(args[1], 10, 32)
    99  		if err != nil {
   100  			return output.NewError(output.ValidationError, "invalid limit", err)
   101  		}
   102  		limit = uint32(val)
   103  	}
   104  	switch method {
   105  	case _bucketlistMethodByVoter:
   106  		return getBucketListByVoter(addr, offset, limit)
   107  	case _bucketlistMethodByCandidate:
   108  		return getBucketListByCand(addr, offset, limit)
   109  	}
   110  	return output.NewError(output.InputError, "unknown <method>", nil)
   111  }
   112  
   113  // getBucketList get bucket list from chain by voter address
   114  func getBucketListByVoter(addr string, offset, limit uint32) error {
   115  	address, err := util.GetAddress(addr)
   116  	if err != nil {
   117  		return output.NewError(output.AddressError, "", err)
   118  	}
   119  	bl, err := getBucketListByVoterAddress(address, offset, limit)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	var bucketlist []*bucket
   124  	for _, b := range bl.Buckets {
   125  		bucket, err := newBucket(b)
   126  		if err != nil {
   127  			return err
   128  		}
   129  		bucketlist = append(bucketlist, bucket)
   130  	}
   131  	message := bucketlistMessage{
   132  		Node:       config.ReadConfig.Endpoint,
   133  		Bucketlist: bucketlist,
   134  	}
   135  	fmt.Println(message.String())
   136  	return nil
   137  }
   138  
   139  func getBucketListByVoterAddress(addr string, offset, limit uint32) (*iotextypes.VoteBucketList, error) {
   140  	readStakingdataRequest := &iotexapi.ReadStakingDataRequest{
   141  		Request: &iotexapi.ReadStakingDataRequest_BucketsByVoter{
   142  			BucketsByVoter: &iotexapi.ReadStakingDataRequest_VoteBucketsByVoter{
   143  				VoterAddress: addr,
   144  				Pagination: &iotexapi.PaginationParam{
   145  					Offset: offset,
   146  					Limit:  limit,
   147  				},
   148  			},
   149  		},
   150  	}
   151  	return GetBucketList(iotexapi.ReadStakingDataMethod_BUCKETS_BY_VOTER, readStakingdataRequest)
   152  }
   153  
   154  // getBucketListByCand get bucket list from chain by candidate name
   155  func getBucketListByCand(candName string, offset, limit uint32) error {
   156  	bl, err := getBucketListByCandidateName(candName, offset, limit)
   157  	if err != nil {
   158  		return err
   159  	}
   160  	var bucketlist []*bucket
   161  	for _, b := range bl.Buckets {
   162  		bucket, err := newBucket(b)
   163  		if err != nil {
   164  			return err
   165  		}
   166  		bucketlist = append(bucketlist, bucket)
   167  	}
   168  	message := bucketlistMessage{
   169  		Node:       config.ReadConfig.Endpoint,
   170  		Bucketlist: bucketlist,
   171  	}
   172  	fmt.Println(message.String())
   173  	return nil
   174  }
   175  
   176  func getBucketListByCandidateName(candName string, offset, limit uint32) (*iotextypes.VoteBucketList, error) {
   177  	readStakingDataRequest := &iotexapi.ReadStakingDataRequest{
   178  		Request: &iotexapi.ReadStakingDataRequest_BucketsByCandidate{
   179  			BucketsByCandidate: &iotexapi.ReadStakingDataRequest_VoteBucketsByCandidate{
   180  				CandName: candName,
   181  				Pagination: &iotexapi.PaginationParam{
   182  					Offset: offset,
   183  					Limit:  limit,
   184  				},
   185  			},
   186  		},
   187  	}
   188  	return GetBucketList(iotexapi.ReadStakingDataMethod_BUCKETS_BY_CANDIDATE, readStakingDataRequest)
   189  }