Skip to content

Commit

Permalink
feat: Enhancement storage module (#102)
Browse files Browse the repository at this point in the history
* enhancement storage module
* add group test
  • Loading branch information
fynnss authored Mar 14, 2023
1 parent fdd68f3 commit 8b9d8a8
Show file tree
Hide file tree
Showing 21 changed files with 3,677 additions and 971 deletions.
12 changes: 12 additions & 0 deletions e2e/tests/permission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/bnb-chain/greenfield/e2e/core"
storageutil "github.com/bnb-chain/greenfield/testutil/storage"
types2 "github.com/bnb-chain/greenfield/types"
"github.com/bnb-chain/greenfield/types/resource"
"github.com/bnb-chain/greenfield/x/permission/types"
storagetypes "github.com/bnb-chain/greenfield/x/storage/types"
)
Expand Down Expand Up @@ -81,7 +82,18 @@ func (s *StorageTestSuite) TestDeleteBucketPermission() {
s.T().Logf("resp: %s, rep %s", verifyPermReq.String(), verifyPermResp.String())
s.Require().NoError(err)
s.Require().Equal(verifyPermResp.Effect, types.EFFECT_ALLOW)

// Query bucket policy
grn := types2.NewBucketGRN(bucketName)
queryPolicyForAccountReq := storagetypes.QueryPolicyForAccountRequest{Resource: grn.String(),
PrincipalAddress: user[1].GetAddr().String()}
queryPolicyForAccountResp, err := s.Client.QueryPolicyForAccount(ctx, &queryPolicyForAccountReq)
s.Require().NoError(err)
s.Require().Equal(queryPolicyForAccountResp.Policy.ResourceType, resource.RESOURCE_TYPE_BUCKET)
s.Require().Equal(queryPolicyForAccountResp.Policy.ResourceId, queryHeadBucketResponse.BucketInfo.Id)

// DeleteBucket
msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user[1].GetAddr(), bucketName)
s.SendTxBlock(msgDeleteBucket, user[1])

}
58 changes: 58 additions & 0 deletions e2e/tests/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"fmt"
"math"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -187,6 +188,63 @@ func (s *StorageTestSuite) TestCreateObject() {
s.SendTxBlock(msgDeleteBucket, user)
}

