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

x/authz: Add DelegateAuthorization, UndelegateAuthorization #8472

Merged
merged 47 commits into from
Feb 20, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
a15aaba
add proto msgs
aleem1314 Jan 28, 2021
c3e1df8
add delegate authorization
aleem1314 Jan 29, 2021
eab3af5
add delegate authorization tests
aleem1314 Jan 29, 2021
c102c8c
add delegate authorization to cli
aleem1314 Jan 29, 2021
3218e5b
fix lint
aleem1314 Jan 29, 2021
0b850d3
add cli tests
aleem1314 Jan 29, 2021
1c6b4d7
made max_tokens optional
aleem1314 Jan 29, 2021
8d32fed
add tests
aleem1314 Jan 29, 2021
954369e
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Jan 29, 2021
c32c59f
add table tests
aleem1314 Jan 29, 2021
0edd383
Merge branch 'master' of https://github.com/cosmos/cosmos-sdk into al…
aleem1314 Jan 30, 2021
db58173
resolve conflicts
aleem1314 Jan 30, 2021
aa6b949
add undelegate authorization
aleem1314 Feb 1, 2021
9f40b83
Merge branch 'aleem/8312-authz-undelegate' into aleem/8312-authz-auth…
aleem1314 Feb 1, 2021
5ed79f9
proto-gen
aleem1314 Feb 1, 2021
b31da1f
fix errors
aleem1314 Feb 1, 2021
7068f13
fix lint
aleem1314 Feb 1, 2021
7bfd109
Merge branch 'master' of https://github.com/cosmos/cosmos-sdk into al…
aleem1314 Feb 1, 2021
f5dfa1b
resolve conflicts
aleem1314 Feb 1, 2021
21ee012
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 4, 2021
460fd14
Merge branch 'master' of https://github.com/cosmos/cosmos-sdk into al…
aleem1314 Feb 4, 2021
819fa6f
fix imports
aleem1314 Feb 4, 2021
e020f10
add allow & deny lists to delegate authorization
aleem1314 Feb 5, 2021
b146584
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 5, 2021
3fb594b
refactor authorizations
aleem1314 Feb 5, 2021
852975c
proto-docs
aleem1314 Feb 5, 2021
c13b28b
fix lint
aleem1314 Feb 5, 2021
8f45bd7
review changes
aleem1314 Feb 7, 2021
73bcb9f
golint
aleem1314 Feb 7, 2021
2ef6dcc
proto lint
aleem1314 Feb 7, 2021
e496d97
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 8, 2021
aa29d3d
review changes
aleem1314 Feb 8, 2021
d197db8
Merge branch 'aleem/8312-authz-authorizations' of https://github.com/…
aleem1314 Feb 8, 2021
1896cf8
add staking authorization
aleem1314 Feb 9, 2021
8be7dd6
review changes
aleem1314 Feb 10, 2021
9c528df
fix protos
aleem1314 Feb 10, 2021
de7b614
review changes
aleem1314 Feb 10, 2021
97de77e
review changes
aleem1314 Feb 11, 2021
4aab63e
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 11, 2021
8ed83b2
clean docs
aleem1314 Feb 12, 2021
9a38c6c
Merge branch 'aleem/8312-authz-authorizations' of https://github.com/…
aleem1314 Feb 12, 2021
3b719bd
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 12, 2021
a8948f3
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 15, 2021
744bd22
proto-docs
aleem1314 Feb 15, 2021
e271872
Merge branch 'master' into aleem/8312-authz-authorizations
aleem1314 Feb 20, 2021
0601031
proto-gen
aleem1314 Feb 20, 2021
012cc59
proto-docs
aleem1314 Feb 20, 2021
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
10,683 changes: 0 additions & 10,683 deletions docs/core/proto-docs.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions proto/cosmos/authz/v1beta1/authz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,14 @@ message DelegateAuthorization {
// empty, there is no spend limit and any amount of coins can be delegated.
cosmos.base.v1beta1.Coin max_tokens = 2 [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"];
}
// UndelegateAuthorization allows the grantee to un-delegate tokens from provided set of validators
// on behalf of the granter's account.
message UndelegateAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";

// validator_address specifies list of validator addresses from whom grantee can un-delegate tokens on behalf of granter's account.
repeated string validator_address = 1;
// max_tokens specifies the maximum amount of tokens can be un-delegate from a validator. If it is
// empty, there is no spend limit and any amount of coins can be un-delegated.
cosmos.base.v1beta1.Coin max_tokens = 2 [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"];
}
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
18 changes: 12 additions & 6 deletions x/authz/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func GetTxCmd() *cobra.Command {

func NewCmdGrantAuthorization() *cobra.Command {
cmd := &cobra.Command{
Use: "grant <grantee> <authorization_type=\"send\"|\"generic\"|\"delegate\"> --from <granter>",
Use: "grant <grantee> <authorization_type=\"send\"|\"generic\"|\"delegate\"|\"unbond\"> --from <granter>",
Short: "Grant authorization to an address",
Long: strings.TrimSpace(
fmt.Sprintf(`Grant authorization to an address to execute a transaction on your behalf:
Expand Down Expand Up @@ -94,7 +94,7 @@ Examples:
}

authorization = types.NewGenericAuthorization(msgType)
case "delegate":
case "delegate", "unbond":
limit, err := cmd.Flags().GetString(FlagSpendLimit)
if err != nil {
return err
Expand Down Expand Up @@ -123,12 +123,18 @@ Examples:
if !spendLimit.IsAllPositive() {
return fmt.Errorf("spend-limit should be greater than zero")
}

authorization = types.NewDelegateAuthorization(vals, &spendLimit[0])
if args[1] == "delegate" {
authorization = types.NewDelegateAuthorization(vals, &spendLimit[0])
} else {
authorization = types.NewUndelegateAuthorization(vals, &spendLimit[0])
}
} else {
authorization = types.NewDelegateAuthorization(vals, nil)
if args[1] == "delegate" {
authorization = types.NewDelegateAuthorization(vals, nil)
} else {
authorization = types.NewUndelegateAuthorization(vals, nil)
}
}

default:
return fmt.Errorf("invalid authorization type, %s", args[1])
}
Expand Down
229 changes: 229 additions & 0 deletions x/authz/client/cli/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
stakingcli "github.com/cosmos/cosmos-sdk/x/staking/client/cli"

"github.com/cosmos/cosmos-sdk/x/authz/types"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
Expand Down Expand Up @@ -208,6 +209,12 @@ func execGrantAuthorization(val *network.Validator, args []string) (testutil.Buf
return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
}

func execDelegate(val *network.Validator, args []string) (testutil.BufferWriter, error) {
cmd := stakingcli.NewDelegateCmd()
clientCtx := val.ClientCtx
return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
}

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

Expand Down Expand Up @@ -738,6 +745,228 @@ func (s *IntegrationTestSuite) TestExecDelegateAuthorization() {
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.NewCmdExecAuthorization()
clientCtx := val.ClientCtx

out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errMsg)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}

func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() {
val := s.network.Validators[0]
grantee := s.grantee
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()

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

// create delegation
_, err = execDelegate(
val,
[]string{
val.ValAddress.String(),
"100stake",
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
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)

tokens := sdk.NewCoins(
sdk.NewCoin("stake", sdk.NewInt(50)),
)

undelegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.Msg/Undelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
tokens.GetDenomByIndex(0), tokens[0].Amount)
execMsg := testutil.WriteToNewTempFile(s.T(), undelegateTx)

testCases := []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
errMsg string
}{
{
"fail invalid grantee",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, "invalid_grantee"),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
nil,
0,
true,
"The specified item could not be found in the keyring",
},
{
"fail invalid json path",
[]string{
"/invalid/file.txt",
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
nil,
0,
true,
"",
},
{
"valid txn: (undelegate half tokens)",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
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()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
0,
false,
"",
},
{
"valid txn: (undelegate remaining half tokens)",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
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()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
0,
false,
"",
},
{
"failed with error no authorization found",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
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()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
4,
false,
"authorization not found",
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.NewCmdExecAuthorization()
clientCtx := val.ClientCtx

out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errMsg)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}

// grant undelegate authorization without limit
_, err = execGrantAuthorization(
val,
[]string{
grantee.String(),
"unbond",
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
fmt.Sprintf("--%s=%s", cli.FlagValidators, fmt.Sprintf("%s", val.ValAddress.String())),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
)
s.Require().NoError(err)
tokens = sdk.NewCoins(
sdk.NewCoin("stake", sdk.NewInt(50)),
)

undelegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.Msg/Undelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
tokens.GetDenomByIndex(0), tokens[0].Amount)
execMsg = testutil.WriteToNewTempFile(s.T(), undelegateTx)

testCases = []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
errMsg string
}{
{
"valid txn",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
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()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
0,
false,
"",
},
{
"valid txn",
[]string{
execMsg.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
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()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
},
&sdk.TxResponse{},
0,
false,
"",
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
Expand Down
2 changes: 1 addition & 1 deletion x/authz/simulation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func SimulateMsgExecuteAuthorized(ak types.AccountKeeper, bk types.BankKeeper, k
sendGrant := targetGrant.Authorization.GetCachedValue().(*types.SendAuthorization)
_, _, err = sendGrant.Accept(execMsg, ctx.BlockHeader())
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, "not allowed"), nil, nil
return simtypes.NoOpMsg(types.ModuleName, TypeMsgExecDelegated, err.Error()), nil, nil
}

txGen := simappparams.MakeTestEncodingConfig().TxConfig
Expand Down
Loading