diff --git a/e2e/tests/payment_test.go b/e2e/tests/payment_test.go index b3fb6fc18..7ceaa3bda 100644 --- a/e2e/tests/payment_test.go +++ b/e2e/tests/payment_test.go @@ -3009,6 +3009,8 @@ func (s *PaymentTestSuite) TestDiscontinue_InBlocks_WithPriceChangeReserveTimeCh s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_CREATED) time.Sleep(200 * time.Millisecond) } + userStreamRecord := s.getStreamRecord(user.GetAddr().String()) + s.Require().True(userStreamRecord.LockBalance.IsPositive()) // update new price msgUpdatePrice := &sptypes.MsgUpdateSpStoragePrice{ @@ -3107,6 +3109,9 @@ func (s *PaymentTestSuite) TestDiscontinue_InBlocks_WithPriceChangeReserveTimeCh s.Require().Equal(streamRecordsAfter.GVG.NetflowRate.Sub(streamRecordsBefore.GVG.NetflowRate).Int64(), int64(0)) s.Require().True(streamRecordsAfter.Tax.NetflowRate.Sub(streamRecordsBefore.Tax.NetflowRate).Int64() <= int64(0)) // there are other auto settling + s.Require().True(streamRecordsAfter.User.LockBalance.IsZero()) + s.Require().True(streamRecordsAfter.User.StaticBalance.Int64() == userStreamRecord.LockBalance.Int64()) + // revert price msgUpdatePrice = &sptypes.MsgUpdateSpStoragePrice{ SpAddress: sp.OperatorKey.GetAddr().String(), diff --git a/x/payment/keeper/storage_fee_charge.go b/x/payment/keeper/storage_fee_charge.go index c5d3239df..6518e82d9 100644 --- a/x/payment/keeper/storage_fee_charge.go +++ b/x/payment/keeper/storage_fee_charge.go @@ -139,7 +139,7 @@ func (k Keeper) applyFrozenUserFlows(ctx sdk.Context, userFlows types.UserFlows, } streamRecordChange := types.NewDefaultStreamRecordChangeWithAddr(from). WithRateChange(totalActiveRate.Neg()).WithFrozenRateChange(totalFrozenRate.Neg()) - err := k.UpdateFrozenStreamRecord(ctx, streamRecord, streamRecordChange) + err := k.UpdateStreamRecord(ctx, streamRecord, streamRecordChange) if err != nil { return fmt.Errorf("apply stream record changes for user failed: %w", err) } diff --git a/x/payment/keeper/stream_record.go b/x/payment/keeper/stream_record.go index a965f44e9..798016b06 100644 --- a/x/payment/keeper/stream_record.go +++ b/x/payment/keeper/stream_record.go @@ -114,6 +114,10 @@ func (k Keeper) GetAllStreamRecord(ctx sdk.Context) (list []types.StreamRecord) // 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 { + forced, _ := ctx.Value(types.ForceUpdateStreamRecordKey).(bool) + if !forced { + return fmt.Errorf("stream record %s is frozen", streamRecord.Account) + } // update lock balance if !change.LockBalanceChange.IsZero() { streamRecord.LockBalance = streamRecord.LockBalance.Add(change.LockBalanceChange) @@ -132,6 +136,10 @@ func (k Keeper) UpdateFrozenStreamRecord(ctx sdk.Context, streamRecord *types.St } func (k Keeper) UpdateStreamRecord(ctx sdk.Context, streamRecord *types.StreamRecord, change *types.StreamRecordChange) error { + if streamRecord.Status == types.STREAM_ACCOUNT_STATUS_FROZEN { + return k.UpdateFrozenStreamRecord(ctx, streamRecord, change) + } + forced, _ := ctx.Value(types.ForceUpdateStreamRecordKey).(bool) // force update in end block isPay := change.StaticBalanceChange.IsNegative() || change.RateChange.IsNegative() currentTimestamp := ctx.BlockTime().Unix() @@ -217,13 +225,11 @@ func (k Keeper) UpdateStreamRecordByAddr(ctx sdk.Context, change *types.StreamRe func (k Keeper) ForceSettle(ctx sdk.Context, streamRecord *types.StreamRecord) error { totalBalance := streamRecord.StaticBalance.Add(streamRecord.BufferBalance) - if totalBalance.IsPositive() { - change := types.NewDefaultStreamRecordChangeWithAddr(types.GovernanceAddress).WithStaticBalanceChange(totalBalance) - _, err := k.UpdateStreamRecordByAddr(ctx, change) - if err != nil { - telemetry.IncrCounter(1, types.GovernanceAddressLackBalanceLabel) - return fmt.Errorf("update governance stream record failed: %w", err) - } + change := types.NewDefaultStreamRecordChangeWithAddr(types.GovernanceAddress).WithStaticBalanceChange(totalBalance) + _, err := k.UpdateStreamRecordByAddr(ctx, change) + if err != nil { + telemetry.IncrCounter(1, types.GovernanceAddressLackBalanceLabel) + return fmt.Errorf("update governance stream record failed: %w", err) } // force settle streamRecord.StaticBalance = sdkmath.ZeroInt() diff --git a/x/payment/keeper/stream_record_test.go b/x/payment/keeper/stream_record_test.go index a726888d4..4c6f57327 100644 --- a/x/payment/keeper/stream_record_test.go +++ b/x/payment/keeper/stream_record_test.go @@ -752,3 +752,40 @@ func TestAutoSettle_SettleInMultipleBlocks_AutoResumeExists(t *testing.T) { require.Equal(t, gvg3StreamRecord.NetflowRate, sdk.NewInt(150)) require.Equal(t, gvg3StreamRecord.FrozenNetflowRate, sdkmath.ZeroInt()) } + +func TestUpdateStreamRecord_FrozenAccountLockBalance(t *testing.T) { + keeper, ctx, _ := makePaymentKeeper(t) + ctx = ctx.WithBlockTime(time.Now()) + + user := sample.RandAccAddress() + streamRecord := &types.StreamRecord{ + StaticBalance: sdkmath.ZeroInt(), + BufferBalance: sdkmath.ZeroInt(), + LockBalance: sdkmath.NewInt(1000), + Account: user.String(), + Status: types.STREAM_ACCOUNT_STATUS_FROZEN, + NetflowRate: sdkmath.NewInt(0), + FrozenNetflowRate: sdkmath.NewInt(100).Neg(), + OutFlowCount: 1, + } + keeper.SetStreamRecord(ctx, streamRecord) + + // update fail when no force flag + change := types.NewDefaultStreamRecordChangeWithAddr(user). + WithLockBalanceChange(streamRecord.LockBalance.Neg()) + _, err := keeper.UpdateStreamRecordByAddr(ctx, change) + require.ErrorContains(t, err, "is frozen") + + // update success when there is force flag + ctx = ctx.WithValue(types.ForceUpdateStreamRecordKey, true) + change = types.NewDefaultStreamRecordChangeWithAddr(user). + WithLockBalanceChange(streamRecord.LockBalance.Neg()) + _, err = keeper.UpdateStreamRecordByAddr(ctx, change) + require.NoError(t, err) + + streamRecord, _ = keeper.GetStreamRecord(ctx, user) + require.True(t, streamRecord.Status == types.STREAM_ACCOUNT_STATUS_FROZEN) + require.True(t, streamRecord.LockBalance.IsZero()) + require.True(t, streamRecord.StaticBalance.Int64() == 1000) + +}