func (s *StorageTestSuite) TestCreateGroup() {
ctx := context.Background()

owner := s.GenAndChargeAccounts(1, 1000000)[0]
member := s.GenAndChargeAccounts(1, 1000000)[0]
groupName := storageutils.GenRandomGroupName()

// 1. CreateGroup
msgCreateGroup := storagetypes.NewMsgCreateGroup(owner.GetAddr(), groupName, []sdk.AccAddress{member.GetAddr()})
s.SendTxBlock(msgCreateGroup, owner)
s.T().Logf("CerateGroup success, owner: %s, group name: %s", owner.GetAddr().String(), groupName)

// 2. HeadGroup
queryHeadGroupReq := storagetypes.QueryHeadGroupRequest{GroupOwner: owner.GetAddr().String(), GroupName: groupName}
queryHeadGroupResp, err := s.Client.HeadGroup(ctx, &queryHeadGroupReq)
s.Require().NoError(err)
s.Require().Equal(queryHeadGroupResp.GroupInfo.GroupName, groupName)
s.Require().Equal(queryHeadGroupResp.GroupInfo.Owner, owner.GetAddr().String())

// 3. HeadGroupMember
queryHeadGroupMemberReq := storagetypes.QueryHeadGroupMemberRequest{
Member: member.GetAddr().String(),
GroupName: groupName,
GroupOwner: owner.GetAddr().String(),
}
queryHeadGroupMemberResp, err := s.Client.HeadGroupMember(ctx, &queryHeadGroupMemberReq)
s.Require().NoError(err)
s.Require().Equal(queryHeadGroupMemberResp.GroupInfo.GroupName, groupName)
s.Require().Equal(queryHeadGroupMemberResp.GroupInfo.Owner, owner.GetAddr().String())

// 4. UpdateGroupMember
member2 := s.GenAndChargeAccounts(1, 1000000)[0]
membersToAdd := []sdk.AccAddress{member2.GetAddr()}
membersToDelete := []sdk.AccAddress{member.GetAddr()}
msgUpdateGroupMember := storagetypes.NewMsgUpdateGroupMember(owner.GetAddr(), groupName, membersToAdd, membersToDelete)
s.SendTxBlock(msgUpdateGroupMember, owner)

// 5. HeadGroupMember (delete)
queryHeadGroupMemberReqDelete := storagetypes.QueryHeadGroupMemberRequest{
Member: member.GetAddr().String(),
GroupName: groupName,
GroupOwner: owner.GetAddr().String(),
}
_, err = s.Client.HeadGroupMember(ctx, &queryHeadGroupMemberReqDelete)
s.Require().True(strings.Contains(err.Error(), storagetypes.ErrNoSuchGroupMember.Error()))
// 5. HeadGroupMember (add)
queryHeadGroupMemberReqAdd := storagetypes.QueryHeadGroupMemberRequest{
Member: member2.GetAddr().String(),
GroupName: groupName,
GroupOwner: owner.GetAddr().String(),
}
queryHeadGroupMemberRespAdd, err := s.Client.HeadGroupMember(ctx, &queryHeadGroupMemberReqAdd)
s.Require().NoError(err)
s.Require().Equal(queryHeadGroupMemberRespAdd.GroupInfo.GroupName, groupName)
s.Require().Equal(queryHeadGroupMemberRespAdd.GroupInfo.Owner, owner.GetAddr().String())
}

