diff --git a/x/registry/keeper/keeper.go b/x/registry/keeper/keeper.go index b96f888d..307e6612 100644 --- a/x/registry/keeper/keeper.go +++ b/x/registry/keeper/keeper.go @@ -418,9 +418,46 @@ func (k Keeper) GetModuleBalances(ctx sdk.Context) []*registrytypes.AccountBalan } // ProcessRecordExpiryQueue tries to renew expiring records (by collecting rent) else marks them as deleted. -func (k Keeper) ProcessRecordExpiryQueue(ctx sdk.Context) { +func (k Keeper) ProcessRecordExpiryQueue(ctx sdk.Context) error { // TODO: process expired records cids, err := k.getAllExpiredRecords(ctx, ctx.BlockHeader().Time) + if err != nil { + return err + } + + for _, cid := range cids { + record, err := k.GetRecordById(ctx, cid) + if err != nil { + return err + } + + bondExists := false + if record.BondId != "" { + bondExists, err = k.bondKeeper.HasBond(ctx, record.BondId) + if err != nil { + return err + } + } + + // If record doesn't have an associated bond or if bond no longer exists, mark it deleted. + if !bondExists { + record.Deleted = true + if err := k.SaveRecord(ctx, record); err != nil { + return err + } + + if err := k.deleteRecordExpiryQueue(ctx, record); err != nil { + return err + } + } + + // Try to renew the record by taking rent. + if err := k.tryTakeRecordRent(ctx, record); err != nil { + return err + } + } + + return nil } // getAllExpiredRecords returns a concatenated list of all the timeslices before currTime. @@ -463,3 +500,64 @@ func (k Keeper) insertRecordExpiryQueue(ctx sdk.Context, record registrytypes.Re return k.RecordExpiryQueue.Set(ctx, expiryTime, existingRecordsList) } + +// deleteRecordExpiryQueue deletes a record CID from the record expiry queue. +func (k Keeper) deleteRecordExpiryQueue(ctx sdk.Context, record registrytypes.Record) error { + expiryTime, err := time.Parse(time.RFC3339, record.ExpiryTime) + if err != nil { + return err + } + + existingRecordsList, err := k.RecordExpiryQueue.Get(ctx, expiryTime) + if err != nil { + return err + } + + newRecordsSlice := []string{} + for _, id := range existingRecordsList.Value { + if id != record.Id { + newRecordsSlice = append(newRecordsSlice, id) + } + } + + if len(existingRecordsList.Value) == 0 { + return k.RecordExpiryQueue.Remove(ctx, expiryTime) + } else { + existingRecordsList.Value = newRecordsSlice + return k.RecordExpiryQueue.Set(ctx, expiryTime, existingRecordsList) + } +} + +// tryTakeRecordRent tries to take rent from the record bond. +func (k Keeper) tryTakeRecordRent(ctx sdk.Context, record registrytypes.Record) error { + params, err := k.GetParams(ctx) + if err != nil { + return err + } + + rent := params.RecordRent + sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, record.BondId, registrytypes.RecordRentModuleAccountName, sdk.NewCoins(rent)) + if sdkErr != nil { + // Insufficient funds, mark record as deleted. + record.Deleted = true + if err := k.SaveRecord(ctx, record); err != nil { + return err + } + + return k.deleteRecordExpiryQueue(ctx, record) + } + + // Delete old expiry queue entry, create new one. + if err := k.deleteRecordExpiryQueue(ctx, record); err != nil { + return err + } + + record.ExpiryTime = ctx.BlockHeader().Time.Add(params.RecordRentDuration).Format(time.RFC3339) + if err := k.insertRecordExpiryQueue(ctx, record); err != nil { + return err + } + + // Save record. + record.Deleted = false + return k.SaveRecord(ctx, record) +} diff --git a/x/registry/module/abci.go b/x/registry/module/abci.go index 60c161dd..f2ae1897 100644 --- a/x/registry/module/abci.go +++ b/x/registry/module/abci.go @@ -13,8 +13,6 @@ func EndBlocker(ctx context.Context, k keeper.Keeper) error { // TODO: Implement sdkCtx := sdk.UnwrapSDKContext(ctx) - k.ProcessRecordExpiryQueue(sdkCtx) + return k.ProcessRecordExpiryQueue(sdkCtx) // k.ProcessAuthorityExpiryQueue(ctx) - - return nil }