Additional registry module commands #6
@ -61,6 +61,26 @@ func newAuthorityIndexes(sb *collections.SchemaBuilder) AuthoritiesIndexes {
|
||||
return AuthoritiesIndexes{}
|
||||
}
|
||||
|
||||
type NameRecordsIndexes struct {
|
||||
Cid *indexes.Multi[string, string, registrytypes.NameRecord]
|
||||
}
|
||||
|
||||
func (b NameRecordsIndexes) IndexesList() []collections.Index[string, registrytypes.NameRecord] {
|
||||
return []collections.Index[string, registrytypes.NameRecord]{b.Cid}
|
||||
}
|
||||
|
||||
func newNameRecordIndexes(sb *collections.SchemaBuilder) NameRecordsIndexes {
|
||||
return NameRecordsIndexes{
|
||||
Cid: indexes.NewMulti(
|
||||
sb, registrytypes.NameRecordsByCidIndexPrefix, "name_records_by_cid",
|
||||
collections.StringKey, collections.StringKey,
|
||||
func(_ string, v registrytypes.NameRecord) (string, error) {
|
||||
return v.Latest.Id, nil
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type Keeper struct {
|
||||
cdc codec.BinaryCodec
|
||||
|
||||
@ -75,6 +95,7 @@ type Keeper struct {
|
||||
Params collections.Item[registrytypes.Params]
|
||||
Records *collections.IndexedMap[string, registrytypes.Record, RecordsIndexes]
|
||||
Authorities *collections.IndexedMap[string, registrytypes.NameAuthority, AuthoritiesIndexes]
|
||||
NameRecords *collections.IndexedMap[string, registrytypes.NameRecord, NameRecordsIndexes]
|
||||
}
|
||||
|
||||
// NewKeeper creates a new Keeper instance
|
||||
@ -106,6 +127,11 @@ func NewKeeper(
|
||||
collections.StringKey, codec.CollValue[registrytypes.NameAuthority](cdc),
|
||||
newAuthorityIndexes(sb),
|
||||
),
|
||||
NameRecords: collections.NewIndexedMap(
|
||||
sb, registrytypes.NameRecordsPrefix, "name_records",
|
||||
collections.StringKey, codec.CollValue[registrytypes.NameRecord](cdc),
|
||||
newNameRecordIndexes(sb),
|
||||
),
|
||||
}
|
||||
|
||||
schema, err := sb.Build()
|
||||
|
@ -51,14 +51,17 @@ func (ms msgServer) SetRecord(c context.Context, msg *registrytypes.MsgSetRecord
|
||||
// nolint: all
|
||||
func (ms msgServer) SetName(c context.Context, msg *registrytypes.MsgSetName) (*registrytypes.MsgSetNameResponse, error) {
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
|
||||
_, err := sdk.AccAddressFromBech32(msg.Signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ms.k.ProcessSetName(ctx, *msg)
|
||||
|
||||
err = ms.k.SetName(ctx, *msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvents(sdk.Events{
|
||||
sdk.NewEvent(
|
||||
registrytypes.EventTypeSetRecord,
|
||||
|
@ -45,8 +45,40 @@ func (k Keeper) HasNameRecord(ctx sdk.Context, crn string) bool {
|
||||
}
|
||||
|
||||
// GetNameRecord - gets a name record from the store.
|
||||
func (k Keeper) GetNameRecord(ctx sdk.Context, crn string) *registrytypes.NameRecord {
|
||||
panic("unimplemented")
|
||||
func (k Keeper) GetNameRecord(ctx sdk.Context, crn string) (*registrytypes.NameRecord, error) {
|
||||
nameRecord, err := k.NameRecords.Get(ctx, crn)
|
||||
if err != nil {
|
||||
if errors.Is(err, collections.ErrNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &nameRecord, nil
|
||||
}
|
||||
|
||||
// LookupNameRecord - gets a name record which is not stale and under active authority.
|
||||
func (k Keeper) LookupNameRecord(ctx sdk.Context, crn string) (*registrytypes.NameRecord, error) {
|
||||
_, _, authority, err := k.getAuthority(ctx, crn)
|
||||
if err != nil || authority.Status != registrytypes.AuthorityActive {
|
||||
// If authority is not active (or any other error), lookup fails.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nameRecord, err := k.GetNameRecord(ctx, crn)
|
||||
|
||||
// Name record may not exist.
|
||||
if nameRecord == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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, nil
|
||||
}
|
||||
|
||||
return nameRecord, nil
|
||||
}
|
||||
|
||||
// ListNameRecords - get all name records.
|
||||
@ -54,9 +86,56 @@ func (k Keeper) ListNameRecords(ctx sdk.Context) []registrytypes.NameEntry {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// ProcessSetName creates a CRN -> Record ID mapping.
|
||||
func (k Keeper) ProcessSetName(ctx sdk.Context, msg registrytypes.MsgSetName) error {
|
||||
panic("unimplemented")
|
||||
// SaveNameRecord - sets a name record.
|
||||
func (k Keeper) SaveNameRecord(ctx sdk.Context, crn string, id string) error {
|
||||
var nameRecord registrytypes.NameRecord
|
||||
x, err := k.GetNameRecord(ctx, crn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if x != nil {
|
||||
nameRecord = *x
|
||||
nameRecord.History = append(nameRecord.History, nameRecord.Latest)
|
||||
}
|
||||
|
||||
nameRecord.Latest = ®istrytypes.NameRecordEntry{
|
||||
Id: id,
|
||||
Height: uint64(ctx.BlockHeight()),
|
||||
}
|
||||
|
||||
// TODO: Check if index gets updated on entry updates
|
||||
if err := k.NameRecords.Set(ctx, crn, nameRecord); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Update changeSet for name.
|
||||
// k.updateBlockChangeSetForName(ctx, crn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetName creates a CRN -> Record ID mapping.
|
||||
func (k Keeper) SetName(ctx sdk.Context, msg registrytypes.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, err := k.LookupNameRecord(ctx, msg.Crn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nameRecord != nil && nameRecord.Latest.Id == msg.Cid {
|
||||
return nil
|
||||
}
|
||||
|
||||
return k.SaveNameRecord(ctx, msg.Crn, msg.Cid)
|
||||
}
|
||||
|
||||
// SaveNameAuthority creates the NameAuthority record.
|
||||
@ -253,6 +332,68 @@ func (k Keeper) ResolveCRN(ctx sdk.Context, crn string) *registrytypes.Record {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (k Keeper) getAuthority(ctx sdk.Context, crn string) (string, *url.URL, *registrytypes.NameAuthority, error) {
|
||||
parsedCRN, err := url.Parse(crn)
|
||||
if err != nil {
|
||||
return "", nil, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.")
|
||||
}
|
||||
|
||||
name := parsedCRN.Host
|
||||
if has, err := k.HasNameAuthority(ctx, name); !has {
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
return "", nil, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.")
|
||||
}
|
||||
|
||||
authority, err := k.GetNameAuthority(ctx, name)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
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 != registrytypes.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)
|
||||
if err = k.SaveNameAuthority(ctx, name, authority); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAuthorityPubKey(pubKey cryptotypes.PubKey) string {
|
||||
if pubKey == nil {
|
||||
return ""
|
||||
|
@ -121,7 +121,7 @@ func (qs queryServer) LookupCrn(c context.Context, req *registrytypes.QueryLooku
|
||||
if !qs.k.HasNameRecord(ctx, crn) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "CRN not found.")
|
||||
}
|
||||
nameRecord := qs.k.GetNameRecord(ctx, crn)
|
||||
nameRecord, _ := qs.k.LookupNameRecord(ctx, crn)
|
||||
if nameRecord == nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "name record not found.")
|
||||
}
|
||||
|
@ -24,4 +24,7 @@ var (
|
||||
AuthoritiesPrefix = collections.NewPrefix(3)
|
||||
AuthoritiesByAuctionIdIndexPrefix = collections.NewPrefix(4)
|
||||
AuthoritiesByBondIdIndexPrefix = collections.NewPrefix(5)
|
||||
|
||||
NameRecordsPrefix = collections.NewPrefix(6)
|
||||
NameRecordsByCidIndexPrefix = collections.NewPrefix(7)
|
||||
)
|
||||
|
@ -80,6 +80,15 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
|
||||
{ProtoField: "bond_id"},
|
||||
},
|
||||
},
|
||||
{
|
||||
RpcMethod: "SetName",
|
||||
Use: "set-name [crn] [cid]",
|
||||
Short: "Set CRN to CID mapping",
|
||||
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
|
||||
{ProtoField: "crn"},
|
||||
{ProtoField: "cid"},
|
||||
},
|
||||
},
|
||||
},
|
||||
EnhanceCustomCommand: true, // Allow additional manual commands
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user