Handle record and authority expiry in registry module #7
@ -22,11 +22,13 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, data *registry.GenesisState) error
|
||||
// Add to record expiry queue if expiry time is in the future.
|
||||
expiryTime, err := time.Parse(time.RFC3339, record.ExpiryTime)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if expiryTime.After(ctx.BlockTime()) {
|
||||
k.insertRecordExpiryQueue(ctx, record)
|
||||
if err := k.insertRecordExpiryQueue(ctx, record); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,9 +39,10 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, data *registry.GenesisState) error
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Add authority name to expiry queue.
|
||||
// k.InsertAuthorityExpiryQueue(ctx, authority.Name, authority.Entry.ExpiryTime)
|
||||
if err := k.insertAuthorityExpiryQueue(ctx, authority.Name, authority.Entry.ExpiryTime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Note: Bond genesis runs first, so bonds will already be present.
|
||||
|
@ -98,6 +98,7 @@ type Keeper struct {
|
||||
Authorities *collections.IndexedMap[string, registrytypes.NameAuthority, AuthoritiesIndexes]
|
||||
NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes]
|
||||
RecordExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue]
|
||||
AuthorityExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue]
|
||||
}
|
||||
|
||||
// NewKeeper creates a new Keeper instance
|
||||
@ -138,6 +139,10 @@ func NewKeeper(
|
||||
sb, registrytypes.RecordExpiryQueuePrefix, "record_expiry_queue",
|
||||
sdk.TimeKey, codec.CollValue[registrytypes.ExpiryQueue](cdc),
|
||||
),
|
||||
AuthorityExpiryQueue: collections.NewMap(
|
||||
sb, registrytypes.AuthorityExpiryQueuePrefix, "authority_expiry_queue",
|
||||
sdk.TimeKey, codec.CollValue[registrytypes.ExpiryQueue](cdc),
|
||||
),
|
||||
}
|
||||
|
||||
schema, err := sb.Build()
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/collections"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
@ -318,10 +319,7 @@ func (k Keeper) createAuthority(ctx sdk.Context, name string, owner string, isRo
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO
|
||||
// k.InsertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime)
|
||||
|
||||
return nil
|
||||
return k.insertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime)
|
||||
}
|
||||
|
||||
func (k Keeper) SetAuthorityBond(ctx sdk.Context, msg registrytypes.MsgSetAuthorityBond) error {
|
||||
@ -520,6 +518,149 @@ func (k Keeper) checkCRNAccess(ctx sdk.Context, signer sdk.AccAddress, crn strin
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessAuthorityExpiryQueue tries to renew expiring authorities (by collecting rent) else marks them as expired.
|
||||
func (k Keeper) ProcessAuthorityExpiryQueue(ctx sdk.Context) error {
|
||||
names, err := k.getAllExpiredAuthorities(ctx, ctx.BlockHeader().Time)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
authority, err := k.GetNameAuthority(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bondExists := false
|
||||
if authority.BondId != "" {
|
||||
bondExists, err = k.bondKeeper.HasBond(ctx, authority.BondId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If authority doesn't have an associated bond or if bond no longer exists, mark it expired.
|
||||
if !bondExists {
|
||||
authority.Status = registrytypes.AuthorityExpired
|
||||
if err = k.SaveNameAuthority(ctx, name, &authority); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = k.deleteAuthorityExpiryQueue(ctx, name, authority); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Setup logger
|
||||
// k.Logger(ctx).Info(fmt.Sprintf("Marking authority expired as no bond present: %s", name))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Try to renew the authority by taking rent.
|
||||
if err := k.tryTakeAuthorityRent(ctx, name, authority); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getAllExpiredAuthorities returns a concatenated list of all the timeslices before currTime.
|
||||
func (k Keeper) getAllExpiredAuthorities(ctx sdk.Context, currTime time.Time) ([]string, error) {
|
||||
var expiredAuthorityNames []string
|
||||
|
||||
// Get all the authorities with expiry time until currTime
|
||||
rng := new(collections.Range[time.Time]).EndInclusive(currTime)
|
||||
err := k.AuthorityExpiryQueue.Walk(ctx, rng, func(key time.Time, value registrytypes.ExpiryQueue) (stop bool, err error) {
|
||||
expiredAuthorityNames = append(expiredAuthorityNames, value.Value...)
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
return expiredAuthorityNames, nil
|
||||
}
|
||||
|
||||
func (k Keeper) insertAuthorityExpiryQueue(ctx sdk.Context, name string, expiryTime time.Time) error {
|
||||
existingNamesList, err := k.AuthorityExpiryQueue.Get(ctx, expiryTime)
|
||||
if err != nil {
|
||||
if errors.Is(err, collections.ErrNotFound) {
|
||||
existingNamesList = registrytypes.ExpiryQueue{
|
||||
Id: expiryTime.String(),
|
||||
Value: []string{},
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
existingNamesList.Value = append(existingNamesList.Value, name)
|
||||
return k.AuthorityExpiryQueue.Set(ctx, expiryTime, existingNamesList)
|
||||
}
|
||||
|
||||
// deleteAuthorityExpiryQueue deletes an authority name from the authority expiry queue.
|
||||
func (k Keeper) deleteAuthorityExpiryQueue(ctx sdk.Context, name string, authority registrytypes.NameAuthority) error {
|
||||
expiryTime := authority.ExpiryTime
|
||||
existingNamesList, err := k.AuthorityExpiryQueue.Get(ctx, expiryTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newNamesSlice := []string{}
|
||||
for _, id := range existingNamesList.Value {
|
||||
if id != name {
|
||||
newNamesSlice = append(newNamesSlice, id)
|
||||
}
|
||||
}
|
||||
|
||||
if len(existingNamesList.Value) == 0 {
|
||||
return k.AuthorityExpiryQueue.Remove(ctx, expiryTime)
|
||||
} else {
|
||||
existingNamesList.Value = newNamesSlice
|
||||
return k.AuthorityExpiryQueue.Set(ctx, expiryTime, existingNamesList)
|
||||
}
|
||||
}
|
||||
|
||||
// tryTakeAuthorityRent tries to take rent from the authority bond.
|
||||
func (k Keeper) tryTakeAuthorityRent(ctx sdk.Context, name string, authority registrytypes.NameAuthority) error {
|
||||
// k.Logger(ctx).Info(fmt.Sprintf("Trying to take rent for authority: %s", name))
|
||||
|
||||
params, err := k.GetParams(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rent := params.AuthorityRent
|
||||
sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, authority.BondId, registrytypes.AuthorityRentModuleAccountName, sdk.NewCoins(rent))
|
||||
if sdkErr != nil {
|
||||
// Insufficient funds, mark authority as expired.
|
||||
authority.Status = registrytypes.AuthorityExpired
|
||||
if err := k.SaveNameAuthority(ctx, name, &authority); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// k.Logger(ctx).Info(fmt.Sprintf("Insufficient funds in owner account to pay authority rent, marking as expired: %s", name))
|
||||
return k.deleteAuthorityExpiryQueue(ctx, name, authority)
|
||||
}
|
||||
|
||||
// Delete old expiry queue entry, create new one.
|
||||
if err := k.deleteAuthorityExpiryQueue(ctx, name, authority); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authority.ExpiryTime = ctx.BlockTime().Add(params.AuthorityRentDuration)
|
||||
if err := k.insertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save authority.
|
||||
authority.Status = registrytypes.AuthorityActive
|
||||
|
||||
// k.Logger(ctx).Info(fmt.Sprintf("Authority rent paid successfully: %s", name))
|
||||
return k.SaveNameAuthority(ctx, name, &authority)
|
||||
}
|
||||
|
||||
func getAuthorityPubKey(pubKey cryptotypes.PubKey) string {
|
||||
if pubKey == nil {
|
||||
return ""
|
||||
|
@ -29,4 +29,5 @@ var (
|
||||
NameRecordsByCidIndexPrefix = collections.NewPrefix(7)
|
||||
|
||||
RecordExpiryQueuePrefix = collections.NewPrefix(8)
|
||||
AuthorityExpiryQueuePrefix = collections.NewPrefix(9)
|
||||
)
|
||||
|
@ -13,6 +13,13 @@ func EndBlocker(ctx context.Context, k keeper.Keeper) error {
|
||||
// TODO: Implement
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
|
||||
return k.ProcessRecordExpiryQueue(sdkCtx)
|
||||
// k.ProcessAuthorityExpiryQueue(ctx)
|
||||
if err := k.ProcessRecordExpiryQueue(sdkCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := k.ProcessAuthorityExpiryQueue(sdkCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user