From e573cf0223b15279a72c3f0bfa640d8c9f954348 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 26 May 2023 18:44:19 +0800 Subject: [PATCH] fix: fail to force delete when the payment addr is frozen (#264) --- x/payment/keeper/stream_record.go | 25 +++++++++++++++++++++++++ x/payment/types/types.go | 4 ++++ x/storage/abci.go | 3 +++ x/storage/keeper/payment_test.go | 17 +++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/x/payment/keeper/stream_record.go b/x/payment/keeper/stream_record.go index f3439ccb1..73eb7fae3 100644 --- a/x/payment/keeper/stream_record.go +++ b/x/payment/keeper/stream_record.go @@ -96,8 +96,33 @@ func (k Keeper) GetAllStreamRecord(ctx sdk.Context) (list []types.StreamRecord) return } +// UpdateFrozenStreamRecord updates frozen streamRecord in `force delete` scenarios +// it only handles the lock balance change and ignore the other changes(since the streams are already changed and the +// accumulated OutFlows are changed outside this function) +func (k Keeper) UpdateFrozenStreamRecord(ctx sdk.Context, streamRecord *types.StreamRecord, change *types.StreamRecordChange) error { + if streamRecord.Status != types.STREAM_ACCOUNT_STATUS_FROZEN { + return fmt.Errorf("stream account %s is not frozen", streamRecord.Account) + } + currentTimestamp := ctx.BlockTime().Unix() + streamRecord.CrudTimestamp = currentTimestamp + // update lock balance + if !change.LockBalanceChange.IsZero() { + streamRecord.LockBalance = streamRecord.LockBalance.Add(change.LockBalanceChange) + streamRecord.StaticBalance = streamRecord.StaticBalance.Sub(change.LockBalanceChange) + if streamRecord.LockBalance.IsNegative() { + return fmt.Errorf("lock balance can not become negative, current: %s", streamRecord.LockBalance) + } + } + return nil +} + func (k Keeper) UpdateStreamRecord(ctx sdk.Context, streamRecord *types.StreamRecord, change *types.StreamRecordChange, autoSettle bool) error { if streamRecord.Status != types.STREAM_ACCOUNT_STATUS_ACTIVE { + if streamRecord.Status == types.STREAM_ACCOUNT_STATUS_FROZEN { + if forced, ok := ctx.Value(types.ForceUpdateFrozenStreamRecordKey).(bool); forced && ok { + return k.UpdateFrozenStreamRecord(ctx, streamRecord, change) + } + } return fmt.Errorf("stream account %s is frozen", streamRecord.Account) } isPay := change.StaticBalanceChange.IsNegative() || change.RateChange.IsNegative() diff --git a/x/payment/types/types.go b/x/payment/types/types.go index 6eddfd703..a09933d85 100644 --- a/x/payment/types/types.go +++ b/x/payment/types/types.go @@ -10,3 +10,7 @@ var ( GovernanceAddress = sdk.AccAddress(address.Module(ModuleName, []byte("governance"))[:sdk.EthAddressLength]) ValidatorTaxPoolAddress = sdk.AccAddress(address.Module(ModuleName, []byte("validator-tax-pool"))[:sdk.EthAddressLength]) ) + +const ( + ForceUpdateFrozenStreamRecordKey = "force_update_frozen_stream_record" +) diff --git a/x/storage/abci.go b/x/storage/abci.go index 3bd22830e..14fa307aa 100644 --- a/x/storage/abci.go +++ b/x/storage/abci.go @@ -1,6 +1,7 @@ package storage import ( + paymenttypes "github.com/bnb-chain/greenfield/x/payment/types" sdk "github.com/cosmos/cosmos-sdk/types" k "github.com/bnb-chain/greenfield/x/storage/keeper" @@ -22,6 +23,8 @@ func EndBlocker(ctx sdk.Context, keeper k.Keeper) { } blockTime := ctx.BlockTime().Unix() + // set ForceUpdateFrozenStreamRecordKey to true in context to force update frozen stream record + ctx = ctx.WithValue(paymenttypes.ForceUpdateFrozenStreamRecordKey, true) // delete objects deleted, err := keeper.DeleteDiscontinueObjectsUntil(ctx, blockTime, deletionMax) if err != nil { diff --git a/x/storage/keeper/payment_test.go b/x/storage/keeper/payment_test.go index 4a3c29e9e..63a43102e 100644 --- a/x/storage/keeper/payment_test.go +++ b/x/storage/keeper/payment_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + paymenttypes "github.com/bnb-chain/greenfield/x/payment/types" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -137,6 +139,21 @@ func (s *IntegrationTestSuiteWithoutMock) TestCreateCreateBucket_Payment() { readRate := primaryStorePriceRes.ReadPrice.MulInt(sdk.NewIntFromUint64(ChargedReadQuota)).TruncateInt() s.T().Logf("primarySpRateDiff: %s, expectedRate: %s, readRate: %s", primarySpRateDiff, expectedRate, readRate) s.Require().Equal(expectedRate.String(), primarySpRateDiff.String()) + + // force delete + err = s.depKeepers.PaymentKeeper.ForceSettle(ctx, userStreamRecordSealObject) + s.Require().NoError(err) + s.depKeepers.PaymentKeeper.SetStreamRecord(ctx, userStreamRecordSealObject) + userStreamRecordSealObject, found = s.depKeepers.PaymentKeeper.GetStreamRecord(ctx, s.UserAddr) + s.Require().True(found) + s.T().Logf("userStreamRecordSealObject: %+v", userStreamRecordSealObject) + s.Require().Equal(userStreamRecordSealObject.Status, paymenttypes.STREAM_ACCOUNT_STATUS_FROZEN) + bucket.ChargedReadQuota += 100000000 + err = s.keeper.ChargeDeleteObject(ctx, &bucket, &object) + s.Require().ErrorContains(err, "is frozen") + ctx = ctx.WithValue(paymenttypes.ForceUpdateFrozenStreamRecordKey, true) + err = s.keeper.ChargeDeleteObject(ctx, &bucket, &object) + s.Require().NoError(err) } func TestKeeperTestSuiteWithoutMock(t *testing.T) {