laconicd/gql/util.go
Roy Crihfield f0f96bc28e [wip] gql server fixes
run gql server

gql cleanup
2025-02-13 11:41:58 +08:00

340 lines
9.2 KiB
Go

package gql
import (
"context"
"fmt" // #nosec G702
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ipld/go-ipld-prime"
"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"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
)
// OwnerAttributeName denotes the owner attribute name for a bond.
const OwnerAttributeName = "owner"
// BondIDAttributeName denotes the record bond ID.
const BondIDAttributeName = "bondId"
// ExpiryTimeAttributeName denotes the record expiry time.
const ExpiryTimeAttributeName = "expiryTime"
func getGQLCoin(coin sdk.Coin) *schema.Coin {
gqlCoin := schema.Coin{
Type: coin.Denom,
Quantity: coin.Amount.BigInt().String(),
}
return &gqlCoin
}
func getGQLCoins(coins sdk.Coins) []*schema.Coin {
gqlCoins := make([]*schema.Coin, len(coins))
for index, coin := range coins {
gqlCoins[index] = getGQLCoin(coin)
}
return gqlCoins
}
func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*schema.AuthorityRecord, error) {
if record == nil {
return nil, nil
}
return &schema.AuthorityRecord{
OwnerAddress: record.OwnerAddress,
OwnerPublicKey: record.OwnerPublicKey,
Height: strconv.FormatUint(record.Height, 10),
Status: record.Status,
BondID: record.GetBondId(),
ExpiryTime: record.GetExpiryTime().String(),
}, nil
}
func getGQLRecord(ctx context.Context, resolver schema.QueryResolver, record registrytypes.Record) (*schema.Record, error) {
// Nil record.
if record.Deleted {
return nil, nil
}
node, err := ipld.Decode(record.Attributes, dagjson.Decode)
if err != nil {
return nil, err
}
if node.Kind() != ipld.Kind_Map {
return nil, fmt.Errorf("invalid record attributes")
}
var links []string
attributes, err := resolveIPLDNode(node, &links)
if err != nil {
return nil, err
}
references, err := resolver.GetRecordsByIds(ctx, links)
if err != nil {
return nil, err
}
return &schema.Record{
ID: record.Id,
BondID: record.GetBondId(),
CreateTime: record.GetCreateTime(),
ExpiryTime: record.GetExpiryTime(),
Owners: record.GetOwners(),
Names: record.GetNames(),
Attributes: attributes.(schema.MapValue).Value,
References: references,
}, nil
}
func resolveIPLDNode(node ipld.Node, links *[]string) (schema.Value, error) {
switch node.Kind() {
case ipld.Kind_Map:
var entries []*schema.Attribute
for itr := node.MapIterator(); !itr.Done(); {
k, v, err := itr.Next()
if err != nil {
return nil, err
}
if k.Kind() != ipld.Kind_String {
return nil, fmt.Errorf("invalid record attribute key type: %s", k.Kind())
}
s, err := k.AsString()
if err != nil {
return nil, err
}
val, err := resolveIPLDNode(v, links)
if err != nil {
return nil, err
}
entries = append(entries, &schema.Attribute{
Key: s,
Value: val,
})
}
return schema.MapValue{entries}, nil
case ipld.Kind_List:
var values []schema.Value
for itr := node.ListIterator(); !itr.Done(); {
_, v, err := itr.Next()
if err != nil {
return nil, err
}
val, err := resolveIPLDNode(v, links)
if err != nil {
return nil, err
}
values = append(values, val)
}
return schema.ArrayValue{values}, nil
case ipld.Kind_Null:
return nil, nil
case ipld.Kind_Bool:
val, err := node.AsBool()
if err != nil {
return nil, err
}
return schema.BooleanValue{val}, nil
case ipld.Kind_Int:
val, err := node.AsInt()
if err != nil {
return nil, err
}
// TODO: handle bigger ints
return schema.IntValue{int(val)}, nil
case ipld.Kind_Float:
val, err := node.AsFloat()
if err != nil {
return nil, err
}
return schema.FloatValue{val}, nil
case ipld.Kind_String:
val, err := node.AsString()
if err != nil {
return nil, err
}
return schema.StringValue{val}, nil
case ipld.Kind_Bytes:
val, err := node.AsBytes()
if err != nil {
return nil, err
}
return schema.BytesValue{string(val)}, nil
case ipld.Kind_Link:
val, err := node.AsLink()
if err != nil {
return nil, err
}
*links = append(*links, val.String())
return schema.LinkValue{schema.Link(val.String())}, nil
default:
return nil, fmt.Errorf("invalid node kind")
}
}
func getGQLNameRecord(record *registrytypes.NameRecord) (*schema.NameRecord, error) {
if record == nil {
return nil, fmt.Errorf("got nil record")
}
records := make([]*schema.NameRecordEntry, len(record.History))
for index, entry := range record.History {
records[index] = getNameRecordEntry(entry)
}
return &schema.NameRecord{
Latest: getNameRecordEntry(record.Latest),
History: records,
}, nil
}
func getNameRecordEntry(record *registrytypes.NameRecordEntry) *schema.NameRecordEntry {
return &schema.NameRecordEntry{
ID: record.Id,
Height: strconv.FormatUint(record.Height, 10),
}
}
func getGQLBond(bondObj *bondtypes.Bond) (*schema.Bond, error) {
// Nil record.
if bondObj == nil {
return nil, nil
}
return &schema.Bond{
ID: bondObj.Id,
Owner: bondObj.Owner,
Balance: getGQLCoins(bondObj.Balance),
}, nil
}
func getAuctionBid(bid *auctiontypes.Bid) *schema.AuctionBid {
return &schema.AuctionBid{
BidderAddress: bid.BidderAddress,
Status: bid.Status,
CommitHash: bid.CommitHash,
CommitTime: bid.GetCommitTime(),
RevealTime: bid.GetRevealTime(),
CommitFee: getGQLCoin(bid.CommitFee),
RevealFee: getGQLCoin(bid.RevealFee),
BidAmount: getGQLCoin(bid.BidAmount),
}
}
func GetGQLAuction(auction *auctiontypes.Auction, bids []*auctiontypes.Bid) (*schema.Auction, error) {
if auction == nil {
return nil, nil
}
numProviders := int(auction.NumProviders)
gqlAuction := schema.Auction{
ID: auction.Id,
Status: auction.Status,
OwnerAddress: auction.OwnerAddress,
CreateTime: auction.GetCreateTime(),
CommitsEndTime: auction.GetCommitsEndTime(),
RevealsEndTime: auction.GetRevealsEndTime(),
CommitFee: getGQLCoin(auction.CommitFee),
RevealFee: getGQLCoin(auction.RevealFee),
MinimumBid: getGQLCoin(auction.MinimumBid),
WinnerAddresses: auction.WinnerAddresses,
WinnerBids: getGQLCoins(auction.WinningBids),
WinnerPrice: getGQLCoin(auction.WinningPrice),
MaxPrice: getGQLCoin(auction.MaxPrice),
Kind: auction.Kind,
NumProviders: &numProviders,
FundsReleased: auction.FundsReleased,
}
auctionBids := make([]*schema.AuctionBid, len(bids))
for index, entry := range bids {
auctionBids[index] = getAuctionBid(entry)
}
gqlAuction.Bids = auctionBids
return &gqlAuction, nil
}
func toRPCValue(value *schema.ValueInput) *registrytypes.QueryRecordsRequest_ValueInput {
var rpcval registrytypes.QueryRecordsRequest_ValueInput
switch {
case value == nil:
return nil
case value.Int != nil:
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_Int{Int: int64(*value.Int)}
case value.Float != nil:
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_Float{Float: *value.Float}
case value.String != nil:
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_String_{String_: *value.String}
case value.Boolean != nil:
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_Boolean{Boolean: *value.Boolean}
case value.Link != nil:
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_Link{Link: value.Link.String()}
case value.Array != nil:
var contents registrytypes.QueryRecordsRequest_ArrayInput
for _, val := range value.Array {
contents.Values = append(contents.Values, toRPCValue(val))
}
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_Array{Array: &contents}
case value.Map != nil:
var contents registrytypes.QueryRecordsRequest_MapInput
for _, kv := range value.Map {
contents.Values[kv.Key] = toRPCValue(kv.Value)
}
rpcval.Value = &registrytypes.QueryRecordsRequest_ValueInput_Map{Map: &contents}
}
return &rpcval
}
func toRPCAttributes(attrs []*schema.KeyValueInput) []*registrytypes.QueryRecordsRequest_KeyValueInput {
kvPairs := []*registrytypes.QueryRecordsRequest_KeyValueInput{}
for _, value := range attrs {
parsedValue := toRPCValue(value.Value)
kvPair := &registrytypes.QueryRecordsRequest_KeyValueInput{
Key: value.Key,
Value: parsedValue,
}
kvPairs = append(kvPairs, kvPair)
}
return kvPairs
}
func getAuthorityRecord(nameAuthority registrytypes.NameAuthority, auctionQueryClient auctiontypes.QueryClient) (*schema.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
}