Skip to content

Commit

Permalink
feat: add methods for updating a credit class (#539)
Browse files Browse the repository at this point in the history
* feat: update methods for credit classes

* change arg name

* regen proto and set metadata check

* feat: cli commands for updating credit class + tests

* refactor tests

* cleanup cli code + address review comments

Co-authored-by: technicallyty <48813565+tytech3@users.noreply.github.com>
  • Loading branch information
technicallyty and technicallyty authored Sep 23, 2021
1 parent 30765ed commit e8981ba
Show file tree
Hide file tree
Showing 11 changed files with 2,763 additions and 507 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ require (
github.com/stretchr/testify v1.7.0
github.com/tendermint/tendermint v0.34.12
github.com/tendermint/tm-db v0.6.4
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6 // indirect
)

replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
Expand Down
10 changes: 4 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,6 @@ github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxm
github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg=
github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ=
github.com/tendermint/tendermint v0.34.10/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0=
github.com/tendermint/tendermint v0.34.11/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0=
github.com/tendermint/tendermint v0.34.12 h1:m+kUYNhONedhJfHmHG8lqsdZvbR5t6vmhaok1yXjpKg=
github.com/tendermint/tendermint v0.34.12/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0=
github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI=
Expand Down Expand Up @@ -866,8 +865,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -1124,7 +1123,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down Expand Up @@ -1207,8 +1205,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af h1:aLMMXFYqw01RA6XJim5uaN+afqNNjc9P8HPAbnpnc5s=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6 h1:2ncG/LajxmrclaZH+ppVi02rQxz4eXYJzGHdFN4Y9UA=
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
Expand Down
59 changes: 58 additions & 1 deletion proto/regen/ecocredit/v1alpha1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ service Msg {
// deducts them from the tradable supply, effectively cancelling their
// issuance on Regen Ledger
rpc Cancel(MsgCancel) returns (MsgCancelResponse);

// UpdateClassAdmin updates the credit class admin
rpc UpdateClassAdmin(MsgUpdateClassAdmin) returns (MsgUpdateClassAdminResponse);

// UpdateClassIssuers updates the credit class issuer list
rpc UpdateClassIssuers(MsgUpdateClassIssuers) returns (MsgUpdateClassIssuersResponse);

// UpdateClassMetadata updates the credit class metadata
rpc UpdateClassMetadata(MsgUpdateClassMetadata) returns (MsgUpdateClassMetadataResponse);
}

// MsgCreateClass is the Msg/CreateClass request type.
Expand Down Expand Up @@ -217,4 +226,52 @@ message MsgCancel {
}

// MsgCancelResponse is the Msg/Cancel response type.
message MsgCancelResponse {}
message MsgCancelResponse {}

// MsgUpdateClassAdmin is the Msg/UpdateClassAdmin request type.
message MsgUpdateClassAdmin {

// admin is the address of the account that is the admin of the credit class.
string admin = 1;

// class_id is the unique ID of the credit class.
string class_id = 2;

// new_admin is the address of the new admin of the credit class.
string new_admin = 3;
}

// MsgUpdateClassAdminResponse is the MsgUpdateClassAdmin response type.
message MsgUpdateClassAdminResponse {}

// MsgUpdateClassIssuers is the Msg/UpdateClassIssuers request type.
message MsgUpdateClassIssuers {

// admin is the address of the account that is the admin of the credit class.
string admin = 1;

// class_id is the unique ID of the credit class.
string class_id = 2;

// issuers are the updated account addresses of the approved issuers.
repeated string issuers = 3;
}

// MsgUpdateClassIssuersResponse is the MsgUpdateClassIssuers response type.
message MsgUpdateClassIssuersResponse {}

// MsgUpdateClassMetadata is the Msg/UpdateClassMetadata request type.
message MsgUpdateClassMetadata {

// admin is the address of the account that is the admin of the credit class.
string admin = 1;

// class_id is the unique ID of the credit class.
string class_id = 2;

// metadata is the updated arbitrary metadata to be attached to the credit class.
bytes metadata = 3;
}

// MsgUpdateClassMetadataResponse is the MsgUpdateClassMetadata response type.
message MsgUpdateClassMetadataResponse {}
223 changes: 218 additions & 5 deletions x/ecocredit/client/testsuite/tx.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package testsuite

import (
"encoding/base64"
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
proto "github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/proto"
"github.com/regen-network/regen-ledger/types/testutil/cli"
"github.com/regen-network/regen-ledger/types/testutil/network"
"github.com/regen-network/regen-ledger/x/ecocredit"
"github.com/regen-network/regen-ledger/x/ecocredit/client"
"github.com/stretchr/testify/suite"
tmcli "github.com/tendermint/tendermint/libs/cli"
"strings"
)

type IntegrationTestSuite struct {
Expand All @@ -25,8 +26,9 @@ type IntegrationTestSuite struct {
cfg network.Config
network *network.Network

classInfo *ecocredit.ClassInfo
batchInfo *ecocredit.BatchInfo
testAccount sdk.AccAddress
classInfo *ecocredit.ClassInfo
batchInfo *ecocredit.BatchInfo
}

const (
Expand Down Expand Up @@ -64,6 +66,9 @@ func (s *IntegrationTestSuite) SetupSuite() {
info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator0", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
s.Require().NoError(err)

_, a1pub, a1 := testdata.KeyTestPubAddr()
val.ClientCtx.Keyring.SavePubKey("throwaway", a1pub, hd.Secp256k1Type)

account := sdk.AccAddress(info.GetPubKey().Address())
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
Expand All @@ -75,6 +80,17 @@ func (s *IntegrationTestSuite) SetupSuite() {
)
s.Require().NoError(err)

_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
a1,
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(2000))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
)
s.Require().NoError(err)
s.testAccount = a1

var commonFlags = []string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
Expand Down Expand Up @@ -1137,3 +1153,200 @@ func (s *IntegrationTestSuite) TestTxCancel() {
})
}
}

