Skip to content

Commit

Permalink
x/authz: Add DelegateAuthorization, UndelegateAuthorization (cosmos#8472
Browse files Browse the repository at this point in the history
)

* add proto msgs

* add delegate authorization

* add delegate authorization tests

* add delegate authorization to cli

* fix lint

* add cli tests

* made max_tokens optional

* add tests

* add table tests

* resolve conflicts

* add undelegate authorization

* proto-gen

* fix errors

* fix lint

* resolve conflicts

* fix imports

* add allow & deny lists to delegate authorization

* refactor authorizations

* proto-docs

* fix lint

* review changes

* golint

* proto lint

* review changes

* add staking authorization

* review changes

* fix protos

* review changes

* review changes

* clean docs

* proto-docs

* proto-gen

* proto-docs
  • Loading branch information
aleem1314 authored Feb 20, 2021
1 parent 7e481cc commit 7df79b5
Show file tree
Hide file tree
Showing 39 changed files with 8,017 additions and 5,938 deletions.
9,485 changes: 4,786 additions & 4,699 deletions docs/core/proto-docs.md

Large diffs are not rendered by default.

10 changes: 0 additions & 10 deletions proto/cosmos/authz/v1beta1/authz.proto
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
syntax = "proto3";
package cosmos.authz.v1beta1;

import "cosmos/base/v1beta1/coin.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";

// SendAuthorization allows the grantee to spend up to spend_limit coins from
// the granter's account.
message SendAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";

repeated cosmos.base.v1beta1.Coin spend_limit = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

// GenericAuthorization gives the grantee unrestricted permissions to execute
// the provided method on behalf of the granter's account.
message GenericAuthorization {
Expand Down
1 change: 0 additions & 1 deletion proto/cosmos/authz/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/authz/v1beta1/tx.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";

Expand Down
3 changes: 0 additions & 3 deletions proto/cosmos/authz/v1beta1/query.proto
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
syntax = "proto3";
package cosmos.authz.v1beta1;

import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/authz/v1beta1/authz.proto";

Expand Down
17 changes: 17 additions & 0 deletions proto/cosmos/bank/v1beta1/authz.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
syntax = "proto3";
package cosmos.bank.v1beta1;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/bank/types";

// SendAuthorization allows the grantee to spend up to spend_limit coins from
// the granter's account.
message SendAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";

repeated cosmos.base.v1beta1.Coin spend_limit = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}
43 changes: 43 additions & 0 deletions proto/cosmos/staking/v1beta1/authz.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
syntax = "proto3";
package cosmos.staking.v1beta1;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/staking/types";

// StakeAuthorization defines authorization for delegate/undelegate/redelegate.
message StakeAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";

// max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is
// empty, there is no spend limit and any amount of coins can be delegated.
cosmos.base.v1beta1.Coin max_tokens = 1 [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"];
// validators is the oneof that represents either allow_list or deny_list
oneof validators {
// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's
// account.
Validators allow_list = 2;
// deny_list specifies list of validator addresses to whom grantee can not delegate tokens.
Validators deny_list = 3;
}
// Validators defines list of validator addresses.
message Validators {
repeated string address = 1;
}
// authorization_type defines one of AuthorizationType.
AuthorizationType authorization_type = 4;
}

// AuthorizationType defines the type of staking module authorization type
enum AuthorizationType {
// AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type
AUTHORIZATION_TYPE_UNSPECIFIED = 0;
// AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate
AUTHORIZATION_TYPE_DELEGATE = 1;
// AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate
AUTHORIZATION_TYPE_UNDELEGATE = 2;
// AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate
AUTHORIZATION_TYPE_REDELEGATE = 3;
}
3 changes: 2 additions & 1 deletion x/authz/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/authz/types"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
)

// GetQueryCmd returns the cli query commands for this module
Expand Down Expand Up @@ -97,7 +98,7 @@ func GetCmdQueryAuthorization() *cobra.Command {
fmt.Sprintf(`Query authorization for a granter-grantee pair that matches the given msg-type:
Example:
$ %s query %s authorization cosmos1skjw.. cosmos1skjwj.. %s
`, version.AppName, types.ModuleName, types.SendAuthorization{}.MethodName()),
`, version.AppName, types.ModuleName, bank.SendAuthorization{}.MethodName()),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
Expand Down
186 changes: 186 additions & 0 deletions x/authz/client/cli/query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// +build norace

package cli_test

import (
"fmt"
"strings"
"time"

tmcli "github.com/tendermint/tendermint/libs/cli"

"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/client/cli"

authztestutil "github.com/cosmos/cosmos-sdk/x/authz/client/testutil"
"github.com/cosmos/cosmos-sdk/x/authz/types"
)

func (s *IntegrationTestSuite) TestQueryAuthorizations() {
val := s.network.Validators[0]

grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()

_, err := authztestutil.ExecGrantAuthorization(
val,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)

testCases := []struct {
name string
args []string
expectErr bool
expErrMsg string
}{
{
"Error: Invalid grantee",
[]string{
val.Address.String(),
"invalid grantee",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"decoding bech32 failed: invalid character in string: ' '",
},
{
"Error: Invalid granter",
[]string{
"invalid granter",
grantee.String(),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"decoding bech32 failed: invalid character in string: ' '",
},
{
"Valid txn (json)",
[]string{
val.Address.String(),
grantee.String(),
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
false,
``,
},
}
for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.GetCmdQueryAuthorizations()
clientCtx := val.ClientCtx
resp, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
s.Require().Contains(string(resp.Bytes()), tc.expErrMsg)
} else {
s.Require().NoError(err)
var grants types.QueryAuthorizationsResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &grants)
s.Require().NoError(err)
}
})
}
}

func (s *IntegrationTestSuite) TestQueryAuthorization() {
val := s.network.Validators[0]

grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()

_, err := authztestutil.ExecGrantAuthorization(
val,
[]string{
grantee.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)

testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"Error: Invalid grantee",
[]string{
val.Address.String(),
"invalid grantee",
typeMsgSend,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"",
},
{
"Error: Invalid granter",
[]string{
"invalid granter",
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"",
},
{
"no authorization found",
[]string{
val.Address.String(),
grantee.String(),
"typeMsgSend",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
"",
},
{
"Valid txn (json)",
[]string{
val.Address.String(),
grantee.String(),
typeMsgSend,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
false,
`{"@type":"/cosmos.bank.v1beta1.SendAuthorization","spend_limit":[{"denom":"steak","amount":"100"}]}`,
},
}
for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.GetCmdQueryAuthorization()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Contains(strings.TrimSpace(out.String()), tc.expectedOutput)
}
})
}
}
Loading

0 comments on commit 7df79b5

Please sign in to comment.