From 6b6c94a83d3a33da78f105b8143584aece2b0c90 Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Fri, 13 May 2022 00:33:41 +0800 Subject: [PATCH 01/11] [ioctl] build block bucket command line into new ioctl --- ioctl/newcmd/bc/bcbucket.go | 269 ++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 ioctl/newcmd/bc/bcbucket.go diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go new file mode 100644 index 0000000000..3e9c3e16f9 --- /dev/null +++ b/ioctl/newcmd/bc/bcbucket.go @@ -0,0 +1,269 @@ +// Copyright (c) 2022 IoTeX Foundation +// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no +// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent +// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache +// License 2.0 that can be found in the LICENSE file. + +package bc + +import ( + "context" + "fmt" + "math/big" + "strconv" + "strings" + "time" + + "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/ioctl" + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" +) + +const ( + _bcBucketOptMax = "max" + _bcBucketOptCount = "count" +) + +// Multi-language support +var ( + _bcBucketCmdShorts = map[config.Language]string{ + config.English: "Get bucket for given index on IoTeX blockchain", + config.Chinese: "在IoTeX区块链上根据索引读取投票", + } + _bcBucketUses = map[config.Language]string{ + config.English: "bucket [OPTION|BUCKET_INDEX]", + config.Chinese: "bucket [选项|票索引]", + } +) + +type bucket struct { + Index uint64 `json:"index"` + Owner string `json:"owner"` + Candidate string `json:"candidate"` + StakedAmount string `json:"stakedAmount"` + StakedDuration uint32 `json:"stakedDuration"` + AutoStake bool `json:"autoStake"` + CreateTime string `json:"createTime"` + StakeStartTime string `json:"stakeStartTime"` + UnstakeStartTime string `json:"unstakeStartTime"` +} + +type bucketMessage struct { + Node string `json:"node"` + Bucket *bucket `json:"bucket"` +} + +// NewBCBucketCmd represents the bc Bucket command +func NewBCBucketCmd(c ioctl.Client) *cobra.Command { + bcBucketUses, _ := c.SelectTranslation(_bcBlockCmdUses) + bcBucketCmdShorts, _ := c.SelectTranslation(_bcBlockCmdShorts) + + cmd := &cobra.Command{ + Use: bcBucketUses, + Short: bcBucketCmdShorts, + Args: cobra.ExactArgs(1), + Example: `ioctl bc bucket [BUCKET_INDEX], to read bucket information by bucket index + ioctl bc bucket max, to query the max bucket index + ioctl bc bucket count, to query total number of active buckets + `, + RunE: func(cmd *cobra.Command, args []string) (err error) { + cmd.SilenceUsage = true + switch args[0] { + case _bcBucketOptMax: + count, err := getBucketsCount() + if err != nil { + return err + } + cmd.Println(count.GetTotal()) + return nil + case _bcBucketOptCount: + count, err := getBucketsCount() + if err != nil { + return err + } + cmd.Println(count.GetActive()) + default: + bucketindex, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + bucketpb, err := getBucketByIndex(bucketindex) + if err != nil { + return err + } + if bucketpb == nil { + return errors.New("The bucket has been withdrawn") + } + bucket, err := newBucket(bucketpb) + if err != nil { + return err + } + message := bucketMessage{ + Node: config.ReadConfig.Endpoint, + Bucket: bucket, + } + cmd.Println(message.Bucket.String()) + } + cmd.Println(err) + return nil + }, + } + return cmd +} + +func newBucket(bucketpb *iotextypes.VoteBucket) (*bucket, error) { + amount, ok := new(big.Int).SetString(bucketpb.StakedAmount, 10) + if !ok { + return nil, errors.New("failed to convert amount into big int") + } + unstakeStartTimeFormat := "none" + if err := bucketpb.UnstakeStartTime.CheckValid(); err != nil { + return nil, err + } + unstakeTime := bucketpb.UnstakeStartTime.AsTime() + if unstakeTime != time.Unix(0, 0).UTC() { + unstakeStartTimeFormat = unstakeTime.Format(time.RFC3339Nano) + } + return &bucket{ + Index: bucketpb.Index, + Owner: bucketpb.Owner, + Candidate: bucketpb.CandidateAddress, + StakedAmount: util.RauToString(amount, util.IotxDecimalNum), + StakedDuration: bucketpb.StakedDuration, + AutoStake: bucketpb.AutoStake, + CreateTime: bucketpb.CreateTime.AsTime().Format(time.RFC3339Nano), + StakeStartTime: bucketpb.StakeStartTime.AsTime().Format(time.RFC3339Nano), + UnstakeStartTime: unstakeStartTimeFormat, + }, nil +} + +func (b *bucket) String() string { + var lines []string + lines = append(lines, "{") + lines = append(lines, fmt.Sprintf(" index: %d", b.Index)) + lines = append(lines, fmt.Sprintf(" owner: %s", b.Owner)) + lines = append(lines, fmt.Sprintf(" candidate: %s", b.Candidate)) + lines = append(lines, fmt.Sprintf(" stakedAmount: %s IOTX", b.StakedAmount)) + lines = append(lines, fmt.Sprintf(" stakedDuration: %d days", b.StakedDuration)) + lines = append(lines, fmt.Sprintf(" autoStake: %v", b.AutoStake)) + lines = append(lines, fmt.Sprintf(" createTime: %s", b.CreateTime)) + lines = append(lines, fmt.Sprintf(" stakeStartTime: %s", b.StakeStartTime)) + lines = append(lines, fmt.Sprintf(" unstakeStartTime: %s", b.UnstakeStartTime)) + lines = append(lines, "}") + return strings.Join(lines, "\n") +} + +func getBucketByIndex(index uint64) (*iotextypes.VoteBucket, error) { + conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) + if err != nil { + return nil, errors.Wrap(err, "failed to connect to endpoint") + } + defer conn.Close() + cli := iotexapi.NewAPIServiceClient(conn) + method := &iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_BUCKETS_BY_INDEXES, + } + methodData, err := proto.Marshal(method) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal read staking data method") + } + readStakingdataRequest := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_BucketsByIndexes{ + BucketsByIndexes: &iotexapi.ReadStakingDataRequest_VoteBucketsByIndexes{ + Index: []uint64{index}, + }, + }, + } + requestData, err := proto.Marshal(readStakingdataRequest) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal read staking data request") + } + + request := &iotexapi.ReadStateRequest{ + ProtocolID: []byte("staking"), + MethodName: methodData, + Arguments: [][]byte{requestData}, + } + + ctx := context.Background() + jwtMD, err := util.JwtAuth() + if err == nil { + ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) + } + + response, err := cli.ReadState(ctx, request) + if err != nil { + sta, ok := status.FromError(err) + if ok { + return nil, errors.New(sta.Message()) + } + return nil, errors.Wrap(err, "failed to invoke ReadState api") + } + buckets := iotextypes.VoteBucketList{} + if err := proto.Unmarshal(response.Data, &buckets); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal response") + } + if len(buckets.GetBuckets()) == 0 { + return nil, errors.New("zero len response") + } + return buckets.GetBuckets()[0], nil +} + +func getBucketsCount() (count *iotextypes.BucketsCount, err error) { + conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) + if err != nil { + return nil, errors.Wrap(err, "failed to connect to endpoint") + } + defer conn.Close() + cli := iotexapi.NewAPIServiceClient(conn) + method := &iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_BUCKETS_COUNT, + } + methodData, err := proto.Marshal(method) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal read staking data method") + } + readStakingdataRequest := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_BucketsCount_{ + BucketsCount: &iotexapi.ReadStakingDataRequest_BucketsCount{}, + }, + } + requestData, err := proto.Marshal(readStakingdataRequest) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal read staking data request") + } + + request := &iotexapi.ReadStateRequest{ + ProtocolID: []byte("staking"), + MethodName: methodData, + Arguments: [][]byte{requestData}, + } + + ctx := context.Background() + jwtMD, err := util.JwtAuth() + if err == nil { + ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) + } + + response, err := cli.ReadState(ctx, request) + if err != nil { + sta, ok := status.FromError(err) + if ok { + return nil, errors.New(sta.Message()) + } + return nil, errors.Wrap(err, "failed to invoke ReadState api") + } + count = &iotextypes.BucketsCount{} + if err := proto.Unmarshal(response.Data, count); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal response") + } + return count, nil +} From 018856068fbb70046e428352c08a58f5ad70b63f Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Fri, 13 May 2022 00:52:34 +0800 Subject: [PATCH 02/11] replace config.ReadConfig with client.Config() --- ioctl/newcmd/bc/bcbucket.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 3e9c3e16f9..5e15a015eb 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -78,14 +78,14 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { cmd.SilenceUsage = true switch args[0] { case _bcBucketOptMax: - count, err := getBucketsCount() + count, err := getBucketsCount(c) if err != nil { return err } cmd.Println(count.GetTotal()) return nil case _bcBucketOptCount: - count, err := getBucketsCount() + count, err := getBucketsCount(c) if err != nil { return err } @@ -95,7 +95,7 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { if err != nil { return err } - bucketpb, err := getBucketByIndex(bucketindex) + bucketpb, err := getBucketByIndex(c, bucketindex) if err != nil { return err } @@ -107,7 +107,7 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { return err } message := bucketMessage{ - Node: config.ReadConfig.Endpoint, + Node: c.Config().Endpoint, Bucket: bucket, } cmd.Println(message.Bucket.String()) @@ -161,8 +161,8 @@ func (b *bucket) String() string { return strings.Join(lines, "\n") } -func getBucketByIndex(index uint64) (*iotextypes.VoteBucket, error) { - conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) +func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { + conn, err := util.ConnectToEndpoint(c.Config().SecureConnect && !config.Insecure) if err != nil { return nil, errors.Wrap(err, "failed to connect to endpoint") } @@ -217,8 +217,8 @@ func getBucketByIndex(index uint64) (*iotextypes.VoteBucket, error) { return buckets.GetBuckets()[0], nil } -func getBucketsCount() (count *iotextypes.BucketsCount, err error) { - conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) +func getBucketsCount(c ioctl.Client) (count *iotextypes.BucketsCount, err error) { + conn, err := util.ConnectToEndpoint(c.Config().SecureConnect && !config.Insecure) if err != nil { return nil, errors.Wrap(err, "failed to connect to endpoint") } From f59e8b52cd937deaed37452c541cbf46a3111d55 Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Sun, 15 May 2022 17:57:04 +0800 Subject: [PATCH 03/11] fix commit --- ioctl/newcmd/bc/bcbucket.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 5e15a015eb..6c49626982 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -83,7 +83,6 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { return err } cmd.Println(count.GetTotal()) - return nil case _bcBucketOptCount: count, err := getBucketsCount(c) if err != nil { @@ -112,7 +111,6 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { } cmd.Println(message.Bucket.String()) } - cmd.Println(err) return nil }, } @@ -162,6 +160,7 @@ func (b *bucket) String() string { } func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { + config.ReadConfig.Endpoint = c.Config().Endpoint conn, err := util.ConnectToEndpoint(c.Config().SecureConnect && !config.Insecure) if err != nil { return nil, errors.Wrap(err, "failed to connect to endpoint") From 296aa47f0b22fe909b8ba18b75969b9c9a30cb84 Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Sat, 28 May 2022 03:23:14 +0800 Subject: [PATCH 04/11] refactor unit test to cover the modification --- ioctl/newcmd/bc/bcbucket.go | 29 ++++++++----- ioctl/newcmd/bc/bcbucket_test.go | 73 ++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 ioctl/newcmd/bc/bcbucket_test.go diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 6c49626982..c0d2d7effc 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -160,13 +160,16 @@ func (b *bucket) String() string { } func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { - config.ReadConfig.Endpoint = c.Config().Endpoint - conn, err := util.ConnectToEndpoint(c.Config().SecureConnect && !config.Insecure) + var endpoint string + var insecure bool + + apiClient, err := c.APIServiceClient(ioctl.APIServiceConfig{ + Endpoint: endpoint, + Insecure: insecure, + }) if err != nil { - return nil, errors.Wrap(err, "failed to connect to endpoint") + return nil, err } - defer conn.Close() - cli := iotexapi.NewAPIServiceClient(conn) method := &iotexapi.ReadStakingDataMethod{ Method: iotexapi.ReadStakingDataMethod_BUCKETS_BY_INDEXES, } @@ -198,7 +201,7 @@ func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, err ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) } - response, err := cli.ReadState(ctx, request) + response, err := apiClient.ReadState(ctx, request) if err != nil { sta, ok := status.FromError(err) if ok { @@ -217,12 +220,16 @@ func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, err } func getBucketsCount(c ioctl.Client) (count *iotextypes.BucketsCount, err error) { - conn, err := util.ConnectToEndpoint(c.Config().SecureConnect && !config.Insecure) + var endpoint string + var insecure bool + + apiClient, err := c.APIServiceClient(ioctl.APIServiceConfig{ + Endpoint: endpoint, + Insecure: insecure, + }) if err != nil { - return nil, errors.Wrap(err, "failed to connect to endpoint") + return nil, err } - defer conn.Close() - cli := iotexapi.NewAPIServiceClient(conn) method := &iotexapi.ReadStakingDataMethod{ Method: iotexapi.ReadStakingDataMethod_BUCKETS_COUNT, } @@ -252,7 +259,7 @@ func getBucketsCount(c ioctl.Client) (count *iotextypes.BucketsCount, err error) ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) } - response, err := cli.ReadState(ctx, request) + response, err := apiClient.ReadState(ctx, request) if err != nil { sta, ok := status.FromError(err) if ok { diff --git a/ioctl/newcmd/bc/bcbucket_test.go b/ioctl/newcmd/bc/bcbucket_test.go new file mode 100644 index 0000000000..bf44737645 --- /dev/null +++ b/ioctl/newcmd/bc/bcbucket_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 IoTeX Foundation +// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no +// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent +// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache +// License 2.0 that can be found in the LICENSE file. + +package bc + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient" + "github.com/iotexproject/iotex-core/testutil" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotexapi/mock_iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestBCBucketCmd(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + client := mock_ioctlclient.NewMockClient(ctrl) + apiServiceClient := mock_iotexapi.NewMockAPIServiceClient(ctrl) + + client.EXPECT().SelectTranslation(gomock.Any()).Return("", config.English).Times(8) + + t.Run("get total blockchain bucket count", func(t *testing.T) { + client.EXPECT().APIServiceClient(gomock.Any()).Return(apiServiceClient, nil).Times(2) + apiServiceClient.EXPECT().ReadState(gomock.Any(), gomock.All()).Return(&iotexapi.ReadStateResponse{}, nil) + + cmd := NewBCBucketCmd(client) + result, err := util.ExecuteCmd(cmd, "max") + require.Equal("0\n", result) + require.NoError(err) + }) + + t.Run("get active blockchain bucket count", func(t *testing.T) { + client.EXPECT().APIServiceClient(gomock.Any()).Return(apiServiceClient, nil).Times(2) + apiServiceClient.EXPECT().ReadState(gomock.Any(), gomock.All()).Return(&iotexapi.ReadStateResponse{}, nil) + + cmd := NewBCBucketCmd(client) + result, err := util.ExecuteCmd(cmd, "count") + require.Equal("0\n", result) + require.NoError(err) + }) + + t.Run("get default blockchain bucket count", func(t *testing.T) { + cfg := config.Config{} + vb := &iotextypes.VoteBucket{ + Index: 1, + StakedAmount: "10", + UnstakeStartTime: timestamppb.New(testutil.TimestampNow()), + } + vblist, _ := proto.Marshal(&iotextypes.VoteBucketList{ + Buckets: []*iotextypes.VoteBucket{vb}, + }) + client.EXPECT().Config().Return(cfg).Times(1) + apiServiceClient.EXPECT().ReadState(gomock.Any(), gomock.All()).Return(&iotexapi.ReadStateResponse{ + Data: vblist, + }, nil) + + cmd := NewBCBucketCmd(client) + result, err := util.ExecuteCmd(cmd, "0") + require.NoError(err) + require.Contains(result, "index: 1") + }) +} From 0191b266f2ce5819af2c02154a051151478886c5 Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Wed, 1 Jun 2022 12:51:59 +0800 Subject: [PATCH 05/11] add chinese translation for example --- ioctl/newcmd/bc/bcbucket.go | 59 ++++++++++++++++---------------- ioctl/newcmd/bc/bcbucket_test.go | 15 ++++---- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index c0d2d7effc..62b46168ae 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -15,6 +15,8 @@ import ( "time" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" "github.com/spf13/cobra" "google.golang.org/grpc/status" @@ -23,8 +25,6 @@ import ( "github.com/iotexproject/iotex-core/ioctl" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/iotexproject/iotex-proto/golang/iotexapi" - "github.com/iotexproject/iotex-proto/golang/iotextypes" ) const ( @@ -34,13 +34,21 @@ const ( // Multi-language support var ( + _bcBucketUses = map[config.Language]string{ + config.English: "bucket [OPTION|BUCKET_INDEX]", + config.Chinese: "bucket [选项|票索引]", + } _bcBucketCmdShorts = map[config.Language]string{ config.English: "Get bucket for given index on IoTeX blockchain", config.Chinese: "在IoTeX区块链上根据索引读取投票", } - _bcBucketUses = map[config.Language]string{ - config.English: "bucket [OPTION|BUCKET_INDEX]", - config.Chinese: "bucket [选项|票索引]", + _bcBucketCmdExample = map[config.Language]string{ + config.English: "ioctl bc bucket [BUCKET_INDEX], to read bucket information by bucket index\n" + + "ioctl bc bucket max, to query the max bucket index\n" + + "ioctl bc bucket count, to query total number of active buckets", + config.Chinese: "ioctl bc bucket [BUCKET_INDEX], 依票索引取得投票资讯\n" + + "ioctl bc bucket max, 查询最大票索引\n" + + "ioctl bc bucket count, 查询活跃总票数", } ) @@ -62,29 +70,27 @@ type bucketMessage struct { } // NewBCBucketCmd represents the bc Bucket command -func NewBCBucketCmd(c ioctl.Client) *cobra.Command { - bcBucketUses, _ := c.SelectTranslation(_bcBlockCmdUses) - bcBucketCmdShorts, _ := c.SelectTranslation(_bcBlockCmdShorts) +func NewBCBucketCmd(client ioctl.Client) *cobra.Command { + bcBucketUses, _ := client.SelectTranslation(_bcBlockCmdUses) + bcBucketCmdShorts, _ := client.SelectTranslation(_bcBlockCmdShorts) + bcBucketCmdExample, _ := client.SelectTranslation(_bcBucketCmdExample) - cmd := &cobra.Command{ - Use: bcBucketUses, - Short: bcBucketCmdShorts, - Args: cobra.ExactArgs(1), - Example: `ioctl bc bucket [BUCKET_INDEX], to read bucket information by bucket index - ioctl bc bucket max, to query the max bucket index - ioctl bc bucket count, to query total number of active buckets - `, + return &cobra.Command{ + Use: bcBucketUses, + Short: bcBucketCmdShorts, + Args: cobra.ExactArgs(1), + Example: bcBucketCmdExample, RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true switch args[0] { case _bcBucketOptMax: - count, err := getBucketsCount(c) + count, err := getBucketsCount(client) if err != nil { return err } cmd.Println(count.GetTotal()) case _bcBucketOptCount: - count, err := getBucketsCount(c) + count, err := getBucketsCount(client) if err != nil { return err } @@ -94,7 +100,7 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { if err != nil { return err } - bucketpb, err := getBucketByIndex(c, bucketindex) + bucketpb, err := getBucketByIndex(client, bucketindex) if err != nil { return err } @@ -105,16 +111,11 @@ func NewBCBucketCmd(c ioctl.Client) *cobra.Command { if err != nil { return err } - message := bucketMessage{ - Node: c.Config().Endpoint, - Bucket: bucket, - } - cmd.Println(message.Bucket.String()) + cmd.Println(bucket.String()) } return nil }, } - return cmd } func newBucket(bucketpb *iotextypes.VoteBucket) (*bucket, error) { @@ -159,11 +160,11 @@ func (b *bucket) String() string { return strings.Join(lines, "\n") } -func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { +func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { var endpoint string var insecure bool - apiClient, err := c.APIServiceClient(ioctl.APIServiceConfig{ + apiClient, err := client.APIServiceClient(ioctl.APIServiceConfig{ Endpoint: endpoint, Insecure: insecure, }) @@ -219,11 +220,11 @@ func getBucketByIndex(c ioctl.Client, index uint64) (*iotextypes.VoteBucket, err return buckets.GetBuckets()[0], nil } -func getBucketsCount(c ioctl.Client) (count *iotextypes.BucketsCount, err error) { +func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err error) { var endpoint string var insecure bool - apiClient, err := c.APIServiceClient(ioctl.APIServiceConfig{ + apiClient, err := client.APIServiceClient(ioctl.APIServiceConfig{ Endpoint: endpoint, Insecure: insecure, }) diff --git a/ioctl/newcmd/bc/bcbucket_test.go b/ioctl/newcmd/bc/bcbucket_test.go index bf44737645..7decd576be 100644 --- a/ioctl/newcmd/bc/bcbucket_test.go +++ b/ioctl/newcmd/bc/bcbucket_test.go @@ -10,16 +10,17 @@ import ( "testing" "github.com/golang/mock/gomock" - "github.com/iotexproject/iotex-core/ioctl/config" - "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient" - "github.com/iotexproject/iotex-core/testutil" "github.com/iotexproject/iotex-proto/golang/iotexapi" "github.com/iotexproject/iotex-proto/golang/iotexapi/mock_iotexapi" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient" + "github.com/iotexproject/iotex-core/testutil" ) func TestBCBucketCmd(t *testing.T) { @@ -28,7 +29,7 @@ func TestBCBucketCmd(t *testing.T) { client := mock_ioctlclient.NewMockClient(ctrl) apiServiceClient := mock_iotexapi.NewMockAPIServiceClient(ctrl) - client.EXPECT().SelectTranslation(gomock.Any()).Return("", config.English).Times(8) + client.EXPECT().SelectTranslation(gomock.Any()).Return("", config.English).Times(9) t.Run("get total blockchain bucket count", func(t *testing.T) { client.EXPECT().APIServiceClient(gomock.Any()).Return(apiServiceClient, nil).Times(2) @@ -36,8 +37,8 @@ func TestBCBucketCmd(t *testing.T) { cmd := NewBCBucketCmd(client) result, err := util.ExecuteCmd(cmd, "max") - require.Equal("0\n", result) require.NoError(err) + require.Equal("0\n", result) }) t.Run("get active blockchain bucket count", func(t *testing.T) { @@ -46,8 +47,8 @@ func TestBCBucketCmd(t *testing.T) { cmd := NewBCBucketCmd(client) result, err := util.ExecuteCmd(cmd, "count") - require.Equal("0\n", result) require.NoError(err) + require.Equal("0\n", result) }) t.Run("get default blockchain bucket count", func(t *testing.T) { From 14d394feac85dd32de9ec4138d4701b45014154a Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Wed, 1 Jun 2022 16:35:51 +0800 Subject: [PATCH 06/11] combine similar code for another function combine getBucketByIndex and getBucketsCount similar code and form another function --- ioctl/newcmd/bc/bcbucket.go | 83 +++++++++++++------------------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 62b46168ae..9540b4865f 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -161,54 +161,19 @@ func (b *bucket) String() string { } func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { - var endpoint string - var insecure bool - - apiClient, err := client.APIServiceClient(ioctl.APIServiceConfig{ - Endpoint: endpoint, - Insecure: insecure, - }) - if err != nil { - return nil, err - } - method := &iotexapi.ReadStakingDataMethod{ + method := iotexapi.ReadStakingDataMethod{ Method: iotexapi.ReadStakingDataMethod_BUCKETS_BY_INDEXES, } - methodData, err := proto.Marshal(method) - if err != nil { - return nil, errors.Wrap(err, "failed to marshal read staking data method") - } - readStakingdataRequest := &iotexapi.ReadStakingDataRequest{ + readStakingdataRequest := iotexapi.ReadStakingDataRequest{ Request: &iotexapi.ReadStakingDataRequest_BucketsByIndexes{ BucketsByIndexes: &iotexapi.ReadStakingDataRequest_VoteBucketsByIndexes{ Index: []uint64{index}, }, }, } - requestData, err := proto.Marshal(readStakingdataRequest) + response, err := getBuckets(client, method, readStakingdataRequest) if err != nil { - return nil, errors.Wrap(err, "failed to marshal read staking data request") - } - - request := &iotexapi.ReadStateRequest{ - ProtocolID: []byte("staking"), - MethodName: methodData, - Arguments: [][]byte{requestData}, - } - - ctx := context.Background() - jwtMD, err := util.JwtAuth() - if err == nil { - ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) - } - - response, err := apiClient.ReadState(ctx, request) - if err != nil { - sta, ok := status.FromError(err) - if ok { - return nil, errors.New(sta.Message()) - } - return nil, errors.Wrap(err, "failed to invoke ReadState api") + return nil, err } buckets := iotextypes.VoteBucketList{} if err := proto.Unmarshal(response.Data, &buckets); err != nil { @@ -221,6 +186,26 @@ func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket } func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err error) { + method := iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_BUCKETS_COUNT, + } + readStakingdataRequest := iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_BucketsCount_{ + BucketsCount: &iotexapi.ReadStakingDataRequest_BucketsCount{}, + }, + } + response, err := getBuckets(client, method, readStakingdataRequest) + if err != nil { + return nil, err + } + count = &iotextypes.BucketsCount{} + if err := proto.Unmarshal(response.Data, count); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal response") + } + return count, nil +} + +func getBuckets(client ioctl.Client, method iotexapi.ReadStakingDataMethod, readStakingdataRequest iotexapi.ReadStakingDataRequest) (response *iotexapi.ReadStateResponse, err error) { var endpoint string var insecure bool @@ -231,19 +216,11 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e if err != nil { return nil, err } - method := &iotexapi.ReadStakingDataMethod{ - Method: iotexapi.ReadStakingDataMethod_BUCKETS_COUNT, - } - methodData, err := proto.Marshal(method) + methodData, err := proto.Marshal(&method) if err != nil { return nil, errors.Wrap(err, "failed to marshal read staking data method") } - readStakingdataRequest := &iotexapi.ReadStakingDataRequest{ - Request: &iotexapi.ReadStakingDataRequest_BucketsCount_{ - BucketsCount: &iotexapi.ReadStakingDataRequest_BucketsCount{}, - }, - } - requestData, err := proto.Marshal(readStakingdataRequest) + requestData, err := proto.Marshal(&readStakingdataRequest) if err != nil { return nil, errors.Wrap(err, "failed to marshal read staking data request") } @@ -260,7 +237,7 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) } - response, err := apiClient.ReadState(ctx, request) + response, err = apiClient.ReadState(ctx, request) if err != nil { sta, ok := status.FromError(err) if ok { @@ -268,9 +245,5 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e } return nil, errors.Wrap(err, "failed to invoke ReadState api") } - count = &iotextypes.BucketsCount{} - if err := proto.Unmarshal(response.Data, count); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal response") - } - return count, nil + return response, nil } From 63aad50379b91384150acd63a1af11d4d1e69ec5 Mon Sep 17 00:00:00 2001 From: huof6890 <68298506@qq.com> Date: Fri, 10 Jun 2022 19:31:44 +0800 Subject: [PATCH 07/11] delete useless message struct --- ioctl/newcmd/bc/bcbucket.go | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 9540b4865f..612fa80563 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -64,11 +64,6 @@ type bucket struct { UnstakeStartTime string `json:"unstakeStartTime"` } -type bucketMessage struct { - Node string `json:"node"` - Bucket *bucket `json:"bucket"` -} - // NewBCBucketCmd represents the bc Bucket command func NewBCBucketCmd(client ioctl.Client) *cobra.Command { bcBucketUses, _ := client.SelectTranslation(_bcBlockCmdUses) @@ -161,10 +156,10 @@ func (b *bucket) String() string { } func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket, error) { - method := iotexapi.ReadStakingDataMethod{ + method := &iotexapi.ReadStakingDataMethod{ Method: iotexapi.ReadStakingDataMethod_BUCKETS_BY_INDEXES, } - readStakingdataRequest := iotexapi.ReadStakingDataRequest{ + readStakingdataRequest := &iotexapi.ReadStakingDataRequest{ Request: &iotexapi.ReadStakingDataRequest_BucketsByIndexes{ BucketsByIndexes: &iotexapi.ReadStakingDataRequest_VoteBucketsByIndexes{ Index: []uint64{index}, @@ -186,10 +181,10 @@ func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket } func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err error) { - method := iotexapi.ReadStakingDataMethod{ + method := &iotexapi.ReadStakingDataMethod{ Method: iotexapi.ReadStakingDataMethod_BUCKETS_COUNT, } - readStakingdataRequest := iotexapi.ReadStakingDataRequest{ + readStakingdataRequest := &iotexapi.ReadStakingDataRequest{ Request: &iotexapi.ReadStakingDataRequest_BucketsCount_{ BucketsCount: &iotexapi.ReadStakingDataRequest_BucketsCount{}, }, @@ -205,7 +200,7 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e return count, nil } -func getBuckets(client ioctl.Client, method iotexapi.ReadStakingDataMethod, readStakingdataRequest iotexapi.ReadStakingDataRequest) (response *iotexapi.ReadStateResponse, err error) { +func getBuckets(client ioctl.Client, method *iotexapi.ReadStakingDataMethod, readStakingdataRequest *iotexapi.ReadStakingDataRequest) (response *iotexapi.ReadStateResponse, err error) { var endpoint string var insecure bool @@ -214,13 +209,13 @@ func getBuckets(client ioctl.Client, method iotexapi.ReadStakingDataMethod, read Insecure: insecure, }) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to connect to endpoint") } - methodData, err := proto.Marshal(&method) + methodData, err := proto.Marshal(method) if err != nil { return nil, errors.Wrap(err, "failed to marshal read staking data method") } - requestData, err := proto.Marshal(&readStakingdataRequest) + requestData, err := proto.Marshal(readStakingdataRequest) if err != nil { return nil, errors.Wrap(err, "failed to marshal read staking data request") } From 02b72ff0c7e7935a83d69af99096666a1ddd6db6 Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Fri, 10 Jun 2022 20:24:58 +0800 Subject: [PATCH 08/11] point argument for method and readStakingdataRequest --- ioctl/newcmd/bc/bcbucket.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 612fa80563..a959366f29 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -166,7 +166,7 @@ func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket }, }, } - response, err := getBuckets(client, method, readStakingdataRequest) + response, err := getBuckets(client, &method, &readStakingdataRequest) if err != nil { return nil, err } @@ -189,7 +189,7 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e BucketsCount: &iotexapi.ReadStakingDataRequest_BucketsCount{}, }, } - response, err := getBuckets(client, method, readStakingdataRequest) + response, err := getBuckets(client, &method, &readStakingdataRequest) if err != nil { return nil, err } From 81cabda4dace78132cf2dac86986ee65306ef6e2 Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Fri, 10 Jun 2022 20:26:20 +0800 Subject: [PATCH 09/11] point argument for method and readStakingdataRequest --- ioctl/newcmd/bc/bcbucket.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index a959366f29..612fa80563 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -166,7 +166,7 @@ func getBucketByIndex(client ioctl.Client, index uint64) (*iotextypes.VoteBucket }, }, } - response, err := getBuckets(client, &method, &readStakingdataRequest) + response, err := getBuckets(client, method, readStakingdataRequest) if err != nil { return nil, err } @@ -189,7 +189,7 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e BucketsCount: &iotexapi.ReadStakingDataRequest_BucketsCount{}, }, } - response, err := getBuckets(client, &method, &readStakingdataRequest) + response, err := getBuckets(client, method, readStakingdataRequest) if err != nil { return nil, err } From 098c3e7ee6d42658982b384986b4e298b7bc15ab Mon Sep 17 00:00:00 2001 From: LuckyPigeon Date: Sat, 18 Jun 2022 19:02:35 +0800 Subject: [PATCH 10/11] fix client.APIServiceClient() --- ioctl/newcmd/bc/bcbucket.go | 8 +------- ioctl/newcmd/bc/bcbucket_test.go | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket.go b/ioctl/newcmd/bc/bcbucket.go index 612fa80563..1a6ad997b0 100644 --- a/ioctl/newcmd/bc/bcbucket.go +++ b/ioctl/newcmd/bc/bcbucket.go @@ -201,13 +201,7 @@ func getBucketsCount(client ioctl.Client) (count *iotextypes.BucketsCount, err e } func getBuckets(client ioctl.Client, method *iotexapi.ReadStakingDataMethod, readStakingdataRequest *iotexapi.ReadStakingDataRequest) (response *iotexapi.ReadStateResponse, err error) { - var endpoint string - var insecure bool - - apiClient, err := client.APIServiceClient(ioctl.APIServiceConfig{ - Endpoint: endpoint, - Insecure: insecure, - }) + apiClient, err := client.APIServiceClient() if err != nil { return nil, errors.Wrap(err, "failed to connect to endpoint") } diff --git a/ioctl/newcmd/bc/bcbucket_test.go b/ioctl/newcmd/bc/bcbucket_test.go index 7decd576be..7fae21255a 100644 --- a/ioctl/newcmd/bc/bcbucket_test.go +++ b/ioctl/newcmd/bc/bcbucket_test.go @@ -32,7 +32,7 @@ func TestBCBucketCmd(t *testing.T) { client.EXPECT().SelectTranslation(gomock.Any()).Return("", config.English).Times(9) t.Run("get total blockchain bucket count", func(t *testing.T) { - client.EXPECT().APIServiceClient(gomock.Any()).Return(apiServiceClient, nil).Times(2) + client.EXPECT().APIServiceClient().Return(apiServiceClient, nil).Times(2) apiServiceClient.EXPECT().ReadState(gomock.Any(), gomock.All()).Return(&iotexapi.ReadStateResponse{}, nil) cmd := NewBCBucketCmd(client) @@ -42,7 +42,7 @@ func TestBCBucketCmd(t *testing.T) { }) t.Run("get active blockchain bucket count", func(t *testing.T) { - client.EXPECT().APIServiceClient(gomock.Any()).Return(apiServiceClient, nil).Times(2) + client.EXPECT().APIServiceClient().Return(apiServiceClient, nil).Times(2) apiServiceClient.EXPECT().ReadState(gomock.Any(), gomock.All()).Return(&iotexapi.ReadStateResponse{}, nil) cmd := NewBCBucketCmd(client) From 5ff4c657e3825b91408ad7dff5fd961ebe95341c Mon Sep 17 00:00:00 2001 From: huof6890 <68298506@qq.com> Date: Mon, 20 Jun 2022 12:12:55 +0800 Subject: [PATCH 11/11] add require.NoError --- ioctl/newcmd/bc/bcbucket_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioctl/newcmd/bc/bcbucket_test.go b/ioctl/newcmd/bc/bcbucket_test.go index 7fae21255a..fb7617edff 100644 --- a/ioctl/newcmd/bc/bcbucket_test.go +++ b/ioctl/newcmd/bc/bcbucket_test.go @@ -28,7 +28,6 @@ func TestBCBucketCmd(t *testing.T) { ctrl := gomock.NewController(t) client := mock_ioctlclient.NewMockClient(ctrl) apiServiceClient := mock_iotexapi.NewMockAPIServiceClient(ctrl) - client.EXPECT().SelectTranslation(gomock.Any()).Return("", config.English).Times(9) t.Run("get total blockchain bucket count", func(t *testing.T) { @@ -58,9 +57,10 @@ func TestBCBucketCmd(t *testing.T) { StakedAmount: "10", UnstakeStartTime: timestamppb.New(testutil.TimestampNow()), } - vblist, _ := proto.Marshal(&iotextypes.VoteBucketList{ + vblist, err := proto.Marshal(&iotextypes.VoteBucketList{ Buckets: []*iotextypes.VoteBucket{vb}, }) + require.NoError(err) client.EXPECT().Config().Return(cfg).Times(1) apiServiceClient.EXPECT().ReadState(gomock.Any(), gomock.All()).Return(&iotexapi.ReadStateResponse{ Data: vblist,