Skip to content

Commit

Permalink
add support for exporting, encoding, and decoding capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Sep 28, 2020
1 parent ebadd6d commit 8ea5185
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 38 deletions.
27 changes: 26 additions & 1 deletion encoding/json/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ const (
domainKey = "domain"
identifierKey = "identifier"
staticTypeKey = "staticType"
addressKey = "address"
pathKey = "path"
)

var ErrInvalidJSONCadence = errors.New("invalid JSON Cadence structure")
Expand Down Expand Up @@ -193,6 +195,8 @@ func decodeJSON(v interface{}) cadence.Value {
return decodePath(valueJSON)
case typeTypeStr:
return decodeTypeValue(valueJSON)
case capabilityTypeStr:
return decodeCapability(valueJSON)
}

panic(ErrInvalidJSONCadence)
Expand Down Expand Up @@ -582,8 +586,13 @@ func decodeStorageReference(valueJSON interface{}) cadence.StorageReference {
func decodeLink(valueJSON interface{}) cadence.Link {
obj := toObject(valueJSON)

targetPath, ok := decodeJSON(obj.Get(targetPathKey)).(cadence.Path)
if !ok {
// TODO: improve error message
panic(ErrInvalidJSONCadence)
}
return cadence.NewLink(
obj.GetString(targetPathKey),
targetPath,
obj.GetString(borrowTypeKey),
)
}
Expand All @@ -605,6 +614,22 @@ func decodeTypeValue(valueJSON interface{}) cadence.TypeValue {
}
}

func decodeCapability(valueJSON interface{}) cadence.Capability {
obj := toObject(valueJSON)

path, ok := decodeJSON(obj.Get(pathKey)).(cadence.Path)
if !ok {
// TODO: improve error message
panic(ErrInvalidJSONCadence)
}

return cadence.Capability{
Path: path,
Address: decodeAddress(obj.Get(addressKey)),
BorrowType: obj.GetString(borrowTypeKey),
}
}

// JSON types

type jsonObject map[string]interface{}
Expand Down
26 changes: 23 additions & 3 deletions encoding/json/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ type jsonStorageReferenceValue struct {
}

type jsonLinkValue struct {
TargetPath string `json:"targetPath"`
BorrowType string `json:"borrowType"`
TargetPath jsonValue `json:"targetPath"`
BorrowType string `json:"borrowType"`
}

