diff --git a/e2e/tests/payment_test.go b/e2e/tests/payment_test.go index 9d6e9fd61..b3fb6fc18 100644 --- a/e2e/tests/payment_test.go +++ b/e2e/tests/payment_test.go @@ -2085,12 +2085,7 @@ func (s *PaymentTestSuite) TestStorageBill_SealObject_WithPriceChangeValidatorTa // assertions streamRecordsAfter = s.getStreamRecords(streamAddresses) gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter = s.calculateReadRatesCurrentTimestamp(sp, bucketName) - gvgFamilyRateStore, gvgRateStore, taxRateStore, userTotalRateStore = s.calculateStorageRatesCurrentTimestamp(sp, bucketName, objectName, payloadSize) - - gvgFamilyRateStore = gvgFamilyRateStore.MulRaw(2) - gvgRateStore = gvgRateStore.MulRaw(2) - taxRateStore = taxRateStore.MulRaw(2) - userTotalRateStore = userTotalRateStore.MulRaw(2) + gvgFamilyRateStore, gvgRateStore, taxRateStore, userTotalRateStore = s.calculateStorageRatesCurrentTimestamp(sp, bucketName, objectName, payloadSize*2) s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) diff --git a/e2e/tests/storage_bill_test.go b/e2e/tests/storage_bill_test.go index 4f063ebb3..0c73fe4d2 100644 --- a/e2e/tests/storage_bill_test.go +++ b/e2e/tests/storage_bill_test.go @@ -33,10 +33,10 @@ func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithoutPriceChange() { }) s.Require().NoError(err) family := queryFamilyResponse.GlobalVirtualGroupFamily - user0 := s.GenAndChargeAccounts(1, 1000000)[0] + user := s.GenAndChargeAccounts(1, 1000000)[0] streamAddresses := []string{ - user0.GetAddr().String(), + user.GetAddr().String(), family.VirtualPaymentAddress, gvg.VirtualPaymentAddress, paymenttypes.ValidatorTaxPoolAddress.String(), @@ -46,11 +46,11 @@ func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithoutPriceChange() { s.T().Logf("paymentParams %s, err: %v", paymentParams, err) s.Require().NoError(err) - bucketName := s.createBucket(sp, user0, 0) + bucketName := s.createBucket(sp, user, 0) // create object with none zero payload size streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, objectId, checksums, payloadSize := s.createObject(user0, bucketName, false) + _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) // assertions streamRecordsAfter := s.getStreamRecords(streamAddresses) @@ -78,7 +78,7 @@ func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithoutPriceChange() { distBucketName := bucketName distObjectName := storagetestutils.GenRandomObjectName() - objectIfo, err := s.copyObject(user0, sp, bucketName, objectName, distBucketName, distObjectName) + objectIfo, err := s.copyObject(user, sp, bucketName, objectName, distBucketName, distObjectName) s.Require().NoError(err) s.sealObject(sp, gvg, distBucketName, distObjectName, objectIfo.Id, objectIfo.Checksums) // assertions @@ -104,10 +104,10 @@ func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithPriceChange() { }) s.Require().NoError(err) family := queryFamilyResponse.GlobalVirtualGroupFamily - user0 := s.GenAndChargeAccounts(1, 1000000)[0] + user := s.GenAndChargeAccounts(1, 1000000)[0] streamAddresses := []string{ - user0.GetAddr().String(), + user.GetAddr().String(), family.VirtualPaymentAddress, gvg.VirtualPaymentAddress, paymenttypes.ValidatorTaxPoolAddress.String(), @@ -117,11 +117,11 @@ func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithPriceChange() { s.T().Logf("paymentParams %s, err: %v", paymentParams, err) s.Require().NoError(err) - bucketName := s.createBucket(sp, user0, 0) + bucketName := s.createBucket(sp, user, 0) // create object with none zero payload size streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, objectId, checksums, payloadSize := s.createObject(user0, bucketName, false) + _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) // assertions streamRecordsAfter := s.getStreamRecords(streamAddresses) @@ -160,9 +160,9 @@ func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithPriceChange() { } s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) - distBucketName := s.createBucket(sp, user0, 0) + distBucketName := s.createBucket(sp, user, 0) distObjectName := storagetestutils.GenRandomObjectName() - objectIfo, err := s.copyObject(user0, sp, bucketName, objectName, distBucketName, distObjectName) + objectIfo, err := s.copyObject(user, sp, bucketName, objectName, distBucketName, distObjectName) s.Require().NoError(err) s.sealObject(sp, gvg, distBucketName, distObjectName, objectIfo.Id, objectIfo.Checksums) // assertions @@ -182,6 +182,7 @@ func (s *PaymentTestSuite) TestStorageBill_UpdateBucketQuota() { var err error ctx := context.Background() sp := s.PickStorageProvider() + user := s.GenAndChargeAccounts(1, 10)[0] // recover price defer s.SetSPPrice(sp, "12.34", "0") gvg, found := sp.GetFirstGlobalVirtualGroup() @@ -191,7 +192,6 @@ func (s *PaymentTestSuite) TestStorageBill_UpdateBucketQuota() { }) s.Require().NoError(err) family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 10)[0] streamAddresses := []string{ user.GetAddr().String(), @@ -320,7 +320,7 @@ func (s *PaymentTestSuite) TestStorageBill_UpdateBucketQuota() { chargedReadQuota := readQuota * 1024 * 1024 msgUpdateBucketInfo := storagetypes.NewMsgUpdateBucketInfo( user.GetAddr(), bucketName, &chargedReadQuota, user.GetAddr(), storagetypes.VISIBILITY_TYPE_PRIVATE) - + s.reduceBNBBalance(user, s.Validator, sdkmath.NewIntWithDecimal(1, 16)) s.SendTxBlockWithExpectErrorString(msgUpdateBucketInfo, user, "apply user flows list failed") } @@ -495,10 +495,10 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { }) s.Require().NoError(err) family := queryFamilyResponse.GlobalVirtualGroupFamily - user0 := s.GenAndChargeAccounts(1, 10)[0] + user := s.GenAndChargeAccounts(1, 10)[0] streamAddresses := []string{ - user0.GetAddr().String(), + user.GetAddr().String(), family.VirtualPaymentAddress, gvg.VirtualPaymentAddress, paymenttypes.ValidatorTaxPoolAddress.String(), @@ -509,7 +509,7 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { s.T().Logf("paymentParams %s, err: %v", paymentParams, err) s.Require().NoError(err) - bucketName := s.createBucket(primarySP, user0, 0) + bucketName := s.createBucket(primarySP, user, 0) bucketInfo, err := s.Client.HeadBucket(context.Background(), &storagetypes.QueryHeadBucketRequest{ BucketName: bucketName, }) @@ -517,7 +517,7 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { // create object with none zero payload size streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, objectId, checksums, payloadSize := s.createObject(user0, bucketName, false) + _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) // assertions streamRecordsAfter := s.getStreamRecords(streamAddresses) @@ -561,7 +561,7 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { s.Require().NoError(err) family = queryFamilyResponse.GlobalVirtualGroupFamily streamAddresses = []string{ - user0.GetAddr().String(), + user.GetAddr().String(), family.VirtualPaymentAddress, dstGVG.VirtualPaymentAddress, paymenttypes.ValidatorTaxPoolAddress.String(), @@ -574,8 +574,8 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { s.Require().NoError(err) // MigrationBucket - msgMigrationBucket, msgCompleteMigrationBucket := s.NewMigrateBucket(primarySP, dstPrimarySP, user0, bucketName, gvg.FamilyId, dstGVG.FamilyId, bucketInfo.BucketInfo.Id) - s.SendTxBlock(user0, msgMigrationBucket) + msgMigrationBucket, msgCompleteMigrationBucket := s.NewMigrateBucket(primarySP, dstPrimarySP, user, bucketName, gvg.FamilyId, dstGVG.FamilyId, bucketInfo.BucketInfo.Id) + s.SendTxBlock(user, msgMigrationBucket) s.Require().NoError(err) // complete MigrationBucket @@ -604,11 +604,11 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { s.Require().NoError(err) streamRecordsBefore = s.getStreamRecords(streamAddresses0) // send msgMigrationBucket - msgMigrationBucket, msgCompleteMigrationBucket = s.NewMigrateBucket(dstPrimarySP, primarySP, user0, bucketName, dstGVG.FamilyId, gvg.FamilyId, bucketInfo.BucketInfo.Id) + msgMigrationBucket, msgCompleteMigrationBucket = s.NewMigrateBucket(dstPrimarySP, primarySP, user, bucketName, dstGVG.FamilyId, gvg.FamilyId, bucketInfo.BucketInfo.Id) - s.SendTxBlock(user0, msgMigrationBucket) + s.SendTxBlock(user, msgMigrationBucket) s.Require().NoError(err) - s.reduceBNBBalance(user0, s.Validator, sdkmath.NewIntWithDecimal(1, 1)) + s.reduceBNBBalance(user, s.Validator, sdkmath.NewIntWithDecimal(1, 1)) s.SendTxBlockWithExpectErrorString(msgCompleteMigrationBucket, primarySP.OperatorKey, "apply stream record changes for user failed") @@ -616,7 +616,7 @@ func (s *PaymentTestSuite) TestStorageBill_MigrationBucket() { readPrice, primaryPrice, secondaryPrice := s.getPrices(primarySP, time.Now().Unix()) s.T().Logf("readPrice: %v, primaryPrice: %v,secondaryPrice: %v", readPrice, primaryPrice, secondaryPrice) - s.transferBNB(s.Validator, user0, sdkmath.NewIntWithDecimal(10000, 18)) + s.transferBNB(s.Validator, user, sdkmath.NewIntWithDecimal(10000, 18)) s.SendTxBlock(primarySP.OperatorKey, msgCompleteMigrationBucket) streamRecordsAfter = s.getStreamRecords(streamAddresses0) diff --git a/x/storage/keeper/payment.go b/x/storage/keeper/payment.go index 7d324b9d9..ff047bbc6 100644 --- a/x/storage/keeper/payment.go +++ b/x/storage/keeper/payment.go @@ -9,6 +9,7 @@ import ( "github.com/bnb-chain/greenfield/x/payment/types" storagetypes "github.com/bnb-chain/greenfield/x/storage/types" + vgtypes "github.com/bnb-chain/greenfield/x/virtualgroup/types" ) func (k Keeper) ChargeBucketReadFee(ctx sdk.Context, bucketInfo *storagetypes.BucketInfo, @@ -390,51 +391,30 @@ func (k Keeper) ChargeViaObjectChange(ctx sdk.Context, bucketInfo *storagetypes. } } - // primary sp - primaryRate := price.PrimaryStorePrice.MulInt(sdkmath.NewIntFromUint64(chargeSize)).TruncateInt() - if primaryRate.IsPositive() { - userFlows.Flows = append(userFlows.Flows, types.OutFlow{ - ToAddress: gvgFamily.VirtualPaymentAddress, - Rate: primaryRate, - }) - } - - //secondary sp gvg, found := k.virtualGroupKeeper.GetGVG(ctx, lvg.GlobalVirtualGroupId) if !found { return fmt.Errorf("get GVG failed: %d, %s", lvg.GlobalVirtualGroupId, lvg.String()) } - secondaryRate := price.SecondaryStorePrice.MulInt(sdkmath.NewIntFromUint64(chargeSize)).TruncateInt() - secondaryRate = secondaryRate.MulRaw(int64(len(gvg.SecondarySpIds))) - if secondaryRate.IsPositive() { - userFlows.Flows = append(userFlows.Flows, types.OutFlow{ - ToAddress: gvg.VirtualPaymentAddress, - Rate: secondaryRate, - }) - } - versionedParams, err := k.paymentKeeper.GetVersionedParamsWithTs(ctx, internalBucketInfo.PriceTime) if err != nil { return fmt.Errorf("failed to get validator tax rate: %w, time: %d", err, internalBucketInfo.PriceTime) } - validatorTaxRate := versionedParams.ValidatorTaxRate.MulInt(primaryRate.Add(secondaryRate)).TruncateInt() - if validatorTaxRate.IsPositive() { - userFlows.Flows = append(userFlows.Flows, types.OutFlow{ - ToAddress: types.ValidatorTaxPoolAddress.String(), - Rate: validatorTaxRate, - }) - } - if !delete { + preOutFlows := k.calculateLVGStoreBill(ctx, price, versionedParams, gvgFamily, gvg, lvg) + var newOutFlows []types.OutFlow + if !delete { // seal object internalBucketInfo.TotalChargeSize = internalBucketInfo.TotalChargeSize + chargeSize lvg.TotalChargeSize = lvg.TotalChargeSize + chargeSize - } else { + newOutFlows = k.calculateLVGStoreBill(ctx, price, versionedParams, gvgFamily, gvg, lvg) + } else { // delete object internalBucketInfo.TotalChargeSize = internalBucketInfo.TotalChargeSize - chargeSize lvg.TotalChargeSize = lvg.TotalChargeSize - chargeSize - - userFlows.Flows = getNegFlows(userFlows.Flows) + newOutFlows = k.calculateLVGStoreBill(ctx, price, versionedParams, gvgFamily, gvg, lvg) } + + userFlows.Flows = append(userFlows.Flows, getNegFlows(preOutFlows)...) + userFlows.Flows = append(userFlows.Flows, newOutFlows...) err = k.paymentKeeper.ApplyUserFlowsList(ctx, []types.UserFlows{userFlows}) if err != nil { ctx.Logger().Error("charge object store fee failed", "err", err.Error()) @@ -444,18 +424,55 @@ func (k Keeper) ChargeViaObjectChange(ctx sdk.Context, bucketInfo *storagetypes. return nil } +func (k Keeper) calculateLVGStoreBill(ctx sdk.Context, price types.StoragePrice, params types.VersionedParams, + gvgFamily *vgtypes.GlobalVirtualGroupFamily, gvg *vgtypes.GlobalVirtualGroup, lvg *storagetypes.LocalVirtualGroup) []types.OutFlow { + outFlows := make([]types.OutFlow, 0) + + // primary sp + primaryStoreFlowRate := price.PrimaryStorePrice.MulInt(sdkmath.NewIntFromUint64(lvg.TotalChargeSize)).TruncateInt() + if primaryStoreFlowRate.IsPositive() { + outFlows = append(outFlows, types.OutFlow{ + ToAddress: gvgFamily.VirtualPaymentAddress, + Rate: primaryStoreFlowRate, + }) + } + + //secondary sp + secondaryStoreFlowRate := price.SecondaryStorePrice.MulInt(sdkmath.NewIntFromUint64(lvg.TotalChargeSize)).TruncateInt() + secondaryStoreFlowRate = secondaryStoreFlowRate.MulRaw(int64(len(gvg.SecondarySpIds))) + if secondaryStoreFlowRate.IsPositive() { + outFlows = append(outFlows, types.OutFlow{ + ToAddress: gvg.VirtualPaymentAddress, + Rate: secondaryStoreFlowRate, + }) + } + + validatorTaxStoreFlowRate := params.ValidatorTaxRate.MulInt(primaryStoreFlowRate.Add(secondaryStoreFlowRate)).TruncateInt() + if validatorTaxStoreFlowRate.IsPositive() { + outFlows = append(outFlows, types.OutFlow{ + ToAddress: types.ValidatorTaxPoolAddress.String(), + Rate: validatorTaxStoreFlowRate, + }) + } + + return outFlows +} + func (k Keeper) GetBucketReadStoreBill(ctx sdk.Context, bucketInfo *storagetypes.BucketInfo, internalBucketInfo *storagetypes.InternalBucketInfo) (userFlows types.UserFlows, err error) { userFlows.From = sdk.MustAccAddressFromHex(bucketInfo.PaymentAddress) + if internalBucketInfo.TotalChargeSize == 0 && bucketInfo.ChargedReadQuota == 0 { + return userFlows, nil + } + + // calculate read fee & store fee separately, for precision + // calculate read fee gvgFamily, found := k.virtualGroupKeeper.GetGVGFamily(ctx, bucketInfo.GlobalVirtualGroupFamilyId) if !found { return userFlows, fmt.Errorf("get GVG family failed: %d", bucketInfo.GlobalVirtualGroupFamilyId) } - if internalBucketInfo.TotalChargeSize == 0 && bucketInfo.ChargedReadQuota == 0 { - return userFlows, nil - } price, err := k.paymentKeeper.GetStoragePrice(ctx, types.StoragePriceParams{ PrimarySp: gvgFamily.PrimarySpId, PriceTime: internalBucketInfo.PriceTime, @@ -464,40 +481,11 @@ func (k Keeper) GetBucketReadStoreBill(ctx sdk.Context, bucketInfo *storagetypes return userFlows, fmt.Errorf("get storage price failed: %w", err) } - // primary sp total rate - primaryTotalFlowRate := price.ReadPrice.MulInt(sdkmath.NewIntFromUint64(bucketInfo.ChargedReadQuota)).TruncateInt() - - // secondary sp total rate - secondaryTotalFlowRate := sdk.ZeroInt() - - for _, lvg := range internalBucketInfo.LocalVirtualGroups { - // primary sp - primaryRate := price.PrimaryStorePrice.MulInt(sdkmath.NewIntFromUint64(lvg.TotalChargeSize)).TruncateInt() - if primaryRate.IsPositive() { - primaryTotalFlowRate = primaryTotalFlowRate.Add(primaryRate) - } - - //secondary sp - gvg, found := k.virtualGroupKeeper.GetGVG(ctx, lvg.GlobalVirtualGroupId) - if !found { - return userFlows, fmt.Errorf("get GVG failed: %d, %s", lvg.GlobalVirtualGroupId, lvg.String()) - } - - secondaryRate := price.SecondaryStorePrice.MulInt(sdkmath.NewIntFromUint64(lvg.TotalChargeSize)).TruncateInt() - secondaryRate = secondaryRate.MulRaw(int64(len(gvg.SecondarySpIds))) - if secondaryRate.IsPositive() { - userFlows.Flows = append(userFlows.Flows, types.OutFlow{ - ToAddress: gvg.VirtualPaymentAddress, - Rate: secondaryRate, - }) - secondaryTotalFlowRate = secondaryTotalFlowRate.Add(secondaryRate) - } - } - - if primaryTotalFlowRate.IsPositive() { + primaryReadFlowRate := price.ReadPrice.MulInt(sdkmath.NewIntFromUint64(bucketInfo.ChargedReadQuota)).TruncateInt() + if primaryReadFlowRate.IsPositive() { userFlows.Flows = append(userFlows.Flows, types.OutFlow{ ToAddress: gvgFamily.VirtualPaymentAddress, - Rate: primaryTotalFlowRate, + Rate: primaryReadFlowRate, }) } @@ -505,14 +493,26 @@ func (k Keeper) GetBucketReadStoreBill(ctx sdk.Context, bucketInfo *storagetypes if err != nil { return userFlows, fmt.Errorf("failed to get validator tax rate: %w, time: %d", err, internalBucketInfo.PriceTime) } - validatorTaxRate := versionedParams.ValidatorTaxRate.MulInt(primaryTotalFlowRate.Add(secondaryTotalFlowRate)).TruncateInt() - if validatorTaxRate.IsPositive() { + validatorTaxReadFlowRate := versionedParams.ValidatorTaxRate.MulInt(primaryReadFlowRate).TruncateInt() + if validatorTaxReadFlowRate.IsPositive() { userFlows.Flows = append(userFlows.Flows, types.OutFlow{ ToAddress: types.ValidatorTaxPoolAddress.String(), - Rate: validatorTaxRate, + Rate: validatorTaxReadFlowRate, }) } + // calculate store fee + // be noted, here we split the fee calculation for each lvg, to make sure each lvg's calculation is precise + for _, lvg := range internalBucketInfo.LocalVirtualGroups { + //secondary sp + gvg, found := k.virtualGroupKeeper.GetGVG(ctx, lvg.GlobalVirtualGroupId) + if !found { + return userFlows, fmt.Errorf("get GVG failed: %d, %s", lvg.GlobalVirtualGroupId, lvg.String()) + } + outFlows := k.calculateLVGStoreBill(ctx, price, versionedParams, gvgFamily, gvg, lvg) + userFlows.Flows = append(userFlows.Flows, outFlows...) + } + return userFlows, nil } diff --git a/x/storage/keeper/payment_test.go b/x/storage/keeper/payment_test.go index 1d3d087e1..5a9614572 100644 --- a/x/storage/keeper/payment_test.go +++ b/x/storage/keeper/payment_test.go @@ -226,18 +226,20 @@ func (s *TestSuite) TestGetBucketReadStoreBill() { ChargedReadQuota: 100, } + lvg1 := &types.LocalVirtualGroup{ + Id: 1, + TotalChargeSize: 100, + GlobalVirtualGroupId: 1, + } + lvg2 := &types.LocalVirtualGroup{ + Id: 2, + TotalChargeSize: 200, + GlobalVirtualGroupId: 2, + } internalBucketInfo := &types.InternalBucketInfo{ TotalChargeSize: 300, LocalVirtualGroups: []*types.LocalVirtualGroup{ - { - Id: 1, - TotalChargeSize: 100, - GlobalVirtualGroupId: 1, - }, { - Id: 2, - TotalChargeSize: 200, - GlobalVirtualGroupId: 2, - }, + lvg1, lvg2, }, } @@ -261,23 +263,47 @@ func (s *TestSuite) TestGetBucketReadStoreBill() { flows, err := s.storageKeeper.GetBucketReadStoreBill(s.ctx, bucketInfo, internalBucketInfo) s.Require().NoError(err) - gvg1StoreSize := internalBucketInfo.LocalVirtualGroups[0].TotalChargeSize * uint64(len(gvg1.SecondarySpIds)) - gvg1StoreRate := price.SecondaryStorePrice.MulInt64(int64(gvg1StoreSize)).TruncateInt() - s.Require().Equal(flows.Flows[0].ToAddress, gvg1.VirtualPaymentAddress) - s.Require().Equal(flows.Flows[0].Rate, gvg1StoreRate) + // read rate to gvg family + s.Require().Equal(flows.Flows[0].ToAddress, gvgFamily.VirtualPaymentAddress) + readRate := price.ReadPrice.MulInt64(int64(bucketInfo.ChargedReadQuota)).TruncateInt() + s.Require().Equal(flows.Flows[0].Rate, readRate) - gvg2StoreSize := internalBucketInfo.LocalVirtualGroups[1].TotalChargeSize * uint64(len(gvg2.SecondarySpIds)) - gvg2StoreRate := price.SecondaryStorePrice.MulInt64(int64(gvg2StoreSize)).TruncateInt() - s.Require().Equal(flows.Flows[1].ToAddress, gvg2.VirtualPaymentAddress) - s.Require().Equal(flows.Flows[1].Rate, gvg2StoreRate) + // read rate to validator tax pool + s.Require().Equal(flows.Flows[1].ToAddress, paymenttypes.ValidatorTaxPoolAddress.String()) + taxPoolRate := params.VersionedParams.ValidatorTaxRate.MulInt(readRate).TruncateInt() + s.Require().Equal(flows.Flows[1].Rate, taxPoolRate) - readRate := price.ReadPrice.MulInt64(int64(bucketInfo.ChargedReadQuota)).TruncateInt() - primaryStoreRate := price.PrimaryStorePrice.MulInt64(int64(internalBucketInfo.TotalChargeSize)).TruncateInt() + // first gvg + // store rate to gvg family s.Require().Equal(flows.Flows[2].ToAddress, gvgFamily.VirtualPaymentAddress) - s.Require().Equal(flows.Flows[2].Rate, readRate.Add(primaryStoreRate)) + primaryStoreRate := price.PrimaryStorePrice.MulInt64(int64(lvg1.TotalChargeSize)).TruncateInt() + s.Require().Equal(flows.Flows[2].Rate, primaryStoreRate) + + // store rate to gvg + gvg1StoreSize := lvg1.TotalChargeSize * uint64(len(gvg1.SecondarySpIds)) + gvg1StoreRate := price.SecondaryStorePrice.MulInt64(int64(gvg1StoreSize)).TruncateInt() + s.Require().Equal(flows.Flows[3].ToAddress, gvg1.VirtualPaymentAddress) + s.Require().Equal(flows.Flows[3].Rate, gvg1StoreRate) + + // store rate to validator tax pool + s.Require().Equal(flows.Flows[4].ToAddress, paymenttypes.ValidatorTaxPoolAddress.String()) + taxPoolRate = params.VersionedParams.ValidatorTaxRate.MulInt(primaryStoreRate.Add(gvg1StoreRate)).TruncateInt() + s.Require().Equal(flows.Flows[4].Rate, taxPoolRate) + + // secondary gvg + // store rate to gvg family + s.Require().Equal(flows.Flows[5].ToAddress, gvgFamily.VirtualPaymentAddress) + primaryStoreRate = price.PrimaryStorePrice.MulInt64(int64(lvg2.TotalChargeSize)).TruncateInt() + s.Require().Equal(flows.Flows[5].Rate, primaryStoreRate) + + // store rate to gvg + gvg2StoreSize := lvg2.TotalChargeSize * uint64(len(gvg2.SecondarySpIds)) + gvg2StoreRate := price.SecondaryStorePrice.MulInt64(int64(gvg2StoreSize)).TruncateInt() + s.Require().Equal(flows.Flows[6].ToAddress, gvg2.VirtualPaymentAddress) + s.Require().Equal(flows.Flows[6].Rate, gvg2StoreRate) - totalRate := readRate.Add(primaryStoreRate).Add(gvg1StoreRate).Add(gvg2StoreRate) - taxPoolRate := params.VersionedParams.ValidatorTaxRate.MulInt(totalRate).TruncateInt() - s.Require().Equal(flows.Flows[3].ToAddress, paymenttypes.ValidatorTaxPoolAddress.String()) - s.Require().Equal(flows.Flows[3].Rate, taxPoolRate) + // store rate to validator tax pool + s.Require().Equal(flows.Flows[7].ToAddress, paymenttypes.ValidatorTaxPoolAddress.String()) + taxPoolRate = params.VersionedParams.ValidatorTaxRate.MulInt(primaryStoreRate.Add(gvg2StoreRate)).TruncateInt() + s.Require().Equal(flows.Flows[7].Rate, taxPoolRate) }