From f176a5889ee97ac15cce2d5641eaac9dc1a82a65 Mon Sep 17 00:00:00 2001 From: nabarun Date: Fri, 2 Aug 2024 09:15:08 +0000 Subject: [PATCH] Implement GQL query for listing authorities (#48) Part of [Create a public laconicd testnet](https://www.notion.so/Create-a-public-laconicd-testnet-896a11bdd8094eff8f1b49c0be0ca3b8) Co-authored-by: IshaVenikar Reviewed-on: https://git.vdb.to/cerc-io/laconicd/pulls/48 --- gql/cerc-io/laconicd/schema.graphql | 8 + gql/generated.go | 323 ++++++++++++++++++++++++++++ gql/models_gen.go | 5 + gql/resolver.go | 50 +++-- gql/util.go | 27 +++ 5 files changed, 394 insertions(+), 19 deletions(-) diff --git a/gql/cerc-io/laconicd/schema.graphql b/gql/cerc-io/laconicd/schema.graphql index d0f4f340..c3fac8f6 100644 --- a/gql/cerc-io/laconicd/schema.graphql +++ b/gql/cerc-io/laconicd/schema.graphql @@ -197,6 +197,11 @@ type AuthorityRecord { auction: Auction # Authority auction. } +type Authority { + name: String! + entry: AuthorityRecord! +} + # Name record entry, created at a particular height. type NameRecordEntry { id: String! # Target record ID. @@ -247,6 +252,9 @@ type Query { # Naming API. # + # Get authorities list. + getAuthorities(owner: String): [Authority] + # Lookup authority information. lookupAuthorities(names: [String!]): [AuthorityRecord]! diff --git a/gql/generated.go b/gql/generated.go index 07f3c369..a243f6df 100644 --- a/gql/generated.go +++ b/gql/generated.go @@ -87,6 +87,11 @@ type ComplexityRoot struct { Status func(childComplexity int) int } + Authority struct { + Entry func(childComplexity int) int + Name func(childComplexity int) int + } + AuthorityRecord struct { Auction func(childComplexity int) int BondID func(childComplexity int) int @@ -169,6 +174,7 @@ type ComplexityRoot struct { Query struct { GetAccounts func(childComplexity int, addresses []string) int GetAuctionsByIds func(childComplexity int, ids []string) int + GetAuthorities func(childComplexity int, owner *string) int GetBondsByIds func(childComplexity int, ids []string) int GetParticipantByAddress func(childComplexity int, address string) int GetParticipantByNitroAddress func(childComplexity int, nitroAddress string) int @@ -231,6 +237,7 @@ type QueryResolver interface { QueryBondsByOwner(ctx context.Context, ownerAddresses []string) ([]*OwnerBonds, error) GetRecordsByIds(ctx context.Context, ids []string) ([]*Record, error) QueryRecords(ctx context.Context, attributes []*KeyValueInput, all *bool) ([]*Record, error) + GetAuthorities(ctx context.Context, owner *string) ([]*Authority, error) LookupAuthorities(ctx context.Context, names []string) ([]*AuthorityRecord, error) LookupNames(ctx context.Context, names []string) ([]*NameRecord, error) ResolveNames(ctx context.Context, names []string) ([]*Record, error) @@ -458,6 +465,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.AuctionBid.Status(childComplexity), true + case "Authority.entry": + if e.complexity.Authority.Entry == nil { + break + } + + return e.complexity.Authority.Entry(childComplexity), true + + case "Authority.name": + if e.complexity.Authority.Name == nil { + break + } + + return e.complexity.Authority.Name(childComplexity), true + case "AuthorityRecord.auction": if e.complexity.AuthorityRecord.Auction == nil { break @@ -720,6 +741,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.GetAuctionsByIds(childComplexity, args["ids"].([]string)), true + case "Query.getAuthorities": + if e.complexity.Query.GetAuthorities == nil { + break + } + + args, err := ec.field_Query_getAuthorities_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.GetAuthorities(childComplexity, args["owner"].(*string)), true + case "Query.getBondsByIds": if e.complexity.Query.GetBondsByIds == nil { break @@ -1141,6 +1174,21 @@ func (ec *executionContext) field_Query_getAuctionsByIds_args(ctx context.Contex return args, nil } +func (ec *executionContext) field_Query_getAuthorities_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["owner"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("owner")) + arg0, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["owner"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_getBondsByIds_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -2674,6 +2722,110 @@ func (ec *executionContext) fieldContext_AuctionBid_bidAmount(ctx context.Contex return fc, nil } +func (ec *executionContext) _Authority_name(ctx context.Context, field graphql.CollectedField, obj *Authority) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Authority_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Authority_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Authority", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Authority_entry(ctx context.Context, field graphql.CollectedField, obj *Authority) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Authority_entry(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Entry, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*AuthorityRecord) + fc.Result = res + return ec.marshalNAuthorityRecord2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthorityRecord(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Authority_entry(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Authority", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "ownerAddress": + return ec.fieldContext_AuthorityRecord_ownerAddress(ctx, field) + case "ownerPublicKey": + return ec.fieldContext_AuthorityRecord_ownerPublicKey(ctx, field) + case "height": + return ec.fieldContext_AuthorityRecord_height(ctx, field) + case "status": + return ec.fieldContext_AuthorityRecord_status(ctx, field) + case "bondId": + return ec.fieldContext_AuthorityRecord_bondId(ctx, field) + case "expiryTime": + return ec.fieldContext_AuthorityRecord_expiryTime(ctx, field) + case "auction": + return ec.fieldContext_AuthorityRecord_auction(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type AuthorityRecord", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _AuthorityRecord_ownerAddress(ctx context.Context, field graphql.CollectedField, obj *AuthorityRecord) (ret graphql.Marshaler) { fc, err := ec.fieldContext_AuthorityRecord_ownerAddress(ctx, field) if err != nil { @@ -4670,6 +4822,64 @@ func (ec *executionContext) fieldContext_Query_queryRecords(ctx context.Context, return fc, nil } +func (ec *executionContext) _Query_getAuthorities(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_getAuthorities(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().GetAuthorities(rctx, fc.Args["owner"].(*string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*Authority) + fc.Result = res + return ec.marshalOAuthority2ᚕᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthority(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_getAuthorities(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext_Authority_name(ctx, field) + case "entry": + return ec.fieldContext_Authority_entry(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Authority", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_getAuthorities_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return + } + return fc, nil +} + func (ec *executionContext) _Query_lookupAuthorities(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_lookupAuthorities(ctx, field) if err != nil { @@ -8623,6 +8833,41 @@ func (ec *executionContext) _AuctionBid(ctx context.Context, sel ast.SelectionSe return out } +var authorityImplementors = []string{"Authority"} + +func (ec *executionContext) _Authority(ctx context.Context, sel ast.SelectionSet, obj *Authority) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, authorityImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Authority") + case "name": + + out.Values[i] = ec._Authority_name(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "entry": + + out.Values[i] = ec._Authority_entry(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var authorityRecordImplementors = []string{"AuthorityRecord"} func (ec *executionContext) _AuthorityRecord(ctx context.Context, sel ast.SelectionSet, obj *AuthorityRecord) graphql.Marshaler { @@ -9323,6 +9568,26 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) } + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) + }) + case "getAuthorities": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_getAuthorities(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + out.Concurrently(i, func() graphql.Marshaler { return rrm(innerCtx) }) @@ -10169,6 +10434,16 @@ func (ec *executionContext) marshalNAuthorityRecord2ᚕᚖgitᚗvdbᚗtoᚋcerc return ret } +func (ec *executionContext) marshalNAuthorityRecord2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthorityRecord(ctx context.Context, sel ast.SelectionSet, v *AuthorityRecord) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._AuthorityRecord(ctx, sel, v) +} + func (ec *executionContext) marshalNBond2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐBond(ctx context.Context, sel ast.SelectionSet, v *Bond) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -10956,6 +11231,54 @@ func (ec *executionContext) marshalOAuctionBid2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋl return ec._AuctionBid(ctx, sel, v) } +func (ec *executionContext) marshalOAuthority2ᚕᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthority(ctx context.Context, sel ast.SelectionSet, v []*Authority) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOAuthority2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthority(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + return ret +} + +func (ec *executionContext) marshalOAuthority2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthority(ctx context.Context, sel ast.SelectionSet, v *Authority) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Authority(ctx, sel, v) +} + func (ec *executionContext) marshalOAuthorityRecord2ᚖgitᚗvdbᚗtoᚋcercᚑioᚋlaconicdᚋgqlᚐAuthorityRecord(ctx context.Context, sel ast.SelectionSet, v *AuthorityRecord) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/gql/models_gen.go b/gql/models_gen.go index 460e8233..9fe30448 100644 --- a/gql/models_gen.go +++ b/gql/models_gen.go @@ -52,6 +52,11 @@ type AuctionBid struct { BidAmount *Coin `json:"bidAmount"` } +type Authority struct { + Name string `json:"name"` + Entry *AuthorityRecord `json:"entry"` +} + type AuthorityRecord struct { OwnerAddress string `json:"ownerAddress"` OwnerPublicKey string `json:"ownerPublicKey"` diff --git a/gql/resolver.go b/gql/resolver.go index dd2b42f4..76f3571f 100644 --- a/gql/resolver.go +++ b/gql/resolver.go @@ -35,6 +35,36 @@ func (r *Resolver) Query() QueryResolver { type queryResolver struct{ *Resolver } +func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Authority, error) { + nsQueryClient := registrytypes.NewQueryClient(q.ctx) + auctionQueryClient := auctiontypes.NewQueryClient(q.ctx) + + authoritiesReq := ®istrytypes.QueryAuthoritiesRequest{} + if owner != nil { + authoritiesReq.Owner = *owner + } + + authoritiesResp, err := nsQueryClient.Authorities(ctx, authoritiesReq) + if err != nil { + return nil, err + } + + authorities := make([]*Authority, len(authoritiesResp.GetAuthorities())) + for i, a := range authoritiesResp.Authorities { + entry, err := getAuthorityRecord(*a.Entry, auctionQueryClient) + if err != nil { + return nil, err + } + + authorities[i] = &Authority{ + Name: a.Name, + Entry: entry, + } + } + + return authorities, nil +} + func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([]*AuthorityRecord, error) { nsQueryClient := registrytypes.NewQueryClient(q.ctx) auctionQueryClient := auctiontypes.NewQueryClient(q.ctx) @@ -52,29 +82,11 @@ func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([ } nameAuthority := res.GetNameAuthority() - gqlNameAuthorityRecord, err := GetGQLNameAuthorityRecord(&nameAuthority) + gqlNameAuthorityRecord, err := getAuthorityRecord(nameAuthority, auctionQueryClient) if err != nil { return nil, err } - if nameAuthority.AuctionId != "" { - auctionResp, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.QueryGetAuctionRequest{Id: nameAuthority.GetAuctionId()}) - if err != nil { - return nil, err - } - bidsResp, err := auctionQueryClient.GetBids(context.Background(), &auctiontypes.QueryGetBidsRequest{AuctionId: nameAuthority.GetAuctionId()}) - if err != nil { - return nil, err - } - - gqlAuctionRecord, err := GetGQLAuction(auctionResp.GetAuction(), bidsResp.GetBids()) - if err != nil { - return nil, err - } - - gqlNameAuthorityRecord.Auction = gqlAuctionRecord - } - gqlResponse = append(gqlResponse, gqlNameAuthorityRecord) } diff --git a/gql/util.go b/gql/util.go index 40bbf9c0..b978264f 100644 --- a/gql/util.go +++ b/gql/util.go @@ -303,3 +303,30 @@ func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryRecordsReques return kvPairs } + +func getAuthorityRecord(nameAuthority registrytypes.NameAuthority, auctionQueryClient auctiontypes.QueryClient) (*AuthorityRecord, error) { + gqlNameAuthorityRecord, err := GetGQLNameAuthorityRecord(&nameAuthority) + if err != nil { + return nil, err + } + + if nameAuthority.AuctionId != "" { + auctionResp, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.QueryGetAuctionRequest{Id: nameAuthority.GetAuctionId()}) + if err != nil { + return nil, err + } + bidsResp, err := auctionQueryClient.GetBids(context.Background(), &auctiontypes.QueryGetBidsRequest{AuctionId: nameAuthority.GetAuctionId()}) + if err != nil { + return nil, err + } + + gqlAuctionRecord, err := GetGQLAuction(auctionResp.GetAuction(), bidsResp.GetBids()) + if err != nil { + return nil, err + } + + gqlNameAuthorityRecord.Auction = gqlAuctionRecord + } + + return gqlNameAuthorityRecord, nil +}