test: migrate e2e/authz to system tests (#21819)
This commit is contained in:
parent
3a20261c78
commit
8eeb3ff6a9
@ -1,20 +0,0 @@
|
||||
//go:build e2e
|
||||
// +build e2e
|
||||
|
||||
package authz
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/simapp"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
)
|
||||
|
||||
func TestE2ETestSuite(t *testing.T) {
|
||||
cfg := network.DefaultConfig(simapp.NewTestNetworkFixture)
|
||||
cfg.NumValidators = 1
|
||||
suite.Run(t, NewE2ETestSuite(cfg))
|
||||
}
|
||||
@ -1,270 +0,0 @@
|
||||
package authz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/x/authz"
|
||||
"cosmossdk.io/x/authz/client/cli"
|
||||
authzclitestutil "cosmossdk.io/x/authz/client/testutil"
|
||||
banktypes "cosmossdk.io/x/bank/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func (s *E2ETestSuite) TestQueryGrantGRPC() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[1]
|
||||
grantsURL := val.GetAPIAddress() + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s&msg_type_url=%s"
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expectErr bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
"fail invalid granter address",
|
||||
fmt.Sprintf(grantsURL, "invalid_granter", grantee.String(), typeMsgSend),
|
||||
true,
|
||||
"decoding bech32 failed: invalid separator index -1: invalid request",
|
||||
},
|
||||
{
|
||||
"fail invalid grantee address",
|
||||
fmt.Sprintf(grantsURL, val.GetAddress().String(), "invalid_grantee", typeMsgSend),
|
||||
true,
|
||||
"decoding bech32 failed: invalid separator index -1: invalid request",
|
||||
},
|
||||
{
|
||||
"fail with empty granter",
|
||||
fmt.Sprintf(grantsURL, "", grantee.String(), typeMsgSend),
|
||||
true,
|
||||
"empty address string is not allowed: invalid request",
|
||||
},
|
||||
{
|
||||
"fail with empty grantee",
|
||||
fmt.Sprintf(grantsURL, val.GetAddress().String(), "", typeMsgSend),
|
||||
true,
|
||||
"empty address string is not allowed: invalid request",
|
||||
},
|
||||
{
|
||||
"fail invalid msg-type",
|
||||
fmt.Sprintf(grantsURL, val.GetAddress().String(), grantee.String(), "invalidMsg"),
|
||||
true,
|
||||
"authorization not found for invalidMsg type",
|
||||
},
|
||||
{
|
||||
"valid query",
|
||||
fmt.Sprintf(grantsURL, val.GetAddress().String(), grantee.String(), typeMsgSend),
|
||||
false,
|
||||
"",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
resp, _ := testutil.GetRequest(tc.url)
|
||||
require := s.Require()
|
||||
if tc.expectErr {
|
||||
require.Contains(string(resp), tc.errorMsg)
|
||||
} else {
|
||||
var g authz.QueryGrantsResponse
|
||||
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &g)
|
||||
require.NoError(err)
|
||||
require.Len(g.Grants, 1)
|
||||
err = g.Grants[0].UnpackInterfaces(val.GetClientCtx().InterfaceRegistry)
|
||||
require.NoError(err)
|
||||
auth, err := g.Grants[0].GetAuthorization()
|
||||
require.NoError(err)
|
||||
require.Equal(auth.MsgTypeURL(), banktypes.SendAuthorization{}.MsgTypeURL())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryGrantsGRPC() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[1]
|
||||
grantsURL := val.GetAPIAddress() + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s"
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expectErr bool
|
||||
errMsg string
|
||||
preRun func()
|
||||
postRun func(*authz.QueryGrantsResponse)
|
||||
}{
|
||||
{
|
||||
"valid query: expect single grant",
|
||||
fmt.Sprintf(grantsURL, val.GetAddress().String(), grantee.String()),
|
||||
false,
|
||||
"",
|
||||
func() {},
|
||||
func(g *authz.QueryGrantsResponse) {
|
||||
s.Require().Len(g.Grants, 1)
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid query: expect two grants",
|
||||
fmt.Sprintf(grantsURL, val.GetAddress().String(), grantee.String()),
|
||||
false,
|
||||
"",
|
||||
func() {
|
||||
_, err := authzclitestutil.CreateGrant(val.GetClientCtx(), []string{
|
||||
grantee.String(),
|
||||
"generic",
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()),
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
},
|
||||
func(g *authz.QueryGrantsResponse) {
|
||||
s.Require().Len(g.Grants, 2)
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid query: expect single grant with pagination",
|
||||
fmt.Sprintf(grantsURL+"&pagination.limit=1", val.GetAddress().String(), grantee.String()),
|
||||
false,
|
||||
"",
|
||||
func() {},
|
||||
func(g *authz.QueryGrantsResponse) {
|
||||
s.Require().Len(g.Grants, 1)
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid query: expect two grants with pagination",
|
||||
fmt.Sprintf(grantsURL+"&pagination.limit=2", val.GetAddress().String(), grantee.String()),
|
||||
false,
|
||||
"",
|
||||
func() {},
|
||||
func(g *authz.QueryGrantsResponse) {
|
||||
s.Require().Len(g.Grants, 2)
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
tc.preRun()
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
s.Require().NoError(err)
|
||||
|
||||
if tc.expectErr {
|
||||
s.Require().Contains(string(resp), tc.errMsg)
|
||||
} else {
|
||||
var authorizations authz.QueryGrantsResponse
|
||||
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &authorizations)
|
||||
s.Require().NoError(err)
|
||||
tc.postRun(&authorizations)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryGranterGrantsGRPC() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[1]
|
||||
require := s.Require()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expectErr bool
|
||||
errMsg string
|
||||
numItems int
|
||||
}{
|
||||
{
|
||||
"invalid account address",
|
||||
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/granter/%s", val.GetAPIAddress(), "invalid address"),
|
||||
true,
|
||||
"decoding bech32 failed",
|
||||
0,
|
||||
},
|
||||
{
|
||||
"no authorizations found",
|
||||
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/granter/%s", val.GetAPIAddress(), grantee.String()),
|
||||
false,
|
||||
"",
|
||||
0,
|
||||
},
|
||||
{
|
||||
"valid query",
|
||||
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/granter/%s", val.GetAPIAddress(), val.GetAddress().String()),
|
||||
false,
|
||||
"",
|
||||
6,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.expectErr {
|
||||
require.Contains(string(resp), tc.errMsg)
|
||||
} else {
|
||||
var authorizations authz.QueryGranterGrantsResponse
|
||||
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &authorizations)
|
||||
require.NoError(err)
|
||||
require.Len(authorizations.Grants, tc.numItems)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryGranteeGrantsGRPC() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[1]
|
||||
require := s.Require()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expectErr bool
|
||||
errMsg string
|
||||
numItems int
|
||||
}{
|
||||
{
|
||||
"invalid account address",
|
||||
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/grantee/%s", val.GetAPIAddress(), "invalid address"),
|
||||
true,
|
||||
"decoding bech32 failed",
|
||||
0,
|
||||
},
|
||||
{
|
||||
"no authorizations found",
|
||||
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/grantee/%s", val.GetAPIAddress(), val.GetAddress().String()),
|
||||
false,
|
||||
"",
|
||||
0,
|
||||
},
|
||||
{
|
||||
"valid query",
|
||||
fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/grantee/%s", val.GetAPIAddress(), grantee.String()),
|
||||
false,
|
||||
"",
|
||||
1,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(err)
|
||||
|
||||
if tc.expectErr {
|
||||
require.Contains(string(resp), tc.errMsg)
|
||||
} else {
|
||||
var authorizations authz.QueryGranteeGrantsResponse
|
||||
err := val.GetClientCtx().Codec.UnmarshalJSON(resp, &authorizations)
|
||||
require.NoError(err)
|
||||
require.Len(authorizations.Grants, tc.numItems)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,923 +0,0 @@
|
||||
package authz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
// without this import amino json encoding will fail when resolving any types
|
||||
_ "cosmossdk.io/api/cosmos/authz/v1beta1"
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/x/authz"
|
||||
"cosmossdk.io/x/authz/client/cli"
|
||||
authzclitestutil "cosmossdk.io/x/authz/client/testutil"
|
||||
bank "cosmossdk.io/x/bank/types"
|
||||
govcli "cosmossdk.io/x/gov/client/cli"
|
||||
govtestutil "cosmossdk.io/x/gov/client/testutil"
|
||||
govv1 "cosmossdk.io/x/gov/types/v1"
|
||||
govv1beta1 "cosmossdk.io/x/gov/types/v1beta1"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
"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"
|
||||
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
)
|
||||
|
||||
type E2ETestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
cfg network.Config
|
||||
network network.NetworkI
|
||||
grantee []sdk.AccAddress
|
||||
}
|
||||
|
||||
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
|
||||
return &E2ETestSuite{cfg: cfg}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) SetupSuite() {
|
||||
s.T().Log("setting up e2e test suite")
|
||||
|
||||
var err error
|
||||
s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg)
|
||||
s.Require().NoError(err)
|
||||
|
||||
val := s.network.GetValidators()[0]
|
||||
s.grantee = make([]sdk.AccAddress, 6)
|
||||
|
||||
// Send some funds to the new account.
|
||||
// Create new account in the keyring.
|
||||
s.grantee[0] = s.createAccount("grantee1")
|
||||
s.msgSendExec(s.grantee[0])
|
||||
|
||||
// create a proposal with deposit
|
||||
_, err = govtestutil.MsgSubmitLegacyProposal(val.GetClientCtx(), val.GetAddress().String(),
|
||||
"Text Proposal 1", "Where is the title!?", govv1beta1.ProposalTypeText,
|
||||
fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govv1.DefaultMinDepositTokens).String()))
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// Create new account in the keyring.
|
||||
s.grantee[1] = s.createAccount("grantee2")
|
||||
// Send some funds to the new account.
|
||||
s.msgSendExec(s.grantee[1])
|
||||
|
||||
// grant send authorization to grantee2
|
||||
out, err := authzclitestutil.CreateGrant(val.GetClientCtx(), []string{
|
||||
s.grantee[1].String(),
|
||||
"send",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()),
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, 0))
|
||||
|
||||
// Create new account in the keyring.
|
||||
s.grantee[2] = s.createAccount("grantee3")
|
||||
|
||||
// grant send authorization to grantee3
|
||||
_, err = authzclitestutil.CreateGrant(val.GetClientCtx(), []string{
|
||||
s.grantee[2].String(),
|
||||
"send",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()),
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// Create new accounts in the keyring.
|
||||
s.grantee[3] = s.createAccount("grantee4")
|
||||
s.msgSendExec(s.grantee[3])
|
||||
|
||||
s.grantee[4] = s.createAccount("grantee5")
|
||||
s.grantee[5] = s.createAccount("grantee6")
|
||||
|
||||
// grant send authorization with allow list to grantee4
|
||||
out, err = authzclitestutil.CreateGrant(val.GetClientCtx(),
|
||||
[]string{
|
||||
s.grantee[3].String(),
|
||||
"send",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagAllowList, s.grantee[4]),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, 0))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) createAccount(uid string) sdk.AccAddress {
|
||||
val := s.network.GetValidators()[0]
|
||||
// Create new account in the keyring.
|
||||
k, _, err := val.GetClientCtx().Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := k.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) msgSendExec(grantee sdk.AccAddress) {
|
||||
val := s.network.GetValidators()[0]
|
||||
// Send some funds to the new account.
|
||||
|
||||
from := val.GetAddress()
|
||||
coins := sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(200)))
|
||||
msgSend := &bank.MsgSend{
|
||||
FromAddress: from.String(),
|
||||
ToAddress: grantee.String(),
|
||||
Amount: coins,
|
||||
}
|
||||
|
||||
out, err := clitestutil.SubmitTestTx(
|
||||
val.GetClientCtx(),
|
||||
msgSend,
|
||||
from,
|
||||
clitestutil.TestTxConfig{},
|
||||
)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().Contains(out.String(), `"code":0`)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TearDownSuite() {
|
||||
s.T().Log("tearing down e2e test suite")
|
||||
s.network.Cleanup()
|
||||
}
|
||||
|
||||
var (
|
||||
typeMsgSend = bank.SendAuthorization{}.MsgTypeURL()
|
||||
typeMsgVote = sdk.MsgTypeURL(&govv1.MsgVote{})
|
||||
)
|
||||
|
||||
func (s *E2ETestSuite) TestExecAuthorizationWithExpiration() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[0]
|
||||
tenSeconds := time.Now().Add(time.Second * time.Duration(10)).Unix()
|
||||
|
||||
_, err := authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"generic",
|
||||
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, tenSeconds),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
// msg vote
|
||||
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.GetAddress().String())
|
||||
execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
|
||||
defer execMsg.Close()
|
||||
|
||||
// waiting for authorization to expires
|
||||
time.Sleep(12 * time.Second)
|
||||
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, []string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, response.TxHash, authz.ErrNoAuthorizationFound.ABCICode()))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestNewExecGenericAuthorized() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[0]
|
||||
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
|
||||
|
||||
_, err := authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"generic",
|
||||
fmt.Sprintf("--%s=%s", cli.FlagMsgType, typeMsgVote),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// msg vote
|
||||
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.GetAddress().String())
|
||||
execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
|
||||
defer execMsg.Close()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
respType proto.Message
|
||||
expectedCode uint32
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"fail invalid grantee",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, "grantee"),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
||||
},
|
||||
nil,
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail invalid json path",
|
||||
[]string{
|
||||
"/invalid/file.txt",
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
},
|
||||
nil,
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid txn",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
&sdk.TxResponse{},
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid tx with amino",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
|
||||
},
|
||||
&sdk.TxResponse{}, 0,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
|
||||
txResp := tc.respType.(*sdk.TxResponse)
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), txResp.TxHash, tc.expectedCode))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestNewExecGrantAuthorized() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[0]
|
||||
grantee1 := s.grantee[2]
|
||||
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
|
||||
|
||||
_, err := authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"send",
|
||||
fmt.Sprintf("--%s=12%stoken", cli.FlagSpendLimit, val.GetMoniker()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
from := val.GetAddress()
|
||||
tokens := sdk.NewCoins(
|
||||
sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(12)),
|
||||
)
|
||||
msgSend := &bank.MsgSend{
|
||||
FromAddress: from.String(),
|
||||
ToAddress: grantee.String(),
|
||||
Amount: tokens,
|
||||
}
|
||||
normalGeneratedTx, err := clitestutil.SubmitTestTx(
|
||||
val.GetClientCtx(),
|
||||
msgSend,
|
||||
from,
|
||||
clitestutil.TestTxConfig{
|
||||
GenOnly: true,
|
||||
},
|
||||
)
|
||||
|
||||
s.Require().NoError(err)
|
||||
execMsg := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
|
||||
defer execMsg.Close()
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedCode uint32
|
||||
expectErr bool
|
||||
expectErrMsg string
|
||||
}{
|
||||
{
|
||||
"valid txn",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"error over grantee doesn't exist on chain",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee1.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
true,
|
||||
"insufficient funds", // earlier the error was account not found here.
|
||||
},
|
||||
{
|
||||
"error over spent",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
authz.ErrNoAuthorizationFound.ABCICode(),
|
||||
false,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
var response sdk.TxResponse
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
switch {
|
||||
case tc.expectErrMsg != "":
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().Contains(response.RawLog, tc.expectErrMsg)
|
||||
|
||||
case tc.expectErr:
|
||||
s.Require().Error(err)
|
||||
|
||||
default:
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, tc.expectedCode))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestExecSendAuthzWithAllowList() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[3]
|
||||
allowedAddr := s.grantee[4]
|
||||
notAllowedAddr := s.grantee[5]
|
||||
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
|
||||
|
||||
_, err := authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"send",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagAllowList, allowedAddr),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
from := val.GetAddress()
|
||||
tokens := sdk.NewCoins(
|
||||
sdk.NewCoin("stake", math.NewInt(12)),
|
||||
)
|
||||
msgSend := &bank.MsgSend{
|
||||
FromAddress: from.String(),
|
||||
ToAddress: allowedAddr.String(),
|
||||
Amount: tokens,
|
||||
}
|
||||
|
||||
validGeneratedTx, err := clitestutil.SubmitTestTx(
|
||||
val.GetClientCtx(),
|
||||
msgSend,
|
||||
from,
|
||||
clitestutil.TestTxConfig{
|
||||
GenOnly: true,
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
execMsg := testutil.WriteToNewTempFile(s.T(), validGeneratedTx.String())
|
||||
defer execMsg.Close()
|
||||
|
||||
msgSend1 := &bank.MsgSend{
|
||||
FromAddress: from.String(),
|
||||
ToAddress: notAllowedAddr.String(),
|
||||
Amount: tokens,
|
||||
}
|
||||
invalidGeneratedTx, err := clitestutil.SubmitTestTx(
|
||||
val.GetClientCtx(),
|
||||
msgSend1,
|
||||
from,
|
||||
clitestutil.TestTxConfig{
|
||||
GenOnly: true,
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
execMsg1 := testutil.WriteToNewTempFile(s.T(), invalidGeneratedTx.String())
|
||||
defer execMsg1.Close()
|
||||
|
||||
// test sending to allowed address
|
||||
args := []string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
}
|
||||
var response sdk.TxResponse
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), cmd, args)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// test sending to not allowed address
|
||||
args = []string{
|
||||
execMsg1.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
}
|
||||
out, err = clitestutil.ExecTestCLICmd(val.GetClientCtx(), cmd, args)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// query tx and check result
|
||||
err = s.network.RetryForBlocks(func() error {
|
||||
out, err = clitestutil.ExecTestCLICmd(val.GetClientCtx(), authcli.QueryTxCmd(), []string{response.TxHash, fmt.Sprintf("--%s=json", flags.FlagOutput)})
|
||||
return err
|
||||
}, 3)
|
||||
s.Require().NoError(err)
|
||||
s.Contains(out.String(), fmt.Sprintf("cannot send to %s address", notAllowedAddr))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestExecDelegateAuthorization() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[0]
|
||||
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
|
||||
|
||||
_, err := authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"delegate",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.GetValAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
tokens := sdk.NewCoins(
|
||||
sdk.NewCoin("stake", math.NewInt(50)),
|
||||
)
|
||||
|
||||
delegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgDelegate","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.GetAddress().String(), val.GetValAddress().String(),
|
||||
tokens.GetDenomByIndex(0), tokens[0].Amount)
|
||||
execMsg := testutil.WriteToNewTempFile(s.T(), delegateTx)
|
||||
defer execMsg.Close()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedCode uint32
|
||||
expectErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
"valid txn: (delegate half tokens)",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid txn: (delegate remaining half tokens)",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
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.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
authz.ErrNoAuthorizationFound.ABCICode(),
|
||||
false,
|
||||
authz.ErrNoAuthorizationFound.Error(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.errMsg)
|
||||
} else {
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, tc.expectedCode))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// test delegate no spend-limit
|
||||
_, err = authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"delegate",
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.GetValAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
tokens = sdk.NewCoins(
|
||||
sdk.NewCoin("stake", math.NewInt(50)),
|
||||
)
|
||||
|
||||
delegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgDelegate","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.GetAddress().String(), val.GetValAddress().String(),
|
||||
tokens.GetDenomByIndex(0), tokens[0].Amount)
|
||||
execMsg = testutil.WriteToNewTempFile(s.T(), delegateTx)
|
||||
defer execMsg.Close()
|
||||
|
||||
testCases = []struct {
|
||||
name string
|
||||
args []string
|
||||
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.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.errMsg)
|
||||
} else {
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, tc.expectedCode))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// test delegating to denied validator
|
||||
_, err = authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"delegate",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.GetValAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
args := []string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
}
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
out, err := clitestutil.ExecTestCLICmd(val.GetClientCtx(), cmd, args)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
|
||||
// query tx and check result
|
||||
err = s.network.RetryForBlocks(func() error {
|
||||
out, err = clitestutil.ExecTestCLICmd(val.GetClientCtx(), authcli.QueryTxCmd(), []string{response.TxHash, fmt.Sprintf("--%s=json", flags.FlagOutput)})
|
||||
return err
|
||||
}, 3)
|
||||
s.Require().NoError(err)
|
||||
s.Contains(out.String(), fmt.Sprintf("cannot delegate/undelegate to %s validator", val.GetValAddress().String()))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestExecUndelegateAuthorization() {
|
||||
val := s.network.GetValidators()[0]
|
||||
grantee := s.grantee[0]
|
||||
twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix()
|
||||
|
||||
// granting undelegate msg authorization
|
||||
_, err := authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"unbond",
|
||||
fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.GetValAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// delegating stakes to validator
|
||||
msg := &stakingtypes.MsgDelegate{
|
||||
DelegatorAddress: val.GetAddress().String(),
|
||||
ValidatorAddress: val.GetValAddress().String(),
|
||||
Amount: sdk.NewCoin("stake", math.NewInt(100)),
|
||||
}
|
||||
|
||||
_, err = clitestutil.SubmitTestTx(val.GetClientCtx(), msg, val.GetAddress(), clitestutil.TestTxConfig{})
|
||||
|
||||
s.Require().NoError(err)
|
||||
|
||||
tokens := sdk.NewCoins(
|
||||
sdk.NewCoin("stake", math.NewInt(50)),
|
||||
)
|
||||
|
||||
undelegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","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.GetAddress().String(), val.GetValAddress().String(),
|
||||
tokens.GetDenomByIndex(0), tokens[0].Amount)
|
||||
execMsg := testutil.WriteToNewTempFile(s.T(), undelegateTx)
|
||||
defer execMsg.Close()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedCode uint32
|
||||
expectErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
"valid txn: (undelegate half tokens)",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid txn: (undelegate remaining half tokens)",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"failed with error no authorization found",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
authz.ErrNoAuthorizationFound.ABCICode(),
|
||||
false,
|
||||
authz.ErrNoAuthorizationFound.Error(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.errMsg)
|
||||
} else {
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, tc.expectedCode))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// grant undelegate authorization without limit
|
||||
_, err = authzclitestutil.CreateGrant(
|
||||
val.GetClientCtx(),
|
||||
[]string{
|
||||
grantee.String(),
|
||||
"unbond",
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
|
||||
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.GetValAddress().String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
},
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
tokens = sdk.NewCoins(
|
||||
sdk.NewCoin("stake", math.NewInt(50)),
|
||||
)
|
||||
|
||||
undelegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","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.GetAddress().String(), val.GetValAddress().String(),
|
||||
tokens.GetDenomByIndex(0), tokens[0].Amount)
|
||||
execMsg = testutil.WriteToNewTempFile(s.T(), undelegateTx)
|
||||
defer execMsg.Close()
|
||||
|
||||
testCases = []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedCode uint32
|
||||
expectErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
"valid txn",
|
||||
[]string{
|
||||
execMsg.Name(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagGas, "250000"),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
},
|
||||
0,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
cmd := cli.NewCmdExecAuthorization()
|
||||
clientCtx := val.GetClientCtx()
|
||||
|
||||
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.errMsg)
|
||||
} else {
|
||||
var response sdk.TxResponse
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String())
|
||||
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.GetClientCtx(), response.TxHash, tc.expectedCode))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
849
tests/systemtests/authz_test.go
Normal file
849
tests/systemtests/authz_test.go
Normal file
@ -0,0 +1,849 @@
|
||||
//go:build system_test
|
||||
|
||||
package systemtests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
msgSendTypeURL = `/cosmos.bank.v1beta1.MsgSend`
|
||||
msgDelegateTypeURL = `/cosmos.staking.v1beta1.MsgDelegate`
|
||||
msgVoteTypeURL = `/cosmos.gov.v1.MsgVote`
|
||||
msgUndelegateTypeURL = `/cosmos.staking.v1beta1.MsgUndelegate`
|
||||
msgRedelegateTypeURL = `/cosmos.staking.v1beta1.MsgBeginRedelegate`
|
||||
sendAuthzTypeURL = `/cosmos.bank.v1beta1.SendAuthorization`
|
||||
genericAuthzTypeURL = `/cosmos.authz.v1beta1.GenericAuthorization`
|
||||
testDenom = "stake"
|
||||
)
|
||||
|
||||
func TestAuthzGrantTxCmd(t *testing.T) {
|
||||
// scenario: test authz grant command
|
||||
// given a running chain
|
||||
|
||||
sut.ResetChain(t)
|
||||
cli := NewCLIWrapper(t, sut, verbose)
|
||||
|
||||
// get validator address which will be used as granter
|
||||
granterAddr := cli.GetKeyAddr("node0")
|
||||
require.NotEmpty(t, granterAddr)
|
||||
|
||||
// add grantee keys which will be used for each valid transaction
|
||||
grantee1Addr := cli.AddKey("grantee1")
|
||||
grantee2Addr := cli.AddKey("grantee2")
|
||||
require.NotEqual(t, granterAddr, grantee2Addr)
|
||||
grantee3Addr := cli.AddKey("grantee3")
|
||||
require.NotEqual(t, granterAddr, grantee3Addr)
|
||||
grantee4Addr := cli.AddKey("grantee4")
|
||||
require.NotEqual(t, granterAddr, grantee4Addr)
|
||||
grantee5Addr := cli.AddKey("grantee5")
|
||||
require.NotEqual(t, granterAddr, grantee5Addr)
|
||||
grantee6Addr := cli.AddKey("grantee6")
|
||||
require.NotEqual(t, granterAddr, grantee6Addr)
|
||||
|
||||
sut.StartChain(t)
|
||||
|
||||
// query validator operator address
|
||||
rsp := cli.CustomQuery("q", "staking", "validators")
|
||||
valOperAddr := gjson.Get(rsp, "validators.#.operator_address").Array()[0].String()
|
||||
|
||||
grantCmdArgs := []string{"tx", "authz", "grant", "--from", granterAddr}
|
||||
expirationTime := time.Now().Add(time.Hour).Unix()
|
||||
|
||||
// test grant command
|
||||
testCases := []struct {
|
||||
name string
|
||||
grantee string
|
||||
cmdArgs []string
|
||||
expErrMsg string
|
||||
queryTx bool
|
||||
}{
|
||||
{
|
||||
"invalid authorization type",
|
||||
grantee1Addr,
|
||||
[]string{"spend"},
|
||||
"invalid authorization type",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"send authorization without spend-limit",
|
||||
grantee1Addr,
|
||||
[]string{"send"},
|
||||
"spend-limit should be greater than zero",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"generic authorization without msg type",
|
||||
grantee1Addr,
|
||||
[]string{"generic"},
|
||||
"msg type cannot be empty",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"delegate authorization without allow or deny list",
|
||||
grantee1Addr,
|
||||
[]string{"delegate"},
|
||||
"both allowed & deny list cannot be empty",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"delegate authorization with invalid allowed validator address",
|
||||
grantee1Addr,
|
||||
[]string{"delegate", "--allowed-validators=invalid"},
|
||||
"decoding bech32 failed",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"delegate authorization with invalid deny validator address",
|
||||
grantee1Addr,
|
||||
[]string{"delegate", "--deny-validators=invalid"},
|
||||
"decoding bech32 failed",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"unbond authorization without allow or deny list",
|
||||
grantee1Addr,
|
||||
[]string{"unbond"},
|
||||
"both allowed & deny list cannot be empty",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"unbond authorization with invalid allowed validator address",
|
||||
grantee1Addr,
|
||||
[]string{"unbond", "--allowed-validators=invalid"},
|
||||
"decoding bech32 failed",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"unbond authorization with invalid deny validator address",
|
||||
grantee1Addr,
|
||||
[]string{"unbond", "--deny-validators=invalid"},
|
||||
"decoding bech32 failed",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"redelegate authorization without allow or deny list",
|
||||
grantee1Addr,
|
||||
[]string{"redelegate"},
|
||||
"both allowed & deny list cannot be empty",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"redelegate authorization with invalid allowed validator address",
|
||||
grantee1Addr,
|
||||
[]string{"redelegate", "--allowed-validators=invalid"},
|
||||
"decoding bech32 failed",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"redelegate authorization with invalid deny validator address",
|
||||
grantee1Addr,
|
||||
[]string{"redelegate", "--deny-validators=invalid"},
|
||||
"decoding bech32 failed",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid send authorization",
|
||||
grantee1Addr,
|
||||
[]string{"send", "--spend-limit=1000" + testDenom},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid send authorization with expiration",
|
||||
grantee2Addr,
|
||||
[]string{"send", "--spend-limit=1000" + testDenom, fmt.Sprintf("--expiration=%d", expirationTime)},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid generic authorization",
|
||||
grantee3Addr,
|
||||
[]string{"generic", "--msg-type=" + msgVoteTypeURL},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid delegate authorization",
|
||||
grantee4Addr,
|
||||
[]string{"delegate", "--allowed-validators=" + valOperAddr},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid unbond authorization",
|
||||
grantee5Addr,
|
||||
[]string{"unbond", "--deny-validators=" + valOperAddr},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid redelegate authorization",
|
||||
grantee6Addr,
|
||||
[]string{"redelegate", "--allowed-validators=" + valOperAddr},
|
||||
"",
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
grantsCount := 0
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmd := append(append(grantCmdArgs, tc.grantee), tc.cmdArgs...)
|
||||
if tc.expErrMsg != "" {
|
||||
if tc.queryTx {
|
||||
rsp := cli.Run(cmd...)
|
||||
RequireTxFailure(t, rsp)
|
||||
require.Contains(t, rsp, tc.expErrMsg)
|
||||
} else {
|
||||
assertErr := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
|
||||
require.Len(t, gotOutputs, 1)
|
||||
output := gotOutputs[0].(string)
|
||||
require.Contains(t, output, tc.expErrMsg)
|
||||
return false
|
||||
}
|
||||
_ = cli.WithRunErrorMatcher(assertErr).Run(cmd...)
|
||||
}
|
||||
return
|
||||
}
|
||||
rsp := cli.RunAndWait(cmd...)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// query granter-grantee grants
|
||||
resp := cli.CustomQuery("q", "authz", "grants", granterAddr, tc.grantee)
|
||||
grants := gjson.Get(resp, "grants").Array()
|
||||
// check grants length equal to 1 to confirm grant created successfully
|
||||
require.Len(t, grants, 1)
|
||||
grantsCount++
|
||||
})
|
||||
}
|
||||
|
||||
// query grants-by-granter
|
||||
resp := cli.CustomQuery("q", "authz", "grants-by-granter", granterAddr)
|
||||
grants := gjson.Get(resp, "grants").Array()
|
||||
require.Len(t, grants, grantsCount)
|
||||
}
|
||||
|
||||
func TestAuthzExecSendAuthorization(t *testing.T) {
|
||||
// scenario: test authz exec send authorization
|
||||
// given a running chain
|
||||
|
||||
sut.ResetChain(t)
|
||||
cli := NewCLIWrapper(t, sut, verbose)
|
||||
|
||||
// get validator address which will be used as granter
|
||||
granterAddr := cli.GetKeyAddr("node0")
|
||||
require.NotEmpty(t, granterAddr)
|
||||
|
||||
// add grantee keys which will be used for each valid transaction
|
||||
granteeAddr := cli.AddKey("grantee")
|
||||
require.NotEqual(t, granterAddr, granteeAddr)
|
||||
allowedAddr := cli.AddKey("allowed")
|
||||
require.NotEqual(t, granteeAddr, allowedAddr)
|
||||
notAllowedAddr := cli.AddKey("notAllowed")
|
||||
require.NotEqual(t, granteeAddr, notAllowedAddr)
|
||||
newAccount := cli.AddKey("newAccount")
|
||||
require.NotEqual(t, granteeAddr, newAccount)
|
||||
|
||||
var initialAmount int64 = 10000000
|
||||
initialBalance := fmt.Sprintf("%d%s", initialAmount, testDenom)
|
||||
sut.ModifyGenesisCLI(t,
|
||||
[]string{"genesis", "add-genesis-account", granteeAddr, initialBalance},
|
||||
[]string{"genesis", "add-genesis-account", allowedAddr, initialBalance},
|
||||
[]string{"genesis", "add-genesis-account", newAccount, initialBalance},
|
||||
)
|
||||
sut.StartChain(t)
|
||||
|
||||
// query balances
|
||||
granterBal := cli.QueryBalance(granterAddr, testDenom)
|
||||
granteeBal := cli.QueryBalance(granteeAddr, testDenom)
|
||||
require.Equal(t, initialAmount, granteeBal)
|
||||
allowedAddrBal := cli.QueryBalance(allowedAddr, testDenom)
|
||||
require.Equal(t, initialAmount, allowedAddrBal)
|
||||
|
||||
var spendLimitAmount int64 = 1000
|
||||
expirationTime := time.Now().Add(time.Second * 10).Unix()
|
||||
|
||||
// test exec send authorization
|
||||
|
||||
// create send authorization grant
|
||||
rsp := cli.RunAndWait("tx", "authz", "grant", granteeAddr, "send",
|
||||
"--spend-limit="+fmt.Sprintf("%d%s", spendLimitAmount, testDenom),
|
||||
"--allow-list="+allowedAddr,
|
||||
"--expiration="+fmt.Sprintf("%d", expirationTime),
|
||||
"--fees=1"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
// reduce fees of above tx from granter balance
|
||||
granterBal--
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
grantee string
|
||||
toAddr string
|
||||
amount int64
|
||||
expErrMsg string
|
||||
}{
|
||||
{
|
||||
"valid exec transaction",
|
||||
granteeAddr,
|
||||
allowedAddr,
|
||||
20,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"send to not allowed address",
|
||||
granteeAddr,
|
||||
notAllowedAddr,
|
||||
10,
|
||||
"cannot send to",
|
||||
},
|
||||
{
|
||||
"amount greater than spend limit",
|
||||
granteeAddr,
|
||||
allowedAddr,
|
||||
spendLimitAmount + 5,
|
||||
"requested amount is more than spend limit",
|
||||
},
|
||||
{
|
||||
"no grant found",
|
||||
newAccount,
|
||||
granteeAddr,
|
||||
20,
|
||||
"authorization not found",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// msg send
|
||||
cmd := msgSendExec(t, granterAddr, tc.grantee, tc.toAddr, testDenom, tc.amount)
|
||||
if tc.expErrMsg != "" {
|
||||
rsp := cli.Run(cmd...)
|
||||
RequireTxFailure(t, rsp)
|
||||
require.Contains(t, rsp, tc.expErrMsg)
|
||||
return
|
||||
}
|
||||
rsp := cli.RunAndWait(cmd...)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// check granter balance equals to granterBal - transferredAmount
|
||||
expGranterBal := granterBal - tc.amount
|
||||
require.Equal(t, expGranterBal, cli.QueryBalance(granterAddr, testDenom))
|
||||
granterBal = expGranterBal
|
||||
|
||||
// check allowed addr balance equals to allowedAddrBal + transferredAmount
|
||||
expAllowAddrBal := allowedAddrBal + tc.amount
|
||||
require.Equal(t, expAllowAddrBal, cli.QueryBalance(allowedAddr, testDenom))
|
||||
allowedAddrBal = expAllowAddrBal
|
||||
})
|
||||
}
|
||||
|
||||
// test grant expiry
|
||||
time.Sleep(time.Second * 10)
|
||||
|
||||
execSendCmd := msgSendExec(t, granterAddr, granteeAddr, allowedAddr, testDenom, 10)
|
||||
rsp = cli.Run(execSendCmd...)
|
||||
RequireTxFailure(t, rsp)
|
||||
require.Contains(t, rsp, "authorization not found")
|
||||
}
|
||||
|
||||
func TestAuthzExecGenericAuthorization(t *testing.T) {
|
||||
// scenario: test authz exec generic authorization
|
||||
// given a running chain
|
||||
|
||||
cli, granterAddr, granteeAddr := setupChain(t)
|
||||
|
||||
allowedAddr := cli.AddKey("allowedAddr")
|
||||
require.NotEqual(t, granterAddr, allowedAddr)
|
||||
|
||||
// query balances
|
||||
granterBal := cli.QueryBalance(granterAddr, testDenom)
|
||||
|
||||
expirationTime := time.Now().Add(time.Second * 5).Unix()
|
||||
execSendCmd := msgSendExec(t, granterAddr, granteeAddr, allowedAddr, testDenom, 10)
|
||||
|
||||
// create generic authorization grant
|
||||
rsp := cli.RunAndWait("tx", "authz", "grant", granteeAddr, "generic",
|
||||
"--msg-type="+msgSendTypeURL,
|
||||
"--expiration="+fmt.Sprintf("%d", expirationTime),
|
||||
"--fees=1"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
granterBal--
|
||||
|
||||
rsp = cli.RunAndWait(execSendCmd...)
|
||||
RequireTxSuccess(t, rsp)
|
||||
// check granter balance equals to granterBal - transferredAmount
|
||||
expGranterBal := granterBal - 10
|
||||
require.Equal(t, expGranterBal, cli.QueryBalance(granterAddr, testDenom))
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
// check grants after expiration
|
||||
resp := cli.CustomQuery("q", "authz", "grants", granterAddr, granteeAddr)
|
||||
grants := gjson.Get(resp, "grants").Array()
|
||||
require.Len(t, grants, 0)
|
||||
}
|
||||
|
||||
func TestAuthzExecDelegateAuthorization(t *testing.T) {
|
||||
// scenario: test authz exec delegate authorization
|
||||
// given a running chain
|
||||
|
||||
cli, granterAddr, granteeAddr := setupChain(t)
|
||||
|
||||
// query balances
|
||||
granterBal := cli.QueryBalance(granterAddr, testDenom)
|
||||
|
||||
// query validator operator address
|
||||
rsp := cli.CustomQuery("q", "staking", "validators")
|
||||
validators := gjson.Get(rsp, "validators.#.operator_address").Array()
|
||||
require.GreaterOrEqual(t, len(validators), 2)
|
||||
val1Addr := validators[0].String()
|
||||
val2Addr := validators[1].String()
|
||||
|
||||
var spendLimitAmount int64 = 1000
|
||||
require.Greater(t, granterBal, spendLimitAmount)
|
||||
|
||||
rsp = cli.RunAndWait("tx", "authz", "grant", granteeAddr, "delegate",
|
||||
"--spend-limit="+fmt.Sprintf("%d%s", spendLimitAmount, testDenom),
|
||||
"--allowed-validators="+val1Addr,
|
||||
"--fees=1"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
// reduce fees of above tx from granter balance
|
||||
granterBal--
|
||||
|
||||
delegateTestCases := []struct {
|
||||
name string
|
||||
grantee string
|
||||
valAddr string
|
||||
amount int64
|
||||
expErrMsg string
|
||||
}{
|
||||
{
|
||||
"valid txn: (delegate half tokens)",
|
||||
granteeAddr,
|
||||
val1Addr,
|
||||
spendLimitAmount / 2,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"amount greater than spend limit",
|
||||
granteeAddr,
|
||||
val1Addr,
|
||||
spendLimitAmount + 5,
|
||||
"negative coin amount",
|
||||
},
|
||||
{
|
||||
"delegate to not allowed address",
|
||||
granteeAddr,
|
||||
val2Addr,
|
||||
10,
|
||||
"cannot delegate",
|
||||
},
|
||||
{
|
||||
"valid txn: (delegate remaining half tokens)",
|
||||
granteeAddr,
|
||||
val1Addr,
|
||||
spendLimitAmount / 2,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"no authorization found as grant prunes",
|
||||
granteeAddr,
|
||||
val1Addr,
|
||||
spendLimitAmount / 2,
|
||||
"authorization not found",
|
||||
},
|
||||
}
|
||||
|
||||
execCmdArgs := []string{"tx", "authz", "exec"}
|
||||
|
||||
for _, tc := range delegateTestCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
delegateTx := fmt.Sprintf(`{"@type":"%s","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%d"}}`,
|
||||
msgDelegateTypeURL, granterAddr, tc.valAddr, testDenom, tc.amount)
|
||||
execMsg := WriteToTempJSONFile(t, delegateTx)
|
||||
|
||||
cmd := append(append(execCmdArgs, execMsg.Name()), "--from="+tc.grantee)
|
||||
if tc.expErrMsg != "" {
|
||||
rsp := cli.Run(cmd...)
|
||||
RequireTxFailure(t, rsp)
|
||||
require.Contains(t, rsp, tc.expErrMsg)
|
||||
return
|
||||
}
|
||||
rsp := cli.RunAndWait(cmd...)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// check granter balance equals to granterBal - transferredAmount
|
||||
expGranterBal := granterBal - tc.amount
|
||||
require.Equal(t, expGranterBal, cli.QueryBalance(granterAddr, testDenom))
|
||||
granterBal = expGranterBal
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthzExecUndelegateAuthorization(t *testing.T) {
|
||||
// scenario: test authz exec undelegate authorization
|
||||
// given a running chain
|
||||
|
||||
cli, granterAddr, granteeAddr := setupChain(t)
|
||||
|
||||
// query validator operator address
|
||||
rsp := cli.CustomQuery("q", "staking", "validators")
|
||||
validators := gjson.Get(rsp, "validators.#.operator_address").Array()
|
||||
require.GreaterOrEqual(t, len(validators), 2)
|
||||
val1Addr := validators[0].String()
|
||||
val2Addr := validators[1].String()
|
||||
|
||||
// delegate some tokens
|
||||
rsp = cli.RunAndWait("tx", "staking", "delegate", val1Addr, "10000"+testDenom, "--from="+granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// query delegated tokens count
|
||||
resp := cli.CustomQuery("q", "staking", "delegation", granterAddr, val1Addr)
|
||||
delegatedAmount := gjson.Get(resp, "delegation_response.balance.amount").Int()
|
||||
|
||||
rsp = cli.RunAndWait("tx", "authz", "grant", granteeAddr, "unbond",
|
||||
"--allowed-validators="+val1Addr,
|
||||
"--fees=1"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
undelegateTestCases := []struct {
|
||||
name string
|
||||
grantee string
|
||||
valAddr string
|
||||
amount int64
|
||||
expErrMsg string
|
||||
}{
|
||||
{
|
||||
"valid transaction",
|
||||
granteeAddr,
|
||||
val1Addr,
|
||||
10,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"undelegate to not allowed address",
|
||||
granteeAddr,
|
||||
val2Addr,
|
||||
10,
|
||||
"cannot delegate/undelegate",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range undelegateTestCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
undelegateTx := fmt.Sprintf(`{"@type":"%s","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%d"}}`,
|
||||
msgUndelegateTypeURL, granterAddr, tc.valAddr, testDenom, tc.amount)
|
||||
execMsg := WriteToTempJSONFile(t, undelegateTx)
|
||||
|
||||
cmd := []string{"tx", "authz", "exec", execMsg.Name(), "--from=" + tc.grantee}
|
||||
if tc.expErrMsg != "" {
|
||||
rsp := cli.Run(cmd...)
|
||||
RequireTxFailure(t, rsp)
|
||||
require.Contains(t, rsp, tc.expErrMsg)
|
||||
return
|
||||
}
|
||||
rsp := cli.RunAndWait(cmd...)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// query delegation and check balance reduced
|
||||
expectedAmount := delegatedAmount - tc.amount
|
||||
resp = cli.CustomQuery("q", "staking", "delegation", granterAddr, val1Addr)
|
||||
delegatedAmount = gjson.Get(resp, "delegation_response.balance.amount").Int()
|
||||
require.Equal(t, expectedAmount, delegatedAmount)
|
||||
})
|
||||
}
|
||||
|
||||
// revoke existing grant
|
||||
rsp = cli.RunAndWait("tx", "authz", "revoke", granteeAddr, msgUndelegateTypeURL, "--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// check grants between granter and grantee after revoking
|
||||
resp = cli.CustomQuery("q", "authz", "grants", granterAddr, granteeAddr)
|
||||
grants := gjson.Get(resp, "grants").Array()
|
||||
require.Len(t, grants, 0)
|
||||
}
|
||||
|
||||
func TestAuthzExecRedelegateAuthorization(t *testing.T) {
|
||||
// scenario: test authz exec redelegate authorization
|
||||
// given a running chain
|
||||
|
||||
cli, granterAddr, granteeAddr := setupChain(t)
|
||||
|
||||
// query validator operator address
|
||||
rsp := cli.CustomQuery("q", "staking", "validators")
|
||||
validators := gjson.Get(rsp, "validators.#.operator_address").Array()
|
||||
require.GreaterOrEqual(t, len(validators), 2)
|
||||
val1Addr := validators[0].String()
|
||||
val2Addr := validators[1].String()
|
||||
|
||||
// delegate some tokens
|
||||
rsp = cli.RunAndWait("tx", "staking", "delegate", val1Addr, "10000"+testDenom, "--from="+granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// test exec redelegate authorization
|
||||
rsp = cli.RunAndWait("tx", "authz", "grant", granteeAddr, "redelegate",
|
||||
fmt.Sprintf("--allowed-validators=%s,%s", val1Addr, val2Addr),
|
||||
"--fees=1"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
var redelegationAmount int64 = 10
|
||||
|
||||
redelegateTx := fmt.Sprintf(`{"@type":"%s","delegator_address":"%s","validator_src_address":"%s","validator_dst_address":"%s","amount":{"denom":"%s","amount":"%d"}}`,
|
||||
msgRedelegateTypeURL, granterAddr, val1Addr, val2Addr, testDenom, redelegationAmount)
|
||||
execMsg := WriteToTempJSONFile(t, redelegateTx)
|
||||
|
||||
redelegateCmd := []string{"tx", "authz", "exec", execMsg.Name(), "--from=" + granteeAddr, "--gas=auto"}
|
||||
rsp = cli.RunAndWait(redelegateCmd...)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// query new delegation and check balance increased
|
||||
resp := cli.CustomQuery("q", "staking", "delegation", granterAddr, val2Addr)
|
||||
delegatedAmount := gjson.Get(resp, "delegation_response.balance.amount").Int()
|
||||
require.GreaterOrEqual(t, delegatedAmount, redelegationAmount)
|
||||
|
||||
// revoke all existing grants
|
||||
rsp = cli.RunAndWait("tx", "authz", "revoke-all", "--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
|
||||
// check grants after revoking
|
||||
resp = cli.CustomQuery("q", "authz", "grants-by-granter", granterAddr)
|
||||
grants := gjson.Get(resp, "grants").Array()
|
||||
require.Len(t, grants, 0)
|
||||
}
|
||||
|
||||
func TestAuthzGRPCQueries(t *testing.T) {
|
||||
// scenario: test authz grpc gateway queries
|
||||
// given a running chain
|
||||
|
||||
cli, granterAddr, grantee1Addr := setupChain(t)
|
||||
|
||||
grantee2Addr := cli.AddKey("grantee2")
|
||||
require.NotEqual(t, granterAddr, grantee2Addr)
|
||||
require.NotEqual(t, grantee1Addr, grantee2Addr)
|
||||
|
||||
// create few grants
|
||||
rsp := cli.RunAndWait("tx", "authz", "grant", grantee1Addr, "send",
|
||||
"--spend-limit=10000"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
grant1 := fmt.Sprintf(`"authorization":{"@type":"%s","spend_limit":[{"denom":"%s","amount":"10000"}],"allow_list":[]},"expiration":null`, sendAuthzTypeURL, testDenom)
|
||||
|
||||
rsp = cli.RunAndWait("tx", "authz", "grant", grantee2Addr, "send",
|
||||
"--spend-limit=1000"+testDenom,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
grant2 := fmt.Sprintf(`"authorization":{"@type":"%s","spend_limit":[{"denom":"%s","amount":"1000"}],"allow_list":[]},"expiration":null`, sendAuthzTypeURL, testDenom)
|
||||
|
||||
rsp = cli.RunAndWait("tx", "authz", "grant", grantee2Addr, "generic",
|
||||
"--msg-type="+msgVoteTypeURL,
|
||||
"--from", granterAddr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
grant3 := fmt.Sprintf(`"authorization":{"@type":"%s","msg":"%s"},"expiration":null`, genericAuthzTypeURL, msgVoteTypeURL)
|
||||
|
||||
rsp = cli.RunAndWait("tx", "authz", "grant", grantee2Addr, "generic",
|
||||
"--msg-type="+msgDelegateTypeURL,
|
||||
"--from", grantee1Addr)
|
||||
RequireTxSuccess(t, rsp)
|
||||
grant4 := fmt.Sprintf(`"authorization":{"@type":"%s","msg":"%s"},"expiration":null`, genericAuthzTypeURL, msgDelegateTypeURL)
|
||||
|
||||
baseurl := sut.APIAddress()
|
||||
|
||||
// test query grant grpc endpoint
|
||||
grantURL := baseurl + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s&msg_type_url=%s"
|
||||
|
||||
bech32FailOutput := `{"code":2, "message":"decoding bech32 failed: invalid separator index -1", "details":[]}`
|
||||
emptyStrOutput := `{"code":2, "message":"empty address string is not allowed", "details":[]}`
|
||||
invalidMsgTypeOutput := `{"code":2, "message":"codespace authz code 2: authorization not found: authorization not found for invalidMsg type", "details":[]}`
|
||||
expGrantOutput := fmt.Sprintf(`{"grants":[{%s}],"pagination":null}`, grant1)
|
||||
|
||||
grantTestCases := []GRPCTestCase{
|
||||
{
|
||||
"invalid granter address",
|
||||
fmt.Sprintf(grantURL, "invalid_granter", grantee1Addr, msgSendTypeURL),
|
||||
bech32FailOutput,
|
||||
},
|
||||
{
|
||||
"invalid grantee address",
|
||||
fmt.Sprintf(grantURL, granterAddr, "invalid_grantee", msgSendTypeURL),
|
||||
bech32FailOutput,
|
||||
},
|
||||
{
|
||||
"with empty granter",
|
||||
fmt.Sprintf(grantURL, "", grantee1Addr, msgSendTypeURL),
|
||||
emptyStrOutput,
|
||||
},
|
||||
{
|
||||
"with empty grantee",
|
||||
fmt.Sprintf(grantURL, granterAddr, "", msgSendTypeURL),
|
||||
emptyStrOutput,
|
||||
},
|
||||
{
|
||||
"invalid msg-type",
|
||||
fmt.Sprintf(grantURL, granterAddr, grantee1Addr, "invalidMsg"),
|
||||
invalidMsgTypeOutput,
|
||||
},
|
||||
{
|
||||
"valid grant query",
|
||||
fmt.Sprintf(grantURL, granterAddr, grantee1Addr, msgSendTypeURL),
|
||||
expGrantOutput,
|
||||
},
|
||||
}
|
||||
|
||||
RunGRPCQueries(t, grantTestCases)
|
||||
|
||||
// test query grants grpc endpoint
|
||||
grantsURL := baseurl + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s"
|
||||
|
||||
grantsTestCases := []GRPCTestCase{
|
||||
{
|
||||
"expect single grant",
|
||||
fmt.Sprintf(grantsURL, granterAddr, grantee1Addr),
|
||||
fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"1"}}`, grant1),
|
||||
},
|
||||
{
|
||||
"expect two grants",
|
||||
fmt.Sprintf(grantsURL, granterAddr, grantee2Addr),
|
||||
fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"2"}}`, grant2, grant3),
|
||||
},
|
||||
{
|
||||
"expect single grant with pagination",
|
||||
fmt.Sprintf(grantsURL+"&pagination.limit=1", granterAddr, grantee2Addr),
|
||||
fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":"L2Nvc21vcy5nb3YudjEuTXNnVm90ZQ==","total":"0"}}`, grant2),
|
||||
},
|
||||
{
|
||||
"expect single grant with pagination limit and offset",
|
||||
fmt.Sprintf(grantsURL+"&pagination.limit=1&pagination.offset=1", granterAddr, grantee2Addr),
|
||||
fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant3),
|
||||
},
|
||||
{
|
||||
"expect two grants with pagination",
|
||||
fmt.Sprintf(grantsURL+"&pagination.limit=2", granterAddr, grantee2Addr),
|
||||
fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant2, grant3),
|
||||
},
|
||||
}
|
||||
|
||||
RunGRPCQueries(t, grantsTestCases)
|
||||
|
||||
// test query grants by granter grpc endpoint
|
||||
grantsByGranterURL := baseurl + "/cosmos/authz/v1beta1/grants/granter/%s"
|
||||
decodingFailedOutput := `{"code":2, "message":"decoding bech32 failed: invalid character in string: ' '", "details":[]}`
|
||||
noAuthorizationsOutput := `{"grants":[],"pagination":{"next_key":null,"total":"0"}}`
|
||||
granterQueryOutput := fmt.Sprintf(`{"grants":[{"granter":"%s","grantee":"%s",%s}],"pagination":{"next_key":null,"total":"1"}}`,
|
||||
grantee1Addr, grantee2Addr, grant4)
|
||||
|
||||
granterTestCases := []GRPCTestCase{
|
||||
{
|
||||
"invalid granter account address",
|
||||
fmt.Sprintf(grantsByGranterURL, "invalid address"),
|
||||
decodingFailedOutput,
|
||||
},
|
||||
{
|
||||
"no authorizations found from granter",
|
||||
fmt.Sprintf(grantsByGranterURL, grantee2Addr),
|
||||
noAuthorizationsOutput,
|
||||
},
|
||||
{
|
||||
"valid granter query",
|
||||
fmt.Sprintf(grantsByGranterURL, grantee1Addr),
|
||||
granterQueryOutput,
|
||||
},
|
||||
}
|
||||
|
||||
RunGRPCQueries(t, granterTestCases)
|
||||
|
||||
// test query grants by grantee grpc endpoint
|
||||
grantsByGranteeURL := baseurl + "/cosmos/authz/v1beta1/grants/grantee/%s"
|
||||
grantee1GrantsOutput := fmt.Sprintf(`{"grants":[{"granter":"%s","grantee":"%s",%s}],"pagination":{"next_key":null,"total":"1"}}`, granterAddr, grantee1Addr, grant1)
|
||||
|
||||
granteeTestCases := []GRPCTestCase{
|
||||
{
|
||||
"invalid grantee account address",
|
||||
fmt.Sprintf(grantsByGranteeURL, "invalid address"),
|
||||
decodingFailedOutput,
|
||||
},
|
||||
{
|
||||
"no authorizations found from grantee",
|
||||
fmt.Sprintf(grantsByGranteeURL, granterAddr),
|
||||
noAuthorizationsOutput,
|
||||
},
|
||||
{
|
||||
"valid grantee query",
|
||||
fmt.Sprintf(grantsByGranteeURL, grantee1Addr),
|
||||
grantee1GrantsOutput,
|
||||
},
|
||||
}
|
||||
|
||||
RunGRPCQueries(t, granteeTestCases)
|
||||
}
|
||||
|
||||
func setupChain(t *testing.T) (*CLIWrapper, string, string) {
|
||||
t.Helper()
|
||||
|
||||
sut.ResetChain(t)
|
||||
cli := NewCLIWrapper(t, sut, verbose)
|
||||
|
||||
require.GreaterOrEqual(t, cli.nodesCount, 2)
|
||||
|
||||
// get validators' address which will be used as granter and grantee
|
||||
granterAddr := cli.GetKeyAddr("node0")
|
||||
require.NotEmpty(t, granterAddr)
|
||||
granteeAddr := cli.GetKeyAddr("node1")
|
||||
require.NotEmpty(t, granteeAddr)
|
||||
|
||||
sut.StartChain(t)
|
||||
|
||||
return cli, granterAddr, granteeAddr
|
||||
}
|
||||
|
||||
func msgSendExec(t *testing.T, granter, grantee, toAddr, denom string, amount int64) []string {
|
||||
t.Helper()
|
||||
|
||||
bankTx := fmt.Sprintf(`{
|
||||
"@type": "%s",
|
||||
"from_address": "%s",
|
||||
"to_address": "%s",
|
||||
"amount": [
|
||||
{
|
||||
"denom": "%s",
|
||||
"amount": "%d"
|
||||
}
|
||||
]
|
||||
}`, msgSendTypeURL, granter, toAddr, denom, amount)
|
||||
execMsg := WriteToTempJSONFile(t, bankTx)
|
||||
|
||||
execSendCmd := []string{"tx", "authz", "exec", execMsg.Name(), "--from=" + grantee}
|
||||
return execSendCmd
|
||||
}
|
||||
|
||||
// Write the given string to a new temporary json file.
|
||||
// Returns an file for the test to use.
|
||||
func WriteToTempJSONFile(tb testing.TB, s string) *os.File {
|
||||
tb.Helper()
|
||||
|
||||
tmpFile, err := os.CreateTemp(tb.TempDir(), "test-*.json")
|
||||
require.NoError(tb, err)
|
||||
|
||||
// Write to the temporary file
|
||||
_, err = tmpFile.WriteString(s)
|
||||
require.NoError(tb, err)
|
||||
|
||||
// Close the file after writing
|
||||
err = tmpFile.Close()
|
||||
require.NoError(tb, err)
|
||||
|
||||
return tmpFile
|
||||
}
|
||||
@ -23,7 +23,7 @@ func TestBankSendTxCmd(t *testing.T) {
|
||||
cli := NewCLIWrapper(t, sut, verbose)
|
||||
|
||||
// get validator address
|
||||
valAddr := gjson.Get(cli.Keys("keys", "list"), "1.address").String()
|
||||
valAddr := cli.GetKeyAddr("node0")
|
||||
require.NotEmpty(t, valAddr)
|
||||
|
||||
// add new key
|
||||
@ -131,28 +131,24 @@ func TestBankMultiSendTxCmd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
cmdArgs []string
|
||||
expectErr bool
|
||||
expectedCode uint32
|
||||
expErrMsg string
|
||||
}{
|
||||
{
|
||||
"valid transaction",
|
||||
append(multiSendCmdArgs, "--fees=1stake"),
|
||||
false,
|
||||
0,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"not enough arguments",
|
||||
[]string{"tx", "bank", "multi-send", account1Addr, account2Addr, "1000stake", "--from=" + account1Addr},
|
||||
true,
|
||||
0,
|
||||
"only received 3",
|
||||
},
|
||||
{
|
||||
"chain-id shouldn't be used with offline and generate-only flags",
|
||||
append(multiSendCmdArgs, "--generate-only", "--offline", "-a=0", "-s=4"),
|
||||
true,
|
||||
0,
|
||||
"chain ID cannot be used",
|
||||
},
|
||||
@ -160,7 +156,7 @@ func TestBankMultiSendTxCmd(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if tc.expectErr {
|
||||
if tc.expErrMsg != "" {
|
||||
assertErr := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
|
||||
require.Len(t, gotOutputs, 1)
|
||||
output := gotOutputs[0].(string)
|
||||
@ -173,24 +169,24 @@ func TestBankMultiSendTxCmd(t *testing.T) {
|
||||
return false // always abort
|
||||
}
|
||||
_ = cli.WithRunErrorMatcher(assertErr).Run(tc.cmdArgs...)
|
||||
} else {
|
||||
rsp := cli.Run(tc.cmdArgs...)
|
||||
txResult, found := cli.AwaitTxCommitted(rsp)
|
||||
require.True(t, found)
|
||||
RequireTxSuccess(t, txResult)
|
||||
// check account1 balance equals to account1Bal - transferredAmount*no_of_accounts - fees
|
||||
expAcc1Balance := account1Bal - (1000 * 2) - 1
|
||||
require.Equal(t, expAcc1Balance, cli.QueryBalance(account1Addr, denom))
|
||||
account1Bal = expAcc1Balance
|
||||
// check account2 balance equals to account2Bal + transferredAmount
|
||||
expAcc2Balance := account2Bal + 1000
|
||||
require.Equal(t, expAcc2Balance, cli.QueryBalance(account2Addr, denom))
|
||||
account2Bal = expAcc2Balance
|
||||
// check account3 balance equals to account3Bal + transferredAmount
|
||||
expAcc3Balance := account3Bal + 1000
|
||||
require.Equal(t, expAcc3Balance, cli.QueryBalance(account3Addr, denom))
|
||||
account3Bal = expAcc3Balance
|
||||
return
|
||||
}
|
||||
rsp := cli.Run(tc.cmdArgs...)
|
||||
txResult, found := cli.AwaitTxCommitted(rsp)
|
||||
require.True(t, found)
|
||||
RequireTxSuccess(t, txResult)
|
||||
// check account1 balance equals to account1Bal - transferredAmount*no_of_accounts - fees
|
||||
expAcc1Balance := account1Bal - (1000 * 2) - 1
|
||||
require.Equal(t, expAcc1Balance, cli.QueryBalance(account1Addr, denom))
|
||||
account1Bal = expAcc1Balance
|
||||
// check account2 balance equals to account2Bal + transferredAmount
|
||||
expAcc2Balance := account2Bal + 1000
|
||||
require.Equal(t, expAcc2Balance, cli.QueryBalance(account2Addr, denom))
|
||||
account2Bal = expAcc2Balance
|
||||
// check account3 balance equals to account3Bal + transferredAmount
|
||||
expAcc3Balance := account3Bal + 1000
|
||||
require.Equal(t, expAcc3Balance, cli.QueryBalance(account3Addr, denom))
|
||||
account3Bal = expAcc3Balance
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -224,7 +220,7 @@ func TestBankGRPCQueries(t *testing.T) {
|
||||
|
||||
// start chain
|
||||
sut.StartChain(t)
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
baseurl := sut.APIAddress()
|
||||
|
||||
// test supply grpc endpoint
|
||||
supplyUrl := baseurl + "/cosmos/bank/v1beta1/supply"
|
||||
@ -283,45 +279,31 @@ func TestBankGRPCQueries(t *testing.T) {
|
||||
|
||||
// test denom metadata endpoint
|
||||
denomMetadataUrl := baseurl + "/cosmos/bank/v1beta1/denoms_metadata"
|
||||
dmTestCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expOut string
|
||||
}{
|
||||
dmTestCases := []GRPCTestCase{
|
||||
{
|
||||
"test GRPC client metadata",
|
||||
denomMetadataUrl,
|
||||
bankDenomMetadata,
|
||||
fmt.Sprintf(`{"metadatas":%s,"pagination":{"next_key":null,"total":"2"}}`, bankDenomMetadata),
|
||||
},
|
||||
{
|
||||
"test GRPC client metadata of a specific denom",
|
||||
denomMetadataUrl + "/uatom",
|
||||
atomDenomMetadata,
|
||||
fmt.Sprintf(`{"metadata":%s}`, atomDenomMetadata),
|
||||
},
|
||||
{
|
||||
"test GRPC client metadata of a bogus denom",
|
||||
denomMetadataUrl + "/foobar",
|
||||
`"details":[]`,
|
||||
`{"code":5, "message":"client metadata for denom foobar", "details":[]}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range dmTestCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, string(resp), tc.expOut)
|
||||
})
|
||||
}
|
||||
RunGRPCQueries(t, dmTestCases)
|
||||
|
||||
// test bank balances endpoint
|
||||
balanceUrl := baseurl + "/cosmos/bank/v1beta1/balances/"
|
||||
allBalancesOutput := `{"balances":[` + specificDenomOutput + `,{"denom":"stake","amount":"10000000"}],"pagination":{"next_key":null,"total":"2"}}`
|
||||
|
||||
balanceTestCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expOut string
|
||||
}{
|
||||
balanceTestCases := []GRPCTestCase{
|
||||
{
|
||||
"test GRPC total account balance",
|
||||
balanceUrl + account1Addr,
|
||||
@ -330,20 +312,14 @@ func TestBankGRPCQueries(t *testing.T) {
|
||||
{
|
||||
"test GRPC account balance of a specific denom",
|
||||
fmt.Sprintf("%s%s/by_denom?denom=%s", balanceUrl, account1Addr, newDenom),
|
||||
specificDenomOutput,
|
||||
fmt.Sprintf(`{"balance":%s}`, specificDenomOutput),
|
||||
},
|
||||
{
|
||||
"test GRPC account balance of a bogus denom",
|
||||
fmt.Sprintf("%s%s/by_denom?denom=foobar", balanceUrl, account1Addr),
|
||||
bogusDenomOutput,
|
||||
fmt.Sprintf(`{"balance":%s}`, bogusDenomOutput),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range balanceTestCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, string(resp), tc.expOut)
|
||||
})
|
||||
}
|
||||
RunGRPCQueries(t, balanceTestCases)
|
||||
}
|
||||
|
||||
29
tests/systemtests/rest_cli.go
Normal file
29
tests/systemtests/rest_cli.go
Normal file
@ -0,0 +1,29 @@
|
||||
package systemtests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
)
|
||||
|
||||
type GRPCTestCase struct {
|
||||
name string
|
||||
url string
|
||||
expOut string
|
||||
}
|
||||
|
||||
// RunGRPCQueries runs given grpc testcases by making requests and
|
||||
// checking response with expected output
|
||||
func RunGRPCQueries(t *testing.T, testCases []GRPCTestCase) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resp, err := testutil.GetRequest(tc.url)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, tc.expOut, string(resp))
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -53,6 +53,7 @@ type SystemUnderTest struct {
|
||||
// since Tendermint consensus does not allow specifying it directly.
|
||||
blockTime time.Duration
|
||||
rpcAddr string
|
||||
apiAddr string
|
||||
initialNodesCount int
|
||||
nodesCount int
|
||||
minGasPrice string
|
||||
@ -86,6 +87,7 @@ func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTi
|
||||
outputDir: "./testnet",
|
||||
blockTime: blockTime,
|
||||
rpcAddr: "tcp://localhost:26657",
|
||||
apiAddr: fmt.Sprintf("http://localhost:%d", apiPortStart),
|
||||
initialNodesCount: nodesCount,
|
||||
outBuff: ring.New(100),
|
||||
errBuff: ring.New(100),
|
||||
@ -638,6 +640,10 @@ func (s *SystemUnderTest) RPCClient(t *testing.T) RPCClient {
|
||||
return NewRPCClient(t, s.rpcAddr)
|
||||
}
|
||||
|
||||
func (s *SystemUnderTest) APIAddress() string {
|
||||
return s.apiAddr
|
||||
}
|
||||
|
||||
func (s *SystemUnderTest) AllPeers(t *testing.T) []string {
|
||||
t.Helper()
|
||||
result := make([]string, s.nodesCount)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user