Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add methods for updating a credit class #539

Merged
merged 9 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
technicallyty marked this conversation as resolved.
Show resolved Hide resolved

// 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