Add commands to reserve and get name authority

This commit is contained in:
Prathamesh Musale 2024-02-16 15:02:52 +05:30
parent 91a8b56183
commit 764fb1f04a
7 changed files with 237 additions and 17 deletions

View File

@ -6,7 +6,23 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
) )
var _ sdk.Msg = &MsgCommitBid{} var (
_ sdk.Msg = &MsgCreateAuction{}
_ sdk.Msg = &MsgCommitBid{}
_ sdk.Msg = &MsgRevealBid{}
)
// NewMsgCreateAuction is the constructor function for MsgCreateAuction.
func NewMsgCreateAuction(params Params, signer sdk.AccAddress) MsgCreateAuction {
return MsgCreateAuction{
CommitsDuration: params.CommitsDuration,
RevealsDuration: params.RevealsDuration,
CommitFee: params.CommitFee,
RevealFee: params.RevealFee,
MinimumBid: params.MinimumBid,
Signer: signer.String(),
}
}
// NewMsgCommitBid is the constructor function for MsgCommitBid. // NewMsgCommitBid is the constructor function for MsgCommitBid.
func NewMsgCommitBid(auctionID string, commitHash string, signer sdk.AccAddress) MsgCommitBid { func NewMsgCommitBid(auctionID string, commitHash string, signer sdk.AccAddress) MsgCommitBid {

View File

@ -40,7 +40,7 @@ func (b RecordsIndexes) IndexesList() []collections.Index[string, registrytypes.
func newRecordIndexes(sb *collections.SchemaBuilder) RecordsIndexes { func newRecordIndexes(sb *collections.SchemaBuilder) RecordsIndexes {
return RecordsIndexes{ return RecordsIndexes{
BondId: indexes.NewMulti( BondId: indexes.NewMulti(
sb, registrytypes.BondIdIndexPrefix, "records_by_bond_id", sb, registrytypes.RecordsByBondIdIndexPrefix, "records_by_bond_id",
collections.StringKey, collections.StringKey, collections.StringKey, collections.StringKey,
func(_ string, v registrytypes.Record) (string, error) { func(_ string, v registrytypes.Record) (string, error) {
return v.BondId, nil return v.BondId, nil
@ -49,6 +49,18 @@ func newRecordIndexes(sb *collections.SchemaBuilder) RecordsIndexes {
} }
} }
// TODO
type AuthoritiesIndexes struct {
}
func (b AuthoritiesIndexes) IndexesList() []collections.Index[string, registrytypes.NameAuthority] {
return []collections.Index[string, registrytypes.NameAuthority]{}
}
func newAuthorityIndexes(sb *collections.SchemaBuilder) AuthoritiesIndexes {
return AuthoritiesIndexes{}
}
type Keeper struct { type Keeper struct {
cdc codec.BinaryCodec cdc codec.BinaryCodec
@ -62,6 +74,7 @@ type Keeper struct {
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]
} }
// NewKeeper creates a new Keeper instance // NewKeeper creates a new Keeper instance
@ -83,7 +96,16 @@ func NewKeeper(
bondKeeper: bondKeeper, bondKeeper: bondKeeper,
auctionKeeper: auctionKeeper, auctionKeeper: auctionKeeper,
Params: collections.NewItem(sb, registrytypes.ParamsPrefix, "params", codec.CollValue[registrytypes.Params](cdc)), Params: collections.NewItem(sb, registrytypes.ParamsPrefix, "params", codec.CollValue[registrytypes.Params](cdc)),
Records: collections.NewIndexedMap(sb, registrytypes.RecordsPrefix, "records", collections.StringKey, codec.CollValue[registrytypes.Record](cdc), newRecordIndexes(sb)), Records: collections.NewIndexedMap(
sb, registrytypes.RecordsPrefix, "records",
collections.StringKey, codec.CollValue[registrytypes.Record](cdc),
newRecordIndexes(sb),
),
Authorities: collections.NewIndexedMap(
sb, registrytypes.AuthoritiesPrefix, "authorities",
collections.StringKey, codec.CollValue[registrytypes.NameAuthority](cdc),
newAuthorityIndexes(sb),
),
} }
schema, err := sb.Build() schema, err := sb.Build()

View File

@ -77,6 +77,7 @@ func (ms msgServer) SetName(c context.Context, msg *registrytypes.MsgSetName) (*
func (ms msgServer) ReserveName(c context.Context, msg *registrytypes.MsgReserveAuthority) (*registrytypes.MsgReserveAuthorityResponse, error) { func (ms msgServer) ReserveName(c context.Context, msg *registrytypes.MsgReserveAuthority) (*registrytypes.MsgReserveAuthorityResponse, error) {
ctx := sdk.UnwrapSDKContext(c) ctx := sdk.UnwrapSDKContext(c)
_, err := sdk.AccAddressFromBech32(msg.Signer) _, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil { if err != nil {
return nil, err return nil, err
@ -85,10 +86,12 @@ func (ms msgServer) ReserveName(c context.Context, msg *registrytypes.MsgReserve
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = ms.k.ProcessReserveAuthority(ctx, *msg)
err = ms.k.ReserveAuthority(ctx, *msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctx.EventManager().EmitEvents(sdk.Events{ ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent( sdk.NewEvent(
registrytypes.EventTypeReserveNameAuthority, registrytypes.EventTypeReserveNameAuthority,

View File

@ -1,14 +1,42 @@
package keeper package keeper
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" "errors"
"fmt"
"net/url"
"cosmossdk.io/collections"
errorsmod "cosmossdk.io/errors"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
auctiontypes "git.vdb.to/cerc-io/laconic2d/x/auction"
registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry"
"git.vdb.to/cerc-io/laconic2d/x/registry/helpers"
) )
// HasNameAuthority - checks if a name/authority exists.
func (k Keeper) HasNameAuthority(ctx sdk.Context, name string) (bool, error) {
has, err := k.Authorities.Has(ctx, name)
if err != nil {
return false, err
}
return has, nil
}
// GetNameAuthority - gets a name authority from the store. // GetNameAuthority - gets a name authority from the store.
func (k Keeper) GetNameAuthority(ctx sdk.Context, name string) registrytypes.NameAuthority { func (k Keeper) GetNameAuthority(ctx sdk.Context, name string) (registrytypes.NameAuthority, error) {
panic("unimplemented") authority, err := k.Authorities.Get(ctx, name)
if err != nil {
if errors.Is(err, collections.ErrNotFound) {
return registrytypes.NameAuthority{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.")
}
return registrytypes.NameAuthority{}, err
}
return authority, nil
} }
// HasNameRecord - checks if a name record exists. // HasNameRecord - checks if a name record exists.
@ -31,9 +59,125 @@ func (k Keeper) ProcessSetName(ctx sdk.Context, msg registrytypes.MsgSetName) er
panic("unimplemented") panic("unimplemented")
} }
// SaveNameAuthority creates the NameAuthority record.
func (k Keeper) SaveNameAuthority(ctx sdk.Context, name string, authority *registrytypes.NameAuthority) error {
return k.Authorities.Set(ctx, name, *authority)
// TODO
// updateBlockChangeSetForNameAuthority(ctx, codec, store, name)
}
// ProcessReserveAuthority reserves a name authority. // ProcessReserveAuthority reserves a name authority.
func (k Keeper) ProcessReserveAuthority(ctx sdk.Context, msg registrytypes.MsgReserveAuthority) error { func (k Keeper) ReserveAuthority(ctx sdk.Context, msg registrytypes.MsgReserveAuthority) error {
panic("unimplemented") 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")
}
// TODO
// 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) createAuthority(ctx sdk.Context, name string, owner string, isRoot bool) error {
moduleParams, err := k.GetParams(ctx)
if err != nil {
return err
}
has, err := k.HasNameAuthority(ctx, name)
if err != nil {
return err
}
if has {
authority, err := k.GetNameAuthority(ctx, name)
if err != nil {
return err
}
if authority.Status != registrytypes.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, "Owner account not found.")
}
authority := registrytypes.NameAuthority{
OwnerPublicKey: getAuthorityPubKey(ownerAccount.GetPubKey()),
OwnerAddress: owner,
Height: uint64(ctx.BlockHeight()),
Status: registrytypes.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 {
// TODO
// 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
}
// TODO
// Create auction ID -> authority name index.
// k.AddAuctionToAuthorityMapping(ctx, auction.Id, name)
authority.Status = registrytypes.AuthorityUnderAuction
authority.AuctionId = auction.Id
authority.ExpiryTime = auction.RevealsEndTime.Add(moduleParams.AuthorityGracePeriod)
}
// Save name authority in store.
if err = k.SaveNameAuthority(ctx, name, &authority); err != nil {
return err
}
// TODO
// k.InsertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime)
return nil
} }
func (k Keeper) ProcessSetAuthorityBond(ctx sdk.Context, msg registrytypes.MsgSetAuthorityBond) error { func (k Keeper) ProcessSetAuthorityBond(ctx sdk.Context, msg registrytypes.MsgSetAuthorityBond) error {
@ -53,3 +197,11 @@ func (k Keeper) GetAuthorityExpiryQueue(ctx sdk.Context) []*registrytypes.Expiry
func (k Keeper) ResolveCRN(ctx sdk.Context, crn string) *registrytypes.Record { func (k Keeper) ResolveCRN(ctx sdk.Context, crn string) *registrytypes.Record {
panic("unimplemented") panic("unimplemented")
} }
func getAuthorityPubKey(pubKey cryptotypes.PubKey) string {
if pubKey == nil {
return ""
}
return helpers.BytesToBase64(pubKey.Bytes())
}

View File

@ -104,7 +104,12 @@ func (qs queryServer) NameRecords(c context.Context, _ *registrytypes.QueryNameR
func (qs queryServer) Whois(c context.Context, request *registrytypes.QueryWhoisRequest) (*registrytypes.QueryWhoisResponse, error) { func (qs queryServer) Whois(c context.Context, request *registrytypes.QueryWhoisRequest) (*registrytypes.QueryWhoisResponse, error) {
ctx := sdk.UnwrapSDKContext(c) ctx := sdk.UnwrapSDKContext(c)
nameAuthority := qs.k.GetNameAuthority(ctx, request.GetName())
nameAuthority, err := qs.k.GetNameAuthority(ctx, request.GetName())
if err != nil {
return nil, err
}
return &registrytypes.QueryWhoisResponse{NameAuthority: nameAuthority}, nil return &registrytypes.QueryWhoisResponse{NameAuthority: nameAuthority}, nil
} }

View File

@ -19,5 +19,9 @@ var (
ParamsPrefix = collections.NewPrefix(0) ParamsPrefix = collections.NewPrefix(0)
RecordsPrefix = collections.NewPrefix(1) RecordsPrefix = collections.NewPrefix(1)
BondIdIndexPrefix = collections.NewPrefix(2) RecordsByBondIdIndexPrefix = collections.NewPrefix(2)
AuthoritiesPrefix = collections.NewPrefix(3)
AuthoritiesByAuctionIdIndexPrefix = collections.NewPrefix(4)
AuthoritiesByBondIdIndexPrefix = collections.NewPrefix(5)
) )

View File

@ -43,11 +43,29 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
{ProtoField: "id"}, {ProtoField: "id"},
}, },
}, },
{
RpcMethod: "Whois",
Use: "whois [name]",
Short: "Get name authority info",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "name"},
},
},
}, },
}, },
Tx: &autocliv1.ServiceCommandDescriptor{ Tx: &autocliv1.ServiceCommandDescriptor{
Service: registryv1.Msg_ServiceDesc.ServiceName, Service: registryv1.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{}, RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "ReserveName",
Use: "reserve-name [name] [owner]",
Short: "Reserve name",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "name"},
{ProtoField: "owner"},
},
},
},
EnhanceCustomCommand: true, // Allow additional manual commands EnhanceCustomCommand: true, // Allow additional manual commands
}, },
} }