cosmos-sdk/x/authz/keeper/keeper_test.go

254 lines
8.8 KiB
Go

package keeper_test
import (
"testing"
"time"
"github.com/stretchr/testify/suite"
tmtime "github.com/tendermint/tendermint/libs/time"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
var bankSendAuthMsgType = banktypes.SendAuthorization{}.MsgTypeURL()
type TestSuite struct {
suite.Suite
app *simapp.SimApp
ctx sdk.Context
addrs []sdk.AccAddress
queryClient authz.QueryClient
}
func (s *TestSuite) SetupTest() {
app := simapp.Setup(s.T(), false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
now := tmtime.Now()
ctx = ctx.WithBlockHeader(tmproto.Header{Time: now})
queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
authz.RegisterQueryServer(queryHelper, app.AuthzKeeper)
queryClient := authz.NewQueryClient(queryHelper)
s.queryClient = queryClient
s.app = app
s.ctx = ctx
s.queryClient = queryClient
s.addrs = simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(30000000))
}
func (s *TestSuite) TestKeeper() {
app, ctx, addrs := s.app, s.ctx, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
recipientAddr := addrs[2]
s.T().Log("verify that no authorization returns nil")
authorization, expiration := app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().Nil(authorization)
s.Require().Equal(expiration, time.Time{})
now := s.ctx.BlockHeader().Time
s.Require().NotNil(now)
newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
s.T().Log("verify if expired authorization is rejected")
x := &banktypes.SendAuthorization{SpendLimit: newCoins}
err := app.AuthzKeeper.SaveGrant(ctx, granterAddr, granteeAddr, x, now.Add(-1*time.Hour))
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().Nil(authorization)
s.T().Log("verify if authorization is accepted")
x = &banktypes.SendAuthorization{SpendLimit: newCoins}
err = app.AuthzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, x, now.Add(time.Hour))
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().NotNil(authorization)
s.Require().Equal(authorization.MsgTypeURL(), bankSendAuthMsgType)
s.T().Log("verify fetching authorization with wrong msg type fails")
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, sdk.MsgTypeURL(&banktypes.MsgMultiSend{}))
s.Require().Nil(authorization)
s.T().Log("verify fetching authorization with wrong grantee fails")
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, recipientAddr, granterAddr, bankSendAuthMsgType)
s.Require().Nil(authorization)
s.T().Log("verify revoke fails with wrong information")
err = app.AuthzKeeper.DeleteGrant(ctx, recipientAddr, granterAddr, bankSendAuthMsgType)
s.Require().Error(err)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, recipientAddr, granterAddr, bankSendAuthMsgType)
s.Require().Nil(authorization)
s.T().Log("verify revoke executes with correct information")
err = app.AuthzKeeper.DeleteGrant(ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().Nil(authorization)
}
func (s *TestSuite) TestKeeperIter() {
app, ctx, addrs := s.app, s.ctx, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
s.T().Log("verify that no authorization returns nil")
authorization, expiration := app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, "Abcd")
s.Require().Nil(authorization)
s.Require().Equal(time.Time{}, expiration)
now := s.ctx.BlockHeader().Time
s.Require().NotNil(now)
newCoins := sdk.NewCoins(sdk.NewInt64Coin("steak", 100))
s.T().Log("verify if expired authorization is rejected")
x := &banktypes.SendAuthorization{SpendLimit: newCoins}
err := app.AuthzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, x, now.Add(-1*time.Hour))
s.Require().NoError(err)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(ctx, granteeAddr, granterAddr, "abcd")
s.Require().Nil(authorization)
app.AuthzKeeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool {
s.Require().Equal(granter, granterAddr)
s.Require().Equal(grantee, granteeAddr)
return true
})
}
func (s *TestSuite) TestKeeperFees() {
app, addrs := s.app, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
recipientAddr := addrs[2]
s.Require().NoError(testutil.FundAccount(app.BankKeeper, s.ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000))))
now := s.ctx.BlockHeader().Time
s.Require().NotNil(now)
smallCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 20))
someCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 123))
msgs := authz.NewMsgExec(granteeAddr, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
})
s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec()))
s.T().Log("verify dispatch fails with invalid authorization")
executeMsgs, err := msgs.GetMessages()
s.Require().NoError(err)
result, err := app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
s.Require().Nil(result)
s.Require().NotNil(err)
s.T().Log("verify dispatch executes with correct information")
// grant authorization
err = app.AuthzKeeper.SaveGrant(s.ctx, granteeAddr, granterAddr, &banktypes.SendAuthorization{SpendLimit: smallCoin}, now)
s.Require().NoError(err)
authorization, _ := app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().NotNil(authorization)
s.Require().Equal(authorization.MsgTypeURL(), bankSendAuthMsgType)
executeMsgs, err = msgs.GetMessages()
s.Require().NoError(err)
result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
s.Require().NoError(err)
s.Require().NotNil(result)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().NotNil(authorization)
s.T().Log("verify dispatch fails with overlimit")
// grant authorization
msgs = authz.NewMsgExec(granteeAddr, []sdk.Msg{
&banktypes.MsgSend{
Amount: someCoin,
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
})
s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec()))
executeMsgs, err = msgs.GetMessages()
s.Require().NoError(err)
result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
s.Require().Nil(result)
s.Require().NotNil(err)
authorization, _ = app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
s.Require().NotNil(authorization)
}
// Tests that all msg events included in an authz MsgExec tx
// Ref: https://github.com/cosmos/cosmos-sdk/issues/9501
func (s *TestSuite) TestDispatchedEvents() {
require := s.Require()
app, addrs := s.app, s.addrs
granterAddr := addrs[0]
granteeAddr := addrs[1]
recipientAddr := addrs[2]
require.NoError(testutil.FundAccount(app.BankKeeper, s.ctx, granterAddr, sdk.NewCoins(sdk.NewInt64Coin("steak", 10000))))
now := s.ctx.BlockHeader().Time
require.NotNil(now)
smallCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 20))
msgs := authz.NewMsgExec(granteeAddr, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
})
// grant authorization
err := app.AuthzKeeper.SaveGrant(s.ctx, granteeAddr, granterAddr, &banktypes.SendAuthorization{SpendLimit: smallCoin}, now)
require.NoError(err)
authorization, _ := app.AuthzKeeper.GetCleanAuthorization(s.ctx, granteeAddr, granterAddr, bankSendAuthMsgType)
require.NotNil(authorization)
require.Equal(authorization.MsgTypeURL(), bankSendAuthMsgType)
executeMsgs, err := msgs.GetMessages()
require.NoError(err)
result, err := app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
require.NoError(err)
require.NotNil(result)
events := s.ctx.EventManager().Events()
// get last 5 events (events that occur *after* the grant)
events = events[len(events)-5:]
requiredEvents := map[string]bool{
"coin_spent": false,
"coin_received": false,
"transfer": false,
"message": false,
}
for _, e := range events {
requiredEvents[e.Type] = true
}
for _, v := range requiredEvents {
require.True(v)
}
}
func TestTestSuite(t *testing.T) {
suite.Run(t, new(TestSuite))
}