diff --git a/x/authz/keeper/keeper.go b/x/authz/keeper/keeper.go index 1b8ec0bf945b..4ab131b8c772 100644 --- a/x/authz/keeper/keeper.go +++ b/x/authz/keeper/keeper.go @@ -194,6 +194,25 @@ func (k Keeper) GetCleanAuthorization(ctx sdk.Context, grantee sdk.AccAddress, g return grant.GetAuthorization(), grant.Expiration } +// GetAuthorization returns an Authorization and it's expiration time. +// A nil Authorization is returned under the following circumstances: +// - No grant is found. +// - A grant is found, but it is expired. +// - There was an error getting the authorization from the grant. +func (k Keeper) GetAuthorization(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) (authz.Authorization, *time.Time) { + grant, found := k.getGrant(ctx, grantStoreKey(grantee, granter, msgType)) + if !found || (grant.Expiration != nil && grant.Expiration.Before(ctx.BlockHeader().Time)) { + return nil, nil + } + + auth, err := grant.GetAuthorization() + if err != nil { + return nil, nil + } + + return auth, grant.Expiration +} + // IterateGrants iterates over all authorization grants // This function should be used with caution because it can involve significant IO operations. // It should not be used in query or msg services without charging additional gas. diff --git a/x/authz/keeper/keeper_test.go b/x/authz/keeper/keeper_test.go index 0421590b7dcb..904ee7f02901 100644 --- a/x/authz/keeper/keeper_test.go +++ b/x/authz/keeper/keeper_test.go @@ -16,7 +16,10 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) -var bankSendAuthMsgType = banktypes.SendAuthorization{}.MsgTypeURL() +var ( + bankSendAuthMsgType = banktypes.SendAuthorization{}.MsgTypeURL() + coins10 = sdk.NewCoins(sdk.NewInt64Coin("stake", 10)) +) type TestSuite struct { suite.Suite @@ -40,7 +43,7 @@ func (s *TestSuite) SetupTest() { s.app = app s.ctx = ctx s.queryClient = queryClient - s.addrs = simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(30000000)) + s.addrs = simapp.AddTestAddrsIncremental(app, ctx, 7, sdk.NewInt(30000000)) } func (s *TestSuite) TestKeeper() { @@ -244,6 +247,85 @@ func (s *TestSuite) TestDispatchedEvents() { } } +func (s *TestSuite) TestGetAuthorization() { + addr1 := s.addrs[3] + addr2 := s.addrs[4] + addr3 := s.addrs[5] + addr4 := s.addrs[6] + + genAuthMulti := authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktypes.MsgMultiSend{})) + genAuthSend := authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktypes.MsgSend{})) + sendAuth := banktypes.NewSendAuthorization(coins10) + + start := s.ctx.BlockHeader().Time + expired := start.Add(time.Duration(1) * time.Second) + notExpired := start.Add(time.Duration(5) * time.Hour) + + s.Require().NoError(s.app.AuthzKeeper.SaveGrant(s.ctx, addr1, addr2, genAuthMulti, nil), "creating grant 1->2") + s.Require().NoError(s.app.AuthzKeeper.SaveGrant(s.ctx, addr1, addr3, genAuthSend, &expired), "creating grant 1->3") + s.Require().NoError(s.app.AuthzKeeper.SaveGrant(s.ctx, addr1, addr4, sendAuth, ¬Expired), "creating grant 1->4") + // Without access to private keeper methods, I don't know how to save a grant with an invalid authorization. + newCtx := s.ctx.WithBlockTime(start.Add(time.Duration(1) * time.Minute)) + + tests := []struct { + name string + grantee sdk.AccAddress + granter sdk.AccAddress + msgType string + expAuth authz.Authorization + expExp *time.Time + }{ + { + name: "grant has nil exp and is returned", + grantee: addr1, + granter: addr2, + msgType: genAuthMulti.MsgTypeURL(), + expAuth: genAuthMulti, + expExp: nil, + }, + { + name: "grant is expired not returned", + grantee: addr1, + granter: addr3, + msgType: genAuthSend.MsgTypeURL(), + expAuth: nil, + expExp: nil, + }, + { + name: "grant is not expired and is returned", + grantee: addr1, + granter: addr4, + msgType: sendAuth.MsgTypeURL(), + expAuth: sendAuth, + expExp: ¬Expired, + }, + { + name: "grant is not expired but wrong msg type returns nil", + grantee: addr1, + granter: addr4, + msgType: genAuthMulti.MsgTypeURL(), + expAuth: nil, + expExp: nil, + }, + { + name: "no grant exists between the two", + grantee: addr2, + granter: addr3, + msgType: genAuthSend.MsgTypeURL(), + expAuth: nil, + expExp: nil, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + actAuth, actExp := s.app.AuthzKeeper.GetAuthorization(newCtx, tc.grantee, tc.granter, tc.msgType) + s.Assert().Equal(tc.expAuth, actAuth, "authorization") + s.Assert().Equal(tc.expExp, actExp, "expiration") + }) + } +} + func TestTestSuite(t *testing.T) { suite.Run(t, new(TestSuite)) }