forked from cerc-io/laconicd-deprecated
Graphql schema for DAG-JSON objects #1
@ -47,24 +47,20 @@ func Int64ToBytes(num int64) []byte {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// MarshalMapToJSONBytes converts map[string]interface{} to bytes.
|
||||
func MarshalMapToJSONBytes(val map[string]interface{}) (bytes []byte) {
|
||||
func MustMarshalJSON[T any](val T) (bytes []byte) {
|
||||
bytes, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
panic("Marshal error.")
|
||||
panic("JSON marshal error:" + err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UnMarshalMapFromJSONBytes converts bytes to map[string]interface{}.
|
||||
func UnMarshalMapFromJSONBytes(bytes []byte) map[string]interface{} {
|
||||
var val map[string]interface{}
|
||||
func MustUnmarshalJSON[T any](bytes []byte) T {
|
||||
var val T
|
||||
err := json.Unmarshal(bytes, &val)
|
||||
if err != nil {
|
||||
panic("Unmarshal error.")
|
||||
panic("JSON unmarshal error:" + err.Error())
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
|
@ -182,9 +182,13 @@ func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
|
||||
sr.Equal(resp.GetRecords()[0].GetBondId(), suite.bond.GetId())
|
||||
|
||||
for _, record := range resp.GetRecords() {
|
||||
recAttr := helpers.UnMarshalMapFromJSONBytes(record.Attributes)
|
||||
recAttr := helpers.MustUnmarshalJSON[registrytypes.AttributeMap](record.Attributes)
|
||||
|
||||
for _, attr := range test.req.GetAttributes() {
|
||||
av := keeper.GetAttributeValue(attr.Value)
|
||||
enc, err := keeper.QueryValueToJSON(attr.Value)
|
||||
sr.NoError(err)
|
||||
av := helpers.MustUnmarshalJSON[any](enc)
|
||||
|
||||
if nil != av && nil != recAttr[attr.Key] &&
|
||||
reflect.Slice == reflect.TypeOf(recAttr[attr.Key]).Kind() &&
|
||||
reflect.Slice != reflect.TypeOf(av).Kind() {
|
||||
|
@ -8,10 +8,6 @@ import (
|
||||
"time"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
auctionkeeper "github.com/cerc-io/laconicd/x/auction/keeper"
|
||||
bondkeeper "github.com/cerc-io/laconicd/x/bond/keeper"
|
||||
"github.com/cerc-io/laconicd/x/registry/helpers"
|
||||
"github.com/cerc-io/laconicd/x/registry/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/legacy"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
@ -20,13 +16,18 @@ import (
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||||
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/gibson042/canonicaljson-go"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/ipld/go-ipld-prime"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
||||
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
|
||||
basicnode "github.com/ipld/go-ipld-prime/node/basic"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
auctionkeeper "github.com/cerc-io/laconicd/x/auction/keeper"
|
||||
bondkeeper "github.com/cerc-io/laconicd/x/bond/keeper"
|
||||
"github.com/cerc-io/laconicd/x/registry/helpers"
|
||||
"github.com/cerc-io/laconicd/x/registry/types"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -152,7 +153,7 @@ func (k Keeper) ListRecords(ctx sdk.Context) []types.Record {
|
||||
func (k Keeper) RecordsFromAttributes(ctx sdk.Context, attributes []*types.QueryListRecordsRequest_KeyValueInput, all bool) ([]types.Record, error) {
|
||||
resultRecordIds := []string{}
|
||||
for i, attr := range attributes {
|
||||
suffix, err := EncodeQueryValue(attr.Value)
|
||||
suffix, err := QueryValueToJSON(attr.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -184,8 +185,9 @@ func (k Keeper) RecordsFromAttributes(ctx sdk.Context, attributes []*types.Query
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// TODO not recursive, and only should be if we want to support querying with whole sub-objects
|
||||
func EncodeQueryValue(input *types.QueryListRecordsRequest_ValueInput) ([]byte, error) {
|
||||
// TODO not recursive, and only should be if we want to support querying with whole sub-objects,
|
||||
// which seems unnecessary.
|
||||
func QueryValueToJSON(input *types.QueryListRecordsRequest_ValueInput) ([]byte, error) {
|
||||
np := basicnode.Prototype.Any
|
||||
nb := np.NewBuilder()
|
||||
|
||||
@ -202,20 +204,19 @@ func EncodeQueryValue(input *types.QueryListRecordsRequest_ValueInput) ([]byte,
|
||||
link := cidlink.Link{Cid: cid.MustParse(value.Link)}
|
||||
nb.AssignLink(link)
|
||||
case *types.QueryListRecordsRequest_ValueInput_Array:
|
||||
// TODO
|
||||
return nil, fmt.Errorf("Recursive query values are not supported")
|
||||
case *types.QueryListRecordsRequest_ValueInput_Map:
|
||||
// TODO
|
||||
return nil, fmt.Errorf("Recursive query values are not supported")
|
||||
default:
|
||||
return nil, fmt.Errorf("Value has unepxpected type %T", value)
|
||||
return nil, fmt.Errorf("Value has unexpected type %T", value)
|
||||
}
|
||||
|
||||
n := nb.Build()
|
||||
var buf bytes.Buffer
|
||||
if err := dagjson.Encode(n, &buf); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("encoding value to JSON failed: %w", err)
|
||||
}
|
||||
value := buf.Bytes()
|
||||
return value, nil
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func getIntersection(a []string, b []string) []string {
|
||||
@ -288,14 +289,12 @@ func (k Keeper) ProcessSetRecord(ctx sdk.Context, msg types.MsgSetRecord) (*type
|
||||
for _, sig := range payload.Signatures {
|
||||
pubKey, err := legacy.PubKeyFromBytes(helpers.BytesFromBase64(sig.PubKey))
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding pubKey from bytes: ", err)
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Invalid public key.")
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, fmt.Sprint("Error decoding pubKey from bytes: ", err))
|
||||
}
|
||||
|
||||
sigOK := pubKey.VerifySignature(resourceSignBytes, helpers.BytesFromBase64(sig.Sig))
|
||||
if !sigOK {
|
||||
fmt.Println("Signature mismatch: ", sig.PubKey)
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Invalid signature.")
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, fmt.Sprint("Signature mismatch: ", sig.PubKey))
|
||||
}
|
||||
record.Owners = append(record.Owners, pubKey.Address().String())
|
||||
}
|
||||
@ -358,17 +357,25 @@ func (k Keeper) PutRecord(ctx sdk.Context, record types.Record) {
|
||||
k.updateBlockChangeSetForRecord(ctx, record.Id)
|
||||
}
|
||||
|
||||
func (k Keeper) processAttributes(ctx sdk.Context, attrs []byte, id string, prefix string) error {
|
||||
func (k Keeper) processAttributes(ctx sdk.Context, attrs types.AttributeMap, id string, prefix string) error {
|
||||
np := basicnode.Prototype.Map
|
||||
nb := np.NewBuilder()
|
||||
err := dagjson.Decode(nb, bytes.NewReader(attrs))
|
||||
encAttrs, err := canonicaljson.Marshal(attrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(attrs) == 0 {
|
||||
encAttrs = []byte("{}")
|
||||
}
|
||||
err = dagjson.Decode(nb, bytes.NewReader(encAttrs))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode attributes: %w", err)
|
||||
}
|
||||
n := nb.Build()
|
||||
if n.Kind() != ipld.Kind_Map {
|
||||
return fmt.Errorf("Record attributes must be a map, not %T", n.Kind())
|
||||
}
|
||||
|
||||
return k.processAttributeMap(ctx, n, id, prefix)
|
||||
}
|
||||
|
||||
@ -406,7 +413,6 @@ func (k Keeper) processAttributeMap(ctx sdk.Context, n ipld.Node, id string, pre
|
||||
func GetAttributesIndexKey(key string, suffix []byte) []byte {
|
||||
keyString := fmt.Sprintf("%s=%s", key, suffix)
|
||||
return append(PrefixAttributesIndex, []byte(keyString)...)
|
||||
// return append(append(PrefixAttributesIndex, key...), suffix...)
|
||||
}
|
||||
|
||||
func (k Keeper) SetAttributeMapping(ctx sdk.Context, key []byte, recordID string) error {
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/registry/helpers"
|
||||
canonicalJson "github.com/gibson042/canonicaljson-go"
|
||||
"github.com/gibson042/canonicaljson-go"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -17,16 +17,12 @@ const (
|
||||
// become specific to content records. schema records will either occupy a new message or have new
|
||||
// more general purpose helper types.
|
||||
|
||||
type DagJsonBlob []byte
|
||||
|
||||
func (b DagJsonBlob) MarshalJSON() ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
type AttributeMap map[string]interface{}
|
||||
|
||||
// ReadablePayload represents a signed record payload that can be serialized from/to YAML.
|
||||
type ReadablePayload struct {
|
||||
Record map[string]interface{} `json:"record"`
|
||||
Signatures []Signature `json:"signatures"`
|
||||
RecordAttributes AttributeMap `json:"record" yaml:"record"`
|
||||
Signatures []Signature `json:"signatures" yaml:"signatures"`
|
||||
}
|
||||
|
||||
// ReadableRecord represents a WNS record.
|
||||
@ -38,7 +34,7 @@ type ReadableRecord struct {
|
||||
ExpiryTime string `json:"expiryTime,omitempty"`
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
Owners []string `json:"owners,omitempty"`
|
||||
Attributes map[string]interface{} `json:"attributes,omitempty"`
|
||||
Attributes AttributeMap `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
// ToPayload converts PayloadEncodable to Payload object.
|
||||
@ -50,7 +46,7 @@ func (payloadObj *ReadablePayload) ToPayload() Payload {
|
||||
Record: &Record{
|
||||
Deleted: false,
|
||||
Owners: nil,
|
||||
Attributes: attributes,
|
||||
Attributes: helpers.MustMarshalJSON(attributes),
|
||||
},
|
||||
Signatures: payloadObj.Signatures,
|
||||
}
|
||||
@ -61,28 +57,12 @@ func (payloadObj *ReadablePayload) ToPayload() Payload {
|
||||
func (payload Payload) ToReadablePayload() ReadablePayload {
|
||||
var encodable ReadablePayload
|
||||
|
||||
encodable.Record = helpers.UnMarshalMapFromJSONBytes(payload.Record.Attributes)
|
||||
encodable.RecordAttributes = helpers.MustUnmarshalJSON[AttributeMap](payload.Record.Attributes)
|
||||
encodable.Signatures = payload.Signatures
|
||||
|
||||
return encodable
|
||||
}
|
||||
|
||||
// ToReadableRecord converts Record to a serializable object
|
||||
func (r *Record) ToReadableRecord() ReadableRecord {
|
||||
var resourceObj ReadableRecord
|
||||
|
||||
resourceObj.ID = r.Id
|
||||
resourceObj.BondID = r.BondId
|
||||
resourceObj.CreateTime = r.CreateTime
|
||||
resourceObj.ExpiryTime = r.ExpiryTime
|
||||
resourceObj.Deleted = r.Deleted
|
||||
resourceObj.Owners = r.Owners
|
||||
resourceObj.Names = r.Names
|
||||
resourceObj.Attributes = helpers.UnMarshalMapFromJSONBytes(r.Attributes)
|
||||
|
||||
return resourceObj
|
||||
}
|
||||
|
||||
// ToRecordObj converts Record to RecordObj.
|
||||
// Why? Because go-amino can't handle maps: https://github.com/tendermint/go-amino/issues/4.
|
||||
func (r *ReadableRecord) ToRecordObj() (Record, error) {
|
||||
@ -96,16 +76,32 @@ func (r *ReadableRecord) ToRecordObj() (Record, error) {
|
||||
resourceObj.ExpiryTime = r.ExpiryTime
|
||||
resourceObj.Deleted = r.Deleted
|
||||
resourceObj.Owners = r.Owners
|
||||
resourceObj.Attributes = attributes
|
||||
resourceObj.Attributes = helpers.MustMarshalJSON(r.Attributes)
|
||||
|
||||
return resourceObj, nil
|
||||
}
|
||||
|
||||
// ToReadableRecord converts Record to a serializable object
|
||||
func (r *Record) ToReadableRecord() RecordEncodable {
|
||||
var resourceObj RecordEncodable
|
||||
|
||||
resourceObj.ID = r.Id
|
||||
resourceObj.BondID = r.BondId
|
||||
resourceObj.CreateTime = r.CreateTime
|
||||
resourceObj.ExpiryTime = r.ExpiryTime
|
||||
resourceObj.Deleted = r.Deleted
|
||||
resourceObj.Owners = r.Owners
|
||||
resourceObj.Names = r.Names
|
||||
resourceObj.Attributes = helpers.MustUnmarshalJSON[AttributeMap](r.Attributes)
|
||||
|
||||
return resourceObj
|
||||
}
|
||||
|
||||
// CanonicalJSON returns the canonical JSON representation of the record.
|
||||
func (r *ReadableRecord) CanonicalJSON() []byte {
|
||||
bytes, err := canonicalJson.Marshal(r.Attributes)
|
||||
bytes, err := canonicaljson.Marshal(r.Attributes)
|
||||
if err != nil {
|
||||
panic("Record marshal error: " + err.Error())
|
||||
panic("error marshalling record: " + err.Error())
|
||||
}
|
||||
|
||||
return bytes
|
||||
|
Loading…
Reference in New Issue
Block a user