func (s *StorageTestSuite) TestDeleteBucket() {
var err error
user := s.GenAndChargeAccounts(1, 1000000)[0]
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ require (
github.com/cosmos/cosmos-proto v1.0.0-beta.1
github.com/cosmos/cosmos-sdk v0.46.4
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/gogoproto v1.4.6
github.com/cosmos/ibc-go/v5 v5.0.0
github.com/ethereum/go-ethereum v1.10.19
github.com/evmos/ethermint v0.6.1-0.20220919141022-34226aa7b1fa //TODO: update to ethermint v0.20.0 after it's released.
Expand All @@ -34,6 +33,8 @@ require (
sigs.k8s.io/yaml v1.3.0
)

require github.com/cosmos/gogoproto v1.4.6

require (
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
Expand Down
78 changes: 69 additions & 9 deletions proto/greenfield/storage/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ service Query {
option (google.api.http).get = "/greenfield/storage/head_object/{bucket_name}/{object_name}";
}

// Queries a object by id
// Queries an object by id
rpc HeadObjectById(QueryHeadObjectByIdRequest) returns (QueryHeadObjectResponse) {
option (google.api.http).get = "/greenfield/storage/head_object_by_id/{object_id}";
}
Expand Down Expand Up @@ -73,15 +73,36 @@ service Query {
rpc HeadGroupNFT(QueryNFTRequest) returns (QueryGroupNFTResponse) {
option (google.api.http).get = "/greenfield/storage/head_group_nft/{token_id}";
}
// Queries policy by policyID
rpc GetPolicy(QueryGetPolicyRequest) returns (QueryGetPolicyResponse) {
option (google.api.http).get = "/greenfield/storage/get_policy/{policy_id}";

// Queries a policy which grants permission to account
rpc QueryPolicyForAccount(QueryPolicyForAccountRequest) returns (QueryPolicyForAccountResponse) {
option (google.api.http).get = "/greenfield/storage/policy_for_account/{resource}/{principal_address}";
}

// Queries a list of VerifyPermission items.
rpc VerifyPermission(QueryVerifyPermissionRequest) returns (QueryVerifyPermissionResponse) {
option (google.api.http).get = "/greenfield/storage/verify_permission/{operator}/{bucket_name}/{object_name}/{action_type}";
}

// Queries a group with specify owner and name .
rpc HeadGroup(QueryHeadGroupRequest) returns (QueryHeadGroupResponse) {
option (google.api.http).get = "/greenfield/storage/head_group/{group_owner}/{group_name}";
}

// Queries a list of ListGroup items.
rpc ListGroup(QueryListGroupRequest) returns (QueryListGroupResponse) {
option (google.api.http).get = "/bnb-chain/greenfield/storage/list_group";
}

// Queries a list of HeadGroupMember items.
rpc HeadGroupMember(QueryHeadGroupMemberRequest) returns (QueryHeadGroupMemberResponse) {
option (google.api.http).get = "/bnb-chain/greenfield/storage/head_group_member";
}

// Queries a policy that grants permission to a group
rpc QueryPolicyForGroup(QueryPolicyForGroupRequest) returns (QueryPolicyForGroupResponse) {
option (google.api.http).get = "/bnb-chain/greenfield/storage/policy_for_group/{resource}/{principal_group_id}";
}
}

// QueryParamsRequest is request type for the Query/Params RPC method.
Expand Down Expand Up @@ -124,7 +145,7 @@ message QueryListBucketsRequest {
}

message QueryListBucketsResponse {
repeated BucketInfo bucket_infos = 1 [(gogoproto.nullable) = false];
repeated BucketInfo bucket_infos = 1;
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

Expand All @@ -139,7 +160,7 @@ message QueryListObjectsByBucketIdRequest {
}

message QueryListObjectsResponse {
repeated ObjectInfo object_infos = 1 [(gogoproto.nullable) = false];
repeated ObjectInfo object_infos = 1;
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

Expand All @@ -159,11 +180,12 @@ message QueryGroupNFTResponse {
GroupMetaData meta_data = 1;
}

message QueryGetPolicyRequest {
string policy_id = 1;
message QueryPolicyForAccountRequest {
string resource = 1;
string principal_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

message QueryGetPolicyResponse {
message QueryPolicyForAccountResponse {
permission.Policy policy = 1;
}

Expand All @@ -177,3 +199,41 @@ message QueryVerifyPermissionRequest {
message QueryVerifyPermissionResponse {
permission.Effect effect = 1;
}

message QueryHeadGroupRequest {
string group_owner = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string group_name = 2;
}

message QueryHeadGroupResponse {
GroupInfo group_info = 1;
}

message QueryListGroupRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
string group_owner = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

message QueryListGroupResponse {
cosmos.base.query.v1beta1.PageResponse pagination = 1;
repeated GroupInfo group_infos = 2;
}

message QueryHeadGroupMemberRequest {
string member = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string group_owner = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string group_name = 3;
}

message QueryHeadGroupMemberResponse {
GroupInfo group_info = 1;
}

message QueryPolicyForGroupRequest {
string resource = 1;
string principal_group_id = 2;
}

message QueryPolicyForGroupResponse {
permission.Policy policy = 1;
}
47 changes: 34 additions & 13 deletions x/permission/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {

func (k Keeper) AddGroupMember(ctx sdk.Context, groupID math.Uint, member sdk.AccAddress) error {
store := ctx.KVStore(k.storeKey)
policy, found := k.getPolicyToAccount(ctx, groupID, resource.RESOURCE_TYPE_GROUP, member)
policy, found := k.GetPolicyForAccount(ctx, groupID, resource.RESOURCE_TYPE_GROUP, member)
if !found {
policy = types.NewDefaultPolicyForGroupMember(groupID, member)
policy.Id = k.policySeq.NextVal(store)
Expand All @@ -77,11 +77,11 @@ func (k Keeper) AddGroupMember(ctx sdk.Context, groupID math.Uint, member sdk.Ac
func (k Keeper) RemoveGroupMember(ctx sdk.Context, groupID math.Uint, member sdk.AccAddress) {
store := ctx.KVStore(k.storeKey)

policy, found := k.getPolicyToAccount(ctx, groupID, resource.RESOURCE_TYPE_GROUP, member)
policy, found := k.GetPolicyForAccount(ctx, groupID, resource.RESOURCE_TYPE_GROUP, member)
if found {
if policy.Statements == nil {
store.Delete(types.GetPolicyByIDKey(policy.Id))
store.Delete(types.GetPolicyToAccountKey(groupID, resource.RESOURCE_TYPE_GROUP, member))
store.Delete(types.GetPolicyForAccountKey(groupID, resource.RESOURCE_TYPE_GROUP, member))
} else {
policy.MemberStatement = nil
store.Set(types.GetPolicyByIDKey(policy.Id), k.cdc.MustMarshal(policy))
Expand All @@ -99,7 +99,7 @@ func (k Keeper) PutPolicy(ctx sdk.Context, policy *types.Policy) (math.Uint, err
store := ctx.KVStore(k.storeKey)

if policy.Principal.Type == types.TYPE_GNFD_ACCOUNT {
policyKey := types.GetPolicyToAccountKey(policy.ResourceId, policy.ResourceType,
policyKey := types.GetPolicyForAccountKey(policy.ResourceId, policy.ResourceType,
policy.Principal.MustGetAccountAddress())
bz := store.Get(policyKey)
if bz != nil {
Expand All @@ -112,7 +112,7 @@ func (k Keeper) PutPolicy(ctx sdk.Context, policy *types.Policy) (math.Uint, err
store.Set(types.GetPolicyByIDKey(policy.Id), bz)
}
} else if policy.Principal.Type == types.TYPE_GNFD_GROUP {
policyGroupKey := types.GetPolicyToGroupKey(policy.ResourceId, policy.ResourceType)
policyGroupKey := types.GetPolicyForGroupKey(policy.ResourceId, policy.ResourceType)
bz := store.Get(policyGroupKey)
if bz != nil {
policyGroup := types.PolicyGroup{}
Expand Down Expand Up @@ -173,11 +173,11 @@ func (k Keeper) MustGetPolicyByID(ctx sdk.Context, policyID math.Uint) *types.Po
return policy
}

func (k Keeper) getPolicyToAccount(ctx sdk.Context, resourceID math.Uint,
func (k Keeper) GetPolicyForAccount(ctx sdk.Context, resourceID math.Uint,
resourceType resource.ResourceType, addr sdk.AccAddress) (policy *types.Policy,
isFound bool) {
store := ctx.KVStore(k.storeKey)
policyKey := types.GetPolicyToAccountKey(resourceID, resourceType, addr)
policyKey := types.GetPolicyForAccountKey(resourceID, resourceType, addr)

bz := store.Get(policyKey)
if bz == nil {
Expand All @@ -187,10 +187,31 @@ func (k Keeper) getPolicyToAccount(ctx sdk.Context, resourceID math.Uint,
return k.GetPolicyByID(ctx, sequence.DecodeSequence(bz))
}

func (k Keeper) GetPolicyForGroup(ctx sdk.Context, resourceID math.Uint,
resourceType resource.ResourceType, groupID math.Uint) (policy *types.Policy,
isFound bool) {
store := ctx.KVStore(k.storeKey)
policyGroupKey := types.GetPolicyForGroupKey(resourceID, resourceType)

bz := store.Get(policyGroupKey)
if bz == nil {
return policy, false
}

var policyGroup types.PolicyGroup
k.cdc.MustUnmarshal(bz, &policyGroup)
for _, item := range policyGroup.Items {
if item.GroupId == groupID {
return k.GetPolicyByID(ctx, item.PolicyId)
}
}
return nil, false
}

func (k Keeper) setPolicyToAccount(ctx sdk.Context, resourceID math.Uint,
resourceType resource.ResourceType, addr sdk.AccAddress, policy *types.Policy) {
store := ctx.KVStore(k.storeKey)
policyKey := types.GetPolicyToAccountKey(resourceID, resourceType, addr)
policyKey := types.GetPolicyForAccountKey(resourceID, resourceType, addr)

store.Set(policyKey, sequence.EncodeSequence(policy.Id))
store.Set(types.GetPolicyByIDKey(policy.Id), k.cdc.MustMarshal(policy))
Expand All @@ -199,7 +220,7 @@ func (k Keeper) setPolicyToAccount(ctx sdk.Context, resourceID math.Uint,
func (k Keeper) VerifyPolicy(ctx sdk.Context, resourceID math.Uint, resourceType resource.ResourceType,
operator sdk.AccAddress, action types.ActionType, resource *string) types.Effect {
// verify policy which grant permission to account
policy, found := k.getPolicyToAccount(ctx, resourceID, resourceType, operator)
policy, found := k.GetPolicyForAccount(ctx, resourceID, resourceType, operator)
if found {
effect := policy.Eval(action, resource)
if effect != types.EFFECT_PASS {
Expand All @@ -209,7 +230,7 @@ func (k Keeper) VerifyPolicy(ctx sdk.Context, resourceID math.Uint, resourceType

// verify policy which grant permission to group
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetPolicyToGroupKey(resourceID, resourceType))
bz := store.Get(types.GetPolicyForGroupKey(resourceID, resourceType))
policyGroup := types.PolicyGroup{}
k.cdc.MustUnmarshal(bz, &policyGroup)

Expand All @@ -220,7 +241,7 @@ func (k Keeper) VerifyPolicy(ctx sdk.Context, resourceID math.Uint, resourceType
effect := p.Eval(action, resource)
if effect != types.EFFECT_PASS {
// check the operator is the member of this group
groupPolicy, found := k.getPolicyToAccount(ctx, item.GroupId, resourceType, operator)
groupPolicy, found := k.GetPolicyForAccount(ctx, item.GroupId, resourceType, operator)
if found {
memberEffect := groupPolicy.Eval(types.ACTION_GROUP_MEMBER, nil)
if memberEffect != types.EFFECT_PASS {
Expand All @@ -247,7 +268,7 @@ func (k Keeper) DeletePolicy(ctx sdk.Context, principal *types.Principal, resour
var policyID math.Uint
if principal.Type == types.TYPE_GNFD_ACCOUNT {
accAddr := sdk.MustAccAddressFromHex(principal.Value)
policyKey := types.GetPolicyToAccountKey(resourceID, resourceType, accAddr)
policyKey := types.GetPolicyForAccountKey(resourceID, resourceType, accAddr)
bz := store.Get(policyKey)
policyID = sequence.DecodeSequence(bz)
if bz != nil {
Expand All @@ -259,7 +280,7 @@ func (k Keeper) DeletePolicy(ctx sdk.Context, principal *types.Principal, resour
if err != nil {
return math.ZeroUint(), err
}
bz := store.Get(types.GetPolicyToGroupKey(resourceID, resourceType))
bz := store.Get(types.GetPolicyForGroupKey(resourceID, resourceType))
if bz != nil {
policyGroup := types.PolicyGroup{}
k.cdc.MustUnmarshal(bz, &policyGroup)
Expand Down
7 changes: 7 additions & 0 deletions x/permission/types/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ func NewPrincipalWithAccount(addr sdk.AccAddress) *Principal {
}
}

func NewPrincipalWithGroup(groupID sdkmath.Uint) *Principal {
return &Principal{
Type: TYPE_GNFD_GROUP,
Value: groupID.String(),
}
}

func (p *Principal) ValidateBasic() error {
switch p.Type {
case TYPE_GNFD_ACCOUNT:
Expand Down
Loading

0 comments on commit 8b9d8a8

Please sign in to comment.