diff --git a/x/registry/keeper/msg_server.go b/x/registry/keeper/msg_server.go index 4152d62f..4688292d 100644 --- a/x/registry/keeper/msg_server.go +++ b/x/registry/keeper/msg_server.go @@ -169,14 +169,17 @@ func (ms msgServer) DeleteName(c context.Context, msg *registrytypes.MsgDeleteNa func (ms msgServer) RenewRecord(c context.Context, msg *registrytypes.MsgRenewRecord) (*registrytypes.MsgRenewRecordResponse, error) { ctx := sdk.UnwrapSDKContext(c) + _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return nil, err } - err = ms.k.ProcessRenewRecord(ctx, *msg) + + err = ms.k.RenewRecord(ctx, *msg) if err != nil { return nil, err } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( registrytypes.EventTypeRenewRecord, diff --git a/x/registry/keeper/record_keeper.go b/x/registry/keeper/record_keeper.go index 27cadb8f..3ce4232a 100644 --- a/x/registry/keeper/record_keeper.go +++ b/x/registry/keeper/record_keeper.go @@ -1,8 +1,12 @@ package keeper import ( + "time" + + errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" auctionkeeper "git.vdb.to/cerc-io/laconic2d/x/auction/keeper" registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" @@ -17,9 +21,32 @@ type RecordKeeper struct { // storeKey storetypes.StoreKey // Unexposed key to access store from sdk.Context } -// ProcessRenewRecord renews a record. -func (k Keeper) ProcessRenewRecord(ctx sdk.Context, msg registrytypes.MsgRenewRecord) error { - panic("unimplemented") +// RenewRecord renews a record. +func (k Keeper) RenewRecord(ctx sdk.Context, msg registrytypes.MsgRenewRecord) error { + if has, err := k.HasRecord(ctx, msg.RecordId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.") + } + + // Check if renewal is required (i.e. expired record marked as deleted). + record, err := k.GetRecordById(ctx, msg.RecordId) + if err != nil { + return err + } + + expiryTime, err := time.Parse(time.RFC3339, record.ExpiryTime) + if err != nil { + return err + } + + if !record.Deleted || expiryTime.After(ctx.BlockTime()) { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Renewal not required.") + } + + readableRecord := record.ToReadableRecord() + return k.processRecord(ctx, &readableRecord, true) } // ProcessAssociateBond associates a record with a bond. diff --git a/x/registry/module/autocli.go b/x/registry/module/autocli.go index e08271ec..a39a7bee 100644 --- a/x/registry/module/autocli.go +++ b/x/registry/module/autocli.go @@ -84,6 +84,14 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { Tx: &autocliv1.ServiceCommandDescriptor{ Service: registryv1.Msg_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "RenewRecord", + Use: "renew-record [record-id]", + Short: "Renew (expired) record", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "record_id"}, + }, + }, { RpcMethod: "ReserveName", Use: "reserve-name [name] [owner]",