From 4a4794ddb796885152fc5abdcba0980802fcfaf2 Mon Sep 17 00:00:00 2001 From: Alexgao001 Date: Fri, 1 Dec 2023 15:54:44 +0800 Subject: [PATCH] restrict on creating GVG and allow empty family --- deployment/localup/localup.sh | 1 + e2e/tests/virtualgroup_test.go | 103 +++++++++++++++++++++++++--- x/virtualgroup/keeper/keeper.go | 20 ++++-- x/virtualgroup/keeper/msg_server.go | 18 ++++- x/virtualgroup/types/errors.go | 1 + 5 files changed, 126 insertions(+), 17 deletions(-) diff --git a/deployment/localup/localup.sh b/deployment/localup/localup.sh index 1acf7890b..43c88d42e 100644 --- a/deployment/localup/localup.sh +++ b/deployment/localup/localup.sh @@ -173,6 +173,7 @@ function generate_genesis() { sed -i -e "s/log_level = \"info\"/\log_level= \"debug\"/g" ${workspace}/.local/validator${i}/config/config.toml echo -e '[[upgrade]]\nname = "Nagqu"\nheight = 20\ninfo = ""' >> ${workspace}/.local/validator${i}/config/app.toml echo -e '[[upgrade]]\nname = "Pampas"\nheight = 20\ninfo = ""' >> ${workspace}/.local/validator${i}/config/app.toml + echo -e '[[upgrade]]\nname = "Eddystone"\nheight = 20\ninfo = ""' >> ${workspace}/.local/validator${i}/config/app.toml done # enable swagger API for validator0 diff --git a/e2e/tests/virtualgroup_test.go b/e2e/tests/virtualgroup_test.go index c344ecfad..9e6bba771 100644 --- a/e2e/tests/virtualgroup_test.go +++ b/e2e/tests/virtualgroup_test.go @@ -42,6 +42,19 @@ func TestVirtualGroupTestSuite(t *testing.T) { suite.Run(t, new(VirtualGroupTestSuite)) } +func (s *VirtualGroupTestSuite) getSecondarySPIDs(primarySPID uint32) []uint32 { + var secondarySPIDs []uint32 + for _, ssp := range s.StorageProviders { + if ssp.Info.Id != primarySPID { + secondarySPIDs = append(secondarySPIDs, ssp.Info.Id) + } + if len(secondarySPIDs) == 6 { + break + } + } + return secondarySPIDs +} + func (s *VirtualGroupTestSuite) queryGlobalVirtualGroup(gvgID uint32) *virtualgroupmoduletypes.GlobalVirtualGroup { resp, err := s.Client.GlobalVirtualGroup( context.Background(), @@ -50,7 +63,7 @@ func (s *VirtualGroupTestSuite) queryGlobalVirtualGroup(gvgID uint32) *virtualgr return resp.GlobalVirtualGroup } -func (s *VirtualGroupTestSuite) queryGlobalVirtualGroupByFamily(familyID uint32) []*virtualgroupmoduletypes.GlobalVirtualGroup { +func (s *VirtualGroupTestSuite) queryGlobalVirtualGroupsByFamily(familyID uint32) []*virtualgroupmoduletypes.GlobalVirtualGroup { s.T().Logf("familyID: %d", familyID) resp, err := s.Client.GlobalVirtualGroupByFamilyID( context.Background(), @@ -93,17 +106,12 @@ func (s *VirtualGroupTestSuite) TestBasic() { availableGvgFamilyIds := s.queryAvailableGlobalVirtualGroupFamilies([]uint32{gvg.FamilyId}) s.Require().Equal(availableGvgFamilyIds[0], gvg.FamilyId) - srcGVGs := s.queryGlobalVirtualGroupByFamily(gvg.FamilyId) + srcGVGs := s.queryGlobalVirtualGroupsByFamily(gvg.FamilyId) - var secondarySPIDs []uint32 - for _, ssp := range s.StorageProviders { - if ssp.Info.Id != primarySP.Info.Id { - secondarySPIDs = append(secondarySPIDs, ssp.Info.Id) - } - } + secondarySPIDs := s.getSecondarySPIDs(primarySP.Info.Id) s.BaseSuite.CreateGlobalVirtualGroup(primarySP, gvg.FamilyId, secondarySPIDs, 1) - gvgs = s.queryGlobalVirtualGroupByFamily(gvg.FamilyId) + gvgs = s.queryGlobalVirtualGroupsByFamily(gvg.FamilyId) s.Require().Equal(len(gvgs), len(srcGVGs)+1) oldGVGIDs := make(map[uint32]bool) @@ -159,7 +167,7 @@ func (s *VirtualGroupTestSuite) TestBasic() { } s.SendTxBlock(primarySP.OperatorKey, &msgDeleteGVG) - newGVGs := s.queryGlobalVirtualGroupByFamily(newGVG.FamilyId) + newGVGs := s.queryGlobalVirtualGroupsByFamily(newGVG.FamilyId) for _, gvg := range newGVGs { if gvg.Id == newGVG.Id { @@ -203,6 +211,26 @@ func (s *VirtualGroupTestSuite) TestBasic() { } s.SendTxBlockWithExpectErrorString(&msgCreateGVG, primarySP.OperatorKey, virtualgroupmoduletypes.ErrDuplicateSecondarySP.Error()) + // test create a duplicated GVG in a family + secondarySPIDs = s.getSecondarySPIDs(primarySP.Info.Id) + gvgID, familyID := s.BaseSuite.CreateGlobalVirtualGroup(primarySP, 0, secondarySPIDs, 1) + gvgResp, err := s.Client.VirtualGroupQueryClient.GlobalVirtualGroup(context.Background(), &virtualgroupmoduletypes.QueryGlobalVirtualGroupRequest{ + GlobalVirtualGroupId: gvgID, + }) + s.Require().NoError(err) + s.Require().Equal(secondarySPIDs, gvgResp.GlobalVirtualGroup.SecondarySpIds) + s.Require().Equal(familyID, gvgResp.GlobalVirtualGroup.FamilyId) + + msgCreateGVG = virtualgroupmoduletypes.MsgCreateGlobalVirtualGroup{ + StorageProvider: primarySP.OperatorKey.GetAddr().String(), + FamilyId: familyID, + SecondarySpIds: secondarySPIDs, + Deposit: sdk.Coin{ + Denom: s.Config.Denom, + Amount: types.NewIntFromInt64WithDecimal(1, types.DecimalBNB), + }, + } + s.SendTxBlockWithExpectErrorString(&msgCreateGVG, primarySP.OperatorKey, virtualgroupmoduletypes.ErrDuplicateGVG.Error()) } func (s *VirtualGroupTestSuite) TestSettle() { @@ -679,3 +707,58 @@ CheckProposalStatus: s.T().Errorf("update params failed") } } + +func (s *VirtualGroupTestSuite) TestEmptyGlobalVirtualGroupFamily() { + primarySP := s.BaseSuite.PickStorageProvider() + user := s.GenAndChargeAccounts(1, 1000000)[0] + + secondarySPIDs := s.getSecondarySPIDs(primarySP.Info.Id) + + // The Sp creates a family which has 1 GVG. + gvgID, familyID := s.BaseSuite.CreateGlobalVirtualGroup(primarySP, 0, secondarySPIDs, 1) + gvgs := s.queryGlobalVirtualGroupsByFamily(familyID) + s.Require().Equal(1, len(gvgs)) + + // a User creates an object served by this GVG + bucketName := storagetestutil.GenRandomBucketName() + objectName := storagetestutil.GenRandomObjectName() + s.BaseSuite.CreateObject(user, primarySP, gvgID, bucketName, objectName) + + // The User deletes the object + s.SendTxBlock(user, storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName)) + + // object isn't found onchain + _, err := s.Client.HeadObject(context.Background(), &storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName, + }) + s.Require().Error(err) + + // The SP deletes the GVG + msgDeleteGVG := virtualgroupmoduletypes.MsgDeleteGlobalVirtualGroup{ + StorageProvider: primarySP.OperatorKey.GetAddr().String(), + GlobalVirtualGroupId: gvgID, + } + s.SendTxBlock(primarySP.OperatorKey, &msgDeleteGVG) + _, err = s.Client.GlobalVirtualGroup(context.Background(), &virtualgroupmoduletypes.QueryGlobalVirtualGroupRequest{GlobalVirtualGroupId: gvgID}) + s.Require().Error(err) + + // The bucket onchain still shows the family info, and the family is indeed exist + bucket, err := s.Client.HeadBucket(context.Background(), &storagetypes.QueryHeadBucketRequest{ + BucketName: bucketName, + }) + s.Require().NoError(err) + s.Require().Equal(familyID, bucket.BucketInfo.GlobalVirtualGroupFamilyId) + + family, err := s.Client.GlobalVirtualGroupFamily(context.Background(), &virtualgroupmoduletypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: bucket.BucketInfo.GlobalVirtualGroupFamilyId, + }) + s.Require().NoError(err) + s.Require().Equal(0, len(family.GlobalVirtualGroupFamily.GlobalVirtualGroupIds)) + + //the SP can create new GVG on this empty family + newGVGID, _ := s.BaseSuite.CreateGlobalVirtualGroup(primarySP, familyID, secondarySPIDs, 1) + gvgs = s.queryGlobalVirtualGroupsByFamily(familyID) + s.Require().Equal(1, len(gvgs)) + s.Require().Equal(gvgs[0].Id, newGVGID) +} diff --git a/x/virtualgroup/keeper/keeper.go b/x/virtualgroup/keeper/keeper.go index c325bc1c1..04f8c004e 100644 --- a/x/virtualgroup/keeper/keeper.go +++ b/x/virtualgroup/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" "fmt" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" math2 "math" "cosmossdk.io/math" @@ -163,12 +164,19 @@ func (k Keeper) DeleteGVG(ctx sdk.Context, primarySp *sptypes.StorageProvider, g } if len(gvgFamily.GlobalVirtualGroupIds) == 0 && k.paymentKeeper.IsEmptyNetFlow(ctx, sdk.MustAccAddressFromHex(gvgFamily.VirtualPaymentAddress)) { - store.Delete(types.GetGVGFamilyKey(gvg.FamilyId)) - if err := ctx.EventManager().EmitTypedEvents(&types.EventDeleteGlobalVirtualGroupFamily{ - Id: gvgFamily.Id, - PrimarySpId: gvgFamily.PrimarySpId, - }); err != nil { - return err + // after Eddystone, the virtual group family can be empty. + if !ctx.IsUpgraded(upgradetypes.Eddystone) { + store.Delete(types.GetGVGFamilyKey(gvg.FamilyId)) + if err := ctx.EventManager().EmitTypedEvents(&types.EventDeleteGlobalVirtualGroupFamily{ + Id: gvgFamily.Id, + PrimarySpId: gvgFamily.PrimarySpId, + }); err != nil { + return err + } + } else { + if err := k.SetGVGFamilyAndEmitUpdateEvent(ctx, gvgFamily); err != nil { + return err + } } } else { if err := k.SetGVGFamilyAndEmitUpdateEvent(ctx, gvgFamily); err != nil { diff --git a/x/virtualgroup/keeper/msg_server.go b/x/virtualgroup/keeper/msg_server.go index 94726bd8a..bb0bf8cf0 100644 --- a/x/virtualgroup/keeper/msg_server.go +++ b/x/virtualgroup/keeper/msg_server.go @@ -2,7 +2,6 @@ package keeper import ( "context" - sdkerrors "cosmossdk.io/errors" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -105,6 +104,23 @@ func (k msgServer) CreateGlobalVirtualGroup(goCtx context.Context, req *types.Ms return nil, err } + if ctx.IsUpgraded(upgradetypes.Eddystone) { + for _, gvgID := range gvgFamily.GlobalVirtualGroupIds { + gvg, found := k.GetGVG(ctx, gvgID) + if !found { + return nil, types.ErrGVGNotExist + } + for i, secondarySPId := range gvg.SecondarySpIds { + if secondarySPId != secondarySpIds[i] { + break + } + if i == len(secondarySpIds)-1 { + return nil, types.ErrDuplicateGVG.Wrapf("the global virtual group family already has a GVG with same SP in same order") + } + } + } + } + // Each family supports only a limited number of GVGS if k.MaxGlobalVirtualGroupNumPerFamily(ctx) < uint32(len(gvgFamily.GlobalVirtualGroupIds)) { return nil, types.ErrLimitationExceed.Wrapf("The gvg number within the family exceeds the limit.") diff --git a/x/virtualgroup/types/errors.go b/x/virtualgroup/types/errors.go index 6f5e85f98..4d19e72d5 100644 --- a/x/virtualgroup/types/errors.go +++ b/x/virtualgroup/types/errors.go @@ -22,6 +22,7 @@ var ( ErrLimitationExceed = errors.Register(ModuleName, 1123, "limitation exceed.") ErrDuplicateSecondarySP = errors.Register(ModuleName, 1124, "the global virtual group has duplicate secondary sp.") ErrInsufficientStaking = errors.Register(ModuleName, 1125, "insufficient staking for gvg") + ErrDuplicateGVG = errors.Register(ModuleName, 1126, "global virtual group is duplicate") ErrInvalidDenom = errors.Register(ModuleName, 2000, "Invalid denom.") )