From fe40617d9ed467556b28969a9c08901ce4ac1d2c Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Tue, 27 Feb 2024 14:59:24 +0530 Subject: [PATCH] Implement auction hooks in registry module --- x/registry/keeper/keeper.go | 24 ++++++-- x/registry/keeper/naming_keeper.go | 11 ++-- x/registry/keeper/record_keeper.go | 92 ++++++++++++++++++++++++++---- x/registry/module/depinject.go | 5 +- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/x/registry/keeper/keeper.go b/x/registry/keeper/keeper.go index 30037c1a..11020b18 100644 --- a/x/registry/keeper/keeper.go +++ b/x/registry/keeper/keeper.go @@ -11,6 +11,7 @@ import ( "cosmossdk.io/collections/indexes" storetypes "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" sdk "github.com/cosmos/cosmos-sdk/types" @@ -52,6 +53,7 @@ func newRecordIndexes(sb *collections.SchemaBuilder) RecordsIndexes { // TODO type AuthoritiesIndexes struct { + AuctionId *indexes.Unique[string, string, registrytypes.NameAuthority] } func (b AuthoritiesIndexes) IndexesList() []collections.Index[string, registrytypes.NameAuthority] { @@ -59,7 +61,15 @@ func (b AuthoritiesIndexes) IndexesList() []collections.Index[string, registryty } func newAuthorityIndexes(sb *collections.SchemaBuilder) AuthoritiesIndexes { - return AuthoritiesIndexes{} + return AuthoritiesIndexes{ + AuctionId: indexes.NewUnique( + sb, registrytypes.AuthoritiesByAuctionIdIndexPrefix, "authorities_by_auction_id", + collections.StringKey, collections.StringKey, + func(name string, v registrytypes.NameAuthority) (string, error) { + return v.AuctionId, nil + }, + ), + } } type NameRecordsIndexes struct { @@ -87,7 +97,6 @@ type Keeper struct { accountKeeper auth.AccountKeeper bankKeeper bank.Keeper - recordKeeper RecordKeeper bondKeeper bondkeeper.Keeper auctionKeeper *auctionkeeper.Keeper @@ -107,7 +116,6 @@ func NewKeeper( storeService storetypes.KVStoreService, accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, - recordKeeper RecordKeeper, bondKeeper bondkeeper.Keeper, auctionKeeper *auctionkeeper.Keeper, ) Keeper { @@ -116,7 +124,6 @@ func NewKeeper( cdc: cdc, accountKeeper: accountKeeper, bankKeeper: bankKeeper, - recordKeeper: recordKeeper, bondKeeper: bondKeeper, auctionKeeper: auctionKeeper, Params: collections.NewItem(sb, registrytypes.ParamsPrefix, "params", codec.CollValue[registrytypes.Params](cdc)), @@ -155,6 +162,15 @@ func NewKeeper( return k } +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return logger(ctx) +} + +func logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", registrytypes.ModuleName) +} + // HasRecord - checks if a record by the given id exists. func (k Keeper) HasRecord(ctx sdk.Context, id string) (bool, error) { has, err := k.Records.Has(ctx, id) diff --git a/x/registry/keeper/naming_keeper.go b/x/registry/keeper/naming_keeper.go index d4722102..3880cbe9 100644 --- a/x/registry/keeper/naming_keeper.go +++ b/x/registry/keeper/naming_keeper.go @@ -546,8 +546,7 @@ func (k Keeper) ProcessAuthorityExpiryQueue(ctx sdk.Context) error { return err } - // TODO: Setup logger - // k.Logger(ctx).Info(fmt.Sprintf("Marking authority expired as no bond present: %s", name)) + k.Logger(ctx).Info(fmt.Sprintf("Marking authority expired as no bond present: %s", name)) return nil } @@ -620,7 +619,7 @@ func (k Keeper) deleteAuthorityExpiryQueue(ctx sdk.Context, name string, authori // 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)) + k.Logger(ctx).Info(fmt.Sprintf("Trying to take rent for authority: %s", name)) params, err := k.GetParams(ctx) if err != nil { @@ -636,7 +635,8 @@ func (k Keeper) tryTakeAuthorityRent(ctx sdk.Context, name string, authority reg return err } - // k.Logger(ctx).Info(fmt.Sprintf("Insufficient funds in owner account to pay authority rent, marking as expired: %s", name)) + 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) } @@ -653,7 +653,8 @@ func (k Keeper) tryTakeAuthorityRent(ctx sdk.Context, name string, authority reg // Save authority. authority.Status = registrytypes.AuthorityActive - // k.Logger(ctx).Info(fmt.Sprintf("Authority rent paid successfully: %s", name)) + k.Logger(ctx).Info(fmt.Sprintf("Authority rent paid successfully: %s", name)) + return k.SaveNameAuthority(ctx, name, &authority) } diff --git a/x/registry/keeper/record_keeper.go b/x/registry/keeper/record_keeper.go index 0a2246ff..758a6cbe 100644 --- a/x/registry/keeper/record_keeper.go +++ b/x/registry/keeper/record_keeper.go @@ -1,8 +1,11 @@ package keeper import ( + "errors" + "fmt" "time" + "cosmossdk.io/collections" errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,37 +27,102 @@ var ( // RecordKeeper exposes the bare minimal read-only API for other modules. type RecordKeeper struct { cdc codec.BinaryCodec // The wire codec for binary encoding/decoding. + k *Keeper auctionKeeper *auctionkeeper.Keeper - // storeKey storetypes.StoreKey // Unexposed key to access store from sdk.Context } // NewRecordKeeper creates new instances of the registry RecordKeeper -func NewRecordKeeper(cdc codec.BinaryCodec, auctionKeeper *auctionkeeper.Keeper) RecordKeeper { +func NewRecordKeeper(cdc codec.BinaryCodec, k *Keeper, auctionKeeper *auctionkeeper.Keeper) RecordKeeper { return RecordKeeper{ - auctionKeeper: auctionKeeper, cdc: cdc, + k: k, + auctionKeeper: auctionKeeper, } } // ModuleName returns the module name. -func (k RecordKeeper) ModuleName() string { +func (rk RecordKeeper) ModuleName() string { return registrytypes.ModuleName } -func (k RecordKeeper) UsesAuction(ctx sdk.Context, auctionId string) bool { - panic("unimplemented") +func (rk RecordKeeper) UsesAuction(ctx sdk.Context, auctionId string) bool { + if _, err := rk.k.Authorities.Indexes.AuctionId.MatchExact(ctx, auctionId); err != nil { + // ErrNotFound + return false + } + + return true } -func (k RecordKeeper) OnAuction(ctx sdk.Context, auctionId string) { - panic("unimplemented") +func (rk RecordKeeper) OnAuction(ctx sdk.Context, auctionId string) { + // no-op } -func (k RecordKeeper) OnAuctionBid(ctx sdk.Context, auctionId string, bidderAddress string) { - panic("unimplemented") +func (rk RecordKeeper) OnAuctionBid(ctx sdk.Context, auctionId string, bidderAddress string) { + // no-op } -func (k RecordKeeper) OnAuctionWinnerSelected(ctx sdk.Context, auctionId string) { - panic("unimplemented") +func (rk RecordKeeper) OnAuctionWinnerSelected(ctx sdk.Context, auctionId string) { + // Update authority status based on auction status/winner. + name, err := rk.k.Authorities.Indexes.AuctionId.MatchExact(ctx, auctionId) + if err != nil && !errors.Is(err, collections.ErrNotFound) { + panic(err) + } + if name == "" { + // We don't know about this auction, ignore. + logger(ctx).Info(fmt.Sprintf("Ignoring auction notification, name mapping not found: %s", auctionId)) + return + } + + if has, err := rk.k.HasNameAuthority(ctx, name); !has { + if err != nil { + panic(err) + } + + // We don't know about this authority, ignore. + logger(ctx).Info(fmt.Sprintf("Ignoring auction notification, authority not found: %s", auctionId)) + return + } + + authority, err := rk.k.GetNameAuthority(ctx, name) + if err != nil { + panic(err) + } + + auctionObj, err := rk.auctionKeeper.GetAuctionById(ctx, auctionId) + if err != nil { + panic(err) + } + + if auctionObj.Status == auctiontypes.AuctionStatusCompleted { + if auctionObj.WinnerAddress != "" { + // Mark authority owner and change status to active. + authority.OwnerAddress = auctionObj.WinnerAddress + authority.Status = registrytypes.AuthorityActive + + // Reset bond id if required, as owner has changed. + authority.BondId = "" + + // Update height for updated/changed authority (owner). + // Can be used to check if names are older than the authority itself (stale names). + authority.Height = uint64(ctx.BlockHeight()) + + logger(ctx).Info(fmt.Sprintf("Winner selected, marking authority as active: %s", name)) + } else { + // Mark as expired. + authority.Status = registrytypes.AuthorityExpired + logger(ctx).Info(fmt.Sprintf("No winner, marking authority as expired: %s", name)) + } + + // Forget about this auction now, we no longer need it. + authority.AuctionId = "" + + if err = rk.k.SaveNameAuthority(ctx, name, &authority); err != nil { + panic(err) + } + } else { + logger(ctx).Info(fmt.Sprintf("Ignoring auction notification, status: %s", auctionObj.Status)) + } } // RenewRecord renews a record. diff --git a/x/registry/module/depinject.go b/x/registry/module/depinject.go index 3978fd17..e600a033 100644 --- a/x/registry/module/depinject.go +++ b/x/registry/module/depinject.go @@ -54,18 +54,17 @@ type ModuleOutputs struct { } func ProvideModule(in ModuleInputs) ModuleOutputs { - recordKeeper := keeper.NewRecordKeeper(in.Cdc, in.AuctionKeeper) - k := keeper.NewKeeper( in.Cdc, in.StoreService, in.AccountKeeper, in.BankKeeper, - recordKeeper, in.BondKeeper, in.AuctionKeeper, ) m := NewAppModule(in.Cdc, k) + recordKeeper := keeper.NewRecordKeeper(in.Cdc, &k, in.AuctionKeeper) + return ModuleOutputs{Module: m, Keeper: k, AuctionHooks: auction.AuctionHooksWrapper{AuctionUsageKeeper: recordKeeper}} }