diff --git a/x/nameservice/keeper/grpc_query.go b/x/nameservice/keeper/grpc_query.go index 1586ffa5..78fdfbae 100644 --- a/x/nameservice/keeper/grpc_query.go +++ b/x/nameservice/keeper/grpc_query.go @@ -30,12 +30,13 @@ func (q Querier) ListRecords(c context.Context, req *types.QueryListRecordsReque ctx := sdk.UnwrapSDKContext(c) attributes := req.GetAttributes() all := req.GetAll() - records := []types.Record{} - + var records []types.Record if len(attributes) > 0 { - records = q.Keeper.MatchRecords(ctx, func(record *types.RecordType) bool { - return MatchOnAttributes(record, attributes, all) - }) + var err error + records, err = q.Keeper.RecordsFromAttributes(ctx, attributes, all) + if err != nil { + return nil, err + } } else { records = q.Keeper.ListRecords(ctx) } @@ -113,115 +114,3 @@ func (q Querier) GetAuthorityExpiryQueue(c context.Context, _ *types.QueryGetAut authorities := q.Keeper.GetAuthorityExpiryQueue(ctx) return &types.QueryGetAuthorityExpiryQueueResponse{Authorities: authorities}, nil } - -func matchOnRecordField(record *types.RecordType, attr *types.QueryListRecordsRequest_KeyValueInput) (fieldFound bool, matched bool) { - fieldFound = false - matched = true - - switch attr.Key { - case BondIDAttributeName: - { - fieldFound = true - if record.BondId != attr.Value.GetString_() { - matched = false - return - } - } - case ExpiryTimeAttributeName: - { - fieldFound = true - if record.ExpiryTime != attr.Value.GetString_() { - matched = false - return - } - } - } - - return -} - -func MatchOnAttributes(record *types.RecordType, attributes []*types.QueryListRecordsRequest_KeyValueInput, all bool) bool { - // Filter deleted records. - if record.Deleted { - return false - } - - // If ONLY named records are requested, check for that condition first. - if !all && len(record.Names) == 0 { - return false - } - - recAttrs := record.Attributes - - for _, attr := range attributes { - // First try matching on record struct fields. - fieldFound, matched := matchOnRecordField(record, attr) - - if fieldFound { - if !matched { - return false - } - - continue - } - - recAttrVal, recAttrFound := recAttrs[attr.Key] - if !recAttrFound { - return false - } - - if attr.Value.Type == "int" { - recAttrValInt, ok := recAttrVal.(int) - if !ok || int(attr.Value.GetInt()) != recAttrValInt { - return false - } - } - - if attr.Value.Type == "float" { - recAttrValFloat, ok := recAttrVal.(float64) - if !ok || attr.Value.GetFloat() != recAttrValFloat { - return false - } - } - - if attr.Value.Type == "string" { - recAttrValString, ok := recAttrVal.(string) - if !ok { - return false - } - - if attr.Value.GetString_() != recAttrValString { - return false - } - } - - if attr.Value.Type == "boolean" { - recAttrValBool, ok := recAttrVal.(bool) - if !ok || attr.Value.GetBoolean() != recAttrValBool { - return false - } - } - - if attr.Value.Type == "reference" { - obj, ok := recAttrVal.(map[string]interface{}) - if !ok { - // Attr value is not an object. - return false - } - - if _, ok := obj["/"].(string); !ok { - // Attr value is not a reference. - return false - } - - recAttrValRefID := obj["/"].(string) - if recAttrValRefID != attr.Value.GetReference().GetId() { - return false - } - } - - // TODO: Handle arrays. - } - - return true -} diff --git a/x/nameservice/keeper/keeper.go b/x/nameservice/keeper/keeper.go index f689a690..7f2925e7 100644 --- a/x/nameservice/keeper/keeper.go +++ b/x/nameservice/keeper/keeper.go @@ -131,29 +131,61 @@ func (k Keeper) ListRecords(ctx sdk.Context) []types.Record { return records } -// MatchRecords - get all matching records. -func (k Keeper) MatchRecords(ctx sdk.Context, matchFn func(*types.RecordType) bool) []types.Record { - var records []types.Record - - store := ctx.KVStore(k.storeKey) - itr := sdk.KVStorePrefixIterator(store, PrefixCIDToRecordIndex) - defer itr.Close() - for ; itr.Valid(); itr.Next() { - bz := store.Get(itr.Key()) - if bz != nil { - var obj types.Record - k.cdc.MustUnmarshal(bz, &obj) - obj = recordObjToRecord(store, k.cdc, obj) - record := obj.ToRecordType() - if matchFn(&record) { - records = append(records, obj) - } +func (k Keeper) RecordsFromAttributes(ctx sdk.Context, attributes []*types.QueryListRecordsRequest_KeyValueInput, all bool) ([]types.Record, error) { + resultRecordIds := []string{} + for i, attr := range attributes { + attributeIndex := GetAttributesIndexKey(attr.Key, attr.Value) + recordIds, err := k.GetAttributeMapping(ctx, attributeIndex) + if err != nil { + return nil, err + } + if i == 0 { + resultRecordIds = recordIds + } else { + resultRecordIds = getIntersection(recordIds, resultRecordIds) } } - return records + records := []types.Record{} + for _, id := range resultRecordIds { + record := k.GetRecord(ctx, id) + if record.Deleted { + continue + } + if !all && len(record.Names) == 0 { + continue + } + records = append(records, record) + } + return records, nil } +func getIntersection(a []string, b []string) []string { + result := []string{} + if len(a) < len(b) { + for _, str := range a { + if contains(b, str) { + result = append(result, str) + } + } + } else { + for _, str := range b { + if contains(a, str) { + result = append(result, str) + } + } + } + return result +} + +func contains(arr []string, str string) bool { + for _, s := range arr { + if s == str { + return true + } + } + return false +} func (k Keeper) GetRecordExpiryQueue(ctx sdk.Context) []*types.ExpiryQueueRecord { var records []*types.ExpiryQueueRecord @@ -292,6 +324,9 @@ func (k Keeper) ProcessAttributes(ctx sdk.Context, record types.RecordType) erro return fmt.Errorf("unsupported record type %s", record.Attributes["type"]) } + expiryTimeKey := GetAttributesIndexKey(ExpiryTimeAttributeName, record.ExpiryTime) + k.SetAttributeMapping(ctx, expiryTimeKey, record.Id) + return nil } @@ -320,6 +355,22 @@ func (k Keeper) SetAttributeMapping(ctx sdk.Context, key []byte, recordId string return nil } +func (k Keeper) GetAttributeMapping(ctx sdk.Context, key []byte) ([]string, error) { + store := ctx.KVStore(k.storeKey) + + if !store.Has(key) { + return nil, fmt.Errorf("store doesn't have key") + } + + var recordIds []string + if err := json.Unmarshal(store.Get(key), &recordIds); err != nil { + return nil, fmt.Errorf("cannont unmarshal byte array, error, %w", err) + } + + return recordIds, nil + +} + // AddBondToRecordIndexEntry adds the Bond ID -> [Record] index entry. func (k Keeper) AddBondToRecordIndexEntry(ctx sdk.Context, bondID string, id string) { store := ctx.KVStore(k.storeKey) diff --git a/x/nameservice/keeper/msg_server.go b/x/nameservice/keeper/msg_server.go index 3bef7bbe..f45e2966 100644 --- a/x/nameservice/keeper/msg_server.go +++ b/x/nameservice/keeper/msg_server.go @@ -161,6 +161,9 @@ func (m msgServer) DeleteName(c context.Context, msg *types.MsgDeleteNameAuthori func (m msgServer) RenewRecord(c context.Context, msg *types.MsgRenewRecord) (*types.MsgRenewRecordResponse, error) { ctx := sdk.UnwrapSDKContext(c) _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return nil, err + } err = m.Keeper.ProcessRenewRecord(ctx, *msg) if err != nil { return nil, err @@ -264,6 +267,9 @@ func (m msgServer) ReAssociateRecords(c context.Context, msg *types.MsgReAssocia return nil, err } err = m.Keeper.ProcessReAssociateRecords(ctx, *msg) + if err != nil { + return nil, err + } ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeReAssociateRecords, diff --git a/x/nameservice/keeper/naming_keeper.go b/x/nameservice/keeper/naming_keeper.go index 4ab6e16e..bfdc9790 100644 --- a/x/nameservice/keeper/naming_keeper.go +++ b/x/nameservice/keeper/naming_keeper.go @@ -651,7 +651,6 @@ func (k Keeper) GetAllExpiredAuthorities(ctx sdk.Context, currTime time.Time) (e defer itr.Close() for ; itr.Valid(); itr.Next() { - timeslice := []string{} timeslice, err := helpers.BytesArrToStringArr(itr.Value()) if err != nil {