func (s *IntegrationTestSuite) TestTxUpdateAdmin() {
// use this classId as to not corrupt other tests
const classId = "C02"
_, _, a1 := testdata.KeyTestPubAddr()
val0 := s.network.Validators[0]
clientCtx := val0.ClientCtx

testCases := []struct {
name string
args []string
expErr bool
expErrMsg string
}{
{
name: "invalid request: not enough args",
args: []string{},
expErr: true,
expErrMsg: "accepts 2 arg(s), received 0",
},
{
name: "invalid request: no id",
args: []string{"", a1.String()},
expErr: true,
expErrMsg: "class-id is required",
},
{
name: "invalid request: no admin address",
args: append([]string{classId, "", makeFlagFrom(a1.String())}, s.commonTxFlags()...),
expErr: true,
expErrMsg: "new admin address is required",
},
{
name: "valid request",
args: append([]string{classId, a1.String(), makeFlagFrom(val0.Address.String())}, s.commonTxFlags()...),
expErr: false,
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := client.TxUpdateClassAdminCmd()
_, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)

// query the class info
query := client.QueryClassInfoCmd()
out, err := cli.ExecTestCLICmd(clientCtx, query, []string{classId, flagOutputJSON})
s.Require().NoError(err, out.String())
var res ecocredit.QueryClassInfoResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res)
s.Require().NoError(err)

// check the admin has been changed
s.Require().Equal(res.Info.Admin, tc.args[1])
}
})
}
}

func (s *IntegrationTestSuite) TestTxUpdateMetadata() {
// use C03 here as C02 will be corrupted by the admin change test
const classId = "C03"
newMetaData := base64.StdEncoding.EncodeToString([]byte("hello"))
_, _, a1 := testdata.KeyTestPubAddr()
val0 := s.network.Validators[0]
clientCtx := val0.ClientCtx

testCases := []struct {
name string
args []string
expErr bool
expErrMsg string
}{
{
name: "invalid request: not enough args",
args: []string{},
expErr: true,
expErrMsg: "accepts 2 arg(s), received 0",
},
{
name: "invalid request: bad id",
args: []string{"", a1.String()},
expErr: true,
expErrMsg: "class-id is required",
},
{
name: "invalid request: no metadata",
args: append([]string{classId, "", makeFlagFrom(a1.String())}, s.commonTxFlags()...),
expErr: true,
expErrMsg: "base64_metadata is required",
},
{
name: "invalid request: bad metadata",
args: append([]string{classId, "test", makeFlagFrom(a1.String())}, s.commonTxFlags()...),
expErr: true,
expErrMsg: "metadata is malformed, proper base64 string is required",
},
{
name: "valid request",
args: append([]string{classId, newMetaData, makeFlagFrom(val0.Address.String())}, s.commonTxFlags()...),
expErr: false,
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := client.TxUpdateClassMetadataCmd()
_, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)

// query the credit class info
query := client.QueryClassInfoCmd()
out, err := cli.ExecTestCLICmd(clientCtx, query, []string{classId, flagOutputJSON})
s.Require().NoError(err, out.String())
var res ecocredit.QueryClassInfoResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res)
s.Require().NoError(err)

// check metadata changed
b, err := base64.StdEncoding.DecodeString(newMetaData)
s.Require().NoError(err)
s.Require().Equal(res.Info.Metadata, b)
}
})
}
}

func (s *IntegrationTestSuite) TestTxUpdateIssuers() {
const classId = "C03"
_, _, a2 := testdata.KeyTestPubAddr()
newIssuers := []string{s.testAccount.String(), a2.String()}
val0 := s.network.Validators[0]
clientCtx := val0.ClientCtx

testCases := []struct {
name string
args []string
expErr bool
expErrMsg string
}{
{
name: "invalid request: not enough args",
args: append([]string{makeFlagFrom(s.testAccount.String())}, s.commonTxFlags()...),
expErr: true,
expErrMsg: "accepts 2 arg(s), received 0",
},
{
name: "invalid request: no id",
args: append([]string{"", s.testAccount.String(), makeFlagFrom(val0.Address.String())}, s.commonTxFlags()...),
expErr: true,
expErrMsg: "class-id is required",
},
{
name: "invalid request: bad issuer addresses",
args: append([]string{classId, "hello,world", makeFlagFrom(s.testAccount.String())}, s.commonTxFlags()...),
expErr: true,
expErrMsg: "invalid address",
},
{
name: "valid request",
args: append([]string{classId, fmt.Sprintf("%s,%s", newIssuers[0], newIssuers[1]), makeFlagFrom(val0.Address.String())}, s.commonTxFlags()...),
expErr: false,
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := client.TxUpdateClassIssuersCmd()
_, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
s.Require().NoError(err)

// query the credit class info
query := client.QueryClassInfoCmd()
out, err := cli.ExecTestCLICmd(clientCtx, query, []string{classId, flagOutputJSON})
s.Require().NoError(err, out.String())
var res ecocredit.QueryClassInfoResponse
err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res)
s.Require().NoError(err)

// check issuers list was changed
s.Require().NoError(err)
s.Require().Equal(res.Info.Issuers, newIssuers)
}
})
}
}
Loading

0 comments on commit e8981ba

Please sign in to comment.