From 6c920ee79f19355437659b87a2d10da1b21ef62a Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Fri, 3 Dec 2021 19:31:07 -0600 Subject: [PATCH 1/4] Optimize HashInput() to use scratch buffer --- runtime/interpreter/value.go | 286 ++++++++++++++++++++++++++++------- 1 file changed, 228 insertions(+), 58 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 60fd4fcde1..acd13432fa 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -338,13 +338,23 @@ func (TypeValue) ChildStorables() []atree.Storable { return nil } +// HashInput returns a byte slice containing: +// - HashInputTypeType (1 byte) +// - type id (n bytes) func (v TypeValue) HashInput(interpreter *Interpreter, _ func() LocationRange, scratch []byte) []byte { typeID := interpreter.MustConvertStaticToSemaType(v.Type).ID() - return append( - []byte{byte(HashInputTypeType)}, - typeID..., - ) + length := 1 + len(typeID) + var buf []byte + if length <= len(scratch) { + buf = scratch[:length] + } else { + buf = make([]byte, length) + } + + buf[0] = byte(HashInputTypeType) + copy(buf[1:], []byte(typeID)) + return buf } // VoidValue @@ -484,6 +494,9 @@ func (v BoolValue) Equal(_ *Interpreter, _ func() LocationRange, other Value) bo return bool(v) == bool(otherBool) } +// HashInput returns a byte slice containing: +// - HashInputTypeBool (1 byte) +// - 1/0 (1 byte) func (v BoolValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeBool) if v { @@ -628,11 +641,21 @@ func (v *StringValue) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v.NormalForm() == otherString.NormalForm() } -func (v *StringValue) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - return append( - []byte{byte(HashInputTypeString)}, - v.Str..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeString (1 byte) +// - string value (n bytes) +func (v *StringValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + length := 1 + len(v.Str) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeString) + copy(buffer[1:], []byte(v.Str)) + return buffer } func (v *StringValue) NormalForm() string { @@ -1934,12 +1957,23 @@ func (v IntValue) Equal(_ *Interpreter, _ func() LocationRange, other Value) boo return cmp == 0 } -func (v IntValue) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - // TODO: optimize? - return append( - []byte{byte(HashInputTypeInt)}, - SignedBigIntToBigEndianBytes(v.BigInt)..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeInt (1 byte) +// - big int encoded in big-endian (n bytes) +func (v IntValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + b := SignedBigIntToBigEndianBytes(v.BigInt) + + length := 1 + len(b) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeInt) + copy(buffer[1:], b) + return buffer } func (v IntValue) BitwiseOr(other IntegerValue) IntegerValue { @@ -2277,6 +2311,9 @@ func (v Int8Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) bo return v == otherInt8 } +// HashInput returns a byte slice containing: +// - HashInputTypeInt8 (1 byte) +// - int8 value (1 byte) func (v Int8Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeInt8) scratch[1] = byte(v) @@ -2625,6 +2662,9 @@ func (v Int16Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) b return v == otherInt16 } +// HashInput returns a byte slice containing: +// - HashInputTypeInt16 (1 byte) +// - int16 value encoded in big-endian (2 bytes) func (v Int16Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeInt16) binary.BigEndian.PutUint16(scratch[1:], uint16(v)) @@ -2975,6 +3015,9 @@ func (v Int32Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) b return v == otherInt32 } +// HashInput returns a byte slice containing: +// - HashInputTypeInt32 (1 byte) +// - int32 value encoded in big-endian (4 bytes) func (v Int32Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeInt32) binary.BigEndian.PutUint32(scratch[1:], uint32(v)) @@ -3329,6 +3372,9 @@ func (v Int64Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) b return v == otherInt64 } +// HashInput returns a byte slice containing: +// - HashInputTypeInt64 (1 byte) +// - int64 value encoded in big-endian (8 bytes) func (v Int64Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeInt64) binary.BigEndian.PutUint64(scratch[1:], uint64(v)) @@ -3731,12 +3777,23 @@ func (v Int128Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return cmp == 0 } -func (v Int128Value) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - // TODO: optimize? - return append( - []byte{byte(HashInputTypeInt128)}, - SignedBigIntToBigEndianBytes(v.BigInt)..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeInt128 (1 byte) +// - big int value encoded in big-endian (n bytes) +func (v Int128Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + b := SignedBigIntToBigEndianBytes(v.BigInt) + + length := 1 + len(b) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeInt128) + copy(buffer[1:], b) + return buffer } func ConvertInt128(value Value) Int128Value { @@ -4155,12 +4212,23 @@ func (v Int256Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return cmp == 0 } -func (v Int256Value) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - // TODO: optimize? - return append( - []byte{byte(HashInputTypeInt256)}, - SignedBigIntToBigEndianBytes(v.BigInt)..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeInt256 (1 byte) +// - big int value encoded in big-endian (n bytes) +func (v Int256Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + b := SignedBigIntToBigEndianBytes(v.BigInt) + + length := 1 + len(b) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeInt256) + copy(buffer[1:], b) + return buffer } func ConvertInt256(value Value) Int256Value { @@ -4492,12 +4560,23 @@ func (v UIntValue) Equal(_ *Interpreter, _ func() LocationRange, other Value) bo return cmp == 0 } -func (v UIntValue) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - // TODO: optimize? - return append( - []byte{byte(HashInputTypeUInt)}, - UnsignedBigIntToBigEndianBytes(v.BigInt)..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeUInt (1 byte) +// - big int value encoded in big-endian (n bytes) +func (v UIntValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + b := UnsignedBigIntToBigEndianBytes(v.BigInt) + + length := 1 + len(b) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeUInt) + copy(buffer[1:], b) + return buffer } func (v UIntValue) BitwiseOr(other IntegerValue) IntegerValue { @@ -4767,6 +4846,9 @@ func (v UInt8Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) b return v == otherUInt8 } +// HashInput returns a byte slice containing: +// - HashInputTypeUInt8 (1 byte) +// - uint8 value (1 byte) func (v UInt8Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeUInt8) scratch[1] = byte(v) @@ -5045,6 +5127,9 @@ func (v UInt16Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherUInt16 } +// HashInput returns a byte slice containing: +// - HashInputTypeUInt16 (1 byte) +// - uint16 value encoded in big-endian (2 bytes) func (v UInt16Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeUInt16) binary.BigEndian.PutUint16(scratch[1:], uint16(v)) @@ -5329,6 +5414,9 @@ func (v UInt32Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherUInt32 } +// HashInput returns a byte slice containing: +// - HashInputTypeUInt32 (1 byte) +// - uint32 value encoded in big-endian (4 bytes) func (v UInt32Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeUInt32) binary.BigEndian.PutUint32(scratch[1:], uint32(v)) @@ -5639,6 +5727,9 @@ func (v UInt64Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherUInt64 } +// HashInput returns a byte slice containing: +// - HashInputTypeUInt64 (1 byte) +// - uint64 value encoded in big-endian (8 bytes) func (v UInt64Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeUInt64) binary.BigEndian.PutUint64(scratch[1:], uint64(v)) @@ -5990,12 +6081,23 @@ func (v UInt128Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return cmp == 0 } -func (v UInt128Value) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - // TODO: optimize? - return append( - []byte{byte(HashInputTypeUInt128)}, - UnsignedBigIntToBigEndianBytes(v.BigInt)..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeUInt128 (1 byte) +// - big int encoded in big endian (n bytes) +func (v UInt128Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + b := UnsignedBigIntToBigEndianBytes(v.BigInt) + + length := 1 + len(b) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeUInt128) + copy(buffer[1:], b) + return buffer } func ConvertUInt128(value Value) UInt128Value { @@ -6361,12 +6463,23 @@ func (v UInt256Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return cmp == 0 } -func (v UInt256Value) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - // TODO: optimize? - return append( - []byte{byte(HashInputTypeUInt256)}, - UnsignedBigIntToBigEndianBytes(v.BigInt)..., - ) +// HashInput returns a byte slice containing: +// - HashInputTypeUInt256 (1 byte) +// - big int encoded in big endian (n bytes) +func (v UInt256Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + b := UnsignedBigIntToBigEndianBytes(v.BigInt) + + length := 1 + len(b) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeUInt256) + copy(buffer[1:], b) + return buffer } func ConvertUInt256(value Value) UInt256Value { @@ -6632,6 +6745,9 @@ func (v Word8Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) b return v == otherWord8 } +// HashInput returns a byte slice containing: +// - HashInputTypeWord8 (1 byte) +// - uint8 value (1 byte) func (v Word8Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeWord8) scratch[1] = byte(v) @@ -6859,6 +6975,9 @@ func (v Word16Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherWord16 } +// HashInput returns a byte slice containing: +// - HashInputTypeWord16 (1 byte) +// - uint16 value encoded in big-endian (2 bytes) func (v Word16Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeWord16) binary.BigEndian.PutUint16(scratch[1:], uint16(v)) @@ -7089,6 +7208,9 @@ func (v Word32Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherWord32 } +// HashInput returns a byte slice containing: +// - HashInputTypeWord32 (1 byte) +// - uint32 value encoded in big-endian (4 bytes) func (v Word32Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeWord32) binary.BigEndian.PutUint32(scratch[1:], uint32(v)) @@ -7340,6 +7462,9 @@ func (v Word64Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherWord64 } +// HashInput returns a byte slice containing: +// - HashInputTypeWord64 (1 byte) +// - uint64 value encoded in big-endian (8 bytes) func (v Word64Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeWord64) binary.BigEndian.PutUint64(scratch[1:], uint64(v)) @@ -7665,6 +7790,9 @@ func (v Fix64Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) b return v == otherFix64 } +// HashInput returns a byte slice containing: +// - HashInputTypeFix64 (1 byte) +// - int64 value encoded in big-endian (8 bytes) func (v Fix64Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeFix64) binary.BigEndian.PutUint64(scratch[1:], uint64(v)) @@ -7955,6 +8083,9 @@ func (v UFix64Value) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherUFix64 } +// HashInput returns a byte slice containing: +// - HashInputTypeUFix64 (1 byte) +// - uint64 value encoded in big-endian (8 bytes) func (v UFix64Value) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { scratch[0] = byte(HashInputTypeUFix64) binary.BigEndian.PutUint64(scratch[1:], uint64(v)) @@ -8527,21 +8658,34 @@ func (v *CompositeValue) Equal(interpreter *Interpreter, getLocationRange func() } } +// HashInput returns a byte slice containing: +// - HashInputTypeEnum (1 byte) +// - type id (n bytes) +// - hash input of raw value field name (n bytes) func (v *CompositeValue) HashInput(interpreter *Interpreter, getLocationRange func() LocationRange, scratch []byte) []byte { if v.Kind == common.CompositeKindEnum { - enumHashInput := append( - []byte{byte(HashInputTypeEnum)}, - v.TypeID()..., - ) + typeID := v.TypeID() rawValue := v.GetField(interpreter, getLocationRange, sema.EnumRawValueFieldName) rawValueHashInput := rawValue.(HashableValue). HashInput(interpreter, getLocationRange, scratch) - return append( - enumHashInput, - rawValueHashInput..., - ) + length := 1 + len(typeID) + len(rawValueHashInput) + if length <= len(scratch) { + // Copy rawValueHashInput first because + // rawValueHashInput and scratch can point to the same underlying scratch buffer + copy(scratch[1+len(typeID):], rawValueHashInput) + + scratch[0] = byte(HashInputTypeEnum) + copy(scratch[1:], typeID) + return scratch[:length] + } + + buffer := make([]byte, length) + buffer[0] = byte(HashInputTypeEnum) + copy(buffer[1:], typeID) + copy(buffer[1+len(typeID):], rawValueHashInput) + return buffer } panic(errors.NewUnreachableError()) @@ -10838,8 +10982,21 @@ func (v AddressValue) Equal(_ *Interpreter, _ func() LocationRange, other Value) return v == otherAddress } -func (v AddressValue) HashInput(_ *Interpreter, _ func() LocationRange, _ []byte) []byte { - return append([]byte{byte(HashInputTypeAddress)}, v[:]...) +// HashInput returns a byte slice containing: +// - HashInputTypeAddress (1 byte) +// - address (8 bytes) +func (v AddressValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { + length := 1 + len(v) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypeAddress) + copy(buffer[1:], v[:]) + return buffer } func (v AddressValue) Hex() string { @@ -11104,10 +11261,23 @@ func (v PathValue) Equal(_ *Interpreter, _ func() LocationRange, other Value) bo otherPath.Domain == v.Domain } +// HashInput returns a byte slice containing: +// - HashInputTypePath (1 byte) +// - domain (1 byte) +// - identifier (n bytes) func (v PathValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch []byte) []byte { - scratch[0] = byte(HashInputTypePath) - scratch[1] = byte(v.Domain) - return append(scratch[:2], []byte(v.Identifier)...) + length := 1 + 1 + len(v.Identifier) + var buffer []byte + if length <= len(scratch) { + buffer = scratch[:length] + } else { + buffer = make([]byte, length) + } + + buffer[0] = byte(HashInputTypePath) + buffer[1] = byte(v.Domain) + copy(buffer[2:], v.Identifier) + return buffer } func (PathValue) IsStorable() bool { From f6f33e5c62363e5701883d4e80080d7bb03d9127 Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Fri, 3 Dec 2021 19:59:09 -0600 Subject: [PATCH 2/4] Fix lint error --- runtime/interpreter/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index acd13432fa..bc4e276274 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -654,7 +654,7 @@ func (v *StringValue) HashInput(_ *Interpreter, _ func() LocationRange, scratch } buffer[0] = byte(HashInputTypeString) - copy(buffer[1:], []byte(v.Str)) + copy(buffer[1:], v.Str) return buffer } From cac07b90291c202ecfe2ac38bfb5f30c3dfd095d Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Wed, 8 Dec 2021 17:53:53 -0600 Subject: [PATCH 3/4] Add more tests for HashInput functions --- runtime/interpreter/value_test.go | 212 ++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index 76d34c4585..fdae457a5c 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -21,6 +21,8 @@ package interpreter_test import ( "fmt" "go/types" + "math" + "strings" "testing" "golang.org/x/tools/go/packages" @@ -1116,82 +1118,242 @@ func TestGetHashInput(t *testing.T) { value: NewUIntValueFromUint64(10), expected: []byte{byte(HashInputTypeUInt), 10}, }, + "UInt min": { + value: NewUIntValueFromUint64(0), + expected: []byte{byte(HashInputTypeUInt), 0}, + }, + "UInt large": { + value: NewUIntValueFromBigInt(sema.UInt256TypeMaxIntBig), + expected: append([]byte{byte(HashInputTypeUInt)}, sema.UInt256TypeMaxIntBig.Bytes()...), + }, "UInt8": { value: UInt8Value(8), expected: []byte{byte(HashInputTypeUInt8), 8}, }, + "UInt8 min": { + value: UInt8Value(0), + expected: []byte{byte(HashInputTypeUInt8), 0}, + }, + "UInt8 max": { + value: UInt8Value(math.MaxUint8), + expected: []byte{byte(HashInputTypeUInt8), 0xff}, + }, "UInt16": { value: UInt16Value(16), expected: []byte{byte(HashInputTypeUInt16), 0, 16}, }, + "UInt16 min": { + value: UInt16Value(0), + expected: []byte{byte(HashInputTypeUInt16), 0, 0}, + }, + "UInt16 max": { + value: UInt16Value(math.MaxUint16), + expected: []byte{byte(HashInputTypeUInt16), 0xff, 0xf}, + }, "UInt32": { value: UInt32Value(32), expected: []byte{byte(HashInputTypeUInt32), 0, 0, 0, 32}, }, + "UInt32 min": { + value: UInt32Value(0), + expected: []byte{byte(HashInputTypeUInt32), 0, 0, 0, 0}, + }, + "UInt32 max": { + value: UInt32Value(math.MaxUint32), + expected: []byte{byte(HashInputTypeUInt32), 0xff, 0xff, 0xff, 0xff}, + }, "UInt64": { value: UInt64Value(64), expected: []byte{byte(HashInputTypeUInt64), 0, 0, 0, 0, 0, 0, 0, 64}, }, + "UInt64 min": { + value: UInt64Value(0), + expected: []byte{byte(HashInputTypeUInt64), 0, 0, 0, 0, 0, 0, 0, 0}, + }, + "UInt64 max": { + value: UInt64Value(math.MaxUint64), + expected: []byte{byte(HashInputTypeUInt64), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, "UInt128": { value: NewUInt128ValueFromUint64(128), expected: []byte{byte(HashInputTypeUInt128), 128}, }, + "UInt128 min": { + value: NewUInt128ValueFromUint64(0), + expected: append([]byte{byte(HashInputTypeUInt128)}, 0), + }, + "UInt128 max": { + value: NewUInt128ValueFromBigInt(sema.UInt128TypeMaxIntBig), + expected: append([]byte{byte(HashInputTypeUInt128)}, sema.UInt128TypeMaxIntBig.Bytes()...), + }, "UInt256": { value: NewUInt256ValueFromUint64(256), expected: []byte{byte(HashInputTypeUInt256), 1, 0}, }, + "UInt256 min": { + value: NewUInt256ValueFromUint64(0), + expected: append([]byte{byte(HashInputTypeUInt256)}, 0), + }, + "UInt256 max": { + value: NewUInt256ValueFromBigInt(sema.UInt256TypeMaxIntBig), + expected: append([]byte{byte(HashInputTypeUInt256)}, sema.UInt256TypeMaxIntBig.Bytes()...), + }, "Int": { value: NewIntValueFromInt64(10), expected: []byte{byte(HashInputTypeInt), 10}, }, + "Int small": { + value: NewIntValueFromBigInt(sema.Int256TypeMinIntBig), + expected: append([]byte{byte(HashInputTypeInt)}, sema.Int256TypeMinIntBig.Bytes()...), + }, + "Int large": { + value: NewIntValueFromBigInt(sema.Int256TypeMaxIntBig), + expected: append([]byte{byte(HashInputTypeInt)}, sema.Int256TypeMaxIntBig.Bytes()...), + }, "Int8": { value: Int8Value(-8), expected: []byte{byte(HashInputTypeInt8), 0xf8}, }, + "Int8 min": { + value: Int8Value(math.MinInt8), + expected: []byte{byte(HashInputTypeInt8), 0x80}, + }, + "Int8 max": { + value: Int8Value(math.MaxInt8), + expected: []byte{byte(HashInputTypeInt8), 0x7f}, + }, "Int16": { value: Int16Value(-16), expected: []byte{byte(HashInputTypeInt16), 0xff, 0xf0}, }, + "Int16 min": { + value: Int16Value(math.MinInt16), + expected: []byte{byte(HashInputTypeInt16), 0x80, 0x00}, + }, + "Int16 max": { + value: Int16Value(math.MaxInt16), + expected: []byte{byte(HashInputTypeInt16), 0x7f, 0xff}, + }, "Int32": { value: Int32Value(-32), expected: []byte{byte(HashInputTypeInt32), 0xff, 0xff, 0xff, 0xe0}, }, + "Int32 min": { + value: Int32Value(math.MinInt32), + expected: []byte{byte(HashInputTypeInt32), 0x80, 0x00, 0x00, 0x00}, + }, + "Int32 max": { + value: Int32Value(math.MaxInt32), + expected: []byte{byte(HashInputTypeInt32), 0x7f, 0xff, 0xff, 0xff}, + }, "Int64": { value: Int64Value(-64), expected: []byte{byte(HashInputTypeInt64), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0}, }, + "Int64 min": { + value: Int64Value(math.MinInt64), + expected: []byte{byte(HashInputTypeInt64), 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + }, + "Int64 max": { + value: Int64Value(math.MaxInt64), + expected: []byte{byte(HashInputTypeInt64), 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, "Int128": { value: NewInt128ValueFromInt64(-128), expected: []byte{byte(HashInputTypeInt128), 0x80}, }, + "Int128 min": { + value: NewInt128ValueFromBigInt(sema.Int128TypeMinIntBig), + expected: append([]byte{byte(HashInputTypeInt128)}, sema.Int128TypeMinIntBig.Bytes()...), + }, + "Int128 max": { + value: NewInt128ValueFromBigInt(sema.Int128TypeMaxIntBig), + expected: append([]byte{byte(HashInputTypeInt128)}, sema.Int128TypeMaxIntBig.Bytes()...), + }, "Int256": { value: NewInt256ValueFromInt64(-256), expected: []byte{byte(HashInputTypeInt256), 0xff, 0x0}, }, + "Int256 min": { + value: NewInt256ValueFromBigInt(sema.Int256TypeMinIntBig), + expected: append([]byte{byte(HashInputTypeInt256)}, sema.Int256TypeMinIntBig.Bytes()...), + }, + "Int256 max": { + value: NewInt256ValueFromBigInt(sema.Int256TypeMaxIntBig), + expected: append([]byte{byte(HashInputTypeInt256)}, sema.Int256TypeMaxIntBig.Bytes()...), + }, "Word8": { value: Word8Value(8), expected: []byte{byte(HashInputTypeWord8), 8}, }, + "Word8 min": { + value: Word8Value(0), + expected: []byte{byte(HashInputTypeWord8), 0}, + }, + "Word8 max": { + value: Word8Value(255), + expected: []byte{byte(HashInputTypeWord8), 0xff}, + }, "Word16": { value: Word16Value(16), expected: []byte{byte(HashInputTypeWord16), 0, 16}, }, + "Word16 min": { + value: Word16Value(0), + expected: []byte{byte(HashInputTypeWord16), 0, 0}, + }, + "Word16 max": { + value: Word16Value(math.MaxUint16), + expected: []byte{byte(HashInputTypeWord16), 0xff, 0xff}, + }, "Word32": { value: Word32Value(32), expected: []byte{byte(HashInputTypeWord32), 0, 0, 0, 32}, }, + "Word32 min": { + value: Word32Value(0), + expected: []byte{byte(HashInputTypeWord32), 0, 0, 0, 0}, + }, + "Word32 max": { + value: Word32Value(math.MaxUint32), + expected: []byte{byte(HashInputTypeWord32), 0xff, 0xff, 0xff, 0xff}, + }, "Word64": { value: Word64Value(64), expected: []byte{byte(HashInputTypeWord64), 0, 0, 0, 0, 0, 0, 0, 64}, }, + "Word64 min": { + value: Word64Value(0), + expected: []byte{byte(HashInputTypeWord64), 0, 0, 0, 0, 0, 0, 0, 0}, + }, + "Word64 max": { + value: Word64Value(math.MaxUint64), + expected: []byte{byte(HashInputTypeWord64), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, "UFix64": { value: NewUFix64ValueWithInteger(64), expected: []byte{byte(HashInputTypeUFix64), 0x0, 0x0, 0x0, 0x1, 0x7d, 0x78, 0x40, 0x0}, }, + "UFix64 min": { + value: NewUFix64ValueWithInteger(0), + expected: []byte{byte(HashInputTypeUFix64), 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + }, + "UFix64 max": { + value: NewUFix64ValueWithInteger(sema.UFix64TypeMaxInt), + expected: []byte{byte(HashInputTypeUFix64), 0xff, 0xff, 0xff, 0xff, 0xff, 0x6e, 0x41, 0x0}, + }, "Fix64": { value: NewFix64ValueWithInteger(-32), expected: []byte{byte(HashInputTypeFix64), 0xff, 0xff, 0xff, 0xff, 0x41, 0x43, 0xe0, 0x0}, }, + "Fix64 min": { + value: NewFix64ValueWithInteger(sema.Fix64TypeMinInt), + expected: []byte{byte(HashInputTypeFix64), 0x80, 0x0, 0x0, 0x0, 0x03, 0x43, 0xd0, 0x0}, + }, + "Fix64 max": { + value: NewFix64ValueWithInteger(sema.Fix64TypeMaxInt), + expected: []byte{byte(HashInputTypeFix64), 0x7f, 0xff, 0xff, 0xff, 0xfc, 0xbc, 0x30, 0x00}, + }, "true": { value: BoolValue(true), expected: []byte{byte(HashInputTypeBool), 1}, @@ -1207,6 +1369,12 @@ func TestGetHashInput(t *testing.T) { 0x46, 0x6c, 0x6f, 0x77, 0x20, 0x72, 0x69, 0x64, 0x61, 0x68, 0x21, }, }, + "String long": { + value: NewStringValue(strings.Repeat("a", 32)), + expected: append([]byte{byte(HashInputTypeString)}, + []byte(strings.Repeat("a", 32))..., + ), + }, "Address": { value: NewAddressValue(common.Address{0, 0, 0, 0, 0, 0, 0, 1}), expected: []byte{byte(HashInputTypeAddress), 0, 0, 0, 0, 0, 0, 0, 1}, @@ -1238,6 +1406,37 @@ func TestGetHashInput(t *testing.T) { 42, }, }, + "enum long identifier": { + value: func() HashableValue { + inter := newTestInterpreter(t) + + fields := []CompositeField{ + { + Name: "rawValue", + Value: UInt8Value(42), + }, + } + return NewCompositeValue( + inter, + utils.TestLocation, + strings.Repeat("a", 32), + common.CompositeKindEnum, + fields, + common.Address{}, + ) + }(), + expected: append( + append([]byte{byte(HashInputTypeEnum)}, + append( + // S.test. + []byte{0x53, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e}, + // identifier + []byte(strings.Repeat("a", 32))..., + )...), + byte(HashInputTypeUInt8), + 42, + ), + }, "Path": { value: PathValue{ Domain: common.PathDomainStorage, @@ -1251,6 +1450,19 @@ func TestGetHashInput(t *testing.T) { 0x66, 0x6f, 0x6f, }, }, + "Path long identifier": { + value: PathValue{ + Domain: common.PathDomainStorage, + Identifier: strings.Repeat("a", 32), + }, + expected: append( + []byte{byte(HashInputTypePath), + // domain: storage + 0x1}, + // identifier: aaa... + []byte(strings.Repeat("a", 32))..., + ), + }, } test := func(name string, testCase testCase) { From ba6da54663084bf0c58bbe2be2cda18ec369f87c Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Wed, 8 Dec 2021 18:18:08 -0600 Subject: [PATCH 4/4] Fix test error --- runtime/interpreter/value_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index fdae457a5c..2cc19fd0e3 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -1148,7 +1148,7 @@ func TestGetHashInput(t *testing.T) { }, "UInt16 max": { value: UInt16Value(math.MaxUint16), - expected: []byte{byte(HashInputTypeUInt16), 0xff, 0xf}, + expected: []byte{byte(HashInputTypeUInt16), 0xff, 0xff}, }, "UInt32": { value: UInt32Value(32),