type jsonPathValue struct {
Expand All @@ -145,6 +145,12 @@ type jsonTypeValue struct {
StaticType string `json:"staticType"`
}

type jsonCapabilityValue struct {
Path jsonValue `json:"path"`
Address string `json:"address"`
BorrowType string `json:"borrowType"`
}

const (
voidTypeStr = "Void"
optionalTypeStr = "Optional"
Expand Down Expand Up @@ -181,6 +187,7 @@ const (
linkTypeStr = "Link"
pathTypeStr = "Path"
typeTypeStr = "Type"
capabilityTypeStr = "Capability"
)

// prepare traverses the object graph of the provided value and constructs
Expand Down Expand Up @@ -257,6 +264,8 @@ func (e *Encoder) prepare(v cadence.Value) jsonValue {
return e.preparePath(x)
case cadence.TypeValue:
return e.prepareTypeValue(x)
case cadence.Capability:
return e.prepareCapability(x)
default:
panic(fmt.Errorf("unsupported value: %T, %v", v, v))
}
Expand Down Expand Up @@ -538,7 +547,7 @@ func (e *Encoder) prepareLink(x cadence.Link) jsonValue {
return jsonValueObject{
Type: linkTypeStr,
Value: jsonLinkValue{
TargetPath: x.TargetPath,
TargetPath: e.preparePath(x.TargetPath),
BorrowType: x.BorrowType,
},
}
Expand All @@ -563,6 +572,17 @@ func (e *Encoder) prepareTypeValue(x cadence.TypeValue) jsonValue {
}
}

func (e *Encoder) prepareCapability(x cadence.Capability) jsonValue {
return jsonValueObject{
Type: capabilityTypeStr,
Value: jsonCapabilityValue{
Path: e.preparePath(x.Path),
Address: encodeBytes(x.Address.Bytes()),
BorrowType: x.BorrowType,
},
}
}

func encodeBytes(v []byte) string {
return fmt.Sprintf("0x%x", v)
}
Expand Down
34 changes: 25 additions & 9 deletions encoding/json/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,8 +978,11 @@ func TestEncodeLink(t *testing.T) {

testEncodeAndDecode(
t,
cadence.NewLink("/storage/foo", "Bar"),
`{"type":"Link","value":{"targetPath":"/storage/foo","borrowType":"Bar"}}`,
cadence.NewLink(
cadence.Path{Domain: "storage", Identifier: "foo"},
"Bar",
),
`{"type":"Link","value":{"targetPath":{"type":"Path","value":{"domain":"storage","identifier":"foo"}},"borrowType":"Bar"}}`,
)
}

Expand All @@ -996,6 +999,21 @@ func TestEncodeType(t *testing.T) {
)
}

func TestEncodeCapability(t *testing.T) {

t.Parallel()

testEncodeAndDecode(
t,
cadence.Capability{
Path: cadence.Path{Domain: "storage", Identifier: "foo"},
Address: cadence.BytesToAddress([]byte{1, 2, 3, 4, 5}),
BorrowType: "Int",
},
`{"type":"Capability","value":{"path":{"type":"Path","value":{"domain":"storage","identifier":"foo"}},"borrowType":"Int","address":"0x0000000102030405"}}`,
)
}

func TestDecodeFixedPoints(t *testing.T) {

t.Parallel()
Expand Down Expand Up @@ -1251,13 +1269,11 @@ func TestEncodePath(t *testing.T) {

t.Parallel()

testAllEncodeAndDecode(t, []encodeTest{
{
"Simple",
cadence.Path{Domain: "storage", Identifier: "foo"},
`{"type":"Path","value":{"domain":"storage","identifier":"foo"}}`,
},
}...)
testEncodeAndDecode(
t,
cadence.Path{Domain: "storage", Identifier: "foo"},
`{"type":"Path","value":{"domain":"storage","identifier":"foo"}}`,
)
}

func convertValueFromScript(t *testing.T, script string) cadence.Value {
Expand Down
55 changes: 32 additions & 23 deletions runtime/convertValues.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ func exportValueWithInterpreter(value interpreter.Value, inter *interpreter.Inte
return exportPathValue(v)
case interpreter.TypeValue:
return exportTypeValue(v, inter)
case interpreter.CapabilityValue:
return exportCapabilityValue(v, inter)
}

panic(fmt.Sprintf("cannot export value of type %T", value))
}

func exportSomeValue(v *interpreter.SomeValue, inter *interpreter.Interpreter) cadence.Value {
func exportSomeValue(v *interpreter.SomeValue, inter *interpreter.Interpreter) cadence.Optional {
if v.Value == nil {
return cadence.NewOptional(nil)
}
Expand All @@ -129,7 +131,7 @@ func exportSomeValue(v *interpreter.SomeValue, inter *interpreter.Interpreter) c
return cadence.NewOptional(value)
}

func exportArrayValue(v *interpreter.ArrayValue, inter *interpreter.Interpreter) cadence.Value {
func exportArrayValue(v *interpreter.ArrayValue, inter *interpreter.Interpreter) cadence.Array {
values := make([]cadence.Value, len(v.Values))

for i, value := range v.Values {
Expand Down Expand Up @@ -183,7 +185,7 @@ func exportCompositeValue(v *interpreter.CompositeValue, inter *interpreter.Inte
))
}

func exportDictionaryValue(v *interpreter.DictionaryValue, inter *interpreter.Interpreter) cadence.Value {
func exportDictionaryValue(v *interpreter.DictionaryValue, inter *interpreter.Interpreter) cadence.Dictionary {
pairs := make([]cadence.KeyValuePair, v.Count())

for i, keyValue := range v.Keys.Values {
Expand All @@ -205,20 +207,41 @@ func exportDictionaryValue(v *interpreter.DictionaryValue, inter *interpreter.In
return cadence.NewDictionary(pairs)
}

func exportStorageReferenceValue(v *interpreter.StorageReferenceValue) cadence.Value {
func exportStorageReferenceValue(v *interpreter.StorageReferenceValue) cadence.StorageReference {
return cadence.NewStorageReference(
v.Authorized,
cadence.NewAddress(v.TargetStorageAddress),
v.TargetKey,
)
}

func exportLinkValue(v interpreter.LinkValue, inter *interpreter.Interpreter) cadence.Value {
func exportLinkValue(v interpreter.LinkValue, inter *interpreter.Interpreter) cadence.Link {
path := exportPathValue(v.TargetPath)
ty := inter.ConvertStaticToSemaType(v.Type).QualifiedString()
return cadence.NewLink(
v.TargetPath.String(),
ty,
)
return cadence.NewLink(path, ty)
}

func exportPathValue(v interpreter.PathValue) cadence.Path {
return cadence.Path{
Domain: v.Domain.Name(),
Identifier: v.Identifier,
}
}

func exportTypeValue(v interpreter.TypeValue, inter *interpreter.Interpreter) cadence.TypeValue {
ty := inter.ConvertStaticToSemaType(v.Type).QualifiedString()
return cadence.TypeValue{
StaticType: ty,
}
}

func exportCapabilityValue(v interpreter.CapabilityValue, inter *interpreter.Interpreter) cadence.Capability {
borrowType := inter.ConvertStaticToSemaType(v.BorrowType).QualifiedString()
return cadence.Capability{
Path: exportPathValue(v.Path),
Address: cadence.NewAddress(v.Address),
BorrowType: borrowType,
}
}

// importValue converts a Cadence value to a runtime value.
Expand Down Expand Up @@ -353,17 +376,3 @@ func importCompositeValue(
nil,
)
}

func exportPathValue(v interpreter.PathValue) cadence.Value {
return cadence.Path{
Domain: v.Domain.Name(),
Identifier: v.Identifier,
}
}

func exportTypeValue(v interpreter.TypeValue, inter *interpreter.Interpreter) cadence.Value {
ty := inter.ConvertStaticToSemaType(v.Type).QualifiedString()
return cadence.TypeValue{
StaticType: ty,
}
}
25 changes: 25 additions & 0 deletions runtime/convertValues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,31 @@ func TestExportTypeValue(t *testing.T) {
assert.Equal(t, expected, actual)
}

func TestExportCapabilityValue(t *testing.T) {

t.Parallel()

capability := interpreter.CapabilityValue{
Address: interpreter.AddressValue{0x1},
Path: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: "foo",
},
BorrowType: interpreter.PrimitiveStaticTypeInt,
}
actual := exportValueWithInterpreter(capability, nil)
expected := cadence.Capability{
Path: cadence.Path{
Domain: "storage",
Identifier: "foo",
},
Address: cadence.Address{0x1},
BorrowType: "Int",
}

assert.Equal(t, expected, actual)
}

const fooID = "Foo"

var fooTypeID = fmt.Sprintf("S.%s.%s", utils.TestLocation, fooID)
Expand Down
23 changes: 21 additions & 2 deletions values.go
Original file line number Diff line number Diff line change
Expand Up @@ -962,12 +962,12 @@ func (v Contract) ToGoValue() interface{} {
// Link

type Link struct {
TargetPath string
TargetPath Path
// TODO: a future version might want to export the whole type
BorrowType string
}

func NewLink(targetPath string, borrowType string) Link {
func NewLink(targetPath Path, borrowType string) Link {
return Link{
TargetPath: targetPath,
BorrowType: borrowType,
Expand Down Expand Up @@ -1043,3 +1043,22 @@ func (TypeValue) Type() Type {
func (TypeValue) ToGoValue() interface{} {
return nil
}

// Capability

type Capability struct {
Path Path
Address Address
// TODO: a future version might want to export the whole type
BorrowType string
}

func (Capability) isValue() {}

func (Capability) Type() Type {
return CapabilityType{}
}

func (Capability) ToGoValue() interface{} {
return nil
}

0 comments on commit 8ea5185

Please sign in to comment.