2024-02-16 06:40:42 +00:00
|
|
|
package registry
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha256"
|
|
|
|
|
|
|
|
"github.com/gibson042/canonicaljson-go"
|
|
|
|
|
2024-04-01 09:57:26 +00:00
|
|
|
"git.vdb.to/cerc-io/laconicd/x/registry/helpers"
|
2024-02-16 06:40:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
AuthorityActive = "active"
|
|
|
|
AuthorityExpired = "expired"
|
|
|
|
AuthorityUnderAuction = "auction"
|
|
|
|
)
|
|
|
|
|
|
|
|
// TODO if schema records are to be more permissive than allowing a map of fields, this type will
|
|
|
|
// become specific to content records. schema records will either occupy a new message or have new
|
|
|
|
// more general purpose helper types.
|
|
|
|
|
|
|
|
type AttributeMap map[string]interface{}
|
|
|
|
|
|
|
|
// ReadablePayload represents a signed record payload that can be serialized from/to YAML.
|
|
|
|
type ReadablePayload struct {
|
|
|
|
RecordAttributes AttributeMap `json:"record" yaml:"record"`
|
|
|
|
Signatures []Signature `json:"signatures" yaml:"signatures"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadableRecord represents a WNS record.
|
|
|
|
type ReadableRecord struct {
|
|
|
|
Id string `json:"id,omitempty"`
|
|
|
|
Names []string `json:"names,omitempty"`
|
|
|
|
BondId string `json:"bond_id,omitempty"`
|
|
|
|
CreateTime string `json:"create_time,omitempty"`
|
|
|
|
ExpiryTime string `json:"expiry_time,omitempty"`
|
|
|
|
Deleted bool `json:"deleted,omitempty"`
|
|
|
|
Owners []string `json:"owners,omitempty"`
|
|
|
|
Attributes AttributeMap `json:"attributes,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToPayload converts PayloadEncodable to Payload object.
|
|
|
|
// Why? Because go-amino can't handle maps: https://github.com/tendermint/go-amino/issues/4.
|
|
|
|
func (payloadObj *ReadablePayload) ToPayload() Payload {
|
|
|
|
// Note: record directly contains the attributes here
|
|
|
|
attributes := payloadObj.RecordAttributes
|
|
|
|
payload := Payload{
|
|
|
|
Record: &Record{
|
|
|
|
Deleted: false,
|
|
|
|
Owners: nil,
|
|
|
|
Attributes: helpers.MustMarshalJSON(attributes),
|
|
|
|
},
|
|
|
|
Signatures: payloadObj.Signatures,
|
|
|
|
}
|
|
|
|
return payload
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToReadablePayload converts Payload to a serializable object
|
|
|
|
func (payload Payload) ToReadablePayload() ReadablePayload {
|
|
|
|
var encodable ReadablePayload
|
|
|
|
|
|
|
|
encodable.RecordAttributes = helpers.MustUnmarshalJSON[AttributeMap](payload.Record.Attributes)
|
|
|
|
encodable.Signatures = payload.Signatures
|
|
|
|
|
|
|
|
return encodable
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
var resourceObj Record
|
|
|
|
|
|
|
|
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.Attributes = helpers.MustMarshalJSON(r.Attributes)
|
|
|
|
|
|
|
|
return resourceObj, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.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)
|
|
|
|
if err != nil {
|
|
|
|
panic("error marshaling record: " + err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSignBytes generates a record hash to be signed.
|
|
|
|
func (r *ReadableRecord) GetSignBytes() ([]byte, []byte) {
|
|
|
|
// Double SHA256 hash.
|
|
|
|
|
|
|
|
// Input to the first round of hashing.
|
|
|
|
bytes := r.CanonicalJSON()
|
|
|
|
|
|
|
|
// First round.
|
|
|
|
first := sha256.New()
|
|
|
|
first.Write(bytes)
|
|
|
|
firstHash := first.Sum(nil)
|
|
|
|
|
|
|
|
// Second round of hashing takes as input the output of the first round.
|
|
|
|
second := sha256.New()
|
|
|
|
second.Write(firstHash)
|
|
|
|
secondHash := second.Sum(nil)
|
|
|
|
|
|
|
|
return secondHash, bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCid gets the record CID.
|
|
|
|
func (r *ReadableRecord) GetCid() (string, error) {
|
|
|
|
id, err := helpers.GetCid(r.CanonicalJSON())
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return id, nil
|
|
|
|
}
|