From 846b6b4fe7df1d653dce0ac5dc03156a29a2a801 Mon Sep 17 00:00:00 2001 From: forcodedancing Date: Tue, 1 Aug 2023 14:32:58 +0800 Subject: [PATCH] chore: add more e2e test cases for payment module (#387) --- deployment/localup/localup.sh | 5 +- e2e/tests/payment_test.go | 1547 ++++----------------- e2e/tests/storage_bill_test.go | 1374 ++++++++++++++++++ x/storage/keeper/payment_test.go | 2 - x/storage/types/expected_keepers.go | 4 - x/storage/types/expected_keepers_mocks.go | 57 - 6 files changed, 1626 insertions(+), 1363 deletions(-) diff --git a/deployment/localup/localup.sh b/deployment/localup/localup.sh index 72fcbacaf..f4fe16708 100644 --- a/deployment/localup/localup.sh +++ b/deployment/localup/localup.sh @@ -150,7 +150,7 @@ function generate_genesis() { sed -i -e "s/\"heartbeat_interval\": \"1000\"/\"heartbeat_interval\": \"100\"/g" ${workspace}/.local/validator${i}/config/genesis.json sed -i -e "s/\"attestation_inturn_interval\": \"120\"/\"attestation_inturn_interval\": \"10\"/g" ${workspace}/.local/validator${i}/config/genesis.json sed -i -e "s/\"discontinue_confirm_period\": \"604800\"/\"discontinue_confirm_period\": \"5\"/g" ${workspace}/.local/validator${i}/config/genesis.json - sed -i -e "s/\"discontinue_deletion_max\": \"10000\"/\"discontinue_deletion_max\": \"2\"/g" ${workspace}/.local/validator${i}/config/genesis.json + sed -i -e "s/\"discontinue_deletion_max\": \"100\"/\"discontinue_deletion_max\": \"2\"/g" ${workspace}/.local/validator${i}/config/genesis.json sed -i -e "s/\"voting_period\": \"30s\"/\"voting_period\": \"5s\"/g" ${workspace}/.local/validator${i}/config/genesis.json #sed -i -e "s/\"community_tax\": \"0.020000000000000000\"/\"community_tax\": \"0\"/g" ${workspace}/.local/validator${i}/config/genesis.json sed -i -e "s/log_level = \"info\"/\log_level= \"debug\"/g" ${workspace}/.local/validator${i}/config/config.toml @@ -159,6 +159,9 @@ function generate_genesis() { # enable swagger API for validator0 sed -i -e "/Enable defines if the API server should be enabled/{N;s/enable = false/enable = true/;}" ${workspace}/.local/validator0/config/app.toml sed -i -e 's/swagger = false/swagger = true/' ${workspace}/.local/validator0/config/app.toml + + # enable telemetry for validator0 + sed -i -e "/other sinks such as Prometheus/{N;s/enable = false/enable = true/;}" ${workspace}/.local/validator0/config/app.toml } function start() { diff --git a/e2e/tests/payment_test.go b/e2e/tests/payment_test.go index 7ceaa3bda..302d403ed 100644 --- a/e2e/tests/payment_test.go +++ b/e2e/tests/payment_test.go @@ -6,7 +6,6 @@ import ( "fmt" "math" "reflect" - "sort" "strconv" "testing" "time" @@ -926,1304 +925,6 @@ func (s *PaymentTestSuite) TestWithdraw() { s.Require().Equal(paymentAccountStreamRecord.StaticBalance.Sub(paymentAccountStreamRecordAfter.StaticBalance).Int64(), amount.Add(staticBalanceChange).Int64()) } -func (s *PaymentTestSuite) TestStorageBill_DeleteBucket_WithReadQuota() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - // CreateBucket - chargedReadQuota := uint64(100) - bucketName := storagetestutils.GenRandomBucketName() - msgCreateBucket := storagetypes.NewMsgCreateBucket( - user.GetAddr(), bucketName, storagetypes.VISIBILITY_TYPE_PUBLIC_READ, sp.OperatorKey.GetAddr(), - nil, math.MaxUint, nil, chargedReadQuota) - msgCreateBucket.PrimarySpApproval.GlobalVirtualGroupFamilyId = gvg.FamilyId - msgCreateBucket.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateBucket.GetApprovalBytes()) - s.Require().NoError(err) - s.SendTxBlock(user, msgCreateBucket) - - streamRecordsBeforeDelete := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsBeforeDelete: %s", core.YamlString(streamRecordsBeforeDelete)) - s.Require().NotEqual(streamRecordsBeforeDelete.User.NetflowRate.String(), "0") - - // DeleteBucket - msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) - s.SendTxBlock(user, msgDeleteBucket) - - // check the billing change - streamRecordsAfterDelete := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsBeforeDelete: %s", core.YamlString(streamRecordsAfterDelete)) - s.Require().Equal(streamRecordsAfterDelete.User.NetflowRate.String(), "0") -} - -func (s *PaymentTestSuite) TestStorageBill_Smoke() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBeforeCreateBucket := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsBeforeCreateBucket: %s", core.YamlString(streamRecordsBeforeCreateBucket)) - - params := s.queryParams() - - // create bucket - bucketName := storagetestutils.GenRandomBucketName() - bucketChargedReadQuota := uint64(1000) - msgCreateBucket := storagetypes.NewMsgCreateBucket( - user.GetAddr(), bucketName, storagetypes.VISIBILITY_TYPE_PRIVATE, sp.OperatorKey.GetAddr(), - nil, math.MaxUint, nil, 0) - msgCreateBucket.ChargedReadQuota = bucketChargedReadQuota - msgCreateBucket.PrimarySpApproval.GlobalVirtualGroupFamilyId = gvg.FamilyId - msgCreateBucket.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateBucket.GetApprovalBytes()) - s.Require().NoError(err) - s.SendTxBlock(user, msgCreateBucket) - - // check bill after creating bucket - userBankAccount, err := s.Client.Balance(ctx, &banktypes.QueryBalanceRequest{ - Address: user.GetAddr().String(), - Denom: s.Config.Denom, - }) - s.Require().NoError(err) - s.T().Logf("user bank account %s", userBankAccount) - - streamRecordsAfterCreateBucket := s.getStreamRecords(streamAddresses) - userStreamRecord := streamRecordsAfterCreateBucket.User - s.Require().Equal(userStreamRecord.StaticBalance, sdkmath.ZeroInt()) - - // check price and rate calculation - queryHeadBucketRequest := storagetypes.QueryHeadBucketRequest{ - BucketName: bucketName, - } - queryHeadBucketResponse, err := s.Client.HeadBucket(ctx, &queryHeadBucketRequest) - s.Require().NoError(err) - - queryGetSpStoragePriceByTimeResp, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: queryHeadBucketResponse.BucketInfo.CreateAt, - }) - s.T().Logf("queryGetSpStoragePriceByTimeResp %s, err: %v", queryGetSpStoragePriceByTimeResp, err) - s.Require().NoError(err) - - readPrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.ReadPrice - readChargeRate := readPrice.MulInt(sdk.NewIntFromUint64(queryHeadBucketResponse.BucketInfo.ChargedReadQuota)).TruncateInt() - s.T().Logf("readPrice: %s, readChargeRate: %s", readPrice, readChargeRate) - userTaxRate := params.VersionedParams.ValidatorTaxRate.MulInt(readChargeRate).TruncateInt() - userTotalRate := readChargeRate.Add(userTaxRate) - s.Require().Equal(userStreamRecord.NetflowRate.Abs(), userTotalRate) - expectedOutFlows := []paymenttypes.OutFlow{ - {ToAddress: family.VirtualPaymentAddress, Rate: readChargeRate}, - {ToAddress: paymenttypes.ValidatorTaxPoolAddress.String(), Rate: userTaxRate}, - } - userOutFlowsResponse, err := s.Client.OutFlows(ctx, &paymenttypes.QueryOutFlowsRequest{Account: user.GetAddr().String()}) - s.Require().NoError(err) - sort.Slice(userOutFlowsResponse.OutFlows, func(i, j int) bool { - return userOutFlowsResponse.OutFlows[i].ToAddress < userOutFlowsResponse.OutFlows[j].ToAddress - }) - sort.Slice(expectedOutFlows, func(i, j int) bool { - return expectedOutFlows[i].ToAddress < expectedOutFlows[j].ToAddress - }) - s.Require().Equal(expectedOutFlows, userOutFlowsResponse.OutFlows) - - // CreateObject - objectName := storagetestutils.GenRandomObjectName() - // create test buffer - var buffer bytes.Buffer - // Create 1MiB content where each line contains 1024 characters. - for i := 0; i < 1024; i++ { - buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line)) - } - payloadSize := buffer.Len() - checksum := sdk.Keccak256(buffer.Bytes()) - expectChecksum := [][]byte{checksum, checksum, checksum, checksum, checksum, checksum, checksum} - contextType := "text/event-stream" - msgCreateObject := storagetypes.NewMsgCreateObject(user.GetAddr(), bucketName, objectName, uint64(payloadSize), storagetypes.VISIBILITY_TYPE_PRIVATE, expectChecksum, contextType, storagetypes.REDUNDANCY_EC_TYPE, math.MaxUint, nil) - msgCreateObject.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateObject.GetApprovalBytes()) - s.Require().NoError(err) - // simulate - res := s.SimulateTx(msgCreateObject, user) - s.T().Logf("res %v", res.Result) - // check EventFeePreview in simulation result - var feePreviewEventEmitted bool - events := res.Result.Events - for _, event := range events { - if event.Type == "greenfield.payment.EventFeePreview" { - s.T().Logf("event %v", event) - feePreviewEventEmitted = true - } - } - s.Require().True(feePreviewEventEmitted) - s.SendTxBlock(user, msgCreateObject) - - // check lock balance - queryHeadBucketResponseAfterCreateObj, err := s.Client.HeadBucket(ctx, &queryHeadBucketRequest) - s.T().Logf("queryHeadBucketResponseAfterCreateObj %s, err: %v", queryHeadBucketResponseAfterCreateObj, err) - s.Require().NoError(err) - queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ - BucketName: bucketName, - ObjectName: objectName, - } - queryHeadObjectResponse, err := s.Client.HeadObject(ctx, &queryHeadObjectRequest) - s.T().Logf("queryHeadObjectResponse %s, err: %v", queryHeadObjectResponse, err) - s.Require().NoError(err) - - queryGetSecondarySpStorePriceByTime, err := s.Client.QueryGetSecondarySpStorePriceByTime(ctx, &sptypes.QueryGetSecondarySpStorePriceByTimeRequest{ - Timestamp: queryHeadBucketResponse.BucketInfo.CreateAt, - }) - s.T().Logf("queryGetSecondarySpStorePriceByTime %s, err: %v", queryGetSecondarySpStorePriceByTime, err) - s.Require().NoError(err) - primaryStorePrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.StorePrice - secondaryStorePrice := queryGetSecondarySpStorePriceByTime.SecondarySpStorePrice.StorePrice - chargeSize := s.getChargeSize(queryHeadObjectResponse.ObjectInfo.PayloadSize) - expectedChargeRate := primaryStorePrice.Add(secondaryStorePrice.MulInt64(6)).MulInt(sdk.NewIntFromUint64(chargeSize)).TruncateInt() - expectedChargeRate = params.VersionedParams.ValidatorTaxRate.MulInt(expectedChargeRate).TruncateInt().Add(expectedChargeRate) - expectedLockedBalance := expectedChargeRate.Mul(sdkmath.NewIntFromUint64(params.VersionedParams.ReserveTime)) - - streamRecordsAfterCreateObject := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsAfterCreateObject %s", core.YamlString(streamRecordsAfterCreateObject)) - userStreamAccountAfterCreateObj := streamRecordsAfterCreateObject.User - - s.Require().Equal(expectedLockedBalance.String(), userStreamAccountAfterCreateObj.LockBalance.String()) - - // seal object - gvgId := gvg.Id - msgSealObject := storagetypes.NewMsgSealObject(sp.SealKey.GetAddr(), bucketName, objectName, gvg.Id, nil) - secondarySigs := make([][]byte, 0) - secondarySPBlsPubKeys := make([]bls.PublicKey, 0) - blsSignHash := storagetypes.NewSecondarySpSealObjectSignDoc(s.GetChainID(), gvgId, queryHeadObjectResponse.ObjectInfo.Id, storagetypes.GenerateHash(expectChecksum[:])).GetBlsSignHash() - // every secondary sp signs the checksums - for _, spID := range gvg.SecondarySpIds { - sig, err := core.BlsSignAndVerify(s.StorageProviders[spID], blsSignHash) - s.Require().NoError(err) - secondarySigs = append(secondarySigs, sig) - pk, err := bls.PublicKeyFromBytes(s.StorageProviders[spID].BlsKey.PubKey().Bytes()) - s.Require().NoError(err) - secondarySPBlsPubKeys = append(secondarySPBlsPubKeys, pk) - } - aggBlsSig, err := core.BlsAggregateAndVerify(secondarySPBlsPubKeys, blsSignHash, secondarySigs) - s.Require().NoError(err) - msgSealObject.SecondarySpBlsAggSignatures = aggBlsSig - s.T().Logf("msg %s", msgSealObject.String()) - s.SendTxBlock(sp.SealKey, msgSealObject) - - // check bill after seal - streamRecordsAfterSeal := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsAfterSeal %s", core.YamlString(streamRecordsAfterSeal)) - s.Require().Equal(sdkmath.ZeroInt(), streamRecordsAfterSeal.User.LockBalance) - s.checkStreamRecordsBeforeAndAfter(streamRecordsAfterCreateObject, streamRecordsAfterSeal, readPrice, readChargeRate, primaryStorePrice, secondaryStorePrice, chargeSize, uint64(payloadSize)) - - // query dynamic balance - time.Sleep(3 * time.Second) - queryDynamicBalanceRequest := paymenttypes.QueryDynamicBalanceRequest{ - Account: user.GetAddr().String(), - } - queryDynamicBalanceResponse, err := s.Client.DynamicBalance(ctx, &queryDynamicBalanceRequest) - s.Require().NoError(err) - s.T().Logf("queryDynamicBalanceResponse %s", core.YamlString(queryDynamicBalanceResponse)) - - // create empty object - streamRecordsBeforeCreateEmptyObject := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsBeforeCreateEmptyObject %s", core.YamlString(streamRecordsBeforeCreateEmptyObject)) - - emptyObjectName := "sub_directory/" - // create empty test buffer - var emptyBuffer bytes.Buffer - emptyPayloadSize := emptyBuffer.Len() - emptyChecksum := sdk.Keccak256(emptyBuffer.Bytes()) - emptyExpectChecksum := [][]byte{emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum} - msgCreateEmptyObject := storagetypes.NewMsgCreateObject(user.GetAddr(), bucketName, emptyObjectName, uint64(emptyPayloadSize), storagetypes.VISIBILITY_TYPE_PRIVATE, emptyExpectChecksum, contextType, storagetypes.REDUNDANCY_EC_TYPE, math.MaxUint, nil) - msgCreateEmptyObject.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateEmptyObject.GetApprovalBytes()) - s.Require().NoError(err) - s.SendTxBlock(user, msgCreateEmptyObject) - - streamRecordsAfterCreateEmptyObject := s.getStreamRecords(streamAddresses) - s.T().Logf("streamRecordsAfterCreateEmptyObject %s", core.YamlString(streamRecordsAfterCreateEmptyObject)) - chargeSize = s.getChargeSize(uint64(emptyPayloadSize)) - s.checkStreamRecordsBeforeAndAfter(streamRecordsBeforeCreateEmptyObject, streamRecordsAfterCreateEmptyObject, readPrice, readChargeRate, primaryStorePrice, secondaryStorePrice, chargeSize, uint64(emptyPayloadSize)) - - // test query auto settle records - queryAllAutoSettleRecordRequest := paymenttypes.QueryAllAutoSettleRecordRequest{} - queryAllAutoSettleRecordResponse, err := s.Client.AutoSettleRecordAll(ctx, &queryAllAutoSettleRecordRequest) - s.Require().NoError(err) - s.T().Logf("queryAllAutoSettleRecordResponse %s", core.YamlString(queryAllAutoSettleRecordResponse)) - s.Require().True(len(queryAllAutoSettleRecordResponse.AutoSettleRecord) >= 1) - - // simulate delete object, check fee preview - deleteObjectMsg := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName) - deleteObjectSimRes := s.SimulateTx(deleteObjectMsg, user) - s.T().Logf("deleteObjectSimRes %v", deleteObjectSimRes.Result) -} - -func (s *PaymentTestSuite) TestStorageBill_DeleteObjectBucket_WithoutPriceChange() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - - // create bucket - bucketName := s.createBucket(sp, user, 256) - - //simulate delete bucket gas - msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) - simulateResponse := s.SimulateTx(msgDeleteBucket, user) - gasLimit := simulateResponse.GasInfo.GetGasUsed() - gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas := gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))) - s.T().Log("total gas", "gas", gas) - - // create & seal objects - _, _, objectName1, objectId1, checksums1, _ := s.createObject(user, bucketName, false) - s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) - - // for payment - time.Sleep(2 * time.Second) - - //transfer gas - msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( - sdk.NewCoin(s.Config.Denom, sdkmath.NewInt(5*types.DecimalGwei)), - )) - simulateResponse = s.SimulateTx(msgSend, user) - gasLimit = simulateResponse.GasInfo.GetGasUsed() - gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) - s.T().Log("total gas", "gas", gas) - - //delete object gas - msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) - simulateResponse = s.SimulateTx(msgDeleteObject, user) - gasLimit = simulateResponse.GasInfo.GetGasUsed() - gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) - s.T().Log("total gas", "gas", gas) - - // transfer out user's balance - queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} - queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - - msgSend.Amount = sdk.NewCoins( - sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gas)), - ) - s.SendTxBlock(user, msgSend) - _, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - - s.SendTxBlock(user, msgDeleteObject) - s.SendTxBlock(user, msgDeleteBucket) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.NetflowRate, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) -} - -func (s *PaymentTestSuite) TestStorageBill_DeleteObjectBucket_WithPriceChange() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - - // create bucket - bucketName := s.createBucket(sp, user, 256) - - //simulate delete bucket gas - msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) - simulateResponse := s.SimulateTx(msgDeleteBucket, user) - gasLimit := simulateResponse.GasInfo.GetGasUsed() - gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas := gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))) - s.T().Log("total gas", "gas", gas) - - // create & seal objects - _, _, objectName1, objectId1, checksums1, _ := s.createObject(user, bucketName, false) - s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) - - // for payment - time.Sleep(2 * time.Second) - - //transfer gas - msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( - sdk.NewCoin(s.Config.Denom, sdkmath.NewInt(5*types.DecimalGwei)), - )) - simulateResponse = s.SimulateTx(msgSend, user) - gasLimit = simulateResponse.GasInfo.GetGasUsed() - gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) - s.T().Log("total gas", "gas", gas) - - //delete object gas - msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) - simulateResponse = s.SimulateTx(msgDeleteObject, user) - gasLimit = simulateResponse.GasInfo.GetGasUsed() - gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) - s.T().Log("total gas", "gas", gas) - - // transfer out user's balance - queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} - queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - - msgSend.Amount = sdk.NewCoins( - sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gas)), - ) - s.SendTxBlock(user, msgSend) - _, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - - // sp price changes - priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: 0, - }) - s.Require().NoError(err) - s.T().Log("price", priceRes.SpStoragePrice) - - // update new price - msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(1000), - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(10000), - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) - - s.SendTxBlock(user, msgDeleteObject) - s.SendTxBlock(user, msgDeleteBucket) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.NetflowRate, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - - // revert price - msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice, - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice, - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) -} - -func (s *PaymentTestSuite) TestStorageBill_DeleteObjectBucket_WithPriceChangeReserveTimeChange() { - defer s.revertParams() - - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - - // create bucket - bucketName := s.createBucket(sp, user, 256) - - //simulate delete bucket gas - msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) - simulateResponse := s.SimulateTx(msgDeleteBucket, user) - gasLimit := simulateResponse.GasInfo.GetGasUsed() - gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas := gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))) - s.T().Log("total gas", "gas", gas) - - // create & seal objects - _, _, objectName1, objectId1, checksums1, _ := s.createObject(user, bucketName, false) - s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) - - // for payment - time.Sleep(2 * time.Second) - - //transfer gas - msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( - sdk.NewCoin(s.Config.Denom, sdkmath.NewInt(5*types.DecimalGwei)), - )) - simulateResponse = s.SimulateTx(msgSend, user) - gasLimit = simulateResponse.GasInfo.GetGasUsed() - gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) - s.T().Log("total gas", "gas", gas) - - //delete object gas - msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) - simulateResponse = s.SimulateTx(msgDeleteObject, user) - gasLimit = simulateResponse.GasInfo.GetGasUsed() - gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - - gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) - s.T().Log("total gas", "gas", gas) - - // transfer out user's balance - queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} - queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - - msgSend.Amount = sdk.NewCoins( - sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gas)), - ) - s.SendTxBlock(user, msgSend) - _, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - - // sp price changes - priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: 0, - }) - s.Require().NoError(err) - s.T().Log("price", priceRes.SpStoragePrice) - - // update new price - msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(1000), - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(10000), - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) - - // update params - params := s.queryParams() - oldReserveTime := params.VersionedParams.ReserveTime - oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate - - params.VersionedParams.ReserveTime = oldReserveTime * 2 - params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2) - s.updateParams(params) - - s.SendTxBlock(user, msgDeleteObject) - s.SendTxBlock(user, msgDeleteBucket) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.NetflowRate, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - - // revert price - msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice, - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice, - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) -} - -func (s *PaymentTestSuite) TestStorageBill_DeleteObject_WithStoreLessThanReserveTime() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - params := s.queryParams() - reserveTime := params.VersionedParams.ReserveTime - - // create bucket - bucketName := s.createBucket(sp, user, 256) - - // create & seal objects - _, _, objectName1, objectId1, checksums1, payloadSize := s.createObject(user, bucketName, false) - s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) - - headObjectRes, err := s.Client.HeadObject(ctx, &storagetypes.QueryHeadObjectRequest{ - BucketName: bucketName, - ObjectName: objectName1, - }) - s.Require().NoError(err) - s.T().Log("headObjectRes", headObjectRes) - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, userRateRead := s.calculateReadRates(sp, bucketName) - _, _, _, userRateStore := s.calculateStorageRates(sp, bucketName, objectName1, payloadSize, 0) - - msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) - s.SendTxBlock(user, msgDeleteObject) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - - settledTime := streamRecordsAfter.User.CrudTimestamp - streamRecordsBefore.User.CrudTimestamp - timeToPay := int64(reserveTime) + headObjectRes.ObjectInfo.CreateAt - streamRecordsAfter.User.CrudTimestamp - balanceDelta := userRateRead.Add(userRateStore).MulRaw(settledTime).Add(userRateStore.MulRaw(timeToPay)) - - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), userRateStore.Int64()) - userBalanceChange := streamRecordsAfter.User.BufferBalance.Add(streamRecordsAfter.User.StaticBalance). - Sub(streamRecordsBefore.User.BufferBalance.Add(streamRecordsBefore.User.StaticBalance)) - s.Require().Equal(userBalanceChange.Neg().Int64(), balanceDelta.Int64()) - - familyDelta := streamRecordsAfter.GVGFamily.StaticBalance.Sub(streamRecordsBefore.GVGFamily.StaticBalance) - gvgDelta := streamRecordsAfter.GVG.StaticBalance.Sub(streamRecordsBefore.GVG.StaticBalance) - taxPoolDelta := streamRecordsAfter.Tax.StaticBalance.Sub(streamRecordsBefore.Tax.StaticBalance) - s.T().Log("familyDelta", familyDelta, "gvgDelta", gvgDelta, "taxPoolDelta", taxPoolDelta) - s.Require().True(familyDelta.Add(gvgDelta).Add(taxPoolDelta).Int64() >= balanceDelta.Int64()) // could exist other buckets/objects on the gvg & family -} - -func (s *PaymentTestSuite) TestStorageBill_DeleteObject_WithStoreMoreThanReserveTime() { - defer s.revertParams() - - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - params := s.queryParams() - params.VersionedParams.ReserveTime = 5 - params.ForcedSettleTime = 2 - s.updateParams(params) - - // create bucket - bucketName := s.createBucket(sp, user, 256) - - // create & seal objects - _, _, objectName1, objectId1, checksums1, payloadSize := s.createObject(user, bucketName, false) - s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) - - headObjectRes, err := s.Client.HeadObject(ctx, &storagetypes.QueryHeadObjectRequest{ - BucketName: bucketName, - ObjectName: objectName1, - }) - s.Require().NoError(err) - s.T().Log("headObjectRes", headObjectRes) - - time.Sleep(5 * time.Second) - queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} - queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - balanceBefore := queryBalanceResponse.Balance.Amount - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, userRateRead := s.calculateReadRates(sp, bucketName) - _, _, _, userRateStore := s.calculateStorageRates(sp, bucketName, objectName1, payloadSize, 0) - - msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) - simulateResponse := s.SimulateTx(msgDeleteObject, user) - gasLimit := simulateResponse.GasInfo.GetGasUsed() - gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) - s.Require().NoError(err) - gas := gasPrice.Amount.MulRaw(int64(gasLimit)) - - // delete object - s.SendTxBlock(user, msgDeleteObject) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - queryBalanceRequest = banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} - queryBalanceResponse, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) - s.Require().NoError(err) - balanceAfter := queryBalanceResponse.Balance.Amount - - settledTime := streamRecordsAfter.User.CrudTimestamp - streamRecordsBefore.User.CrudTimestamp - balanceDelta := userRateRead.Add(userRateStore).MulRaw(settledTime) - - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), userRateStore.Int64()) - userBalanceChange := streamRecordsBefore.User.BufferBalance.Add(streamRecordsBefore.User.StaticBalance). - Sub(streamRecordsAfter.User.BufferBalance.Add(streamRecordsAfter.User.StaticBalance)) - userBalanceChange = userBalanceChange.Add(balanceBefore.Sub(balanceAfter)).Sub(gas) - s.Require().Equal(userBalanceChange.Int64(), balanceDelta.Int64()) - - familyDelta := streamRecordsAfter.GVGFamily.StaticBalance.Sub(streamRecordsBefore.GVGFamily.StaticBalance) - gvgDelta := streamRecordsAfter.GVG.StaticBalance.Sub(streamRecordsBefore.GVG.StaticBalance) - taxPoolDelta := streamRecordsAfter.Tax.StaticBalance.Sub(streamRecordsBefore.Tax.StaticBalance) - s.T().Log("familyDelta", familyDelta, "gvgDelta", gvgDelta, "taxPoolDelta", taxPoolDelta) - s.Require().True(familyDelta.Add(gvgDelta).Add(taxPoolDelta).Int64() >= balanceDelta.Int64()) // could exist other buckets/objects on the gvg & family -} - -func (s *PaymentTestSuite) TestStorageBill_CreateBucket_WithZeroNoneZeroReadQuota() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - - params := s.queryParams() - - // case: create bucket with zero read quota - bucketName := s.createBucket(sp, user, 0) - - // bucket created - queryHeadBucketRequest := storagetypes.QueryHeadBucketRequest{ - BucketName: bucketName, - } - _, err = s.Client.HeadBucket(ctx, &queryHeadBucketRequest) - s.Require().NoError(err) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.NetflowRate, streamRecordsBefore.User.NetflowRate) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate, streamRecordsBefore.GVGFamily.NetflowRate) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate, streamRecordsBefore.Tax.NetflowRate) - - // case: create bucket with none zero read quota - bucketName = s.createBucket(sp, user, 10240) - - // bucket created - queryHeadBucketRequest = storagetypes.QueryHeadBucketRequest{ - BucketName: bucketName, - } - queryHeadBucketResponse, err := s.Client.HeadBucket(ctx, &queryHeadBucketRequest) - s.Require().NoError(err) - - // check price and rate calculation - queryGetSpStoragePriceByTimeResp, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: queryHeadBucketResponse.BucketInfo.CreateAt, - }) - s.T().Logf("queryGetSpStoragePriceByTimeResp %s, err: %v", queryGetSpStoragePriceByTimeResp, err) - s.Require().NoError(err) - - readPrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.ReadPrice - readChargeRate := readPrice.MulInt(sdk.NewIntFromUint64(queryHeadBucketResponse.BucketInfo.ChargedReadQuota)).TruncateInt() - s.T().Logf("readPrice: %s, readChargeRate: %s", readPrice, readChargeRate) - taxRate := params.VersionedParams.ValidatorTaxRate.MulInt(readChargeRate).TruncateInt() - userTotalRate := readChargeRate.Add(taxRate) - - // assertions - streamRecordsAfter = s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRate.Neg()) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), readChargeRate) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRate) - - expectedOutFlows := []paymenttypes.OutFlow{ - {ToAddress: family.VirtualPaymentAddress, Rate: readChargeRate}, - {ToAddress: paymenttypes.ValidatorTaxPoolAddress.String(), Rate: taxRate}, - } - userOutFlowsResponse, err := s.Client.OutFlows(ctx, &paymenttypes.QueryOutFlowsRequest{Account: user.GetAddr().String()}) - s.Require().NoError(err) - sort.Slice(userOutFlowsResponse.OutFlows, func(i, j int) bool { - return userOutFlowsResponse.OutFlows[i].ToAddress < userOutFlowsResponse.OutFlows[j].ToAddress - }) - sort.Slice(expectedOutFlows, func(i, j int) bool { - return expectedOutFlows[i].ToAddress < expectedOutFlows[j].ToAddress - }) - s.Require().Equal(expectedOutFlows, userOutFlowsResponse.OutFlows) -} - -func (s *PaymentTestSuite) TestStorageBill_CreateObject_WithZeroNoneZeroPayload() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - bucketName := s.createBucket(sp, user, 0) - - // case: create object with zero payload size - streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, _, _, payloadSize := s.createObject(user, bucketName, true) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) - gvgFamilyRate, gvgRate, taxRate, userTotalRate := s.calculateStorageRates(sp, bucketName, objectName, payloadSize, 0) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRate.Neg()) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRate) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRate) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRate) - - // case: create object with none zero payload size - streamRecordsBefore = s.getStreamRecords(streamAddresses) - _, _, objectName, _, _, payloadSize = s.createObject(user, bucketName, false) - - // assertions - streamRecordsAfter = s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) - s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) -} - -func (s *PaymentTestSuite) TestStorageBill_CreateObject_WithReserveTimeValidatorTaxRateChange() { - defer s.revertParams() - - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - bucketName := s.createBucket(sp, user, 0) - - // create object with none zero payload size - streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, _, _, payloadSize := s.createObject(user, bucketName, false) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) - s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - - // update params - - params := s.queryParams() - oldReserveTime := params.VersionedParams.ReserveTime - oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate - - params.VersionedParams.ReserveTime = oldReserveTime * 2 - params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2) - s.updateParams(params) - - // create another object after parameter changes - streamRecordsBefore = s.getStreamRecords(streamAddresses) - _, _, objectName, _, _, payloadSize = s.createObject(user, bucketName, false) - - // assertions - streamRecordsAfter = s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - lockFeeAfterParameterChange := s.calculateLockFee(sp, bucketName, objectName, payloadSize) - s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFeeAfterParameterChange) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - s.Require().True(lockFeeAfterParameterChange.GT(lockFee.MulRaw(2))) -} - -func (s *PaymentTestSuite) TestStorageBill_CancelCreateObject() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - bucketName := s.createBucket(sp, user, 0) - - // create object with none zero payload size - streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, _, _, payloadSize := s.createObject(user, bucketName, false) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) - s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - - // cancel create object - s.cancelCreateObject(user, bucketName, objectName) - - // assertions - streamRecordsAfter = s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, lockFee) - s.Require().Equal(streamRecordsAfter.User.LockBalance.Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) -} - -func (s *PaymentTestSuite) TestStorageBill_SealObject_WithoutPriceChange() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - bucketName := s.createBucket(sp, user, 0) - - // create object with none zero payload size - streamRecordsBefore := s.getStreamRecords(streamAddresses) - _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) - s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - - // case: seal object without price change - s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) - - // assertions - streamRecordsAfter = s.getStreamRecords(streamAddresses) - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) - gvgFamilyRate, gvgRate, taxRate, userTotalRate := s.calculateStorageRates(sp, bucketName, objectName, payloadSize, 0) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRate.Neg()) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRate) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRate) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRate) -} - -func (s *PaymentTestSuite) TestStorageBill_SealObject_WithPriceChange() { - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - bucketName := s.createBucket(sp, user, 102400) - - // case: seal object with read price change and storage price change - _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) - - priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: 0, - }) - s.Require().NoError(err) - // update new price - msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(2), - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(2), - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) - - streamRecordsBefore := s.getStreamRecords(streamAddresses) - gvgFamilyRateReadBefore, taxRateReadBefore, userTotalRateReadBefore := s.calculateReadRates(sp, bucketName) - - // seal object - s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter := s.calculateReadRatesCurrentTimestamp(sp, bucketName) - gvgFamilyRateStore, gvgRateStore, taxRateStore, userTotalRateStore := s.calculateStorageRatesCurrentTimestamp(sp, bucketName, objectName, payloadSize) - - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) - - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRateReadAfter.Sub(userTotalRateReadBefore).Add(userTotalRateStore).Neg()) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRateStore) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRateReadAfter.Sub(gvgFamilyRateReadBefore).Add(gvgFamilyRateStore)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRateReadAfter.Sub(taxRateReadBefore).Add(taxRateStore)) -} - -func (s *PaymentTestSuite) TestStorageBill_SealObject_WithPriceChangeValidatorTaxRateChange() { - defer s.revertParams() - - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - - bucketName := s.createBucket(sp, user, 102400) - - // case: seal object with read price change and storage price change - _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) - - priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: 0, - }) - s.Require().NoError(err) - // update new price - msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(2), - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(2), - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) - - streamRecordsBefore := s.getStreamRecords(streamAddresses) - gvgFamilyRateReadBefore, taxRateReadBefore, userTotalRateReadBefore := s.calculateReadRates(sp, bucketName) - - // seal object - s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter := s.calculateReadRatesCurrentTimestamp(sp, bucketName) - gvgFamilyRateStore, gvgRateStore, taxRateStore, userTotalRateStore := s.calculateStorageRatesCurrentTimestamp(sp, bucketName, objectName, payloadSize) - - s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) - s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) - - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRateReadAfter.Sub(userTotalRateReadBefore).Add(userTotalRateStore).Neg()) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRateStore) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRateReadAfter.Sub(gvgFamilyRateReadBefore).Add(gvgFamilyRateStore)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRateReadAfter.Sub(taxRateReadBefore).Add(taxRateStore)) - - // update params - params := s.queryParams() - oldReserveTime := params.VersionedParams.ReserveTime - oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate - - params.VersionedParams.ReserveTime = oldReserveTime * 2 - params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2) - s.updateParams(params) - - _, _, objectName, objectId, checksums, payloadSize = s.createObject(user, bucketName, false) - s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) - - // assertions - streamRecordsAfter = s.getStreamRecords(streamAddresses) - gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter = s.calculateReadRatesCurrentTimestamp(sp, bucketName) - 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()) - - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRateReadAfter.Sub(userTotalRateReadBefore).Add(userTotalRateStore).Neg()) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRateStore) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRateReadAfter.Sub(gvgFamilyRateReadBefore).Add(gvgFamilyRateStore)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRateReadAfter.Sub(taxRateReadBefore).Add(taxRateStore)) -} - -func (s *PaymentTestSuite) TestStorageBill_FullLifecycle() { - defer s.revertParams() - - var err error - ctx := context.Background() - sp := s.PickStorageProvider() - gvg, found := sp.GetFirstGlobalVirtualGroup() - s.Require().True(found) - queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ - FamilyId: gvg.FamilyId, - }) - s.Require().NoError(err) - family := queryFamilyResponse.GlobalVirtualGroupFamily - user := s.GenAndChargeAccounts(1, 1000000)[0] - - // query storage price - priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ - SpAddr: sp.OperatorKey.GetAddr().String(), - Timestamp: 0, - }) - s.Require().NoError(err) - s.T().Log("price", priceRes.SpStoragePrice) - - streamAddresses := []string{ - user.GetAddr().String(), - family.VirtualPaymentAddress, - gvg.VirtualPaymentAddress, - paymenttypes.ValidatorTaxPoolAddress.String(), - } - streamRecordsBefore := s.getStreamRecords(streamAddresses) - - // full lifecycle - bucketName1 := s.createBucket(sp, user, 0) - _, _, objectName1, _, _, _ := s.createObject(user, bucketName1, true) - _, _, objectName2, objectId2, checksums2, _ := s.createObject(user, bucketName1, false) - s.sealObject(sp, gvg, bucketName1, objectName2, objectId2, checksums2) - - bucketName2 := s.createBucket(sp, user, 1024) - _, _, objectName3, objectId3, checksums3, _ := s.createObject(user, bucketName2, false) - s.sealObject(sp, gvg, bucketName2, objectName3, objectId3, checksums3) - - // update params - params := s.queryParams() - params.VersionedParams.ReserveTime = params.VersionedParams.ReserveTime * 3 - params.ForcedSettleTime = params.ForcedSettleTime * 2 - s.updateParams(params) - - _, _, objectName4, objectId4, checksums4, _ := s.createObject(user, bucketName2, false) - s.sealObject(sp, gvg, bucketName2, objectName4, objectId4, checksums4) - - bucketName3 := s.createBucket(sp, user, 1024) - _, _, objectName5, objectId5, checksums5, _ := s.createObject(user, bucketName3, false) - s.sealObject(sp, gvg, bucketName3, objectName5, objectId5, checksums5) - - // update new price - msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice, - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(10000), - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) - - // update params - params = s.queryParams() - params.VersionedParams.ReserveTime = params.VersionedParams.ReserveTime / 2 - params.ForcedSettleTime = params.ForcedSettleTime / 3 - s.updateParams(params) - - _, _, objectName6, objectId6, checksums6, _ := s.createObject(user, bucketName3, false) - s.sealObject(sp, gvg, bucketName3, objectName6, objectId6, checksums6) - - bucketName4 := s.createBucket(sp, user, 1024) - _, _, objectName7, objectId7, checksums7, _ := s.createObject(user, bucketName4, false) - s.sealObject(sp, gvg, bucketName4, objectName7, objectId7, checksums7) - - // update params - params = s.queryParams() - params.VersionedParams.ValidatorTaxRate = params.VersionedParams.ValidatorTaxRate.MulInt64(2) - s.updateParams(params) - - _, _, objectName8, objectId8, checksums8, _ := s.createObject(user, bucketName4, false) - s.sealObject(sp, gvg, bucketName4, objectName8, objectId8, checksums8) - - time.Sleep(3 * time.Second) - - _ = s.deleteObject(user, bucketName1, objectName1) - _ = s.deleteObject(user, bucketName1, objectName2) - - // update params - params = s.queryParams() - params.VersionedParams.ValidatorTaxRate = params.VersionedParams.ValidatorTaxRate.MulInt64(3) - s.updateParams(params) - - _ = s.deleteObject(user, bucketName2, objectName3) - _ = s.deleteObject(user, bucketName2, objectName4) - err = s.deleteBucket(user, bucketName1) - s.Require().Error(err) - err = s.deleteBucket(user, bucketName2) - s.Require().Error(err) - - _ = s.deleteObject(user, bucketName3, objectName5) - _ = s.deleteObject(user, bucketName3, objectName6) - _ = s.deleteObject(user, bucketName4, objectName7) - _ = s.deleteObject(user, bucketName4, objectName8) - err = s.deleteBucket(user, bucketName3) - s.Require().Error(err) - err = s.deleteBucket(user, bucketName4) - s.Require().Error(err) - - // assertions - streamRecordsAfter := s.getStreamRecords(streamAddresses) - s.Require().True(!streamRecordsAfter.User.StaticBalance.IsZero()) - s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) - s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) - - // revert price - msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ - SpAddress: sp.OperatorKey.GetAddr().String(), - ReadPrice: priceRes.SpStoragePrice.ReadPrice, - FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, - StorePrice: priceRes.SpStoragePrice.StorePrice, - } - s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) -} - func (s *PaymentTestSuite) TestVirtualGroup_Settle() { var err error ctx := context.Background() @@ -3038,6 +1739,8 @@ func (s *PaymentTestSuite) TestDiscontinue_InBlocks_WithPriceChangeReserveTimeCh s.Require().NoError(err) s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_SEALED) time.Sleep(200 * time.Millisecond) + userStream := s.getStreamRecord(user.GetAddr().String()) + s.Require().True(userStream.LockBalance.IsPositive()) } queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} @@ -3122,6 +1825,238 @@ func (s *PaymentTestSuite) TestDiscontinue_InBlocks_WithPriceChangeReserveTimeCh s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) } +func (s *PaymentTestSuite) TestDiscontinue_MultiObjects() { + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + // create bucket + bucketName := s.createBucket(sp, user, 0) + objectIds := []sdkmath.Uint{} + + // create objects + for i := 0; i < 3; i++ { + _, _, objectName, objectId, _, _ := s.createObject(user, bucketName, false) + queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName, + } + queryHeadObjectResponse, err := s.Client.HeadObject(ctx, &queryHeadObjectRequest) + s.Require().NoError(err) + s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_CREATED) + time.Sleep(200 * time.Millisecond) + objectIds = append(objectIds, objectId) + } + + // create & seal objects + for i := 0; i < 3; i++ { + _, _, objectName, objectId, checksums, _ := s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) + queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName, + } + queryHeadObjectResponse, err := s.Client.HeadObject(ctx, &queryHeadObjectRequest) + s.Require().NoError(err) + s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_SEALED) + time.Sleep(200 * time.Millisecond) + objectIds = append(objectIds, objectId) + } + + queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.SubRaw(5*types.DecimalGwei)), + )) + + simulateResponse := s.SimulateTx(msgSend, user) + gasLimit := simulateResponse.GasInfo.GetGasUsed() + gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + msgSend.Amount = sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))))), + ) + s.SendTxBlock(user, msgSend) + queryBalanceResponse, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + s.Require().Equal(int64(0), queryBalanceResponse.Balance.Amount.Int64()) + + // for payment + time.Sleep(2 * time.Second) + + // force objects + msgs := make([]sdk.Msg, 0) + for _, id := range objectIds { + msgDiscontinueObject := storagetypes.NewMsgDiscontinueObject(sp.GcKey.GetAddr(), bucketName, []sdkmath.Uint{id}, "test") + msgs = append(msgs, msgDiscontinueObject) + } + msgs = append(msgs, storagetypes.NewMsgDiscontinueBucket(sp.GcKey.GetAddr(), bucketName, "test")) + txRes := s.SendTxBlock(sp.GcKey, msgs...) + deleteAt := filterDiscontinueObjectEventFromTx(txRes).DeleteAt + + for { + time.Sleep(200 * time.Millisecond) + statusRes, err := s.TmClient.TmClient.Status(context.Background()) + s.Require().NoError(err) + blockTime := statusRes.SyncInfo.LatestBlockTime.Unix() + + s.T().Logf("current blockTime: %d, delete blockTime: %d", blockTime, deleteAt) + + if blockTime > deleteAt+5 { + break + } + } + + _, err = s.Client.HeadBucket(ctx, &storagetypes.QueryHeadBucketRequest{BucketName: bucketName}) + s.Require().ErrorContains(err, "No such bucket") + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + s.Require().True(streamRecordsAfter.User.LockBalance.IsZero()) +} + +func (s *PaymentTestSuite) TestDiscontinue_MultiBuckets() { + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + bucketNames := []string{} + // create bucket + bucketName1 := s.createBucket(sp, user, 1023) + bucketNames = append(bucketNames, bucketName1) + + // create objects + for i := 0; i < 2; i++ { + _, _, objectName, _, _, _ := s.createObject(user, bucketName1, false) + queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName1, + ObjectName: objectName, + } + queryHeadObjectResponse, err := s.Client.HeadObject(ctx, &queryHeadObjectRequest) + s.Require().NoError(err) + s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_CREATED) + time.Sleep(200 * time.Millisecond) + } + + // create & seal objects + for i := 0; i < 2; i++ { + _, _, objectName, objectId, checksums, _ := s.createObject(user, bucketName1, false) + s.sealObject(sp, gvg, bucketName1, objectName, objectId, checksums) + queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName1, + ObjectName: objectName, + } + queryHeadObjectResponse, err := s.Client.HeadObject(ctx, &queryHeadObjectRequest) + s.Require().NoError(err) + s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_SEALED) + time.Sleep(200 * time.Millisecond) + } + + // create bucket + bucketName2 := s.createBucket(sp, user, 21023) + bucketNames = append(bucketNames, bucketName2) + + // create bucket + bucketName3 := s.createBucket(sp, user, 0) + bucketNames = append(bucketNames, bucketName3) + + // create bucket + bucketName4 := s.createBucket(sp, user, 55) + bucketNames = append(bucketNames, bucketName4) + + queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.SubRaw(5*types.DecimalGwei)), + )) + + simulateResponse := s.SimulateTx(msgSend, user) + gasLimit := simulateResponse.GasInfo.GetGasUsed() + gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + msgSend.Amount = sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))))), + ) + s.SendTxBlock(user, msgSend) + queryBalanceResponse, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + s.Require().Equal(int64(0), queryBalanceResponse.Balance.Amount.Int64()) + + // for payment + time.Sleep(2 * time.Second) + + // force objects + msgs := make([]sdk.Msg, 0) + for _, bucketName := range bucketNames { + msgDiscontinueBucket := storagetypes.NewMsgDiscontinueBucket(sp.GcKey.GetAddr(), bucketName, "test") + msgs = append(msgs, msgDiscontinueBucket) + } + txRes := s.SendTxBlock(sp.GcKey, msgs...) + deleteAt := filterDiscontinueBucketEventFromTx(txRes).DeleteAt + + for { + time.Sleep(200 * time.Millisecond) + statusRes, err := s.TmClient.TmClient.Status(context.Background()) + s.Require().NoError(err) + blockTime := statusRes.SyncInfo.LatestBlockTime.Unix() + + s.T().Logf("current blockTime: %d, delete blockTime: %d", blockTime, deleteAt) + + if blockTime > deleteAt+5 { + break + } + } + + for _, bucketName := range bucketNames { + _, err = s.Client.HeadBucket(ctx, &storagetypes.QueryHeadBucketRequest{BucketName: bucketName}) + s.Require().ErrorContains(err, "No such bucket") + } + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + s.Require().True(streamRecordsAfter.User.LockBalance.IsZero()) +} + func TestPaymentTestSuite(t *testing.T) { suite.Run(t, new(PaymentTestSuite)) } @@ -3576,6 +2511,20 @@ func (s *PaymentTestSuite) sealObject(sp *core.StorageProvider, gvg *virtualgrou return gvg } +func (s *PaymentTestSuite) rejectSealObject(sp *core.StorageProvider, gvg *virtualgrouptypes.GlobalVirtualGroup, bucketName, objectName string) { + msgRejectSealObject := storagetypes.NewMsgRejectUnsealedObject(sp.SealKey.GetAddr(), bucketName, objectName) + + s.T().Logf("msg %s", msgRejectSealObject.String()) + s.SendTxBlock(sp.SealKey, msgRejectSealObject) + + queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName, + } + _, err := s.Client.HeadObject(context.Background(), &queryHeadObjectRequest) + s.Require().Error(err) +} + func (s *PaymentTestSuite) deleteObject(user keys.KeyManager, bucketName, objectName string) error { msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName) s.SendTxBlock(user, msgDeleteObject) diff --git a/e2e/tests/storage_bill_test.go b/e2e/tests/storage_bill_test.go index 0c73fe4d2..b55bf930b 100644 --- a/e2e/tests/storage_bill_test.go +++ b/e2e/tests/storage_bill_test.go @@ -1,7 +1,9 @@ package tests import ( + "bytes" "context" + "fmt" "math" "sort" "time" @@ -21,6 +23,1378 @@ import ( virtualgrouptypes "github.com/bnb-chain/greenfield/x/virtualgroup/types" ) +func (s *PaymentTestSuite) TestStorageBill_DeleteBucket_WithReadQuota() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + // CreateBucket + chargedReadQuota := uint64(100) + bucketName := storagetestutils.GenRandomBucketName() + msgCreateBucket := storagetypes.NewMsgCreateBucket( + user.GetAddr(), bucketName, storagetypes.VISIBILITY_TYPE_PUBLIC_READ, sp.OperatorKey.GetAddr(), + nil, math.MaxUint, nil, chargedReadQuota) + msgCreateBucket.PrimarySpApproval.GlobalVirtualGroupFamilyId = gvg.FamilyId + msgCreateBucket.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateBucket.GetApprovalBytes()) + s.Require().NoError(err) + s.SendTxBlock(user, msgCreateBucket) + + streamRecordsBeforeDelete := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsBeforeDelete: %s", core.YamlString(streamRecordsBeforeDelete)) + s.Require().NotEqual(streamRecordsBeforeDelete.User.NetflowRate.String(), "0") + + // DeleteBucket + msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) + s.SendTxBlock(user, msgDeleteBucket) + + // check the billing change + streamRecordsAfterDelete := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsBeforeDelete: %s", core.YamlString(streamRecordsAfterDelete)) + s.Require().Equal(streamRecordsAfterDelete.User.NetflowRate.String(), "0") +} + +func (s *PaymentTestSuite) TestStorageBill_Smoke() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBeforeCreateBucket := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsBeforeCreateBucket: %s", core.YamlString(streamRecordsBeforeCreateBucket)) + + params := s.queryParams() + + // create bucket + bucketName := storagetestutils.GenRandomBucketName() + bucketChargedReadQuota := uint64(1000) + msgCreateBucket := storagetypes.NewMsgCreateBucket( + user.GetAddr(), bucketName, storagetypes.VISIBILITY_TYPE_PRIVATE, sp.OperatorKey.GetAddr(), + nil, math.MaxUint, nil, 0) + msgCreateBucket.ChargedReadQuota = bucketChargedReadQuota + msgCreateBucket.PrimarySpApproval.GlobalVirtualGroupFamilyId = gvg.FamilyId + msgCreateBucket.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateBucket.GetApprovalBytes()) + s.Require().NoError(err) + s.SendTxBlock(user, msgCreateBucket) + + // check bill after creating bucket + userBankAccount, err := s.Client.Balance(ctx, &banktypes.QueryBalanceRequest{ + Address: user.GetAddr().String(), + Denom: s.Config.Denom, + }) + s.Require().NoError(err) + s.T().Logf("user bank account %s", userBankAccount) + + streamRecordsAfterCreateBucket := s.getStreamRecords(streamAddresses) + userStreamRecord := streamRecordsAfterCreateBucket.User + s.Require().Equal(userStreamRecord.StaticBalance, sdkmath.ZeroInt()) + + // check price and rate calculation + queryHeadBucketRequest := storagetypes.QueryHeadBucketRequest{ + BucketName: bucketName, + } + queryHeadBucketResponse, err := s.Client.HeadBucket(ctx, &queryHeadBucketRequest) + s.Require().NoError(err) + + queryGetSpStoragePriceByTimeResp, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: queryHeadBucketResponse.BucketInfo.CreateAt, + }) + s.T().Logf("queryGetSpStoragePriceByTimeResp %s, err: %v", queryGetSpStoragePriceByTimeResp, err) + s.Require().NoError(err) + + readPrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.ReadPrice + readChargeRate := readPrice.MulInt(sdk.NewIntFromUint64(queryHeadBucketResponse.BucketInfo.ChargedReadQuota)).TruncateInt() + s.T().Logf("readPrice: %s, readChargeRate: %s", readPrice, readChargeRate) + userTaxRate := params.VersionedParams.ValidatorTaxRate.MulInt(readChargeRate).TruncateInt() + userTotalRate := readChargeRate.Add(userTaxRate) + s.Require().Equal(userStreamRecord.NetflowRate.Abs(), userTotalRate) + expectedOutFlows := []paymenttypes.OutFlow{ + {ToAddress: family.VirtualPaymentAddress, Rate: readChargeRate}, + {ToAddress: paymenttypes.ValidatorTaxPoolAddress.String(), Rate: userTaxRate}, + } + userOutFlowsResponse, err := s.Client.OutFlows(ctx, &paymenttypes.QueryOutFlowsRequest{Account: user.GetAddr().String()}) + s.Require().NoError(err) + sort.Slice(userOutFlowsResponse.OutFlows, func(i, j int) bool { + return userOutFlowsResponse.OutFlows[i].ToAddress < userOutFlowsResponse.OutFlows[j].ToAddress + }) + sort.Slice(expectedOutFlows, func(i, j int) bool { + return expectedOutFlows[i].ToAddress < expectedOutFlows[j].ToAddress + }) + s.Require().Equal(expectedOutFlows, userOutFlowsResponse.OutFlows) + + // CreateObject + objectName := storagetestutils.GenRandomObjectName() + // create test buffer + var buffer bytes.Buffer + // Create 1MiB content where each line contains 1024 characters. + for i := 0; i < 1024; i++ { + buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line)) + } + payloadSize := buffer.Len() + checksum := sdk.Keccak256(buffer.Bytes()) + expectChecksum := [][]byte{checksum, checksum, checksum, checksum, checksum, checksum, checksum} + contextType := "text/event-stream" + msgCreateObject := storagetypes.NewMsgCreateObject(user.GetAddr(), bucketName, objectName, uint64(payloadSize), storagetypes.VISIBILITY_TYPE_PRIVATE, expectChecksum, contextType, storagetypes.REDUNDANCY_EC_TYPE, math.MaxUint, nil) + msgCreateObject.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateObject.GetApprovalBytes()) + s.Require().NoError(err) + // simulate + res := s.SimulateTx(msgCreateObject, user) + s.T().Logf("res %v", res.Result) + // check EventFeePreview in simulation result + var feePreviewEventEmitted bool + events := res.Result.Events + for _, event := range events { + if event.Type == "greenfield.payment.EventFeePreview" { + s.T().Logf("event %v", event) + feePreviewEventEmitted = true + } + } + s.Require().True(feePreviewEventEmitted) + s.SendTxBlock(user, msgCreateObject) + + // check lock balance + queryHeadBucketResponseAfterCreateObj, err := s.Client.HeadBucket(ctx, &queryHeadBucketRequest) + s.T().Logf("queryHeadBucketResponseAfterCreateObj %s, err: %v", queryHeadBucketResponseAfterCreateObj, err) + s.Require().NoError(err) + queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName, + } + queryHeadObjectResponse, err := s.Client.HeadObject(ctx, &queryHeadObjectRequest) + s.T().Logf("queryHeadObjectResponse %s, err: %v", queryHeadObjectResponse, err) + s.Require().NoError(err) + + queryGetSecondarySpStorePriceByTime, err := s.Client.QueryGetSecondarySpStorePriceByTime(ctx, &sptypes.QueryGetSecondarySpStorePriceByTimeRequest{ + Timestamp: queryHeadBucketResponse.BucketInfo.CreateAt, + }) + s.T().Logf("queryGetSecondarySpStorePriceByTime %s, err: %v", queryGetSecondarySpStorePriceByTime, err) + s.Require().NoError(err) + primaryStorePrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.StorePrice + secondaryStorePrice := queryGetSecondarySpStorePriceByTime.SecondarySpStorePrice.StorePrice + chargeSize := s.getChargeSize(queryHeadObjectResponse.ObjectInfo.PayloadSize) + expectedChargeRate := primaryStorePrice.Add(secondaryStorePrice.MulInt64(6)).MulInt(sdk.NewIntFromUint64(chargeSize)).TruncateInt() + expectedChargeRate = params.VersionedParams.ValidatorTaxRate.MulInt(expectedChargeRate).TruncateInt().Add(expectedChargeRate) + expectedLockedBalance := expectedChargeRate.Mul(sdkmath.NewIntFromUint64(params.VersionedParams.ReserveTime)) + + streamRecordsAfterCreateObject := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsAfterCreateObject %s", core.YamlString(streamRecordsAfterCreateObject)) + userStreamAccountAfterCreateObj := streamRecordsAfterCreateObject.User + + s.Require().Equal(expectedLockedBalance.String(), userStreamAccountAfterCreateObj.LockBalance.String()) + + // seal object + gvgId := gvg.Id + msgSealObject := storagetypes.NewMsgSealObject(sp.SealKey.GetAddr(), bucketName, objectName, gvg.Id, nil) + secondarySigs := make([][]byte, 0) + secondarySPBlsPubKeys := make([]bls.PublicKey, 0) + blsSignHash := storagetypes.NewSecondarySpSealObjectSignDoc(s.GetChainID(), gvgId, queryHeadObjectResponse.ObjectInfo.Id, storagetypes.GenerateHash(expectChecksum[:])).GetBlsSignHash() + // every secondary sp signs the checksums + for _, spID := range gvg.SecondarySpIds { + sig, err := core.BlsSignAndVerify(s.StorageProviders[spID], blsSignHash) + s.Require().NoError(err) + secondarySigs = append(secondarySigs, sig) + pk, err := bls.PublicKeyFromBytes(s.StorageProviders[spID].BlsKey.PubKey().Bytes()) + s.Require().NoError(err) + secondarySPBlsPubKeys = append(secondarySPBlsPubKeys, pk) + } + aggBlsSig, err := core.BlsAggregateAndVerify(secondarySPBlsPubKeys, blsSignHash, secondarySigs) + s.Require().NoError(err) + msgSealObject.SecondarySpBlsAggSignatures = aggBlsSig + s.T().Logf("msg %s", msgSealObject.String()) + s.SendTxBlock(sp.SealKey, msgSealObject) + + // check bill after seal + streamRecordsAfterSeal := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsAfterSeal %s", core.YamlString(streamRecordsAfterSeal)) + s.Require().Equal(sdkmath.ZeroInt(), streamRecordsAfterSeal.User.LockBalance) + s.checkStreamRecordsBeforeAndAfter(streamRecordsAfterCreateObject, streamRecordsAfterSeal, readPrice, readChargeRate, primaryStorePrice, secondaryStorePrice, chargeSize, uint64(payloadSize)) + + // query dynamic balance + time.Sleep(3 * time.Second) + queryDynamicBalanceRequest := paymenttypes.QueryDynamicBalanceRequest{ + Account: user.GetAddr().String(), + } + queryDynamicBalanceResponse, err := s.Client.DynamicBalance(ctx, &queryDynamicBalanceRequest) + s.Require().NoError(err) + s.T().Logf("queryDynamicBalanceResponse %s", core.YamlString(queryDynamicBalanceResponse)) + + // create empty object + streamRecordsBeforeCreateEmptyObject := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsBeforeCreateEmptyObject %s", core.YamlString(streamRecordsBeforeCreateEmptyObject)) + + emptyObjectName := "sub_directory/" + // create empty test buffer + var emptyBuffer bytes.Buffer + emptyPayloadSize := emptyBuffer.Len() + emptyChecksum := sdk.Keccak256(emptyBuffer.Bytes()) + emptyExpectChecksum := [][]byte{emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum, emptyChecksum} + msgCreateEmptyObject := storagetypes.NewMsgCreateObject(user.GetAddr(), bucketName, emptyObjectName, uint64(emptyPayloadSize), storagetypes.VISIBILITY_TYPE_PRIVATE, emptyExpectChecksum, contextType, storagetypes.REDUNDANCY_EC_TYPE, math.MaxUint, nil) + msgCreateEmptyObject.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateEmptyObject.GetApprovalBytes()) + s.Require().NoError(err) + s.SendTxBlock(user, msgCreateEmptyObject) + + streamRecordsAfterCreateEmptyObject := s.getStreamRecords(streamAddresses) + s.T().Logf("streamRecordsAfterCreateEmptyObject %s", core.YamlString(streamRecordsAfterCreateEmptyObject)) + chargeSize = s.getChargeSize(uint64(emptyPayloadSize)) + s.checkStreamRecordsBeforeAndAfter(streamRecordsBeforeCreateEmptyObject, streamRecordsAfterCreateEmptyObject, readPrice, readChargeRate, primaryStorePrice, secondaryStorePrice, chargeSize, uint64(emptyPayloadSize)) + + // test query auto settle records + queryAllAutoSettleRecordRequest := paymenttypes.QueryAllAutoSettleRecordRequest{} + queryAllAutoSettleRecordResponse, err := s.Client.AutoSettleRecordAll(ctx, &queryAllAutoSettleRecordRequest) + s.Require().NoError(err) + s.T().Logf("queryAllAutoSettleRecordResponse %s", core.YamlString(queryAllAutoSettleRecordResponse)) + s.Require().True(len(queryAllAutoSettleRecordResponse.AutoSettleRecord) >= 1) + + // simulate delete object, check fee preview + deleteObjectMsg := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName) + deleteObjectSimRes := s.SimulateTx(deleteObjectMsg, user) + s.T().Logf("deleteObjectSimRes %v", deleteObjectSimRes.Result) +} + +func (s *PaymentTestSuite) TestStorageBill_DeleteObjectBucket_WithoutPriceChange() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + // create bucket + bucketName := s.createBucket(sp, user, 256) + + //simulate delete bucket gas + msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) + simulateResponse := s.SimulateTx(msgDeleteBucket, user) + gasLimit := simulateResponse.GasInfo.GetGasUsed() + gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas := gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))) + s.T().Log("total gas", "gas", gas) + + // create & seal objects + _, _, objectName1, objectId1, checksums1, _ := s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) + + // for payment + time.Sleep(2 * time.Second) + + //transfer gas + msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, sdkmath.NewInt(5*types.DecimalGwei)), + )) + simulateResponse = s.SimulateTx(msgSend, user) + gasLimit = simulateResponse.GasInfo.GetGasUsed() + gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) + s.T().Log("total gas", "gas", gas) + + //delete object gas + msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) + simulateResponse = s.SimulateTx(msgDeleteObject, user) + gasLimit = simulateResponse.GasInfo.GetGasUsed() + gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) + s.T().Log("total gas", "gas", gas) + + // transfer out user's balance + queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + msgSend.Amount = sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gas)), + ) + s.SendTxBlock(user, msgSend) + _, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + s.SendTxBlock(user, msgDeleteObject) + s.SendTxBlock(user, msgDeleteBucket) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.NetflowRate, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) +} + +func (s *PaymentTestSuite) TestStorageBill_DeleteObjectBucket_WithPriceChange() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + // create bucket + bucketName := s.createBucket(sp, user, 256) + + //simulate delete bucket gas + msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) + simulateResponse := s.SimulateTx(msgDeleteBucket, user) + gasLimit := simulateResponse.GasInfo.GetGasUsed() + gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas := gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))) + s.T().Log("total gas", "gas", gas) + + // create & seal objects + _, _, objectName1, objectId1, checksums1, _ := s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) + + // for payment + time.Sleep(2 * time.Second) + + //transfer gas + msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, sdkmath.NewInt(5*types.DecimalGwei)), + )) + simulateResponse = s.SimulateTx(msgSend, user) + gasLimit = simulateResponse.GasInfo.GetGasUsed() + gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) + s.T().Log("total gas", "gas", gas) + + //delete object gas + msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) + simulateResponse = s.SimulateTx(msgDeleteObject, user) + gasLimit = simulateResponse.GasInfo.GetGasUsed() + gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) + s.T().Log("total gas", "gas", gas) + + // transfer out user's balance + queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + msgSend.Amount = sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gas)), + ) + s.SendTxBlock(user, msgSend) + _, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + // sp price changes + priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: 0, + }) + s.Require().NoError(err) + s.T().Log("price", priceRes.SpStoragePrice) + + // update new price + msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(1000), + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(10000), + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) + + s.SendTxBlock(user, msgDeleteObject) + s.SendTxBlock(user, msgDeleteBucket) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.NetflowRate, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // revert price + msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice, + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice, + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) +} + +func (s *PaymentTestSuite) TestStorageBill_DeleteObjectBucket_WithPriceChangeReserveTimeChange() { + defer s.revertParams() + + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + // create bucket + bucketName := s.createBucket(sp, user, 256) + + //simulate delete bucket gas + msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName) + simulateResponse := s.SimulateTx(msgDeleteBucket, user) + gasLimit := simulateResponse.GasInfo.GetGasUsed() + gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas := gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit))) + s.T().Log("total gas", "gas", gas) + + // create & seal objects + _, _, objectName1, objectId1, checksums1, _ := s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) + + // for payment + time.Sleep(2 * time.Second) + + //transfer gas + msgSend := banktypes.NewMsgSend(user.GetAddr(), core.GenRandomAddr(), sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, sdkmath.NewInt(5*types.DecimalGwei)), + )) + simulateResponse = s.SimulateTx(msgSend, user) + gasLimit = simulateResponse.GasInfo.GetGasUsed() + gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) + s.T().Log("total gas", "gas", gas) + + //delete object gas + msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) + simulateResponse = s.SimulateTx(msgDeleteObject, user) + gasLimit = simulateResponse.GasInfo.GetGasUsed() + gasPrice, err = sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + + gas = gas.Add(gasPrice.Amount.Mul(sdk.NewInt(int64(gasLimit)))) + s.T().Log("total gas", "gas", gas) + + // transfer out user's balance + queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + msgSend.Amount = sdk.NewCoins( + sdk.NewCoin(s.Config.Denom, queryBalanceResponse.Balance.Amount.Sub(gas)), + ) + s.SendTxBlock(user, msgSend) + _, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + + // sp price changes + priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: 0, + }) + s.Require().NoError(err) + s.T().Log("price", priceRes.SpStoragePrice) + + // update new price + msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(1000), + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(10000), + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) + + // update params + params := s.queryParams() + oldReserveTime := params.VersionedParams.ReserveTime + oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate + + params.VersionedParams.ReserveTime = oldReserveTime * 2 + params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2) + s.updateParams(params) + + s.SendTxBlock(user, msgDeleteObject) + s.SendTxBlock(user, msgDeleteBucket) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.NetflowRate, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // revert price + msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice, + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice, + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) +} + +func (s *PaymentTestSuite) TestStorageBill_DeleteObject_WithStoreLessThanReserveTime() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + params := s.queryParams() + reserveTime := params.VersionedParams.ReserveTime + + // create bucket + bucketName := s.createBucket(sp, user, 256) + + // create & seal objects + _, _, objectName1, objectId1, checksums1, payloadSize := s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) + + headObjectRes, err := s.Client.HeadObject(ctx, &storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName1, + }) + s.Require().NoError(err) + s.T().Log("headObjectRes", headObjectRes) + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + _, _, userRateRead := s.calculateReadRates(sp, bucketName) + _, _, _, userRateStore := s.calculateStorageRates(sp, bucketName, objectName1, payloadSize, 0) + + msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) + s.SendTxBlock(user, msgDeleteObject) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + + settledTime := streamRecordsAfter.User.CrudTimestamp - streamRecordsBefore.User.CrudTimestamp + timeToPay := int64(reserveTime) + headObjectRes.ObjectInfo.CreateAt - streamRecordsAfter.User.CrudTimestamp + balanceDelta := userRateRead.Add(userRateStore).MulRaw(settledTime).Add(userRateStore.MulRaw(timeToPay)) + + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), userRateStore.Int64()) + userBalanceChange := streamRecordsAfter.User.BufferBalance.Add(streamRecordsAfter.User.StaticBalance). + Sub(streamRecordsBefore.User.BufferBalance.Add(streamRecordsBefore.User.StaticBalance)) + s.Require().Equal(userBalanceChange.Neg().Int64(), balanceDelta.Int64()) + + familyDelta := streamRecordsAfter.GVGFamily.StaticBalance.Sub(streamRecordsBefore.GVGFamily.StaticBalance) + gvgDelta := streamRecordsAfter.GVG.StaticBalance.Sub(streamRecordsBefore.GVG.StaticBalance) + taxPoolDelta := streamRecordsAfter.Tax.StaticBalance.Sub(streamRecordsBefore.Tax.StaticBalance) + s.T().Log("familyDelta", familyDelta, "gvgDelta", gvgDelta, "taxPoolDelta", taxPoolDelta) + s.Require().True(familyDelta.Add(gvgDelta).Add(taxPoolDelta).Int64() >= balanceDelta.Int64()) // could exist other buckets/objects on the gvg & family +} + +func (s *PaymentTestSuite) TestStorageBill_DeleteObject_WithStoreMoreThanReserveTime() { + defer s.revertParams() + + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + params := s.queryParams() + params.VersionedParams.ReserveTime = 5 + params.ForcedSettleTime = 2 + s.updateParams(params) + + // create bucket + bucketName := s.createBucket(sp, user, 256) + + // create & seal objects + _, _, objectName1, objectId1, checksums1, payloadSize := s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName1, objectId1, checksums1) + + headObjectRes, err := s.Client.HeadObject(ctx, &storagetypes.QueryHeadObjectRequest{ + BucketName: bucketName, + ObjectName: objectName1, + }) + s.Require().NoError(err) + s.T().Log("headObjectRes", headObjectRes) + + time.Sleep(5 * time.Second) + queryBalanceRequest := banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err := s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + balanceBefore := queryBalanceResponse.Balance.Amount + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + _, _, userRateRead := s.calculateReadRates(sp, bucketName) + _, _, _, userRateStore := s.calculateStorageRates(sp, bucketName, objectName1, payloadSize, 0) + + msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName1) + simulateResponse := s.SimulateTx(msgDeleteObject, user) + gasLimit := simulateResponse.GasInfo.GetGasUsed() + gasPrice, err := sdk.ParseCoinNormalized(simulateResponse.GasInfo.GetMinGasPrice()) + s.Require().NoError(err) + gas := gasPrice.Amount.MulRaw(int64(gasLimit)) + + // delete object + s.SendTxBlock(user, msgDeleteObject) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + queryBalanceRequest = banktypes.QueryBalanceRequest{Denom: s.Config.Denom, Address: user.GetAddr().String()} + queryBalanceResponse, err = s.Client.BankQueryClient.Balance(ctx, &queryBalanceRequest) + s.Require().NoError(err) + balanceAfter := queryBalanceResponse.Balance.Amount + + settledTime := streamRecordsAfter.User.CrudTimestamp - streamRecordsBefore.User.CrudTimestamp + balanceDelta := userRateRead.Add(userRateStore).MulRaw(settledTime) + + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), userRateStore.Int64()) + userBalanceChange := streamRecordsBefore.User.BufferBalance.Add(streamRecordsBefore.User.StaticBalance). + Sub(streamRecordsAfter.User.BufferBalance.Add(streamRecordsAfter.User.StaticBalance)) + userBalanceChange = userBalanceChange.Add(balanceBefore.Sub(balanceAfter)).Sub(gas) + s.Require().Equal(userBalanceChange.Int64(), balanceDelta.Int64()) + + familyDelta := streamRecordsAfter.GVGFamily.StaticBalance.Sub(streamRecordsBefore.GVGFamily.StaticBalance) + gvgDelta := streamRecordsAfter.GVG.StaticBalance.Sub(streamRecordsBefore.GVG.StaticBalance) + taxPoolDelta := streamRecordsAfter.Tax.StaticBalance.Sub(streamRecordsBefore.Tax.StaticBalance) + s.T().Log("familyDelta", familyDelta, "gvgDelta", gvgDelta, "taxPoolDelta", taxPoolDelta) + s.Require().True(familyDelta.Add(gvgDelta).Add(taxPoolDelta).Int64() >= balanceDelta.Int64()) // could exist other buckets/objects on the gvg & family +} + +func (s *PaymentTestSuite) TestStorageBill_CreateBucket_WithZeroNoneZeroReadQuota() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + params := s.queryParams() + + // case: create bucket with zero read quota + bucketName := s.createBucket(sp, user, 0) + + // bucket created + queryHeadBucketRequest := storagetypes.QueryHeadBucketRequest{ + BucketName: bucketName, + } + _, err = s.Client.HeadBucket(ctx, &queryHeadBucketRequest) + s.Require().NoError(err) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.NetflowRate, streamRecordsBefore.User.NetflowRate) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate, streamRecordsBefore.GVGFamily.NetflowRate) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate, streamRecordsBefore.Tax.NetflowRate) + + // case: create bucket with none zero read quota + bucketName = s.createBucket(sp, user, 10240) + + // bucket created + queryHeadBucketRequest = storagetypes.QueryHeadBucketRequest{ + BucketName: bucketName, + } + queryHeadBucketResponse, err := s.Client.HeadBucket(ctx, &queryHeadBucketRequest) + s.Require().NoError(err) + + // check price and rate calculation + queryGetSpStoragePriceByTimeResp, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: queryHeadBucketResponse.BucketInfo.CreateAt, + }) + s.T().Logf("queryGetSpStoragePriceByTimeResp %s, err: %v", queryGetSpStoragePriceByTimeResp, err) + s.Require().NoError(err) + + readPrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.ReadPrice + readChargeRate := readPrice.MulInt(sdk.NewIntFromUint64(queryHeadBucketResponse.BucketInfo.ChargedReadQuota)).TruncateInt() + s.T().Logf("readPrice: %s, readChargeRate: %s", readPrice, readChargeRate) + taxRate := params.VersionedParams.ValidatorTaxRate.MulInt(readChargeRate).TruncateInt() + userTotalRate := readChargeRate.Add(taxRate) + + // assertions + streamRecordsAfter = s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRate.Neg()) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), readChargeRate) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRate) + + expectedOutFlows := []paymenttypes.OutFlow{ + {ToAddress: family.VirtualPaymentAddress, Rate: readChargeRate}, + {ToAddress: paymenttypes.ValidatorTaxPoolAddress.String(), Rate: taxRate}, + } + userOutFlowsResponse, err := s.Client.OutFlows(ctx, &paymenttypes.QueryOutFlowsRequest{Account: user.GetAddr().String()}) + s.Require().NoError(err) + sort.Slice(userOutFlowsResponse.OutFlows, func(i, j int) bool { + return userOutFlowsResponse.OutFlows[i].ToAddress < userOutFlowsResponse.OutFlows[j].ToAddress + }) + sort.Slice(expectedOutFlows, func(i, j int) bool { + return expectedOutFlows[i].ToAddress < expectedOutFlows[j].ToAddress + }) + s.Require().Equal(expectedOutFlows, userOutFlowsResponse.OutFlows) +} + +func (s *PaymentTestSuite) TestStorageBill_CreateObject_WithZeroNoneZeroPayload() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 0) + + // case: create object with zero payload size + streamRecordsBefore := s.getStreamRecords(streamAddresses) + _, _, objectName, _, _, payloadSize := s.createObject(user, bucketName, true) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) + gvgFamilyRate, gvgRate, taxRate, userTotalRate := s.calculateStorageRates(sp, bucketName, objectName, payloadSize, 0) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRate.Neg()) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRate) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRate) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRate) + + // case: create object with none zero payload size + streamRecordsBefore = s.getStreamRecords(streamAddresses) + _, _, objectName, _, _, payloadSize = s.createObject(user, bucketName, false) + + // assertions + streamRecordsAfter = s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) + s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) +} + +func (s *PaymentTestSuite) TestStorageBill_CreateObject_WithReserveTimeValidatorTaxRateChange() { + defer s.revertParams() + + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 0) + + // create object with none zero payload size + streamRecordsBefore := s.getStreamRecords(streamAddresses) + _, _, objectName, _, _, payloadSize := s.createObject(user, bucketName, false) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) + s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // update params + + params := s.queryParams() + oldReserveTime := params.VersionedParams.ReserveTime + oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate + + params.VersionedParams.ReserveTime = oldReserveTime * 2 + params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2) + s.updateParams(params) + + // create another object after parameter changes + streamRecordsBefore = s.getStreamRecords(streamAddresses) + _, _, objectName, _, _, payloadSize = s.createObject(user, bucketName, false) + + // assertions + streamRecordsAfter = s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + lockFeeAfterParameterChange := s.calculateLockFee(sp, bucketName, objectName, payloadSize) + s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFeeAfterParameterChange) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + s.Require().True(lockFeeAfterParameterChange.GT(lockFee.MulRaw(2))) +} + +func (s *PaymentTestSuite) TestStorageBill_CancelCreateObject() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 0) + + // create object with none zero payload size + streamRecordsBefore := s.getStreamRecords(streamAddresses) + _, _, objectName, _, _, payloadSize := s.createObject(user, bucketName, false) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) + s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // cancel create object + s.cancelCreateObject(user, bucketName, objectName) + + // assertions + streamRecordsAfter = s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, lockFee) + s.Require().Equal(streamRecordsAfter.User.LockBalance.Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) +} + +func (s *PaymentTestSuite) TestStorageBill_SealObject_WithoutPriceChange() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 0) + + // create object with none zero payload size + streamRecordsBefore := s.getStreamRecords(streamAddresses) + _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + lockFee := s.calculateLockFee(sp, bucketName, objectName, payloadSize) + s.Require().Equal(streamRecordsAfter.User.LockBalance.Sub(streamRecordsBefore.User.LockBalance), lockFee) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // case: seal object without price change + s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) + + // assertions + streamRecordsAfter = s.getStreamRecords(streamAddresses) + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) + gvgFamilyRate, gvgRate, taxRate, userTotalRate := s.calculateStorageRates(sp, bucketName, objectName, payloadSize, 0) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRate.Neg()) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRate) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRate) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRate) +} + +func (s *PaymentTestSuite) TestStorageBill_SealObject_WithPriceChange() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 102400) + + // case: seal object with read price change and storage price change + _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) + + priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: 0, + }) + s.Require().NoError(err) + // update new price + msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(2), + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(2), + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) + + streamRecordsBefore := s.getStreamRecords(streamAddresses) + gvgFamilyRateReadBefore, taxRateReadBefore, userTotalRateReadBefore := s.calculateReadRates(sp, bucketName) + + // seal object + s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter := s.calculateReadRatesCurrentTimestamp(sp, bucketName) + gvgFamilyRateStore, gvgRateStore, taxRateStore, userTotalRateStore := s.calculateStorageRatesCurrentTimestamp(sp, bucketName, objectName, payloadSize) + + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) + + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRateReadAfter.Sub(userTotalRateReadBefore).Add(userTotalRateStore).Neg()) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRateStore) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRateReadAfter.Sub(gvgFamilyRateReadBefore).Add(gvgFamilyRateStore)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRateReadAfter.Sub(taxRateReadBefore).Add(taxRateStore)) +} + +func (s *PaymentTestSuite) TestStorageBill_SealObject_WithPriceChangeValidatorTaxRateChange() { + defer s.revertParams() + + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 102400) + + // case: seal object with read price change and storage price change + _, _, objectName, objectId, checksums, payloadSize := s.createObject(user, bucketName, false) + + priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: 0, + }) + s.Require().NoError(err) + // update new price + msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(2), + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(2), + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) + + streamRecordsBefore := s.getStreamRecords(streamAddresses) + gvgFamilyRateReadBefore, taxRateReadBefore, userTotalRateReadBefore := s.calculateReadRates(sp, bucketName) + + // seal object + s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter := s.calculateReadRatesCurrentTimestamp(sp, bucketName) + gvgFamilyRateStore, gvgRateStore, taxRateStore, userTotalRateStore := s.calculateStorageRatesCurrentTimestamp(sp, bucketName, objectName, payloadSize) + + s.Require().Equal(streamRecordsAfter.User.StaticBalance, sdkmath.ZeroInt()) + s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) + + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRateReadAfter.Sub(userTotalRateReadBefore).Add(userTotalRateStore).Neg()) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRateStore) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRateReadAfter.Sub(gvgFamilyRateReadBefore).Add(gvgFamilyRateStore)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRateReadAfter.Sub(taxRateReadBefore).Add(taxRateStore)) + + // update params + params := s.queryParams() + oldReserveTime := params.VersionedParams.ReserveTime + oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate + + params.VersionedParams.ReserveTime = oldReserveTime * 2 + params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2) + s.updateParams(params) + + _, _, objectName, objectId, checksums, payloadSize = s.createObject(user, bucketName, false) + s.sealObject(sp, gvg, bucketName, objectName, objectId, checksums) + + // assertions + streamRecordsAfter = s.getStreamRecords(streamAddresses) + gvgFamilyRateReadAfter, taxRateReadAfter, userTotalRateReadAfter = s.calculateReadRatesCurrentTimestamp(sp, bucketName) + 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()) + + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate), userTotalRateReadAfter.Sub(userTotalRateReadBefore).Add(userTotalRateStore).Neg()) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate), gvgRateStore) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate), gvgFamilyRateReadAfter.Sub(gvgFamilyRateReadBefore).Add(gvgFamilyRateStore)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate), taxRateReadAfter.Sub(taxRateReadBefore).Add(taxRateStore)) + + // revert price + msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice, + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice, + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) +} + +func (s *PaymentTestSuite) TestStorageBill_RejectSealObject_WithPriceChange() { + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + + bucketName := s.createBucket(sp, user, 102400) + + // case: seal object with read price change and storage price change + _, _, objectName, _, _, _ := s.createObject(user, bucketName, false) + + priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: 0, + }) + s.Require().NoError(err) + // update new price + msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice.MulInt64(2), + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(2), + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) + + streamRecordsBefore := s.getStreamRecords(streamAddresses) + s.Require().True(streamRecordsBefore.User.LockBalance.IsPositive()) + + // reject seal object + s.rejectSealObject(sp, gvg, bucketName, objectName) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().True(streamRecordsAfter.User.StaticBalance.IsPositive()) + s.Require().Equal(streamRecordsAfter.User.LockBalance, sdkmath.ZeroInt()) + + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // revert price + msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice, + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice, + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) +} + +func (s *PaymentTestSuite) TestStorageBill_FullLifecycle() { + defer s.revertParams() + + var err error + ctx := context.Background() + sp := s.PickStorageProvider() + gvg, found := sp.GetFirstGlobalVirtualGroup() + s.Require().True(found) + queryFamilyResponse, err := s.Client.GlobalVirtualGroupFamily(ctx, &virtualgrouptypes.QueryGlobalVirtualGroupFamilyRequest{ + FamilyId: gvg.FamilyId, + }) + s.Require().NoError(err) + family := queryFamilyResponse.GlobalVirtualGroupFamily + user := s.GenAndChargeAccounts(1, 1000000)[0] + + // query storage price + priceRes, err := s.Client.QueryGetSpStoragePriceByTime(ctx, &sptypes.QueryGetSpStoragePriceByTimeRequest{ + SpAddr: sp.OperatorKey.GetAddr().String(), + Timestamp: 0, + }) + s.Require().NoError(err) + s.T().Log("price", priceRes.SpStoragePrice) + + streamAddresses := []string{ + user.GetAddr().String(), + family.VirtualPaymentAddress, + gvg.VirtualPaymentAddress, + paymenttypes.ValidatorTaxPoolAddress.String(), + } + streamRecordsBefore := s.getStreamRecords(streamAddresses) + + // full lifecycle + bucketName1 := s.createBucket(sp, user, 0) + _, _, objectName1, _, _, _ := s.createObject(user, bucketName1, true) + _, _, objectName2, objectId2, checksums2, _ := s.createObject(user, bucketName1, false) + s.sealObject(sp, gvg, bucketName1, objectName2, objectId2, checksums2) + + bucketName2 := s.createBucket(sp, user, 1024) + _, _, objectName3, objectId3, checksums3, _ := s.createObject(user, bucketName2, false) + s.sealObject(sp, gvg, bucketName2, objectName3, objectId3, checksums3) + + // update params + params := s.queryParams() + params.VersionedParams.ReserveTime = params.VersionedParams.ReserveTime * 3 + params.ForcedSettleTime = params.ForcedSettleTime * 2 + s.updateParams(params) + + _, _, objectName4, objectId4, checksums4, _ := s.createObject(user, bucketName2, false) + s.sealObject(sp, gvg, bucketName2, objectName4, objectId4, checksums4) + + bucketName3 := s.createBucket(sp, user, 1024) + _, _, objectName5, objectId5, checksums5, _ := s.createObject(user, bucketName3, false) + s.sealObject(sp, gvg, bucketName3, objectName5, objectId5, checksums5) + + // update new price + msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice, + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice.MulInt64(10000), + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) + + // update params + params = s.queryParams() + params.VersionedParams.ReserveTime = params.VersionedParams.ReserveTime / 2 + params.ForcedSettleTime = params.ForcedSettleTime / 3 + s.updateParams(params) + + _, _, objectName6, objectId6, checksums6, _ := s.createObject(user, bucketName3, false) + s.sealObject(sp, gvg, bucketName3, objectName6, objectId6, checksums6) + + bucketName4 := s.createBucket(sp, user, 1024) + _, _, objectName7, objectId7, checksums7, _ := s.createObject(user, bucketName4, false) + s.sealObject(sp, gvg, bucketName4, objectName7, objectId7, checksums7) + + // update params + params = s.queryParams() + params.VersionedParams.ValidatorTaxRate = params.VersionedParams.ValidatorTaxRate.MulInt64(2) + s.updateParams(params) + + _, _, objectName8, objectId8, checksums8, _ := s.createObject(user, bucketName4, false) + s.sealObject(sp, gvg, bucketName4, objectName8, objectId8, checksums8) + + time.Sleep(3 * time.Second) + + _ = s.deleteObject(user, bucketName1, objectName1) + _ = s.deleteObject(user, bucketName1, objectName2) + + // update params + params = s.queryParams() + params.VersionedParams.ValidatorTaxRate = params.VersionedParams.ValidatorTaxRate.MulInt64(3) + s.updateParams(params) + + _ = s.deleteObject(user, bucketName2, objectName3) + _ = s.deleteObject(user, bucketName2, objectName4) + err = s.deleteBucket(user, bucketName1) + s.Require().Error(err) + err = s.deleteBucket(user, bucketName2) + s.Require().Error(err) + + _ = s.deleteObject(user, bucketName3, objectName5) + _ = s.deleteObject(user, bucketName3, objectName6) + _ = s.deleteObject(user, bucketName4, objectName7) + _ = s.deleteObject(user, bucketName4, objectName8) + err = s.deleteBucket(user, bucketName3) + s.Require().Error(err) + err = s.deleteBucket(user, bucketName4) + s.Require().Error(err) + + // assertions + streamRecordsAfter := s.getStreamRecords(streamAddresses) + s.Require().True(!streamRecordsAfter.User.StaticBalance.IsZero()) + s.Require().Equal(streamRecordsAfter.User.NetflowRate.Sub(streamRecordsBefore.User.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVGFamily.NetflowRate.Sub(streamRecordsBefore.GVGFamily.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) + s.Require().Equal(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64(), int64(0)) + + // revert price + msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ + SpAddress: sp.OperatorKey.GetAddr().String(), + ReadPrice: priceRes.SpStoragePrice.ReadPrice, + FreeReadQuota: priceRes.SpStoragePrice.FreeReadQuota, + StorePrice: priceRes.SpStoragePrice.StorePrice, + } + s.SendTxBlock(sp.OperatorKey, msgUpdatePrice) +} + // TestStorageBill_CopyObject_WithoutPriceChange func (s *PaymentTestSuite) TestStorageBill_CopyObject_WithoutPriceChange() { var err error diff --git a/x/storage/keeper/payment_test.go b/x/storage/keeper/payment_test.go index 5a9614572..a13db11d6 100644 --- a/x/storage/keeper/payment_test.go +++ b/x/storage/keeper/payment_test.go @@ -112,8 +112,6 @@ func (s *TestSuite) TestGetObjectLockFee() { s.paymentKeeper.EXPECT().GetStoragePrice(gomock.Any(), gomock.Any()). Return(price, nil).AnyTimes() params := paymenttypes.DefaultParams() - s.paymentKeeper.EXPECT().GetParams(gomock.Any()). - Return(params).AnyTimes() s.paymentKeeper.EXPECT().GetVersionedParamsWithTs(gomock.Any(), gomock.Any()). Return(params.VersionedParams, nil).AnyTimes() diff --git a/x/storage/types/expected_keepers.go b/x/storage/types/expected_keepers.go index 85b43af1f..1ff74670e 100644 --- a/x/storage/types/expected_keepers.go +++ b/x/storage/types/expected_keepers.go @@ -41,15 +41,11 @@ type SpKeeper interface { } type PaymentKeeper interface { - GetParams(ctx sdk.Context) paymenttypes.Params GetVersionedParamsWithTs(ctx sdk.Context, time int64) (paymenttypes.VersionedParams, error) IsPaymentAccountOwner(ctx sdk.Context, addr, owner sdk.AccAddress) bool GetStoragePrice(ctx sdk.Context, params paymenttypes.StoragePriceParams) (price paymenttypes.StoragePrice, err error) ApplyUserFlowsList(ctx sdk.Context, userFlows []paymenttypes.UserFlows) (err error) UpdateStreamRecordByAddr(ctx sdk.Context, change *paymenttypes.StreamRecordChange) (ret *paymenttypes.StreamRecord, err error) - GetStreamRecord(ctx sdk.Context, account sdk.AccAddress) (val *paymenttypes.StreamRecord, found bool) - UpdateStreamRecord(ctx sdk.Context, streamRecord *paymenttypes.StreamRecord, change *paymenttypes.StreamRecordChange) error - Withdraw(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amount math.Int) error } type PermissionKeeper interface { diff --git a/x/storage/types/expected_keepers_mocks.go b/x/storage/types/expected_keepers_mocks.go index 12d9f9a5f..e5a20df47 100644 --- a/x/storage/types/expected_keepers_mocks.go +++ b/x/storage/types/expected_keepers_mocks.go @@ -285,20 +285,6 @@ func (mr *MockPaymentKeeperMockRecorder) ApplyUserFlowsList(ctx, userFlows inter return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyUserFlowsList", reflect.TypeOf((*MockPaymentKeeper)(nil).ApplyUserFlowsList), ctx, userFlows) } -// GetParams mocks base method. -func (m *MockPaymentKeeper) GetParams(ctx types3.Context) types.Params { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetParams", ctx) - ret0, _ := ret[0].(types.Params) - return ret0 -} - -// GetParams indicates an expected call of GetParams. -func (mr *MockPaymentKeeperMockRecorder) GetParams(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*MockPaymentKeeper)(nil).GetParams), ctx) -} - // GetStoragePrice mocks base method. func (m *MockPaymentKeeper) GetStoragePrice(ctx types3.Context, params types.StoragePriceParams) (types.StoragePrice, error) { m.ctrl.T.Helper() @@ -314,21 +300,6 @@ func (mr *MockPaymentKeeperMockRecorder) GetStoragePrice(ctx, params interface{} return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStoragePrice", reflect.TypeOf((*MockPaymentKeeper)(nil).GetStoragePrice), ctx, params) } -// GetStreamRecord mocks base method. -func (m *MockPaymentKeeper) GetStreamRecord(ctx types3.Context, account types3.AccAddress) (*types.StreamRecord, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetStreamRecord", ctx, account) - ret0, _ := ret[0].(*types.StreamRecord) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetStreamRecord indicates an expected call of GetStreamRecord. -func (mr *MockPaymentKeeperMockRecorder) GetStreamRecord(ctx, account interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStreamRecord", reflect.TypeOf((*MockPaymentKeeper)(nil).GetStreamRecord), ctx, account) -} - // GetVersionedParamsWithTs mocks base method. func (m *MockPaymentKeeper) GetVersionedParamsWithTs(ctx types3.Context, time int64) (types.VersionedParams, error) { m.ctrl.T.Helper() @@ -358,20 +329,6 @@ func (mr *MockPaymentKeeperMockRecorder) IsPaymentAccountOwner(ctx, addr, owner return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPaymentAccountOwner", reflect.TypeOf((*MockPaymentKeeper)(nil).IsPaymentAccountOwner), ctx, addr, owner) } -// UpdateStreamRecord mocks base method. -func (m *MockPaymentKeeper) UpdateStreamRecord(ctx types3.Context, streamRecord *types.StreamRecord, change *types.StreamRecordChange) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateStreamRecord", ctx, streamRecord, change) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateStreamRecord indicates an expected call of UpdateStreamRecord. -func (mr *MockPaymentKeeperMockRecorder) UpdateStreamRecord(ctx, streamRecord, change interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStreamRecord", reflect.TypeOf((*MockPaymentKeeper)(nil).UpdateStreamRecord), ctx, streamRecord, change) -} - // UpdateStreamRecordByAddr mocks base method. func (m *MockPaymentKeeper) UpdateStreamRecordByAddr(ctx types3.Context, change *types.StreamRecordChange) (*types.StreamRecord, error) { m.ctrl.T.Helper() @@ -387,20 +344,6 @@ func (mr *MockPaymentKeeperMockRecorder) UpdateStreamRecordByAddr(ctx, change in return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStreamRecordByAddr", reflect.TypeOf((*MockPaymentKeeper)(nil).UpdateStreamRecordByAddr), ctx, change) } -// Withdraw mocks base method. -func (m *MockPaymentKeeper) Withdraw(ctx types3.Context, fromAddr, toAddr types3.AccAddress, amount math.Int) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Withdraw", ctx, fromAddr, toAddr, amount) - ret0, _ := ret[0].(error) - return ret0 -} - -// Withdraw indicates an expected call of Withdraw. -func (mr *MockPaymentKeeperMockRecorder) Withdraw(ctx, fromAddr, toAddr, amount interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Withdraw", reflect.TypeOf((*MockPaymentKeeper)(nil).Withdraw), ctx, fromAddr, toAddr, amount) -} - // MockPermissionKeeper is a mock of PermissionKeeper interface. type MockPermissionKeeper struct { ctrl *gomock.Controller