Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Word256 integer type #2510

Merged
merged 1 commit into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions encoding/ccf/ccf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2561,6 +2561,102 @@ func TestDecodeWord128Invalid(t *testing.T) {
assert.Equal(t, "ccf: failed to decode: failed to decode Word128: cbor: cannot decode CBOR tag type to big.Int", err.Error())
}

func TestEncodeWord256(t *testing.T) {

t.Parallel()

testAllEncodeAndDecode(t, []encodeTest{
{
name: "Zero",
val: cadence.NewWord256(0),
expected: []byte{
// language=json, format=json-cdc
// {"type":"Word256","value":"0"}
//
// language=edn, format=ccf
// 130([137(53), 0])
//
// language=cbor, format=ccf
// tag
0xd8, ccf.CBORTagTypeAndValue,
// array, 2 items follow
0x82,
// tag
0xd8, ccf.CBORTagSimpleType,
// Word256 type ID (53)
0x18, 0x35,
// tag (big num)
0xc2,
// bytes, 0 bytes follow
0x40,
},
},
{
name: "Max",
val: cadence.Word256{Value: sema.Word256TypeMaxIntBig},
expected: []byte{
// language=json, format=json-cdc
// {"type":"Word256","value":"115792089237316195423570985008687907853269984665640564039457584007913129639935"}
//
// language=edn, format=ccf
// 130([137(53), 115792089237316195423570985008687907853269984665640564039457584007913129639935])
//
// language=cbor, format=ccf
// tag
0xd8, ccf.CBORTagTypeAndValue,
// array, 2 items follow
0x82,
// tag
0xd8, ccf.CBORTagSimpleType,
// Word256 type ID (53)
0x18, 0x35,
// tag (big num)
0xc2,
// bytes, 32 bytes follow
0x58, 0x20,
// 115792089237316195423570985008687907853269984665640564039457584007913129639935
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
},
}...)
}

func TestDecodeWord256Invalid(t *testing.T) {
t.Parallel()

_, err := ccf.Decode(nil, []byte{
// language=json, format=json-cdc
// {"type":"Word256","value":"115792089237316195423570985008687907853269984665640564039457584007913129639935"}
//
// language=edn, format=ccf
// 130([137(53), 0])
//
// language=cbor, format=ccf
// tag
0xd8, ccf.CBORTagTypeAndValue,
// array, 2 items follow
0x82,
// tag
0xd8, ccf.CBORTagSimpleType,
// Word256 type ID (53)
0x18, 0x35,
// Invalid type
0xd7,
// bytes, 32 bytes follow
0x58, 0x20,
// 115792089237316195423570985008687907853269984665640564039457584007913129639935
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
})
require.Error(t, err)
assert.Equal(t, "ccf: failed to decode: failed to decode Word256: cbor: cannot decode CBOR tag type to big.Int", err.Error())
}

func TestEncodeFix64(t *testing.T) {

t.Parallel()
Expand Down Expand Up @@ -7682,6 +7778,7 @@ func TestEncodeSimpleTypes(t *testing.T) {
{cadence.Word32Type{}, ccf.TypeWord32},
{cadence.Word64Type{}, ccf.TypeWord64},
{cadence.Word128Type{}, ccf.TypeWord128},
{cadence.Word256Type{}, ccf.TypeWord256},
{cadence.Fix64Type{}, ccf.TypeFix64},
{cadence.UFix64Type{}, ccf.TypeUFix64},
{cadence.BlockType{}, ccf.TypeBlock},
Expand Down
21 changes: 21 additions & 0 deletions encoding/ccf/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ func (d *Decoder) decodeTypeAndValue(types *cadenceTypeByCCFTypeID) (cadence.Val
// / word32-value
// / word64-value
// / word128-value
// / word256-value
// / fix64-value
// / ufix64-value
func (d *Decoder) decodeValue(t cadence.Type, types *cadenceTypeByCCFTypeID) (cadence.Value, error) {
Expand Down Expand Up @@ -356,6 +357,9 @@ func (d *Decoder) decodeValue(t cadence.Type, types *cadenceTypeByCCFTypeID) (ca
case cadence.Word128Type:
return d.decodeWord128()

case cadence.Word256Type:
return d.decodeWord256()

case cadence.Fix64Type:
return d.decodeFix64()

Expand Down Expand Up @@ -819,6 +823,23 @@ func (d *Decoder) decodeWord128() (cadence.Value, error) {
)
}

// decodeWord256 decodes word256-value as
// language=CDDL
// word256-value = bigint .ge 0
func (d *Decoder) decodeWord256() (cadence.Value, error) {
// NewMeteredWord256FromBig checks if decoded big.Int is positive.
return cadence.NewMeteredWord256FromBig(
d.gauge,
func() *big.Int {
bigInt, err := d.dec.DecodeBigInt()
if err != nil {
panic(fmt.Errorf("failed to decode Word256: %s", err))
}
return bigInt
},
)
}

// decodeFix64 decodes fix64-value as
// language=CDDL
// fix64-value = (int .ge -9223372036854775808) .le 9223372036854775807
Expand Down
3 changes: 3 additions & 0 deletions encoding/ccf/decode_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ func (d *Decoder) decodeSimpleTypeID() (cadence.Type, error) {
case TypeWord128:
return cadence.TheWord128Type, nil

case TypeWord256:
return cadence.TheWord256Type, nil

case TypeFix64:
return cadence.TheFix64Type, nil

Expand Down
11 changes: 11 additions & 0 deletions encoding/ccf/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ func (e *Encoder) encodeTypeDefs(types []cadence.Type, tids ccfTypeIDByCadenceTy
// / word32-value
// / word64-value
// / word128-value
// / word256-value
// / fix64-value
// / ufix64-value
//
Expand Down Expand Up @@ -451,6 +452,9 @@ func (e *Encoder) encodeValue(
case cadence.Word128:
return e.encodeWord128(v)

case cadence.Word256:
return e.encodeWord256(v)

case cadence.Fix64:
return e.encodeFix64(v)

Expand Down Expand Up @@ -701,6 +705,13 @@ func (e *Encoder) encodeWord128(v cadence.Word128) error {
return e.enc.EncodeBigInt(v.Big())
}

// encodeWord256 encodes cadence.Word256 as
// language=CDDL
// word256-value = uint .ge 0
func (e *Encoder) encodeWord256(v cadence.Word256) error {
return e.enc.EncodeBigInt(v.Big())
}

// encodeFix64 encodes cadence.Fix64 as
// language=CDDL
// fix64-value = (int .ge -9223372036854775808) .le 9223372036854775807
Expand Down
4 changes: 4 additions & 0 deletions encoding/ccf/simple_type_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const ( // Cadence simple type IDs
TypeVoid
TypeFunction
TypeWord128
TypeWord256
)

// NOTE: cadence.FunctionType isn't included in simpleTypeIDByType
Expand Down Expand Up @@ -198,6 +199,9 @@ func simpleTypeIDByType(typ cadence.Type) (uint64, bool) {
case cadence.Word128Type:
return TypeWord128, true

case cadence.Word256Type:
return TypeWord256, true

case cadence.Fix64Type:
return TypeFix64, true

Expand Down
1 change: 1 addition & 0 deletions encoding/ccf/traverse_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func (ct *compositeTypes) traverseType(typ cadence.Type) (checkRuntimeType bool)
cadence.Word32Type,
cadence.Word64Type,
cadence.Word128Type,
cadence.Word256Type,
cadence.Fix64Type,
cadence.UFix64Type,
cadence.PathType,
Expand Down
22 changes: 22 additions & 0 deletions encoding/json/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ func (d *Decoder) decodeJSON(v any) cadence.Value {
return d.decodeWord64(valueJSON)
case word128TypeStr:
return d.decodeWord128(valueJSON)
case word256TypeStr:
return d.decodeWord256(valueJSON)
case fix64TypeStr:
return d.decodeFix64(valueJSON)
case ufix64TypeStr:
Expand Down Expand Up @@ -585,6 +587,24 @@ func (d *Decoder) decodeWord128(valueJSON any) cadence.Word128 {
return value
}

func (d *Decoder) decodeWord256(valueJSON any) cadence.Word256 {
value, err := cadence.NewMeteredWord256FromBig(
d.gauge,
func() *big.Int {
bigInt := d.decodeBigInt(valueJSON)
if bigInt == nil {
// TODO: propagate toString error from decodeBigInt
panic(errors.NewDefaultUserError("invalid Word256: %s", valueJSON))
}
return bigInt
},
)
if err != nil {
panic(errors.NewDefaultUserError("invalid Word256: %w", err))
}
return value
}

func (d *Decoder) decodeFix64(valueJSON any) cadence.Fix64 {
v, err := cadence.NewMeteredFix64(d.gauge, func() (string, error) {
return toString(valueJSON), nil
Expand Down Expand Up @@ -1235,6 +1255,8 @@ func (d *Decoder) decodeType(valueJSON any, results typeDecodingResults) cadence
return cadence.TheWord64Type
case "Word128":
return cadence.TheWord128Type
case "Word256":
return cadence.TheWord256Type
case "Fix64":
return cadence.TheFix64Type
case "UFix64":
Expand Down
11 changes: 11 additions & 0 deletions encoding/json/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ const (
word32TypeStr = "Word32"
word64TypeStr = "Word64"
word128TypeStr = "Word128"
word256TypeStr = "Word256"
fix64TypeStr = "Fix64"
ufix64TypeStr = "UFix64"
arrayTypeStr = "Array"
Expand Down Expand Up @@ -317,6 +318,8 @@ func Prepare(v cadence.Value) jsonValue {
return prepareWord64(v)
case cadence.Word128:
return prepareWord128(v)
case cadence.Word256:
return prepareWord256(v)
case cadence.Fix64:
return prepareFix64(v)
case cadence.UFix64:
Expand Down Expand Up @@ -532,6 +535,13 @@ func prepareWord128(v cadence.Word128) jsonValue {
}
}

func prepareWord256(v cadence.Word256) jsonValue {
return jsonValueObject{
Type: word256TypeStr,
Value: encodeBig(v.Big()),
}
}

func prepareFix64(v cadence.Fix64) jsonValue {
return jsonValueObject{
Type: fix64TypeStr,
Expand Down Expand Up @@ -769,6 +779,7 @@ func prepareType(typ cadence.Type, results typePreparationResults) jsonValue {
cadence.Word32Type,
cadence.Word64Type,
cadence.Word128Type,
cadence.Word256Type,
cadence.Fix64Type,
cadence.UFix64Type,
cadence.BlockType,
Expand Down
21 changes: 21 additions & 0 deletions encoding/json/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,26 @@ func TestEncodeWord128(t *testing.T) {
}...)
}

func TestEncodeWord256(t *testing.T) {

t.Parallel()

testAllEncodeAndDecode(t, []encodeTest{
{
"Zero",
cadence.NewWord256(0),
// language=json
`{"type":"Word256","value":"0"}`,
},
{
"Max",
cadence.Word256{Value: sema.Word256TypeMaxIntBig},
// language=json
`{"type":"Word256","value":"115792089237316195423570985008687907853269984665640564039457584007913129639935"}`,
},
}...)
}

func TestEncodeFix64(t *testing.T) {

t.Parallel()
Expand Down Expand Up @@ -1757,6 +1777,7 @@ func TestEncodeSimpleTypes(t *testing.T) {
cadence.Word32Type{},
cadence.Word64Type{},
cadence.Word128Type{},
cadence.Word256Type{},
cadence.Fix64Type{},
cadence.UFix64Type{},
cadence.BlockType{},
Expand Down
4 changes: 4 additions & 0 deletions runtime/convertTypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ func ExportMeteredType(
return cadence.TheWord64Type
case sema.Word128Type:
return cadence.TheWord128Type
case sema.Word256Type:
return cadence.TheWord256Type
case sema.Fix64Type:
return cadence.TheFix64Type
case sema.UFix64Type:
Expand Down Expand Up @@ -606,6 +608,8 @@ func ImportType(memoryGauge common.MemoryGauge, t cadence.Type) interpreter.Stat
return interpreter.NewPrimitiveStaticType(memoryGauge, interpreter.PrimitiveStaticTypeWord64)
case cadence.Word128Type:
return interpreter.NewPrimitiveStaticType(memoryGauge, interpreter.PrimitiveStaticTypeWord128)
case cadence.Word256Type:
return interpreter.NewPrimitiveStaticType(memoryGauge, interpreter.PrimitiveStaticTypeWord256)
case cadence.Fix64Type:
return interpreter.NewPrimitiveStaticType(memoryGauge, interpreter.PrimitiveStaticTypeFix64)
case cadence.UFix64Type:
Expand Down
18 changes: 18 additions & 0 deletions runtime/convertValues.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ func exportValueWithInterpreter(
return v.ToBigInt(inter)
},
)
case interpreter.Word256Value:
return cadence.NewMeteredWord256FromBig(
inter,
func() *big.Int {
return v.ToBigInt(inter)
},
)
case interpreter.Fix64Value:
return cadence.Fix64(v), nil
case interpreter.UFix64Value:
Expand Down Expand Up @@ -802,6 +809,8 @@ func (i valueImporter) importValue(value cadence.Value, expectedType sema.Type)
return i.importWord64(v), nil
case cadence.Word128:
return i.importWord128(v), nil
case cadence.Word256:
return i.importWord256(v), nil
case cadence.Fix64:
return i.importFix64(v), nil
case cadence.UFix64:
Expand Down Expand Up @@ -1051,6 +1060,15 @@ func (i valueImporter) importWord128(v cadence.Word128) interpreter.Word128Value
)
}

func (i valueImporter) importWord256(v cadence.Word256) interpreter.Word256Value {
return interpreter.NewWord256ValueFromBigInt(
i.inter,
func() *big.Int {
return v.Value
},
)
}

func (i valueImporter) importFix64(v cadence.Fix64) interpreter.Fix64Value {
return interpreter.NewFix64Value(
i.inter,
Expand Down
Loading