diff --git a/x/registry/keeper/msg_server.go b/x/registry/keeper/msg_server.go index 4688292d..d7b3e422 100644 --- a/x/registry/keeper/msg_server.go +++ b/x/registry/keeper/msg_server.go @@ -120,10 +120,12 @@ func (ms msgServer) SetAuthorityBond(c context.Context, msg *registrytypes.MsgSe if err != nil { return nil, err } + err = ms.k.SetAuthorityBond(ctx, *msg) if err != nil { return nil, err } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( registrytypes.EventTypeAuthorityBond, @@ -137,6 +139,7 @@ func (ms msgServer) SetAuthorityBond(c context.Context, msg *registrytypes.MsgSe sdk.NewAttribute(registrytypes.AttributeKeySigner, msg.Signer), ), }) + return ®istrytypes.MsgSetAuthorityBondResponse{}, nil } @@ -147,6 +150,7 @@ func (ms msgServer) DeleteName(c context.Context, msg *registrytypes.MsgDeleteNa if err != nil { return nil, err } + err = ms.k.DeleteName(ctx, *msg) if err != nil { return nil, err @@ -198,15 +202,17 @@ func (ms msgServer) RenewRecord(c context.Context, msg *registrytypes.MsgRenewRe // nolint: all func (ms msgServer) AssociateBond(c context.Context, msg *registrytypes.MsgAssociateBond) (*registrytypes.MsgAssociateBondResponse, error) { ctx := sdk.UnwrapSDKContext(c) + _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return nil, err } - err = ms.k.ProcessAssociateBond(ctx, *msg) + err = ms.k.AssociateBond(ctx, *msg) if err != nil { return nil, err } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( registrytypes.EventTypeAssociateBond, @@ -220,19 +226,23 @@ func (ms msgServer) AssociateBond(c context.Context, msg *registrytypes.MsgAssoc sdk.NewAttribute(registrytypes.AttributeKeySigner, msg.Signer), ), }) + return ®istrytypes.MsgAssociateBondResponse{}, nil } func (ms msgServer) DissociateBond(c context.Context, msg *registrytypes.MsgDissociateBond) (*registrytypes.MsgDissociateBondResponse, error) { ctx := sdk.UnwrapSDKContext(c) + _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return nil, err } - err = ms.k.ProcessDissociateBond(ctx, *msg) + + err = ms.k.DissociateBond(ctx, *msg) if err != nil { return nil, err } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( registrytypes.EventTypeDissociateBond, @@ -245,19 +255,23 @@ func (ms msgServer) DissociateBond(c context.Context, msg *registrytypes.MsgDiss sdk.NewAttribute(registrytypes.AttributeKeySigner, msg.Signer), ), }) + return ®istrytypes.MsgDissociateBondResponse{}, nil } func (ms msgServer) DissociateRecords(c context.Context, msg *registrytypes.MsgDissociateRecords) (*registrytypes.MsgDissociateRecordsResponse, error) { ctx := sdk.UnwrapSDKContext(c) + _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return nil, err } - err = ms.k.ProcessDissociateRecords(ctx, *msg) + + err = ms.k.DissociateRecords(ctx, *msg) if err != nil { return nil, err } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( registrytypes.EventTypeDissociateRecords, @@ -270,19 +284,23 @@ func (ms msgServer) DissociateRecords(c context.Context, msg *registrytypes.MsgD sdk.NewAttribute(registrytypes.AttributeKeySigner, msg.Signer), ), }) + return ®istrytypes.MsgDissociateRecordsResponse{}, nil } func (ms msgServer) ReAssociateRecords(c context.Context, msg *registrytypes.MsgReAssociateRecords) (*registrytypes.MsgReAssociateRecordsResponse, error) { //nolint: all ctx := sdk.UnwrapSDKContext(c) + _, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return nil, err } - err = ms.k.ProcessReAssociateRecords(ctx, *msg) + + err = ms.k.ReAssociateRecords(ctx, *msg) if err != nil { return nil, err } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( registrytypes.EventTypeReAssociateRecords, @@ -296,5 +314,6 @@ func (ms msgServer) ReAssociateRecords(c context.Context, msg *registrytypes.Msg sdk.NewAttribute(registrytypes.AttributeKeySigner, msg.Signer), ), }) + return ®istrytypes.MsgReAssociateRecordsResponse{}, nil } diff --git a/x/registry/keeper/record_keeper.go b/x/registry/keeper/record_keeper.go index 3ce4232a..c71f54b6 100644 --- a/x/registry/keeper/record_keeper.go +++ b/x/registry/keeper/record_keeper.go @@ -49,22 +49,176 @@ func (k Keeper) RenewRecord(ctx sdk.Context, msg registrytypes.MsgRenewRecord) e return k.processRecord(ctx, &readableRecord, true) } -// ProcessAssociateBond associates a record with a bond. -func (k Keeper) ProcessAssociateBond(ctx sdk.Context, msg registrytypes.MsgAssociateBond) error { - panic("unimplemented") +// AssociateBond associates a record with a bond. +func (k Keeper) AssociateBond(ctx sdk.Context, msg registrytypes.MsgAssociateBond) error { + if has, err := k.HasRecord(ctx, msg.RecordId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.") + } + + if has, err := k.bondKeeper.HasBond(ctx, msg.BondId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.") + } + + // Check if already associated with a bond. + record, err := k.GetRecordById(ctx, msg.RecordId) + if err != nil { + return err + } + + if len(record.BondId) != 0 { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond already exists.") + } + + // Only the bond owner can associate a record with the bond. + bond, err := k.bondKeeper.GetBondById(ctx, msg.BondId) + if err != nil { + return err + } + if msg.Signer != bond.Owner { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.") + } + + record.BondId = msg.BondId + if err = k.SaveRecord(ctx, record); err != nil { + return err + } + + // Required so that renewal is triggered (with new bond ID) for expired records. + if record.Deleted { + return k.insertRecordExpiryQueue(ctx, record) + } + + return nil } -// ProcessDissociateBond dissociates a record from its bond. -func (k Keeper) ProcessDissociateBond(ctx sdk.Context, msg registrytypes.MsgDissociateBond) error { - panic("unimplemented") +// DissociateBond dissociates a record from its bond. +func (k Keeper) DissociateBond(ctx sdk.Context, msg registrytypes.MsgDissociateBond) error { + if has, err := k.HasRecord(ctx, msg.RecordId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.") + } + + record, err := k.GetRecordById(ctx, msg.RecordId) + if err != nil { + return err + } + + // Check if record associated with a bond. + bondId := record.BondId + if len(bondId) == 0 { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond not found.") + } + + // Only the bond owner can dissociate a record with the bond. + bond, err := k.bondKeeper.GetBondById(ctx, bondId) + if err != nil { + return err + } + if msg.Signer != bond.Owner { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.") + } + + // Clear bond Id. + record.BondId = "" + return k.SaveRecord(ctx, record) } -// ProcessDissociateRecords dissociates all records associated with a given bond. -func (k Keeper) ProcessDissociateRecords(ctx sdk.Context, msg registrytypes.MsgDissociateRecords) error { - panic("unimplemented") +// DissociateRecords dissociates all records associated with a given bond. +func (k Keeper) DissociateRecords(ctx sdk.Context, msg registrytypes.MsgDissociateRecords) error { + if has, err := k.bondKeeper.HasBond(ctx, msg.BondId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.") + } + + // Only the bond owner can dissociate all records from the bond. + bond, err := k.bondKeeper.GetBondById(ctx, msg.BondId) + if err != nil { + return err + } + if msg.Signer != bond.Owner { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.") + } + + // Dissociate all records from the bond. + records, err := k.GetRecordsByBondId(ctx, msg.BondId) + if err != nil { + return err + } + + for _, record := range records { + // Clear bond Id. + record.BondId = "" + if err = k.SaveRecord(ctx, record); err != nil { + return err + } + } + + return nil } -// ProcessReAssociateRecords switches records from and old to new bond. -func (k Keeper) ProcessReAssociateRecords(ctx sdk.Context, msg registrytypes.MsgReAssociateRecords) error { - panic("unimplemented") +// ReAssociateRecords switches records from and old to new bond. +func (k Keeper) ReAssociateRecords(ctx sdk.Context, msg registrytypes.MsgReAssociateRecords) error { + if has, err := k.bondKeeper.HasBond(ctx, msg.OldBondId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Old bond not found.") + } + + if has, err := k.bondKeeper.HasBond(ctx, msg.NewBondId); !has { + if err != nil { + return err + } + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "New bond not found.") + } + + // Only the bond owner can re-associate all records. + oldBond, err := k.bondKeeper.GetBondById(ctx, msg.OldBondId) + if err != nil { + return err + } + if msg.Signer != oldBond.Owner { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Old bond owner mismatch.") + } + + newBond, err := k.bondKeeper.GetBondById(ctx, msg.NewBondId) + if err != nil { + return err + } + if msg.Signer != newBond.Owner { + return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "New bond owner mismatch.") + } + + // Re-associate all records. + records, err := k.GetRecordsByBondId(ctx, msg.OldBondId) + if err != nil { + return err + } + + for _, record := range records { + // Switch bond ID. + record.BondId = msg.NewBondId + if err = k.SaveRecord(ctx, record); err != nil { + return err + } + + // Required so that renewal is triggered (with new bond ID) for expired records. + if record.Deleted { + if err = k.insertRecordExpiryQueue(ctx, record); err != nil { + return err + } + } + } + + return nil } diff --git a/x/registry/module/autocli.go b/x/registry/module/autocli.go index a39a7bee..0a8bfcc0 100644 --- a/x/registry/module/autocli.go +++ b/x/registry/module/autocli.go @@ -127,6 +127,40 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { {ProtoField: "crn"}, }, }, + { + RpcMethod: "AssociateBond", + Use: "associate-bond [record-id] [bond-id]", + Short: "Associate record with a bond", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "record_id"}, + {ProtoField: "bond_id"}, + }, + }, + { + RpcMethod: "DissociateBond", + Use: "dissociate-bond [record-id]", + Short: "Dissociate record from (existing) bond", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "record_id"}, + }, + }, + { + RpcMethod: "DissociateRecords", + Use: "dissociate-records [bond-id]", + Short: "Dissociate all records from a bond", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "bond_id"}, + }, + }, + { + RpcMethod: "ReAssociateRecords", + Use: "reassociate-records [old-bond-id] [new-bond-id]", + Short: "Re-associate all records from an old to a new bond", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "old_bond_id"}, + {ProtoField: "new_bond_id"}, + }, + }, }, EnhanceCustomCommand: true, // Allow additional manual commands },