nabarun
f176a5889e
All checks were successful
Integration Tests / test-integration (push) Successful in 2m42s
Unit Tests / test-unit (push) Successful in 2m54s
E2E Tests / test-e2e (push) Successful in 4m31s
SDK Tests / sdk_tests (push) Successful in 10m49s
SDK Tests / sdk_tests_auctions (push) Successful in 14m42s
SDK Tests / sdk_tests_nameservice_expiry (push) Successful in 7m10s
Publish on release / Run docker build and publish (release) Successful in 2m37s
Part of [Create a public laconicd testnet](https://www.notion.so/Create-a-public-laconicd-testnet-896a11bdd8094eff8f1b49c0be0ca3b8) Co-authored-by: IshaVenikar <ishavenikar7@gmail.com> Reviewed-on: #48
333 lines
8.7 KiB
Go
333 lines
8.7 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"
|
|
|
|
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) *Coin {
|
|
gqlCoin := Coin{
|
|
Type: coin.Denom,
|
|
Quantity: coin.Amount.BigInt().String(),
|
|
}
|
|
|
|
return &gqlCoin
|
|
}
|
|
|
|
func getGQLCoins(coins sdk.Coins) []*Coin {
|
|
gqlCoins := make([]*Coin, len(coins))
|
|
for index, coin := range coins {
|
|
gqlCoins[index] = getGQLCoin(coin)
|
|
}
|
|
|
|
return gqlCoins
|
|
}
|
|
|
|
func GetGQLNameAuthorityRecord(record *registrytypes.NameAuthority) (*AuthorityRecord, error) {
|
|
if record == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return &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 QueryResolver, record registrytypes.Record) (*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 &Record{
|
|
ID: record.Id,
|
|
BondID: record.GetBondId(),
|
|
CreateTime: record.GetCreateTime(),
|
|
ExpiryTime: record.GetExpiryTime(),
|
|
Owners: record.GetOwners(),
|
|
Names: record.GetNames(),
|
|
Attributes: attributes.(MapValue).Value,
|
|
References: references,
|
|
}, nil
|
|
}
|
|
|
|
func resolveIPLDNode(node ipld.Node, links *[]string) (Value, error) {
|
|
switch node.Kind() {
|
|
case ipld.Kind_Map:
|
|
var entries []*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, &Attribute{
|
|
Key: s,
|
|
Value: val,
|
|
})
|
|
}
|
|
return MapValue{entries}, nil
|
|
case ipld.Kind_List:
|
|
var values []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 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 BooleanValue{val}, nil
|
|
case ipld.Kind_Int:
|
|
val, err := node.AsInt()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// TODO: handle bigger ints
|
|
return IntValue{int(val)}, nil
|
|
case ipld.Kind_Float:
|
|
val, err := node.AsFloat()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return FloatValue{val}, nil
|
|
case ipld.Kind_String:
|
|
val, err := node.AsString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return StringValue{val}, nil
|
|
case ipld.Kind_Bytes:
|
|
val, err := node.AsBytes()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return BytesValue{string(val)}, nil
|
|
case ipld.Kind_Link:
|
|
val, err := node.AsLink()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
*links = append(*links, val.String())
|
|
return LinkValue{Link(val.String())}, nil
|
|
default:
|
|
return nil, fmt.Errorf("invalid node kind")
|
|
}
|
|
}
|
|
|
|
func getGQLNameRecord(record *registrytypes.NameRecord) (*NameRecord, error) {
|
|
if record == nil {
|
|
return nil, fmt.Errorf("got nil record")
|
|
}
|
|
|
|
records := make([]*NameRecordEntry, len(record.History))
|
|
for index, entry := range record.History {
|
|
records[index] = getNameRecordEntry(entry)
|
|
}
|
|
|
|
return &NameRecord{
|
|
Latest: getNameRecordEntry(record.Latest),
|
|
History: records,
|
|
}, nil
|
|
}
|
|
|
|
func getNameRecordEntry(record *registrytypes.NameRecordEntry) *NameRecordEntry {
|
|
return &NameRecordEntry{
|
|
ID: record.Id,
|
|
Height: strconv.FormatUint(record.Height, 10),
|
|
}
|
|
}
|
|
|
|
func getGQLBond(bondObj *bondtypes.Bond) (*Bond, error) {
|
|
// Nil record.
|
|
if bondObj == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return &Bond{
|
|
ID: bondObj.Id,
|
|
Owner: bondObj.Owner,
|
|
Balance: getGQLCoins(bondObj.Balance),
|
|
}, nil
|
|
}
|
|
|
|
func getAuctionBid(bid *auctiontypes.Bid) *AuctionBid {
|
|
return &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) (*Auction, error) {
|
|
if auction == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
gqlAuction := 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),
|
|
WinnerAddress: auction.WinnerAddress,
|
|
WinnerBid: getGQLCoin(auction.WinningBid),
|
|
WinnerPrice: getGQLCoin(auction.WinningPrice),
|
|
}
|
|
|
|
auctionBids := make([]*AuctionBid, len(bids))
|
|
for index, entry := range bids {
|
|
auctionBids[index] = getAuctionBid(entry)
|
|
}
|
|
|
|
gqlAuction.Bids = auctionBids
|
|
|
|
return &gqlAuction, nil
|
|
}
|
|
|
|
func toRPCValue(value *ValueInput) *registrytypes.QueryRecordsRequest_ValueInput {
|
|
var rpcval registrytypes.QueryRecordsRequest_ValueInput
|
|
|
|
switch {
|
|
case value == nil:
|
|
return nil
|
|
case value.Int != nil:
|
|
rpcval.Value = ®istrytypes.QueryRecordsRequest_ValueInput_Int{Int: int64(*value.Int)}
|
|
case value.Float != nil:
|
|
rpcval.Value = ®istrytypes.QueryRecordsRequest_ValueInput_Float{Float: *value.Float}
|
|
case value.String != nil:
|
|
rpcval.Value = ®istrytypes.QueryRecordsRequest_ValueInput_String_{String_: *value.String}
|
|
case value.Boolean != nil:
|
|
rpcval.Value = ®istrytypes.QueryRecordsRequest_ValueInput_Boolean{Boolean: *value.Boolean}
|
|
case value.Link != nil:
|
|
rpcval.Value = ®istrytypes.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 = ®istrytypes.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 = ®istrytypes.QueryRecordsRequest_ValueInput_Map{Map: &contents}
|
|
}
|
|
return &rpcval
|
|
}
|
|
|
|
func toRPCAttributes(attrs []*KeyValueInput) []*registrytypes.QueryRecordsRequest_KeyValueInput {
|
|
kvPairs := []*registrytypes.QueryRecordsRequest_KeyValueInput{}
|
|
|
|
for _, value := range attrs {
|
|
parsedValue := toRPCValue(value.Value)
|
|
kvPair := ®istrytypes.QueryRecordsRequest_KeyValueInput{
|
|
Key: value.Key,
|
|
Value: parsedValue,
|
|
}
|
|
kvPairs = append(kvPairs, kvPair)
|
|
}
|
|
|
|
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
|
|
}
|