package keeper import ( "bytes" "fmt" "net/url" "strings" "time" errorsmod "cosmossdk.io/errors" auctiontypes "github.com/cerc-io/laconicd/x/auction/types" "github.com/cerc-io/laconicd/x/registry/helpers" "github.com/cerc-io/laconicd/x/registry/types" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func getAuthorityPubKey(pubKey cryptotypes.PubKey) string { if pubKey != nil { return helpers.BytesToBase64(pubKey.Bytes()) } return "" } // GetNameAuthorityIndexKey Generates name -> NameAuthority index key. func GetNameAuthorityIndexKey(name string) []byte { return append(PrefixNameAuthorityRecordIndex, []byte(name)...) } // GetNameRecordIndexKey Generates CRN -> NameRecord index key. func GetNameRecordIndexKey(crn string) []byte { return append(PrefixCRNToNameRecordIndex, []byte(crn)...) } func GetCIDToNamesIndexKey(id string) []byte { return append(PrefixCIDToNamesIndex, []byte(id)...) } func SetNameAuthority(ctx sdk.Context, store sdk.KVStore, codec codec.BinaryCodec, name string, authority *types.NameAuthority) { store.Set(GetNameAuthorityIndexKey(name), codec.MustMarshal(authority)) updateBlockChangeSetForNameAuthority(ctx, codec, store, name) } // SetNameAuthority creates the NameAuthority record. func (k Keeper) SetNameAuthority(ctx sdk.Context, name string, authority *types.NameAuthority) { SetNameAuthority(ctx, ctx.KVStore(k.storeKey), k.cdc, name, authority) } func removeAuctionToAuthorityMapping(store sdk.KVStore, auctionID string) { store.Delete(GetAuctionToAuthorityIndexKey(auctionID)) } func (k Keeper) RemoveAuctionToAuthorityMapping(ctx sdk.Context, auctionID string) { removeAuctionToAuthorityMapping(ctx.KVStore(k.storeKey), auctionID) } // GetNameAuthority - gets a name authority from the store. func GetNameAuthority(store sdk.KVStore, codec codec.BinaryCodec, name string) types.NameAuthority { authorityKey := GetNameAuthorityIndexKey(name) if !store.Has(authorityKey) { return types.NameAuthority{} } bz := store.Get(authorityKey) var obj types.NameAuthority codec.MustUnmarshal(bz, &obj) return obj } // GetNameAuthority - gets a name authority from the store. func (k Keeper) GetNameAuthority(ctx sdk.Context, name string) types.NameAuthority { return GetNameAuthority(ctx.KVStore(k.storeKey), k.cdc, name) } // HasNameAuthority - checks if a name authority entry exists. func HasNameAuthority(store sdk.KVStore, name string) bool { return store.Has(GetNameAuthorityIndexKey(name)) } // HasNameAuthority - checks if a name/authority exists. func (k Keeper) HasNameAuthority(ctx sdk.Context, name string) bool { return HasNameAuthority(ctx.KVStore(k.storeKey), name) } func getBondIDToAuthoritiesIndexKey(bondID string, name string) []byte { return append(append(PrefixBondIDToAuthoritiesIndex, []byte(bondID)...), []byte(name)...) } // AddBondToAuthorityIndexEntry adds the Bond ID -> [Authority] index entry. func (k Keeper) AddBondToAuthorityIndexEntry(ctx sdk.Context, bondID string, name string) { store := ctx.KVStore(k.storeKey) store.Set(getBondIDToAuthoritiesIndexKey(bondID, name), []byte{}) } // RemoveBondToAuthorityIndexEntry removes the Bond ID -> [Authority] index entry. func (k Keeper) RemoveBondToAuthorityIndexEntry(ctx sdk.Context, bondID string, name string) { RemoveBondToAuthorityIndexEntry(ctx.KVStore(k.storeKey), bondID, name) } func RemoveBondToAuthorityIndexEntry(store sdk.KVStore, bondID string, name string) { store.Delete(getBondIDToAuthoritiesIndexKey(bondID, name)) } func (k Keeper) updateBlockChangeSetForName(ctx sdk.Context, crn string) { changeSet := k.getOrCreateBlockChangeSet(ctx, ctx.BlockHeight()) changeSet.Names = append(changeSet.Names, crn) k.saveBlockChangeSet(ctx, changeSet) } func (k Keeper) getAuthority(ctx sdk.Context, crn string) (string, *url.URL, *types.NameAuthority, error) { parsedCRN, err := url.Parse(crn) if err != nil { return "", nil, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.") } name := parsedCRN.Host if !k.HasNameAuthority(ctx, name) { return name, nil, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.") } authority := k.GetNameAuthority(ctx, name) return name, parsedCRN, &authority, nil } func (k Keeper) checkCRNAccess(ctx sdk.Context, signer sdk.AccAddress, crn string) error { name, parsedCRN, authority, err := k.getAuthority(ctx, crn) if err != nil { return err } formattedCRN := fmt.Sprintf("crn://%s%s", name, parsedCRN.RequestURI()) if formattedCRN != crn { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.") } if authority.OwnerAddress != signer.String() { return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Access denied.") } if authority.Status != types.AuthorityActive { return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Authority is not active.") } if authority.BondId == "" || len(authority.BondId) == 0 { return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Authority bond not found.") } if authority.OwnerPublicKey == "" { // Try to set owner public key if account has it available now. ownerAccount := k.accountKeeper.GetAccount(ctx, signer) pubKey := ownerAccount.GetPubKey() if pubKey != nil { // Update public key in authority record. authority.OwnerPublicKey = getAuthorityPubKey(pubKey) k.SetNameAuthority(ctx, name, authority) } } return nil } // HasNameRecord - checks if a name record exists. func (k Keeper) HasNameRecord(ctx sdk.Context, crn string) bool { store := ctx.KVStore(k.storeKey) return store.Has(GetNameRecordIndexKey(crn)) } // GetNameRecord - gets a name record from the store. func GetNameRecord(store sdk.KVStore, codec codec.BinaryCodec, crn string) *types.NameRecord { nameRecordKey := GetNameRecordIndexKey(crn) if !store.Has(nameRecordKey) { return nil } bz := store.Get(nameRecordKey) var obj types.NameRecord codec.MustUnmarshal(bz, &obj) return &obj } // GetNameRecord - gets a name record from the store. func (k Keeper) GetNameRecord(ctx sdk.Context, crn string) *types.NameRecord { _, _, authority, err := k.getAuthority(ctx, crn) if err != nil || authority.Status != types.AuthorityActive { // If authority is not active (or any other error), lookup fails. return nil } nameRecord := GetNameRecord(ctx.KVStore(k.storeKey), k.cdc, crn) // Name record may not exist. if nameRecord == nil { return nil } // Name lookup should fail if the name record is stale. // i.e. authority was registered later than the name. if authority.Height > nameRecord.Latest.Height { return nil } return nameRecord } // RemoveRecordToNameMapping removes a name from the record ID -> []names index. func RemoveRecordToNameMapping(store sdk.KVStore, id string, crn string) { reverseNameIndexKey := GetCIDToNamesIndexKey(id) names, _ := helpers.BytesArrToStringArr(store.Get(reverseNameIndexKey)) nameSet := helpers.SliceToSet(names) nameSet.Remove(crn) if nameSet.Cardinality() == 0 { // Delete as storing empty slice throws error from baseapp. store.Delete(reverseNameIndexKey) } else { data, _ := helpers.StrArrToBytesArr(helpers.SetToSlice(nameSet)) store.Set(reverseNameIndexKey, data) } } // AddRecordToNameMapping adds a name to the record ID -> []names index. func AddRecordToNameMapping(store sdk.KVStore, id string, crn string) { reverseNameIndexKey := GetCIDToNamesIndexKey(id) var names []string if store.Has(reverseNameIndexKey) { names, _ = helpers.BytesArrToStringArr(store.Get(reverseNameIndexKey)) } nameSet := helpers.SliceToSet(names) nameSet.Add(crn) bz, _ := helpers.StrArrToBytesArr(helpers.SetToSlice(nameSet)) store.Set(reverseNameIndexKey, bz) } // SetNameRecord - sets a name record. func SetNameRecord(store sdk.KVStore, codec codec.BinaryCodec, crn string, id string, height int64) { nameRecordIndexKey := GetNameRecordIndexKey(crn) var nameRecord types.NameRecord if store.Has(nameRecordIndexKey) { bz := store.Get(nameRecordIndexKey) codec.MustUnmarshal(bz, &nameRecord) nameRecord.History = append(nameRecord.History, nameRecord.Latest) // Update old CID -> []Name index. if nameRecord.Latest.Id != "" || len(nameRecord.Latest.Id) != 0 { RemoveRecordToNameMapping(store, nameRecord.Latest.Id, crn) } } nameRecord.Latest = &types.NameRecordEntry{ Id: id, Height: uint64(height), } store.Set(nameRecordIndexKey, codec.MustMarshal(&nameRecord)) // Update new CID -> []Name index. if id != "" { AddRecordToNameMapping(store, id, crn) } } // SetNameRecord - sets a name record. func (k Keeper) SetNameRecord(ctx sdk.Context, crn string, id string) { SetNameRecord(ctx.KVStore(k.storeKey), k.cdc, crn, id, ctx.BlockHeight()) // Update changeSet for name. k.updateBlockChangeSetForName(ctx, crn) } // ProcessSetName creates a CRN -> Record ID mapping. func (k Keeper) ProcessSetName(ctx sdk.Context, msg types.MsgSetName) error { signerAddress, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return err } err = k.checkCRNAccess(ctx, signerAddress, msg.Crn) if err != nil { return err } nameRecord := k.GetNameRecord(ctx, msg.Crn) if nameRecord != nil && nameRecord.Latest.Id == msg.Cid { return nil } k.SetNameRecord(ctx, msg.Crn, msg.Cid) return nil } // ListNameRecords - get all name records. func (k Keeper) ListNameRecords(ctx sdk.Context) []types.NameEntry { var nameEntries []types.NameEntry store := ctx.KVStore(k.storeKey) itr := sdk.KVStorePrefixIterator(store, PrefixCRNToNameRecordIndex) defer itr.Close() for ; itr.Valid(); itr.Next() { bz := store.Get(itr.Key()) if bz != nil { var record types.NameRecord k.cdc.MustUnmarshal(bz, &record) nameEntries = append(nameEntries, types.NameEntry{ Name: string(itr.Key()[len(PrefixCRNToNameRecordIndex):]), Entry: &record, }) } } return nameEntries } // ProcessReserveSubAuthority reserves a sub-authority. func (k Keeper) ProcessReserveSubAuthority(ctx sdk.Context, name string, msg types.MsgReserveAuthority) error { // Get parent authority name. names := strings.Split(name, ".") parent := strings.Join(names[1:], ".") // Check if parent authority exists. if !k.HasNameAuthority(ctx, parent) { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Parent authority not found.") } parentAuthority := k.GetNameAuthority(ctx, parent) // Sub-authority creator needs to be the owner of the parent authority. if parentAuthority.OwnerAddress != msg.Signer { return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Access denied.") } // Sub-authority owner defaults to parent authority owner. subAuthorityOwner := msg.Signer if len(msg.Owner) != 0 { // Override sub-authority owner if provided in message. subAuthorityOwner = msg.Owner } sdkErr := k.createAuthority(ctx, name, subAuthorityOwner, false) if sdkErr != nil { return sdkErr } return nil } func GetAuctionToAuthorityIndexKey(auctionID string) []byte { return append(PrefixAuctionToAuthorityNameIndex, []byte(auctionID)...) } func (k Keeper) AddAuctionToAuthorityMapping(ctx sdk.Context, auctionID string, name string) { store := ctx.KVStore(k.storeKey) store.Set(GetAuctionToAuthorityIndexKey(auctionID), []byte(name)) } func (k Keeper) createAuthority(ctx sdk.Context, name string, owner string, isRoot bool) error { moduleParams := k.GetParams(ctx) if k.HasNameAuthority(ctx, name) { authority := k.GetNameAuthority(ctx, name) if authority.Status != types.AuthorityExpired { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name already reserved.") } } ownerAddress, err := sdk.AccAddressFromBech32(owner) if err != nil { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid owner address.") } ownerAccount := k.accountKeeper.GetAccount(ctx, ownerAddress) if ownerAccount == nil { return errorsmod.Wrap(sdkerrors.ErrUnknownAddress, "Account not found.") } authority := types.NameAuthority{ OwnerPublicKey: getAuthorityPubKey(ownerAccount.GetPubKey()), OwnerAddress: owner, Height: uint64(ctx.BlockHeight()), Status: types.AuthorityActive, AuctionId: "", BondId: "", ExpiryTime: ctx.BlockTime().Add(moduleParams.AuthorityGracePeriod), } if isRoot && moduleParams.AuthorityAuctionEnabled { // If auctions are enabled, clear out owner fields. They will be set after a winner is picked. authority.OwnerAddress = "" authority.OwnerPublicKey = "" // Reset bond ID if required. if authority.BondId != "" || len(authority.BondId) != 0 { k.RemoveBondToAuthorityIndexEntry(ctx, authority.BondId, name) authority.BondId = "" } params := auctiontypes.Params{ CommitsDuration: moduleParams.AuthorityAuctionCommitsDuration, RevealsDuration: moduleParams.AuthorityAuctionRevealsDuration, CommitFee: moduleParams.AuthorityAuctionCommitFee, RevealFee: moduleParams.AuthorityAuctionRevealFee, MinimumBid: moduleParams.AuthorityAuctionMinimumBid, } // Create an auction. msg := auctiontypes.NewMsgCreateAuction(params, ownerAddress) auction, sdkErr := k.auctionKeeper.CreateAuction(ctx, msg) if sdkErr != nil { return sdkErr } // Create auction ID -> authority name index. k.AddAuctionToAuthorityMapping(ctx, auction.Id, name) authority.Status = types.AuthorityUnderAuction authority.AuctionId = auction.Id authority.ExpiryTime = auction.RevealsEndTime.Add(moduleParams.AuthorityGracePeriod) } k.SetNameAuthority(ctx, name, &authority) k.InsertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime) return nil } // ProcessReserveAuthority reserves a name authority. func (k Keeper) ProcessReserveAuthority(ctx sdk.Context, msg types.MsgReserveAuthority) error { crn := fmt.Sprintf("crn://%s", msg.GetName()) parsedCrn, err := url.Parse(crn) if err != nil { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid name") } name := parsedCrn.Host if fmt.Sprintf("crn://%s", name) != crn { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid name") } if strings.Contains(name, ".") { return k.ProcessReserveSubAuthority(ctx, name, msg) } err = k.createAuthority(ctx, name, msg.GetSigner(), true) if err != nil { return err } return nil } func (k Keeper) ProcessSetAuthorityBond(ctx sdk.Context, msg types.MsgSetAuthorityBond) error { name := msg.GetName() signer := msg.GetSigner() if !k.HasNameAuthority(ctx, name) { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.") } authority := k.GetNameAuthority(ctx, name) if authority.OwnerAddress != signer { return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Access denied") } if !k.bondKeeper.HasBond(ctx, msg.BondId) { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.") } // bond := k.bondKeeper.GetBond(ctx, msg.BondId) if bond.Owner != signer { return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.") } // No-op if bond hasn't changed. if authority.BondId == msg.BondId { return nil } // Remove old bond ID mapping, if any. if authority.BondId != "" { k.RemoveBondToAuthorityIndexEntry(ctx, authority.BondId, name) } // Update bond ID for authority. authority.BondId = bond.Id k.SetNameAuthority(ctx, name, &authority) // Add new bond ID mapping. k.AddBondToAuthorityIndexEntry(ctx, authority.BondId, name) return nil } // ProcessDeleteName removes a CRN -> Record ID mapping. func (k Keeper) ProcessDeleteName(ctx sdk.Context, msg types.MsgDeleteNameAuthority) error { signerAddress, err := sdk.AccAddressFromBech32(msg.Signer) if err != nil { return err } err = k.checkCRNAccess(ctx, signerAddress, msg.Crn) if err != nil { return err } if !k.HasNameRecord(ctx, msg.Crn) { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name not found.") } // Set CID to empty string. k.SetNameRecord(ctx, msg.Crn, "") return nil } func (k Keeper) GetAuthorityExpiryQueue(ctx sdk.Context) []*types.ExpiryQueueRecord { var authorities []*types.ExpiryQueueRecord store := ctx.KVStore(k.storeKey) itr := sdk.KVStorePrefixIterator(store, PrefixExpiryTimeToAuthoritiesIndex) defer itr.Close() for ; itr.Valid(); itr.Next() { var record []string record, err := helpers.BytesArrToStringArr(itr.Value()) if err != nil { return authorities } authorities = append(authorities, &types.ExpiryQueueRecord{ Id: string(itr.Key()[len(PrefixExpiryTimeToAuthoritiesIndex):]), Value: record, }) } return authorities } // ResolveCRN resolves a CRN to a record. func (k Keeper) ResolveCRN(ctx sdk.Context, crn string) *types.Record { _, _, authority, err := k.getAuthority(ctx, crn) if err != nil || authority.Status != types.AuthorityActive { // If authority is not active (or any other error), resolution fails. return nil } // Name should not resolve if it's stale. // i.e. authority was registered later than the name. record, nameRecord := ResolveCRN(ctx.KVStore(k.storeKey), crn, k, ctx) if authority.Height > nameRecord.Latest.Height { return nil } return record } // ResolveCRN resolves a CRN to a record. func ResolveCRN(store sdk.KVStore, crn string, k Keeper, c sdk.Context) (*types.Record, *types.NameRecord) { nameKey := GetNameRecordIndexKey(crn) if store.Has(nameKey) { bz := store.Get(nameKey) var obj types.NameRecord k.cdc.MustUnmarshal(bz, &obj) recordExists := k.HasRecord(c, obj.Latest.Id) if !recordExists || obj.Latest.Id == "" { return nil, &obj } record := k.GetRecord(c, obj.Latest.Id) return &record, &obj } return nil, nil } func getAuthorityExpiryQueueTimeKey(timestamp time.Time) []byte { timeBytes := sdk.FormatTimeBytes(timestamp) return append(PrefixExpiryTimeToAuthoritiesIndex, timeBytes...) } func (k Keeper) InsertAuthorityExpiryQueue(ctx sdk.Context, name string, expiryTime time.Time) { timeSlice := k.GetAuthorityExpiryQueueTimeSlice(ctx, expiryTime) timeSlice = append(timeSlice, name) k.SetAuthorityExpiryQueueTimeSlice(ctx, expiryTime, timeSlice) } func (k Keeper) GetAuthorityExpiryQueueTimeSlice(ctx sdk.Context, timestamp time.Time) []string { store := ctx.KVStore(k.storeKey) bz := store.Get(getAuthorityExpiryQueueTimeKey(timestamp)) if bz == nil { return []string{} } names, err := helpers.BytesArrToStringArr(bz) if err != nil { return []string{} } return names } func (k Keeper) SetAuthorityExpiryQueueTimeSlice(ctx sdk.Context, timestamp time.Time, names []string) { store := ctx.KVStore(k.storeKey) bz, _ := helpers.StrArrToBytesArr(names) store.Set(getAuthorityExpiryQueueTimeKey(timestamp), bz) } // ProcessAuthorityExpiryQueue tries to renew expiring authorities (by collecting rent) else marks them as expired. func (k Keeper) ProcessAuthorityExpiryQueue(ctx sdk.Context) { names := k.GetAllExpiredAuthorities(ctx, ctx.BlockHeader().Time) for _, name := range names { authority := k.GetNameAuthority(ctx, name) // If authority doesn't have an associated bond or if bond no longer exists, mark it expired. if authority.BondId == "" || !k.bondKeeper.HasBond(ctx, authority.BondId) { authority.Status = types.AuthorityExpired k.SetNameAuthority(ctx, name, &authority) k.DeleteAuthorityExpiryQueue(ctx, name, authority) k.Logger(ctx).Info(fmt.Sprintf("Marking authority expired as no bond present: %s", name)) return } // Try to renew the authority by taking rent. k.TryTakeAuthorityRent(ctx, name, authority) } } // DeleteAuthorityExpiryQueueTimeSlice deletes a specific authority expiry queue timeslice. func (k Keeper) DeleteAuthorityExpiryQueueTimeSlice(ctx sdk.Context, timestamp time.Time) { store := ctx.KVStore(k.storeKey) store.Delete(getAuthorityExpiryQueueTimeKey(timestamp)) } // DeleteAuthorityExpiryQueue deletes an authority name from the authority expiry queue. func (k Keeper) DeleteAuthorityExpiryQueue(ctx sdk.Context, name string, authority types.NameAuthority) { timeSlice := k.GetAuthorityExpiryQueueTimeSlice(ctx, authority.ExpiryTime) newTimeSlice := []string{} for _, existingName := range timeSlice { if !bytes.Equal([]byte(existingName), []byte(name)) { newTimeSlice = append(newTimeSlice, existingName) } } if len(newTimeSlice) == 0 { k.DeleteAuthorityExpiryQueueTimeSlice(ctx, authority.ExpiryTime) } else { k.SetAuthorityExpiryQueueTimeSlice(ctx, authority.ExpiryTime, newTimeSlice) } } // GetAllExpiredAuthorities returns a concatenated list of all the timeslices before currTime. func (k Keeper) GetAllExpiredAuthorities(ctx sdk.Context, currTime time.Time) (expiredAuthorityNames []string) { // Gets an iterator for all timeslices from time 0 until the current block header time. itr := k.AuthorityExpiryQueueIterator(ctx, ctx.BlockHeader().Time) defer itr.Close() for ; itr.Valid(); itr.Next() { timeslice, err := helpers.BytesArrToStringArr(itr.Value()) if err != nil { panic(err) } expiredAuthorityNames = append(expiredAuthorityNames, timeslice...) } return expiredAuthorityNames } // AuthorityExpiryQueueIterator returns all the authority expiry queue timeslices from time 0 until endTime. func (k Keeper) AuthorityExpiryQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { store := ctx.KVStore(k.storeKey) rangeEndBytes := sdk.InclusiveEndBytes(getAuthorityExpiryQueueTimeKey(endTime)) return store.Iterator(PrefixExpiryTimeToAuthoritiesIndex, rangeEndBytes) } // TryTakeAuthorityRent tries to take rent from the authority bond. func (k Keeper) TryTakeAuthorityRent(ctx sdk.Context, name string, authority types.NameAuthority) { k.Logger(ctx).Info(fmt.Sprintf("Trying to take rent for authority: %s", name)) params := k.GetParams(ctx) rent := params.AuthorityRent sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, authority.BondId, types.AuthorityRentModuleAccountName, sdk.NewCoins(rent)) if sdkErr != nil { // Insufficient funds, mark authority as expired. authority.Status = types.AuthorityExpired k.SetNameAuthority(ctx, name, &authority) k.DeleteAuthorityExpiryQueue(ctx, name, authority) k.Logger(ctx).Info(fmt.Sprintf("Insufficient funds in owner account to pay authority rent, marking as expired: %s", name)) return } // Delete old expiry queue entry, create new one. k.DeleteAuthorityExpiryQueue(ctx, name, authority) authority.ExpiryTime = ctx.BlockTime().Add(params.AuthorityRentDuration) k.InsertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime) // Save authority. authority.Status = types.AuthorityActive k.SetNameAuthority(ctx, name, &authority) k.AddBondToAuthorityIndexEntry(ctx, authority.BondId, name) k.Logger(ctx).Info(fmt.Sprintf("Authority rent paid successfully: %s", name)) } // ListNameAuthorityRecords - get all name authority records. func (k Keeper) ListNameAuthorityRecords(ctx sdk.Context) map[string]types.NameAuthority { nameAuthorityRecords := make(map[string]types.NameAuthority) store := ctx.KVStore(k.storeKey) itr := sdk.KVStorePrefixIterator(store, PrefixNameAuthorityRecordIndex) defer itr.Close() for ; itr.Valid(); itr.Next() { bz := store.Get(itr.Key()) if bz != nil { var record types.NameAuthority k.cdc.MustUnmarshal(bz, &record) nameAuthorityRecords[string(itr.Key()[len(PrefixNameAuthorityRecordIndex):])] = record } } return nameAuthorityRecords }