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 }