From fcec0b5d70f6187655b61840064ef1877f3bfd80 Mon Sep 17 00:00:00 2001 From: forcodedancing Date: Thu, 7 Mar 2024 12:01:25 +0800 Subject: [PATCH] fix: disallow update payment address when there are created objects --- x/payment/keeper/stream_record.go | 16 +++++- x/storage/keeper/keeper.go | 85 +++++++++++++++++++++++++++++++ x/storage/types/errors.go | 1 + x/storage/types/keys.go | 7 +++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/x/payment/keeper/stream_record.go b/x/payment/keeper/stream_record.go index 2956f7c97..e0d728656 100644 --- a/x/payment/keeper/stream_record.go +++ b/x/payment/keeper/stream_record.go @@ -3,6 +3,8 @@ package keeper import ( "fmt" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/store/prefix" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -123,7 +125,12 @@ func (k Keeper) UpdateFrozenStreamRecord(ctx sdk.Context, streamRecord *types.St 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) + if ctx.IsUpgraded(upgradetypes.Pawnee) { + streamRecord.StaticBalance = streamRecord.StaticBalance.Add(streamRecord.LockBalance) + streamRecord.LockBalance = sdkmath.ZeroInt() + } else { + return fmt.Errorf("lock balance can not become negative, current: %s", streamRecord.LockBalance) + } } } if !change.RateChange.IsZero() { @@ -158,7 +165,12 @@ func (k Keeper) UpdateStreamRecord(ctx sdk.Context, streamRecord *types.StreamRe 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) + if ctx.IsUpgraded(upgradetypes.Pawnee) { + streamRecord.StaticBalance = streamRecord.StaticBalance.Add(streamRecord.LockBalance) + streamRecord.LockBalance = sdkmath.ZeroInt() + } else { + return fmt.Errorf("lock balance can not become negative, current: %s", streamRecord.LockBalance) + } } } // update buffer balance diff --git a/x/storage/keeper/keeper.go b/x/storage/keeper/keeper.go index 2c4927b51..65d76f9f5 100644 --- a/x/storage/keeper/keeper.go +++ b/x/storage/keeper/keeper.go @@ -235,6 +235,7 @@ func (k Keeper) doDeleteBucket(ctx sdk.Context, operator sdk.AccAddress, bucketI store.Delete(types.GetQuotaKey(bucketInfo.Id)) store.Delete(types.GetInternalBucketInfoKey(bucketInfo.Id)) store.Delete(types.GetMigrationBucketKey(bucketInfo.Id)) + store.Delete(types.GetCreatedObjectCountKey(bucketInfo.Id)) err := k.appendResourceIdForGarbageCollection(ctx, resource.RESOURCE_TYPE_BUCKET, bucketInfo.Id) if err != nil { @@ -334,6 +335,9 @@ func (k Keeper) ForceDeleteBucket(ctx sdk.Context, bucketId sdkmath.Uint, cap ui ctx.Logger().Error("unlock store fee error", "err", err) return false, deleted, err } + if ctx.IsUpgraded(upgradetypes.Pawnee) { + k.DecreaseCreatedObjectCount(ctx, bucketInfo.Id) + } } else if objectStatus == types.OBJECT_STATUS_SEALED { internalBucketInfo := k.MustGetInternalBucketInfo(ctx, bucketInfo.Id) if err = k.UnChargeObjectStoreFee(ctx, bucketInfo, internalBucketInfo, &objectInfo); err != nil { @@ -422,6 +426,12 @@ func (k Keeper) UpdateBucketInfo(ctx sdk.Context, operator sdk.AccAddress, bucke if err != nil { return err } + + if ctx.IsUpgraded(upgradetypes.Pawnee) { + if k.GetCreatedObjectCount(ctx, bucketInfo.Id) != 0 { + return types.ErrUpdatePaymentAccountFailed.Wrapf("The bucket %s has unseald objects", bucketInfo.BucketName) + } + } } else { paymentAcc = sdk.MustAccAddressFromHex(bucketInfo.PaymentAddress) } @@ -641,6 +651,11 @@ func (k Keeper) CreateObject( bbz := k.cdc.MustMarshal(bucketInfo) store.Set(types.GetBucketByIDKey(bucketInfo.Id), bbz) + if ctx.IsUpgraded(upgradetypes.Pawnee) { + if objectInfo.ObjectStatus == types.OBJECT_STATUS_CREATED { + k.IncreaseCreatedObjectCount(ctx, bucketInfo.Id) + } + } obz := k.cdc.MustMarshal(&objectInfo) store.Set(objectKey, k.objectSeq.EncodeSequence(objectInfo.Id)) @@ -841,6 +856,9 @@ func (k Keeper) SealObject( bbz := k.cdc.MustMarshal(bucketInfo) store.Set(types.GetBucketByIDKey(bucketInfo.Id), bbz) + if ctx.IsUpgraded(upgradetypes.Pawnee) { + k.DecreaseCreatedObjectCount(ctx, bucketInfo.Id) + } obz := k.cdc.MustMarshal(objectInfo) store.Set(types.GetObjectByIDKey(objectInfo.Id), obz) @@ -915,6 +933,11 @@ func (k Keeper) CancelCreateObject( bbz := k.cdc.MustMarshal(bucketInfo) store.Set(types.GetBucketByIDKey(bucketInfo.Id), bbz) + if ctx.IsUpgraded(upgradetypes.Pawnee) { + if objectInfo.ObjectStatus == types.OBJECT_STATUS_CREATED { + k.DecreaseCreatedObjectCount(ctx, bucketInfo.Id) + } + } store.Delete(types.GetObjectKey(bucketName, objectName)) store.Delete(types.GetObjectByIDKey(objectInfo.Id)) @@ -1039,6 +1062,9 @@ func (k Keeper) ForceDeleteObject(ctx sdk.Context, objectId sdkmath.Uint) error ctx.Logger().Error("unlock store fee error", "err", err) return err } + if ctx.IsUpgraded(upgradetypes.Pawnee) { + k.DecreaseCreatedObjectCount(ctx, bucketInfo.Id) + } } else if objectStatus == types.OBJECT_STATUS_SEALED { internalBucketInfo := k.MustGetInternalBucketInfo(ctx, bucketInfo.Id) err := k.UnChargeObjectStoreFee(ctx, bucketInfo, internalBucketInfo, objectInfo) @@ -1153,6 +1179,11 @@ func (k Keeper) CopyObject( bbz := k.cdc.MustMarshal(dstBucketInfo) store.Set(types.GetBucketByIDKey(dstBucketInfo.Id), bbz) + if ctx.IsUpgraded(upgradetypes.Pawnee) { + if objectInfo.ObjectStatus == types.OBJECT_STATUS_CREATED { + k.IncreaseCreatedObjectCount(ctx, dstBucketInfo.Id) + } + } obz := k.cdc.MustMarshal(&objectInfo) store.Set(types.GetObjectKey(dstBucketName, dstObjectName), k.objectSeq.EncodeSequence(objectInfo.Id)) @@ -2556,3 +2587,57 @@ func (k Keeper) CancelUpdateObjectContent( ObjectId: objectInfo.Id, }) } + +func (k Keeper) GetCreatedObjectCount(ctx sdk.Context, bucketId sdkmath.Uint) uint64 { + store := ctx.KVStore(k.storeKey) + + key := types.GetCreatedObjectCountKey(bucketId) + bz := store.Get(key) + current := uint64(0) + if bz != nil { + current = binary.BigEndian.Uint64(bz) + } + return current +} + +func (k Keeper) IncreaseCreatedObjectCount(ctx sdk.Context, bucketId sdkmath.Uint) { + store := ctx.KVStore(k.storeKey) + + key := types.GetCreatedObjectCountKey(bucketId) + bz := store.Get(key) + before := uint64(0) + if bz != nil { + before = binary.BigEndian.Uint64(bz) + } + after := before + 1 + + binary.BigEndian.PutUint64(bz, after) + store.Set(key, bz) +} + +func (k Keeper) DecreaseCreatedObjectCount(ctx sdk.Context, bucketId sdkmath.Uint) { + store := ctx.KVStore(k.storeKey) + + key := types.GetCreatedObjectCountKey(bucketId) + bz := store.Get(key) + before := uint64(0) + if bz != nil { + before = binary.BigEndian.Uint64(bz) + } + + after := before + if before > 0 { + after = before - 1 + } + // this feature is not introduced from the genesis, which means that some buckets do not have such + // indicators earlier, they could have created objects even the indicator is zero. For such buckets, + // after they delete or seal all the created objects, the indicator will become correct finally. + + binary.BigEndian.PutUint64(bz, after) + store.Set(key, bz) +} + +func (k Keeper) DeleteCreatedObjectCount(ctx sdk.Context, bucketId sdkmath.Uint) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.GetCreatedObjectCountKey(bucketId)) +} diff --git a/x/storage/types/errors.go b/x/storage/types/errors.go index 32509e1c7..17366d9f6 100644 --- a/x/storage/types/errors.go +++ b/x/storage/types/errors.go @@ -34,6 +34,7 @@ var ( ErrUpdateObjectNotAllowed = errors.Register(ModuleName, 1126, "Object is not allowed to update") ErrObjectIsUpdating = errors.Register(ModuleName, 1127, "Object is being updated") ErrObjectIsNotUpdating = errors.Register(ModuleName, 1128, "Object is not being updated") + ErrUpdatePaymentAccountFailed = errors.Register(ModuleName, 1129, "Update payment account failed") ErrInvalidCrossChainPackage = errors.Register(ModuleName, 3000, "invalid cross chain package") ErrAlreadyMirrored = errors.Register(ModuleName, 3001, "resource is already mirrored") diff --git a/x/storage/types/keys.go b/x/storage/types/keys.go index 7300507a9..d5e12bc17 100644 --- a/x/storage/types/keys.go +++ b/x/storage/types/keys.go @@ -40,6 +40,8 @@ var ( ShadowObjectInfoPrefix = []byte{0x16} + CreatedObjectCountPrefix = []byte{0x17} + BucketByIDPrefix = []byte{0x21} ObjectByIDPrefix = []byte{0x22} GroupByIDPrefix = []byte{0x23} @@ -165,3 +167,8 @@ func GetInternalBucketInfoKey(bucketID math.Uint) []byte { var seq sequence.Sequence[math.Uint] return append(InternalBucketInfoPrefix, seq.EncodeSequence(bucketID)...) } + +func GetCreatedObjectCountKey(bucketId math.Uint) []byte { + var seq sequence.Sequence[math.Uint] + return append(CreatedObjectCountPrefix, seq.EncodeSequence(bucketId)...) +}