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.
|
// Add to record expiry queue if expiry time is in the future.
|
||||||
expiryTime, err := time.Parse(time.RFC3339, record.ExpiryTime)
|
expiryTime, err := time.Parse(time.RFC3339, record.ExpiryTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if expiryTime.After(ctx.BlockTime()) {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
// Add authority name to expiry queue.
|
// 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
|
// TODO
|
||||||
// Note: Bond genesis runs first, so bonds will already be present.
|
// Note: Bond genesis runs first, so bonds will already be present.
|
||||||
|
@ -92,12 +92,13 @@ type Keeper struct {
|
|||||||
auctionKeeper auctionkeeper.Keeper
|
auctionKeeper auctionkeeper.Keeper
|
||||||
|
|
||||||
// state management
|
// state management
|
||||||
Schema collections.Schema
|
Schema collections.Schema
|
||||||
Params collections.Item[registrytypes.Params]
|
Params collections.Item[registrytypes.Params]
|
||||||
Records *collections.IndexedMap[string, registrytypes.Record, RecordsIndexes]
|
Records *collections.IndexedMap[string, registrytypes.Record, RecordsIndexes]
|
||||||
Authorities *collections.IndexedMap[string, registrytypes.NameAuthority, AuthoritiesIndexes]
|
Authorities *collections.IndexedMap[string, registrytypes.NameAuthority, AuthoritiesIndexes]
|
||||||
NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes]
|
NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes]
|
||||||
RecordExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue]
|
RecordExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue]
|
||||||
|
AuthorityExpiryQueue collections.Map[time.Time, registrytypes.ExpiryQueue]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeeper creates a new Keeper instance
|
// NewKeeper creates a new Keeper instance
|
||||||
@ -138,6 +139,10 @@ func NewKeeper(
|
|||||||
sb, registrytypes.RecordExpiryQueuePrefix, "record_expiry_queue",
|
sb, registrytypes.RecordExpiryQueuePrefix, "record_expiry_queue",
|
||||||
sdk.TimeKey, codec.CollValue[registrytypes.ExpiryQueue](cdc),
|
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()
|
schema, err := sb.Build()
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"cosmossdk.io/collections"
|
"cosmossdk.io/collections"
|
||||||
errorsmod "cosmossdk.io/errors"
|
errorsmod "cosmossdk.io/errors"
|
||||||
@ -318,10 +319,7 @@ func (k Keeper) createAuthority(ctx sdk.Context, name string, owner string, isRo
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
return k.insertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime)
|
||||||
// k.InsertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) SetAuthorityBond(ctx sdk.Context, msg registrytypes.MsgSetAuthorityBond) error {
|
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
|
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 {
|
func getAuthorityPubKey(pubKey cryptotypes.PubKey) string {
|
||||||
if pubKey == nil {
|
if pubKey == nil {
|
||||||
return ""
|
return ""
|
||||||
|
@ -28,5 +28,6 @@ var (
|
|||||||
NameRecordsPrefix = collections.NewPrefix(6)
|
NameRecordsPrefix = collections.NewPrefix(6)
|
||||||
NameRecordsByCidIndexPrefix = collections.NewPrefix(7)
|
NameRecordsByCidIndexPrefix = collections.NewPrefix(7)
|
||||||
|
|
||||||
RecordExpiryQueuePrefix = collections.NewPrefix(8)
|
RecordExpiryQueuePrefix = collections.NewPrefix(8)
|
||||||
|
AuthorityExpiryQueuePrefix = collections.NewPrefix(9)
|
||||||
)
|
)
|
||||||
|
@ -13,6 +13,13 @@ func EndBlocker(ctx context.Context, k keeper.Keeper) error {
|
|||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||||
|
|
||||||
return k.ProcessRecordExpiryQueue(sdkCtx)
|
if err := k.ProcessRecordExpiryQueue(sdkCtx); err != nil {
|
||||||
// k.ProcessAuthorityExpiryQueue(ctx)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := k.ProcessAuthorityExpiryQueue(sdkCtx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user