[wip] gql server fixes

run gql server

gql cleanup
This commit is contained in:
Roy Crihfield 2024-12-28 16:05:51 +08:00
parent c48710ab82
commit f0f96bc28e
13 changed files with 642 additions and 277 deletions

View File

@ -34,6 +34,7 @@ import (
genutilv2cli "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli" genutilv2cli "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli"
"git.vdb.to/cerc-io/laconicd/app" "git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/gql"
"git.vdb.to/cerc-io/laconicd/nitro" "git.vdb.to/cerc-io/laconicd/nitro"
// "git.vdb.to/cerc-io/laconicd/x/nitrobank" // "git.vdb.to/cerc-io/laconicd/x/nitrobank"
) )
@ -90,6 +91,7 @@ func InitRootCmd[T app.Tx](
&telemetry.Server[T]{}, &telemetry.Server[T]{},
&rest.Server[T]{}, &rest.Server[T]{},
&nitro.Server{}, &nitro.Server{},
&gql.Server{},
) )
} }
@ -152,6 +154,11 @@ func InitRootCmd[T app.Tx](
return nil, err return nil, err
} }
gqlServer, err := gql.New(logger, deps.GlobalConfig, deps.ClientContext)
if err != nil {
return nil, err
}
// wire server commands // wire server commands
return serverv2.AddCommands[T]( return serverv2.AddCommands[T](
rootCmd, rootCmd,
@ -165,6 +172,7 @@ func InitRootCmd[T app.Tx](
telemetryServer, telemetryServer,
restServer, restServer,
nitroServer, nitroServer,
gqlServer,
) )
} }

View File

@ -29,7 +29,7 @@ On having some change in the GQL schema (for example: adding a new query) update
## Start server ## Start server
```shell ```shell
laconicd start --gql-playground --gql-server laconicd start --gql.playground --gql.server
``` ```
Basic node status: Basic node status:

19
gql/config.go Normal file
View File

@ -0,0 +1,19 @@
package gql
func DefaultConfig() *Config {
return &Config{
Enable: false,
Playground: false,
PlaygroundAPIBase: "",
Port: 9473,
// LogFile: "",
}
}
type Config struct {
Enable bool `mapstructure:"enable" toml:"enable" comment:"Enable the GraphQL server."`
Playground bool `mapstructure:"playground" toml:"playground" comment:"Enable the GraphQL playground."`
PlaygroundAPIBase string `mapstructure:"playground-api-base" toml:"playground-api-base" comment:"GraphQL API base path to use in the playground."`
Port uint `mapstructure:"port" toml:"port" comment:"Port to use for the GraphQL server."`
// LogFile string `mapstructure:"log-file" toml:"log-file" comment:"File to tail for the 'getLogs' API."`
}

View File

@ -1,15 +1,24 @@
package gql package gql
import "github.com/spf13/cobra" import "github.com/spf13/pflag"
// AddGQLFlags adds gql flags for var (
func AddGQLFlags(cmd *cobra.Command) *cobra.Command { FlagEnable = prefix("enable")
// Add flags for GQL server. FlagPlayground = prefix("playground")
cmd.PersistentFlags().Bool("gql-server", false, "Start GQL server.") FlagPlaygroundAPIBase = prefix("playground-api-base")
cmd.PersistentFlags().Bool("gql-playground", false, "Enable GQL playground.") FlagPort = prefix("port")
cmd.PersistentFlags().String("gql-playground-api-base", "", "GQL API base path to use in GQL playground.") //FlagLogFile = prefix("log-file")
cmd.PersistentFlags().String("gql-port", "9473", "Port to use for the GQL server.") )
cmd.PersistentFlags().String("log-file", "", "File to tail for GQL 'getLogs' API.")
return cmd // AddGQLFlags adds flags for the GraphQL server.
func AddGQLFlags(flags *pflag.FlagSet) {
flags.Bool(FlagEnable, false, "Enable the GraphQL server")
flags.Bool(FlagPlayground, false, "Enable the GraphQL playground")
flags.String(FlagPlaygroundAPIBase, "", "GraphQL API base path to use in the playground")
flags.String(FlagPort, "9473", "Port to use for the GraphQL server.")
// cmd.PersistentFlags().String(FlagLogFile, "", "File to tail for GraphQL 'getLogs' API")
}
func prefix(f string) string {
return ServerName + "." + f
} }

View File

@ -4,9 +4,9 @@
schema: schema:
- cerc-io/laconicd/*.graphql - cerc-io/laconicd/*.graphql
exec: exec:
filename: generated.go filename: schema/generated.go
model: model:
filename: models_gen.go filename: schema/models_gen.go
resolver: resolver:
filename: resolver.go filename: resolver.go
type: Resolver type: Resolver
@ -14,4 +14,4 @@ resolver:
models: models:
Link: Link:
model: model:
- git.vdb.to/cerc-io/laconicd/gql.Link - git.vdb.to/cerc-io/laconicd/gql/schema.Link

View File

@ -6,12 +6,13 @@ import (
"strconv" "strconv"
"strings" "strings"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/types/query"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "cosmossdk.io/x/bank/types"
"git.vdb.to/cerc-io/laconicd/gql/schema"
auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction" auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond" bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
onboardingTypes "git.vdb.to/cerc-io/laconicd/x/onboarding" onboardingTypes "git.vdb.to/cerc-io/laconicd/x/onboarding"
@ -33,13 +34,13 @@ type Resolver struct {
} }
// Query is the entry point to query execution. // Query is the entry point to query execution.
func (r *Resolver) Query() QueryResolver { func (r *Resolver) Query() schema.QueryResolver {
return &queryResolver{r} return &queryResolver{r}
} }
type queryResolver struct{ *Resolver } type queryResolver struct{ *Resolver }
func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Authority, error) { func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*schema.Authority, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx) nsQueryClient := registrytypes.NewQueryClient(q.ctx)
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx) auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
@ -53,14 +54,14 @@ func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Au
return nil, err return nil, err
} }
authorities := make([]*Authority, len(authoritiesResp.GetAuthorities())) authorities := make([]*schema.Authority, len(authoritiesResp.GetAuthorities()))
for i, a := range authoritiesResp.Authorities { for i, a := range authoritiesResp.Authorities {
entry, err := getAuthorityRecord(*a.Entry, auctionQueryClient) entry, err := getAuthorityRecord(*a.Entry, auctionQueryClient)
if err != nil { if err != nil {
return nil, err return nil, err
} }
authorities[i] = &Authority{ authorities[i] = &schema.Authority{
Name: a.Name, Name: a.Name,
Entry: entry, Entry: entry,
} }
@ -69,10 +70,10 @@ func (q queryResolver) GetAuthorities(ctx context.Context, owner *string) ([]*Au
return authorities, nil return authorities, nil
} }
func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([]*AuthorityRecord, error) { func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([]*schema.AuthorityRecord, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx) nsQueryClient := registrytypes.NewQueryClient(q.ctx)
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx) auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
gqlResponse := []*AuthorityRecord{} gqlResponse := []*schema.AuthorityRecord{}
for _, name := range names { for _, name := range names {
res, err := nsQueryClient.Whois(context.Background(), &registrytypes.QueryWhoisRequest{Name: name}) res, err := nsQueryClient.Whois(context.Background(), &registrytypes.QueryWhoisRequest{Name: name})
@ -97,9 +98,9 @@ func (q queryResolver) LookupAuthorities(ctx context.Context, names []string) ([
return gqlResponse, nil return gqlResponse, nil
} }
func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*Record, error) { func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*schema.Record, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx) nsQueryClient := registrytypes.NewQueryClient(q.ctx)
var gqlResponse []*Record var gqlResponse []*schema.Record
for _, name := range names { for _, name := range names {
res, err := nsQueryClient.ResolveLrn(context.Background(), &registrytypes.QueryResolveLrnRequest{Lrn: name}) res, err := nsQueryClient.ResolveLrn(context.Background(), &registrytypes.QueryResolveLrnRequest{Lrn: name})
if err != nil { if err != nil {
@ -118,9 +119,9 @@ func (q queryResolver) ResolveNames(ctx context.Context, names []string) ([]*Rec
return gqlResponse, nil return gqlResponse, nil
} }
func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*NameRecord, error) { func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*schema.NameRecord, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx) nsQueryClient := registrytypes.NewQueryClient(q.ctx)
var gqlResponse []*NameRecord var gqlResponse []*schema.NameRecord
for _, name := range names { for _, name := range names {
res, err := nsQueryClient.LookupLrn(context.Background(), &registrytypes.QueryLookupLrnRequest{Lrn: name}) res, err := nsQueryClient.LookupLrn(context.Background(), &registrytypes.QueryLookupLrnRequest{Lrn: name})
@ -140,7 +141,7 @@ func (q queryResolver) LookupNames(ctx context.Context, names []string) ([]*Name
return gqlResponse, nil return gqlResponse, nil
} }
func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueInput, all *bool, limit *int, offset *int) ([]*Record, error) { func (q queryResolver) QueryRecords(ctx context.Context, attributes []*schema.KeyValueInput, all *bool, limit *int, offset *int) ([]*schema.Record, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx) nsQueryClient := registrytypes.NewQueryClient(q.ctx)
var pagination *query.PageRequest var pagination *query.PageRequest
@ -175,7 +176,7 @@ func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueI
} }
records := res.GetRecords() records := res.GetRecords()
gqlResponse := make([]*Record, len(records)) gqlResponse := make([]*schema.Record, len(records))
for i, record := range records { for i, record := range records {
gqlRecord, err := getGQLRecord(context.Background(), q, record) gqlRecord, err := getGQLRecord(context.Background(), q, record)
@ -188,9 +189,9 @@ func (q queryResolver) QueryRecords(ctx context.Context, attributes []*KeyValueI
return gqlResponse, nil return gqlResponse, nil
} }
func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*Record, error) { func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*schema.Record, error) {
nsQueryClient := registrytypes.NewQueryClient(q.ctx) nsQueryClient := registrytypes.NewQueryClient(q.ctx)
gqlResponse := make([]*Record, len(ids)) gqlResponse := make([]*schema.Record, len(ids))
for i, id := range ids { for i, id := range ids {
res, err := nsQueryClient.GetRecord(context.Background(), &registrytypes.QueryGetRecordRequest{Id: id}) res, err := nsQueryClient.GetRecord(context.Background(), &registrytypes.QueryGetRecordRequest{Id: id})
@ -209,7 +210,7 @@ func (q queryResolver) GetRecordsByIds(ctx context.Context, ids []string) ([]*Re
return gqlResponse, nil return gqlResponse, nil
} }
func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) { func (q queryResolver) GetStatus(ctx context.Context) (*schema.Status, error) {
nodeInfo, syncInfo, validatorInfo, err := getStatusInfo(q.ctx) nodeInfo, syncInfo, validatorInfo, err := getStatusInfo(q.ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -230,7 +231,7 @@ func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) {
return nil, err return nil, err
} }
return &Status{ return &schema.Status{
Version: RegistryVersion, Version: RegistryVersion,
Node: nodeInfo, Node: nodeInfo,
Sync: syncInfo, Sync: syncInfo,
@ -242,8 +243,8 @@ func (q queryResolver) GetStatus(ctx context.Context) (*Status, error) {
}, nil }, nil
} }
func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*Account, error) { func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*schema.Account, error) {
accounts := make([]*Account, len(addresses)) accounts := make([]*schema.Account, len(addresses))
for index, address := range addresses { for index, address := range addresses {
account, err := q.GetAccount(ctx, address) account, err := q.GetAccount(ctx, address)
if err != nil { if err != nil {
@ -254,7 +255,7 @@ func (q queryResolver) GetAccounts(ctx context.Context, addresses []string) ([]*
return accounts, nil return accounts, nil
} }
func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account, error) { func (q queryResolver) GetAccount(ctx context.Context, address string) (*schema.Account, error) {
authQueryClient := authtypes.NewQueryClient(q.ctx) authQueryClient := authtypes.NewQueryClient(q.ctx)
accountResponse, err := authQueryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: address}) accountResponse, err := authQueryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: address})
if err != nil { if err != nil {
@ -280,7 +281,7 @@ func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account
accNum := strconv.FormatUint(account.GetAccountNumber(), 10) accNum := strconv.FormatUint(account.GetAccountNumber(), 10)
seq := strconv.FormatUint(account.GetSequence(), 10) seq := strconv.FormatUint(account.GetSequence(), 10)
return &Account{ return &schema.Account{
Address: address, Address: address,
Number: accNum, Number: accNum,
Sequence: seq, Sequence: seq,
@ -289,8 +290,8 @@ func (q queryResolver) GetAccount(ctx context.Context, address string) (*Account
}, nil }, nil
} }
func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*Bond, error) { func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*schema.Bond, error) {
bonds := make([]*Bond, len(ids)) bonds := make([]*schema.Bond, len(ids))
for index, id := range ids { for index, id := range ids {
bondObj, err := q.GetBond(ctx, id) bondObj, err := q.GetBond(ctx, id)
if err != nil { if err != nil {
@ -302,7 +303,7 @@ func (q queryResolver) GetBondsByIds(ctx context.Context, ids []string) ([]*Bond
return bonds, nil return bonds, nil
} }
func (q *queryResolver) GetBond(ctx context.Context, id string) (*Bond, error) { func (q *queryResolver) GetBond(ctx context.Context, id string) (*schema.Bond, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx) bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bondResp, err := bondQueryClient.GetBondById(context.Background(), &bondtypes.QueryGetBondByIdRequest{Id: id}) bondResp, err := bondQueryClient.GetBondById(context.Background(), &bondtypes.QueryGetBondByIdRequest{Id: id})
if err != nil { if err != nil {
@ -320,14 +321,14 @@ func (q *queryResolver) GetBond(ctx context.Context, id string) (*Bond, error) {
return getGQLBond(bondResp.GetBond()) return getGQLBond(bondResp.GetBond())
} }
func (q queryResolver) QueryBonds(ctx context.Context) ([]*Bond, error) { func (q queryResolver) QueryBonds(ctx context.Context) ([]*schema.Bond, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx) bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bonds, err := bondQueryClient.Bonds(context.Background(), &bondtypes.QueryBondsRequest{}) bonds, err := bondQueryClient.Bonds(context.Background(), &bondtypes.QueryBondsRequest{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
gqlResponse := make([]*Bond, len(bonds.GetBonds())) gqlResponse := make([]*schema.Bond, len(bonds.GetBonds()))
for i, bondObj := range bonds.GetBonds() { for i, bondObj := range bonds.GetBonds() {
gqlBond, err := getGQLBond(bondObj) gqlBond, err := getGQLBond(bondObj)
if err != nil { if err != nil {
@ -340,8 +341,8 @@ func (q queryResolver) QueryBonds(ctx context.Context) ([]*Bond, error) {
} }
// QueryBondsByOwner will return bonds by owner // QueryBondsByOwner will return bonds by owner
func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []string) ([]*OwnerBonds, error) { func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []string) ([]*schema.OwnerBonds, error) {
ownerBonds := make([]*OwnerBonds, len(ownerAddresses)) ownerBonds := make([]*schema.OwnerBonds, len(ownerAddresses))
for index, ownerAddress := range ownerAddresses { for index, ownerAddress := range ownerAddresses {
bondsObj, err := q.GetBondsByOwner(ctx, ownerAddress) bondsObj, err := q.GetBondsByOwner(ctx, ownerAddress)
if err != nil { if err != nil {
@ -353,14 +354,14 @@ func (q queryResolver) QueryBondsByOwner(ctx context.Context, ownerAddresses []s
return ownerBonds, nil return ownerBonds, nil
} }
func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*OwnerBonds, error) { func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*schema.OwnerBonds, error) {
bondQueryClient := bondtypes.NewQueryClient(q.ctx) bondQueryClient := bondtypes.NewQueryClient(q.ctx)
bondResp, err := bondQueryClient.GetBondsByOwner(context.Background(), &bondtypes.QueryGetBondsByOwnerRequest{Owner: address}) bondResp, err := bondQueryClient.GetBondsByOwner(context.Background(), &bondtypes.QueryGetBondsByOwnerRequest{Owner: address})
if err != nil { if err != nil {
return nil, err return nil, err
} }
ownerBonds := make([]*Bond, len(bondResp.GetBonds())) ownerBonds := make([]*schema.Bond, len(bondResp.GetBonds()))
for i, bond := range bondResp.GetBonds() { for i, bond := range bondResp.GetBonds() {
// #nosec G601 // #nosec G601
bondObj, err := getGQLBond(&bond) //nolint: all bondObj, err := getGQLBond(&bond) //nolint: all
@ -370,12 +371,12 @@ func (q queryResolver) GetBondsByOwner(ctx context.Context, address string) (*Ow
ownerBonds[i] = bondObj ownerBonds[i] = bondObj
} }
return &OwnerBonds{Bonds: ownerBonds, Owner: address}, nil return &schema.OwnerBonds{Bonds: ownerBonds, Owner: address}, nil
} }
func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*Auction, error) { func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*schema.Auction, error) {
auctionQueryClient := auctiontypes.NewQueryClient(q.ctx) auctionQueryClient := auctiontypes.NewQueryClient(q.ctx)
gqlAuctionResponse := make([]*Auction, len(ids)) gqlAuctionResponse := make([]*schema.Auction, len(ids))
for i, id := range ids { for i, id := range ids {
auctionObj, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.QueryGetAuctionRequest{Id: id}) auctionObj, err := auctionQueryClient.GetAuction(context.Background(), &auctiontypes.QueryGetAuctionRequest{Id: id})
if err != nil { if err != nil {
@ -397,16 +398,16 @@ func (q queryResolver) GetAuctionsByIds(ctx context.Context, ids []string) ([]*A
return gqlAuctionResponse, nil return gqlAuctionResponse, nil
} }
func (q queryResolver) GetParticipants(ctx context.Context) ([]*Participant, error) { func (q queryResolver) GetParticipants(ctx context.Context) ([]*schema.Participant, error) {
onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx) onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx)
participantResp, err := onboardingQueryClient.Participants(context.Background(), &onboardingTypes.QueryParticipantsRequest{}) participantResp, err := onboardingQueryClient.Participants(context.Background(), &onboardingTypes.QueryParticipantsRequest{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
participants := make([]*Participant, len(participantResp.GetParticipants())) participants := make([]*schema.Participant, len(participantResp.GetParticipants()))
for i, p := range participantResp.Participants { for i, p := range participantResp.Participants {
participants[i] = &Participant{ participants[i] = &schema.Participant{
CosmosAddress: p.CosmosAddress, CosmosAddress: p.CosmosAddress,
NitroAddress: p.NitroAddress, NitroAddress: p.NitroAddress,
Role: p.Role, Role: p.Role,
@ -417,7 +418,7 @@ func (q queryResolver) GetParticipants(ctx context.Context) ([]*Participant, err
return participants, nil return participants, nil
} }
func (q queryResolver) GetParticipantByAddress(ctx context.Context, address string) (*Participant, error) { func (q queryResolver) GetParticipantByAddress(ctx context.Context, address string) (*schema.Participant, error) {
onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx) onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx)
participantResp, err := onboardingQueryClient.GetParticipantByAddress(ctx, &onboardingTypes.QueryGetParticipantByAddressRequest{Address: address}) participantResp, err := onboardingQueryClient.GetParticipantByAddress(ctx, &onboardingTypes.QueryGetParticipantByAddressRequest{Address: address})
if err != nil { if err != nil {
@ -425,7 +426,7 @@ func (q queryResolver) GetParticipantByAddress(ctx context.Context, address stri
} }
p := participantResp.Participant p := participantResp.Participant
participant := &Participant{ participant := &schema.Participant{
CosmosAddress: p.CosmosAddress, CosmosAddress: p.CosmosAddress,
NitroAddress: p.NitroAddress, NitroAddress: p.NitroAddress,
Role: p.Role, Role: p.Role,
@ -435,7 +436,7 @@ func (q queryResolver) GetParticipantByAddress(ctx context.Context, address stri
return participant, nil return participant, nil
} }
func (q queryResolver) GetParticipantByNitroAddress(ctx context.Context, nitroAddress string) (*Participant, error) { func (q queryResolver) GetParticipantByNitroAddress(ctx context.Context, nitroAddress string) (*schema.Participant, error) {
onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx) onboardingQueryClient := onboardingTypes.NewQueryClient(q.ctx)
participantResp, err := onboardingQueryClient.GetParticipantByNitroAddress( participantResp, err := onboardingQueryClient.GetParticipantByNitroAddress(
ctx, ctx,
@ -448,7 +449,7 @@ func (q queryResolver) GetParticipantByNitroAddress(ctx context.Context, nitroAd
} }
p := participantResp.Participant p := participantResp.Participant
participant := &Participant{ participant := &schema.Participant{
CosmosAddress: p.CosmosAddress, CosmosAddress: p.CosmosAddress,
NitroAddress: p.NitroAddress, NitroAddress: p.NitroAddress,
Role: p.Role, Role: p.Role,

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
package gql package schema
import ( import (
"context" "context"

View File

@ -1,6 +1,6 @@
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
package gql package schema
type Value interface { type Value interface {
IsValue() IsValue()

View File

@ -2,74 +2,124 @@ package gql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"time" "time"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log" "cosmossdk.io/log"
serverv2 "cosmossdk.io/server/v2"
"github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/rs/cors" "github.com/rs/cors"
"github.com/spf13/viper" "github.com/spf13/pflag"
"git.vdb.to/cerc-io/laconicd/gql/schema"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
) )
// Server configures and starts the GQL server. const (
func Server(ctx context.Context, clientCtx client.Context, logger log.Logger) error { ServerName = "gql"
if !viper.GetBool("gql-server") { )
return nil
var (
_ serverv2.ServerComponent[transaction.Tx] = (*Server)(nil)
_ serverv2.HasStartFlags = (*Server)(nil)
_ serverv2.HasConfig = (*Server)(nil)
)
type Server struct {
logger log.Logger
router chi.Router
config *Config
httpServer *http.Server
}
func New(logger log.Logger, cfg server.ConfigMap, clientCtx client.Context) (*Server, error) {
s := &Server{
logger: logger.With(log.ModuleKey, ServerName),
router: chi.NewRouter(),
} }
router := chi.NewRouter() s.config = s.Config().(*Config)
if len(cfg) > 0 {
if err := serverv2.UnmarshalSubConfig(cfg, s.Name(), &s.config); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
}
// Add CORS middleware around every request // Add CORS middleware around every request
// See https://github.com/rs/cors for full option listing // See https://github.com/rs/cors for full option listing
router.Use(cors.New(cors.Options{ s.router.Use(cors.New(cors.Options{
AllowedOrigins: []string{"*"}, AllowedOrigins: []string{"*"},
Debug: false, Debug: false,
}).Handler) }).Handler)
logFile := viper.GetString("log-file") srv := handler.NewDefaultServer(schema.NewExecutableSchema(schema.Config{Resolvers: &Resolver{
port := viper.GetString("gql-port")
srv := handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: &Resolver{
ctx: clientCtx, ctx: clientCtx,
logFile: logFile, // logFile: logFile,
}})) }}))
router.Handle("/", PlaygroundHandler("/api")) s.router.Handle("/", PlaygroundHandler("/api"))
if viper.GetBool("gql-playground") { if s.config.Playground {
apiBase := viper.GetString("gql-playground-api-base") apiBase := s.config.PlaygroundAPIBase
s.router.Handle("/webui", PlaygroundHandler(apiBase+"/api"))
router.Handle("/webui", PlaygroundHandler(apiBase+"/api")) s.router.Handle("/console", PlaygroundHandler(apiBase+"/graphql"))
router.Handle("/console", PlaygroundHandler(apiBase+"/graphql"))
} }
router.Handle("/api", srv) s.router.Handle("/api", srv)
router.Handle("/graphql", srv) s.router.Handle("/graphql", srv)
return s, nil
}
errCh := make(chan error) func (s *Server) Name() string {
return ServerName
}
go func() { // Server configures and starts the GQL server.
logger.Info(fmt.Sprintf("Connect to GraphQL playground url: http://localhost:%s", port)) func (s *Server) Start(ctx context.Context) error {
server := &http.Server{ if !s.config.Enable {
Addr: ":" + port, s.logger.Info(fmt.Sprintf("%s server is disabled via config", s.Name()))
Handler: router, return nil
}
if s.config.Playground {
s.logger.Info(fmt.Sprintf("Connect to GraphQL playground URL at http://localhost:%d", s.config.Port))
}
s.httpServer = &http.Server{
Addr: fmt.Sprintf(":%d", s.config.Port),
Handler: s.router,
ReadHeaderTimeout: 3 * time.Second, ReadHeaderTimeout: 3 * time.Second,
} }
errCh <- server.ListenAndServe() if err := s.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
}() s.logger.Error("Failed to start GraphQL server", "error", err)
select {
case <-ctx.Done():
// Gracefully stop the GQL server.
logger.Info("Stopping GQL server...")
return nil
case err := <-errCh:
logger.Error(fmt.Sprintf("Failed to start GQL server: %s", err))
return err return err
} }
return nil
}
func (s *Server) Stop(ctx context.Context) error {
if !s.config.Enable {
return nil
}
s.logger.Info("stopping GraphQL server")
return s.httpServer.Shutdown(ctx)
}
func (s *Server) Config() any {
if s.config == nil {
return DefaultConfig()
}
return s.config
}
func (s *Server) StartCmdFlags() *pflag.FlagSet {
flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError)
AddGQLFlags(flags)
return flags
} }

View File

@ -7,13 +7,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.vdb.to/cerc-io/laconicd/gql/schema"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
) )
// NodeDataPath is the path to the laconicd data folder. // NodeDataPath is the path to the laconicd data folder.
var NodeDataPath = os.ExpandEnv("$HOME/.laconicd/data") var NodeDataPath = os.ExpandEnv("$HOME/.laconicd/data")
func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo, error) { func getStatusInfo(client client.Context) (*schema.NodeInfo, *schema.SyncInfo, *schema.ValidatorInfo, error) {
nodeClient, err := client.GetNode() nodeClient, err := client.GetNode()
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
@ -23,16 +24,16 @@ func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo,
return nil, nil, nil, err return nil, nil, nil, err
} }
return &NodeInfo{ return &schema.NodeInfo{
ID: string(nodeStatus.NodeInfo.ID()), ID: string(nodeStatus.NodeInfo.ID()),
Network: nodeStatus.NodeInfo.Network, Network: nodeStatus.NodeInfo.Network,
Moniker: nodeStatus.NodeInfo.Moniker, Moniker: nodeStatus.NodeInfo.Moniker,
}, &SyncInfo{ }, &schema.SyncInfo{
LatestBlockHash: nodeStatus.SyncInfo.LatestBlockHash.String(), LatestBlockHash: nodeStatus.SyncInfo.LatestBlockHash.String(),
LatestBlockHeight: strconv.FormatInt(nodeStatus.SyncInfo.LatestBlockHeight, 10), LatestBlockHeight: strconv.FormatInt(nodeStatus.SyncInfo.LatestBlockHeight, 10),
LatestBlockTime: nodeStatus.SyncInfo.LatestBlockTime.String(), LatestBlockTime: nodeStatus.SyncInfo.LatestBlockTime.String(),
CatchingUp: nodeStatus.SyncInfo.CatchingUp, CatchingUp: nodeStatus.SyncInfo.CatchingUp,
}, &ValidatorInfo{ }, &schema.ValidatorInfo{
Address: nodeStatus.ValidatorInfo.Address.String(), Address: nodeStatus.ValidatorInfo.Address.String(),
VotingPower: strconv.FormatInt(nodeStatus.ValidatorInfo.VotingPower, 10), VotingPower: strconv.FormatInt(nodeStatus.ValidatorInfo.VotingPower, 10),
ProposerPriority: nil, ProposerPriority: nil,
@ -40,7 +41,7 @@ func getStatusInfo(client client.Context) (*NodeInfo, *SyncInfo, *ValidatorInfo,
} }
// nolint: all // nolint: all
func getNetInfo(_ client.Context) (string, []*PeerInfo, error) { func getNetInfo(_ client.Context) (string, []*schema.PeerInfo, error) {
// TODO: Implement // TODO: Implement
// nodeClient, err := client.GetNode() // nodeClient, err := client.GetNode()
@ -68,10 +69,10 @@ func getNetInfo(_ client.Context) (string, []*PeerInfo, error) {
// return strconv.FormatInt(int64(netInfo.NPeers), 10), peersInfo, nil // return strconv.FormatInt(int64(netInfo.NPeers), 10), peersInfo, nil
return strconv.FormatInt(int64(0), 10), []*PeerInfo{}, nil return strconv.FormatInt(int64(0), 10), []*schema.PeerInfo{}, nil
} }
func getValidatorSet(client client.Context) ([]*ValidatorInfo, error) { func getValidatorSet(client client.Context) ([]*schema.ValidatorInfo, error) {
nodeClient, err := client.GetNode() nodeClient, err := client.GetNode()
if err != nil { if err != nil {
return nil, err return nil, err
@ -81,10 +82,10 @@ func getValidatorSet(client client.Context) ([]*ValidatorInfo, error) {
return nil, err return nil, err
} }
validatorSet := make([]*ValidatorInfo, len(res.Validators)) validatorSet := make([]*schema.ValidatorInfo, len(res.Validators))
for index, validator := range res.Validators { for index, validator := range res.Validators {
proposerPriority := strconv.FormatInt(validator.ProposerPriority, 10) proposerPriority := strconv.FormatInt(validator.ProposerPriority, 10)
validatorSet[index] = &ValidatorInfo{ validatorSet[index] = &schema.ValidatorInfo{
Address: validator.Address.String(), Address: validator.Address.String(),
VotingPower: strconv.FormatInt(validator.VotingPower, 10), VotingPower: strconv.FormatInt(validator.VotingPower, 10),
ProposerPriority: &proposerPriority, ProposerPriority: &proposerPriority,

View File

@ -9,6 +9,7 @@ import (
"github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagjson" "github.com/ipld/go-ipld-prime/codec/dagjson"
"git.vdb.to/cerc-io/laconicd/gql/schema"
auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction" auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond" bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry" registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
@ -23,8 +24,8 @@ const BondIDAttributeName = "bondId"
// ExpiryTimeAttributeName denotes the record expiry time. // ExpiryTimeAttributeName denotes the record expiry time.
const ExpiryTimeAttributeName = "expiryTime" const ExpiryTimeAttributeName = "expiryTime"
func getGQLCoin(coin sdk.Coin) *Coin { func getGQLCoin(coin sdk.Coin) *schema.Coin {
gqlCoin := Coin{ gqlCoin := schema.Coin{
Type: coin.Denom, Type: coin.Denom,
Quantity: coin.Amount.BigInt().String(), Quantity: coin.Amount.BigInt().String(),
} }
@ -32,8 +33,8 @@ func getGQLCoin(coin sdk.Coin) *Coin {
return &gqlCoin return &gqlCoin
} }
func getGQLCoins(coins sdk.Coins) []*Coin { func getGQLCoins(coins sdk.Coins) []*schema.Coin {
gqlCoins := make([]*Coin, len(coins)) gqlCoins := make([]*schema.Coin, len(coins))
for index, coin := range coins { for index, coin := range coins {
gqlCoins[index] = getGQLCoin(coin) gqlCoins[index] = getGQLCoin(coin)
} }
@ -41,12 +42,12 @@ func getGQLCoins(coins sdk.Coins) []*Coin {
return gqlCoins return gqlCoins
} }
func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*AuthorityRecord, error) { func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*schema.AuthorityRecord, error) {
if record == nil { if record == nil {
return nil, nil return nil, nil
} }
return &AuthorityRecord{ return &schema.AuthorityRecord{
OwnerAddress: record.OwnerAddress, OwnerAddress: record.OwnerAddress,
OwnerPublicKey: record.OwnerPublicKey, OwnerPublicKey: record.OwnerPublicKey,
Height: strconv.FormatUint(record.Height, 10), Height: strconv.FormatUint(record.Height, 10),
@ -56,7 +57,7 @@ func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*AuthorityR
}, nil }, nil
} }
func getGQLRecord(ctx context.Context, resolver QueryResolver, record registrytypes.Record) (*Record, error) { func getGQLRecord(ctx context.Context, resolver schema.QueryResolver, record registrytypes.Record) (*schema.Record, error) {
// Nil record. // Nil record.
if record.Deleted { if record.Deleted {
return nil, nil return nil, nil
@ -81,22 +82,22 @@ func getGQLRecord(ctx context.Context, resolver QueryResolver, record registryty
return nil, err return nil, err
} }
return &Record{ return &schema.Record{
ID: record.Id, ID: record.Id,
BondID: record.GetBondId(), BondID: record.GetBondId(),
CreateTime: record.GetCreateTime(), CreateTime: record.GetCreateTime(),
ExpiryTime: record.GetExpiryTime(), ExpiryTime: record.GetExpiryTime(),
Owners: record.GetOwners(), Owners: record.GetOwners(),
Names: record.GetNames(), Names: record.GetNames(),
Attributes: attributes.(MapValue).Value, Attributes: attributes.(schema.MapValue).Value,
References: references, References: references,
}, nil }, nil
} }
func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) { func resolveIPLDNode(node ipld.Node, links *[]string) (schema.Value, error) {
switch node.Kind() { switch node.Kind() {
case ipld.Kind_Map: case ipld.Kind_Map:
var entries []*Attribute var entries []*schema.Attribute
for itr := node.MapIterator(); !itr.Done(); { for itr := node.MapIterator(); !itr.Done(); {
k, v, err := itr.Next() k, v, err := itr.Next()
if err != nil { if err != nil {
@ -113,14 +114,14 @@ func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
entries = append(entries, &Attribute{ entries = append(entries, &schema.Attribute{
Key: s, Key: s,
Value: val, Value: val,
}) })
} }
return MapValue{entries}, nil return schema.MapValue{entries}, nil
case ipld.Kind_List: case ipld.Kind_List:
var values []Value var values []schema.Value
for itr := node.ListIterator(); !itr.Done(); { for itr := node.ListIterator(); !itr.Done(); {
_, v, err := itr.Next() _, v, err := itr.Next()
if err != nil { if err != nil {
@ -132,7 +133,7 @@ func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
} }
values = append(values, val) values = append(values, val)
} }
return ArrayValue{values}, nil return schema.ArrayValue{values}, nil
case ipld.Kind_Null: case ipld.Kind_Null:
return nil, nil return nil, nil
case ipld.Kind_Bool: case ipld.Kind_Bool:
@ -140,82 +141,82 @@ func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return BooleanValue{val}, nil return schema.BooleanValue{val}, nil
case ipld.Kind_Int: case ipld.Kind_Int:
val, err := node.AsInt() val, err := node.AsInt()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: handle bigger ints // TODO: handle bigger ints
return IntValue{int(val)}, nil return schema.IntValue{int(val)}, nil
case ipld.Kind_Float: case ipld.Kind_Float:
val, err := node.AsFloat() val, err := node.AsFloat()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return FloatValue{val}, nil return schema.FloatValue{val}, nil
case ipld.Kind_String: case ipld.Kind_String:
val, err := node.AsString() val, err := node.AsString()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return StringValue{val}, nil return schema.StringValue{val}, nil
case ipld.Kind_Bytes: case ipld.Kind_Bytes:
val, err := node.AsBytes() val, err := node.AsBytes()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return BytesValue{string(val)}, nil return schema.BytesValue{string(val)}, nil
case ipld.Kind_Link: case ipld.Kind_Link:
val, err := node.AsLink() val, err := node.AsLink()
if err != nil { if err != nil {
return nil, err return nil, err
} }
*links = append(*links, val.String()) *links = append(*links, val.String())
return LinkValue{Link(val.String())}, nil return schema.LinkValue{schema.Link(val.String())}, nil
default: default:
return nil, fmt.Errorf("invalid node kind") return nil, fmt.Errorf("invalid node kind")
} }
} }
func getGQLNameRecord(record *registrytypes.NameRecord) (*NameRecord, error) { func getGQLNameRecord(record *registrytypes.NameRecord) (*schema.NameRecord, error) {
if record == nil { if record == nil {
return nil, fmt.Errorf("got nil record") return nil, fmt.Errorf("got nil record")
} }
records := make([]*NameRecordEntry, len(record.History)) records := make([]*schema.NameRecordEntry, len(record.History))
for index, entry := range record.History { for index, entry := range record.History {
records[index] = getNameRecordEntry(entry) records[index] = getNameRecordEntry(entry)
} }
return &NameRecord{ return &schema.NameRecord{
Latest: getNameRecordEntry(record.Latest), Latest: getNameRecordEntry(record.Latest),
History: records, History: records,
}, nil }, nil
} }
func getNameRecordEntry(record *registrytypes.NameRecordEntry) *NameRecordEntry { func getNameRecordEntry(record *registrytypes.NameRecordEntry) *schema.NameRecordEntry {
return &NameRecordEntry{ return &schema.NameRecordEntry{
ID: record.Id, ID: record.Id,
Height: strconv.FormatUint(record.Height, 10), Height: strconv.FormatUint(record.Height, 10),
} }
} }
func getGQLBond(bondObj *bondtypes.Bond) (*Bond, error) { func getGQLBond(bondObj *bondtypes.Bond) (*schema.Bond, error) {
// Nil record. // Nil record.
if bondObj == nil { if bondObj == nil {
return nil, nil return nil, nil
} }
return &Bond{ return &schema.Bond{
ID: bondObj.Id, ID: bondObj.Id,
Owner: bondObj.Owner, Owner: bondObj.Owner,
Balance: getGQLCoins(bondObj.Balance), Balance: getGQLCoins(bondObj.Balance),
}, nil }, nil
} }
func getAuctionBid(bid *auctiontypes.Bid) *AuctionBid { func getAuctionBid(bid *auctiontypes.Bid) *schema.AuctionBid {
return &AuctionBid{ return &schema.AuctionBid{
BidderAddress: bid.BidderAddress, BidderAddress: bid.BidderAddress,
Status: bid.Status, Status: bid.Status,
CommitHash: bid.CommitHash, CommitHash: bid.CommitHash,
@ -227,14 +228,14 @@ func getAuctionBid(bid *auctiontypes.Bid) *AuctionBid {
} }
} }
func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Auction, error) { func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*schema.Auction, error) {
if auction == nil { if auction == nil {
return nil, nil return nil, nil
} }
numProviders := int(auction.NumProviders) numProviders := int(auction.NumProviders)
gqlAuction := Auction{ gqlAuction := schema.Auction{
ID: auction.Id, ID: auction.Id,
Status: auction.Status, Status: auction.Status,
OwnerAddress: auction.OwnerAddress, OwnerAddress: auction.OwnerAddress,
@ -253,7 +254,7 @@ func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Au
FundsReleased: auction.FundsReleased, FundsReleased: auction.FundsReleased,
} }
auctionBids := make([]*AuctionBid, len(bids)) auctionBids := make([]*schema.AuctionBid, len(bids))
for index, entry := range bids { for index, entry := range bids {
auctionBids[index] = getAuctionBid(entry) auctionBids[index] = getAuctionBid(entry)
} }
@ -263,7 +264,7 @@ func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*Au
return &gqlAuction, nil return &gqlAuction, nil
} }
func toRPCValue(value *ValueInput) *registrytypes.QueryRecordsRequest_ValueInput { func toRPCValue(value *schema.ValueInput) *registrytypes.QueryRecordsRequest_ValueInput {
var rpcval registrytypes.QueryRecordsRequest_ValueInput var rpcval registrytypes.QueryRecordsRequest_ValueInput
switch { switch {
@ -295,7 +296,7 @@ func toRPCValue(value *ValueInput) *registrytypes.QueryRecordsRequest_ValueInput
return &rpcval return &rpcval
} }
func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryRecordsRequest_KeyValueInput { func toRPCAttributes(attrs []*schema.KeyValueInput) []*registrytypes.QueryRecordsRequest_KeyValueInput {
kvPairs := []*registrytypes.QueryRecordsRequest_KeyValueInput{} kvPairs := []*registrytypes.QueryRecordsRequest_KeyValueInput{}
for _, value := range attrs { for _, value := range attrs {
@ -310,7 +311,7 @@ func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryRecordsReques
return kvPairs return kvPairs
} }
func getAuthorityRecord(nameAuthority registrytypes.NameAuthority, auctionQueryClient auctiontypes.QueryClient) (*AuthorityRecord, error) { func getAuthorityRecord(nameAuthority registrytypes.NameAuthority, auctionQueryClient auctiontypes.QueryClient) (*schema.AuthorityRecord, error) {
gqlNameAuthorityRecord, err := GetGQLNameAuthorityRecord(&nameAuthority) gqlNameAuthorityRecord, err := GetGQLNameAuthorityRecord(&nameAuthority)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -137,4 +137,4 @@ $laconicd start \
--server.minimum-gas-prices=1$DENOM \ --server.minimum-gas-prices=1$DENOM \
--rpc.laddr="tcp://0.0.0.0:26657" \ --rpc.laddr="tcp://0.0.0.0:26657" \
--grpc.address="127.0.0.1:9091" \ --grpc.address="127.0.0.1:9091" \
--gql-server --gql-playground --gql.enable --gql.playground