From fb2e94d6002319ffd6a9bb0eb8f6e8d5278f01b5 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Mon, 15 Aug 2022 09:54:07 -0700 Subject: [PATCH] Rename `BaseType` to `TypeKind` (#7) --- abi/encode.go | 10 +++--- abi/encode_test.go | 14 ++++---- abi/json.go | 14 ++++---- abi/type.go | 81 +++++++++++++++++++++------------------------- abi/type_test.go | 72 +++++++++++++++++++++-------------------- 5 files changed, 93 insertions(+), 98 deletions(-) diff --git a/abi/encode.go b/abi/encode.go index ea0f2b0..58d1ebf 100644 --- a/abi/encode.go +++ b/abi/encode.go @@ -12,7 +12,7 @@ import ( func (t Type) typeCastToTuple(tupLen ...int) (Type, error) { var childT []Type - switch t.abiTypeID { + switch t.kind { case String: if len(tupLen) != 1 { return Type{}, fmt.Errorf("string type conversion to tuple need 1 length argument") @@ -52,7 +52,7 @@ func (t Type) typeCastToTuple(tupLen ...int) (Type, error) { // Encode is an ABI type method to encode go values into bytes following ABI encoding rules func (t Type) Encode(value interface{}) ([]byte, error) { - switch t.abiTypeID { + switch t.kind { case Uint, Ufixed: return encodeInt(value, t.bitSize) case Bool: @@ -211,7 +211,7 @@ func encodeTuple(value interface{}, childT []Type) ([]byte, error) { } tails[i] = tailEncoding isDynamicIndex[i] = true - } else if childT[i].abiTypeID == Bool { + } else if childT[i].kind == Bool { // search previous bool before := findBoolLR(childT, i, -1) // search after bool @@ -317,7 +317,7 @@ func decodeUint(encoded []byte, bitSize uint16) (interface{}, error) { // Decode is an ABI type method to decode bytes to go values from ABI encoding rules func (t Type) Decode(encoded []byte) (interface{}, error) { - switch t.abiTypeID { + switch t.kind { case Uint, Ufixed: return decodeUint(encoded, t.bitSize) case Bool: @@ -389,7 +389,7 @@ func decodeTuple(encoded []byte, childT []Type) ([]interface{}, error) { dynamicSegments = append(dynamicSegments, int(dynamicIndex)) valuePartition = append(valuePartition, nil) iterIndex += lengthEncodeByteSize - } else if childT[i].abiTypeID == Bool { + } else if childT[i].kind == Bool { // search previous bool before := findBoolLR(childT, i, -1) // search after bool diff --git a/abi/encode_test.go b/abi/encode_test.go index e621a16..a8ac5a4 100644 --- a/abi/encode_test.go +++ b/abi/encode_test.go @@ -885,7 +885,7 @@ func categorySelfRoundTripTest(t *testing.T, category []testUnit) { } } -func addPrimitiveRandomValues(t *testing.T, pool *map[BaseType][]testUnit) { +func addPrimitiveRandomValues(t *testing.T, pool *map[TypeKind][]testUnit) { (*pool)[Uint] = make([]testUnit, uintTestCaseCount*uintEnd/uintStepLength) (*pool)[Ufixed] = make([]testUnit, ufixedPrecision*uintEnd/uintStepLength) @@ -964,7 +964,7 @@ func addPrimitiveRandomValues(t *testing.T, pool *map[BaseType][]testUnit) { } func takeSomeFromCategoryAndGenerateArray( - t *testing.T, abiT BaseType, srtIndex int, takeNum uint16, pool *map[BaseType][]testUnit) { + t *testing.T, abiT TypeKind, srtIndex int, takeNum uint16, pool *map[TypeKind][]testUnit) { tempArray := make([]interface{}, takeNum) for i := 0; i < int(takeNum); i++ { @@ -986,7 +986,7 @@ func takeSomeFromCategoryAndGenerateArray( }) } -func addArrayRandomValues(t *testing.T, pool *map[BaseType][]testUnit) { +func addArrayRandomValues(t *testing.T, pool *map[TypeKind][]testUnit) { for intIndex := 0; intIndex < len((*pool)[Uint]); intIndex += uintTestCaseCount { takeSomeFromCategoryAndGenerateArray(t, Uint, intIndex, takeNum, pool) } @@ -999,16 +999,16 @@ func addArrayRandomValues(t *testing.T, pool *map[BaseType][]testUnit) { categorySelfRoundTripTest(t, (*pool)[ArrayDynamic]) } -func addTupleRandomValues(t *testing.T, slotRange BaseType, pool *map[BaseType][]testUnit) { +func addTupleRandomValues(t *testing.T, slotRange TypeKind, pool *map[TypeKind][]testUnit) { for i := 0; i < tupleTestCaseCount; i++ { tupleLenBig, err := rand.Int(rand.Reader, big.NewInt(tupleMaxLength)) require.NoError(t, err, "generate random tuple length should not return error") tupleLen := tupleLenBig.Int64() + 1 testUnits := make([]testUnit, tupleLen) for index := 0; index < int(tupleLen); index++ { - tupleTypeIndexBig, err := rand.Int(rand.Reader, big.NewInt(int64(slotRange)+1)) + tupleTypeIndexBig, err := rand.Int(rand.Reader, big.NewInt(int64(slotRange))) require.NoError(t, err, "generate random tuple element type index should not return error") - tupleTypeIndex := BaseType(tupleTypeIndexBig.Int64()) + tupleTypeIndex := TypeKind(tupleTypeIndexBig.Int64() + 1) tupleElemChoiceRange := len((*pool)[tupleTypeIndex]) tupleElemRangeIndexBig, err := rand.Int(rand.Reader, big.NewInt(int64(tupleElemChoiceRange))) @@ -1036,7 +1036,7 @@ func addTupleRandomValues(t *testing.T, slotRange BaseType, pool *map[BaseType][ func TestRandomABIEncodeDecodeRoundTrip(t *testing.T) { t.Parallel() - testValuePool := make(map[BaseType][]testUnit) + testValuePool := make(map[TypeKind][]testUnit) addPrimitiveRandomValues(t, &testValuePool) addArrayRandomValues(t, &testValuePool) addTupleRandomValues(t, String, &testValuePool) diff --git a/abi/json.go b/abi/json.go index 621d572..a932d6f 100644 --- a/abi/json.go +++ b/abi/json.go @@ -77,7 +77,7 @@ func castBigIntToNearestPrimitive(num *big.Int, bitSize uint16) (interface{}, er // MarshalToJSON convert golang value to JSON format from ABI type func (t Type) MarshalToJSON(value interface{}) ([]byte, error) { - switch t.abiTypeID { + switch t.kind { case Uint: bytesUint, err := encodeInt(value, t.bitSize) if err != nil { @@ -122,10 +122,10 @@ func (t Type) MarshalToJSON(value interface{}) ([]byte, error) { if err != nil { return nil, err } - if t.abiTypeID == ArrayStatic && int(t.staticLength) != len(values) { + if t.kind == ArrayStatic && int(t.staticLength) != len(values) { return nil, fmt.Errorf("length of slice %d != type specific length %d", len(values), t.staticLength) } - if t.childTypes[0].abiTypeID == Byte { + if t.childTypes[0].kind == Byte { byteArr := make([]byte, len(values)) for i := 0; i < len(values); i++ { tempByte, ok := values[i].(byte) @@ -173,7 +173,7 @@ func (t Type) MarshalToJSON(value interface{}) ([]byte, error) { // UnmarshalFromJSON convert bytes to golang value following ABI type and encoding rules func (t Type) UnmarshalFromJSON(jsonEncoded []byte) (interface{}, error) { - switch t.abiTypeID { + switch t.kind { case Uint: num := new(big.Int) if err := num.UnmarshalJSON(jsonEncoded); err != nil { @@ -217,13 +217,13 @@ func (t Type) UnmarshalFromJSON(jsonEncoded []byte) (interface{}, error) { return addrBytes[:], nil case ArrayStatic, ArrayDynamic: - if t.childTypes[0].abiTypeID == Byte && bytes.HasPrefix(jsonEncoded, []byte{'"'}) { + if t.childTypes[0].kind == Byte && bytes.HasPrefix(jsonEncoded, []byte{'"'}) { var byteArr []byte err := json.Unmarshal(jsonEncoded, &byteArr) if err != nil { return nil, fmt.Errorf("cannot cast JSON encoded (%s) to bytes: %w", string(jsonEncoded), err) } - if t.abiTypeID == ArrayStatic && len(byteArr) != int(t.staticLength) { + if t.kind == ArrayStatic && len(byteArr) != int(t.staticLength) { return nil, fmt.Errorf("length of slice %d != type specific length %d", len(byteArr), t.staticLength) } outInterface := make([]interface{}, len(byteArr)) @@ -236,7 +236,7 @@ func (t Type) UnmarshalFromJSON(jsonEncoded []byte) (interface{}, error) { if err := json.Unmarshal(jsonEncoded, &elems); err != nil { return nil, fmt.Errorf("cannot cast JSON encoded (%s) to array: %w", string(jsonEncoded), err) } - if t.abiTypeID == ArrayStatic && len(elems) != int(t.staticLength) { + if t.kind == ArrayStatic && len(elems) != int(t.staticLength) { return nil, fmt.Errorf("JSON array element number != ABI array elem number") } values := make([]interface{}, len(elems)) diff --git a/abi/type.go b/abi/type.go index 39e6e35..7c86c51 100644 --- a/abi/type.go +++ b/abi/type.go @@ -8,39 +8,29 @@ import ( "strings" ) -/* - ABI-Types: uint: An N-bit unsigned integer (8 <= N <= 512 and N % 8 = 0). - | byte (alias for uint8) - | ufixed x (8 <= N <= 512, N % 8 = 0, and 0 < M <= 160) - | bool - | address (alias for byte[32]) - | [] - | [] - | string - | (T1, ..., Tn) -*/ - -// BaseType is an type-alias for uint32. A BaseType value indicates the type of an ABI value. -type BaseType uint32 +// TypeKind is an enum value which indicates the kind of an ABI type. +type TypeKind uint32 const ( - // Uint is the index (0) for `Uint` type in ABI encoding. - Uint BaseType = iota - // Byte is the index (1) for `Byte` type in ABI encoding. + // InvalidType represents an invalid and unused kind. + InvalidType = iota + // Uint is kind for ABI unsigned integer types, i.e. `uint`. + Uint + // Byte is kind for the ABI `byte` type. Byte - // Ufixed is the index (2) for `UFixed` type in ABI encoding. + // Ufixed is the kind for ABI unsigned fixed point decimal types, i.e. `ufixedx`. Ufixed - // Bool is the index (3) for `Bool` type in ABI encoding. + // Bool is the kind for the ABI `bool` type. Bool - // ArrayStatic is the index (4) for static length array ([length]) type in ABI encoding. + // ArrayStatic is the kind for ABI static array types, i.e. `[]`. ArrayStatic - // Address is the index (5) for `Address` type in ABI encoding (an type alias of Byte[32]). + // Address is the the kind for the ABI `address` type. Address - // ArrayDynamic is the index (6) for dynamic length array ([]) type in ABI encoding. + // ArrayDynamic is the kind for ABI dynamic array types, i.e. `[]`. ArrayDynamic - // String is the index (7) for `String` type in ABI encoding (an type alias of Byte[]). + // String is the kind for the ABI `string` type. String - // Tuple is the index (8) for tuple `(, ..., )` in ABI encoding. + // Tuple is the kind for ABI tuple types, i.e. `(,...,)`. Tuple ) @@ -53,9 +43,12 @@ const ( abiEncodingLengthLimit = 1 << 16 ) -// Type is the struct that stores information about an ABI value's type. +// Type is the struct that represents an ABI type. +// +// Do not use the zero value of this struct. Use the `TypeOf` function to create an instance of an +// ABI type. type Type struct { - abiTypeID BaseType + kind TypeKind childTypes []Type // only can be applied to `uint` bitSize or `ufixed` bitSize @@ -75,7 +68,7 @@ type Type struct { // String serialize an ABI Type to a string in ABI encoding. func (t Type) String() string { - switch t.abiTypeID { + switch t.kind { case Uint: return fmt.Sprintf("uint%d", t.bitSize) case Byte: @@ -99,7 +92,7 @@ func (t Type) String() string { } return "(" + strings.Join(typeStrings, ",") + ")" default: - panic("Type Serialization Error, fail to infer from abiTypeID (bruh you shouldn't be here)") + return "" } } @@ -275,23 +268,23 @@ func makeUintType(typeSize int) (Type, error) { return Type{}, fmt.Errorf("unsupported uint type bitSize: %d", typeSize) } return Type{ - abiTypeID: Uint, - bitSize: uint16(typeSize), + kind: Uint, + bitSize: uint16(typeSize), }, nil } var ( // byteType is ABI type constant for byte - byteType = Type{abiTypeID: Byte} + byteType = Type{kind: Byte} // boolType is ABI type constant for bool - boolType = Type{abiTypeID: Bool} + boolType = Type{kind: Bool} // addressType is ABI type constant for address - addressType = Type{abiTypeID: Address} + addressType = Type{kind: Address} // stringType is ABI type constant for string - stringType = Type{abiTypeID: String} + stringType = Type{kind: String} ) // makeUfixedType makes `UFixed` ABI type by taking type bitSize and type precision as arguments. @@ -305,7 +298,7 @@ func makeUfixedType(typeSize int, typePrecision int) (Type, error) { return Type{}, fmt.Errorf("unsupported ufixed type precision: %d", typePrecision) } return Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: uint16(typeSize), precision: uint16(typePrecision), }, nil @@ -315,7 +308,7 @@ func makeUfixedType(typeSize int, typePrecision int) (Type, error) { // array element type and array length as arguments. func makeStaticArrayType(argumentType Type, arrayLength uint16) Type { return Type{ - abiTypeID: ArrayStatic, + kind: ArrayStatic, childTypes: []Type{argumentType}, staticLength: arrayLength, } @@ -324,7 +317,7 @@ func makeStaticArrayType(argumentType Type, arrayLength uint16) Type { // makeDynamicArrayType makes dynamic length array by taking array element type as argument. func makeDynamicArrayType(argumentType Type) Type { return Type{ - abiTypeID: ArrayDynamic, + kind: ArrayDynamic, childTypes: []Type{argumentType}, } } @@ -335,7 +328,7 @@ func MakeTupleType(argumentTypes []Type) (Type, error) { return Type{}, fmt.Errorf("tuple type child type number larger than maximum uint16 error") } return Type{ - abiTypeID: Tuple, + kind: Tuple, childTypes: argumentTypes, staticLength: uint16(len(argumentTypes)), }, nil @@ -343,7 +336,7 @@ func MakeTupleType(argumentTypes []Type) (Type, error) { // Equal method decides the equality of two types: t == t0. func (t Type) Equal(t0 Type) bool { - if t.abiTypeID != t0.abiTypeID { + if t.kind != t0.kind { return false } if t.precision != t0.precision || t.bitSize != t0.bitSize { @@ -366,7 +359,7 @@ func (t Type) Equal(t0 Type) bool { // IsDynamic method decides if an ABI type is dynamic or static. func (t Type) IsDynamic() bool { - switch t.abiTypeID { + switch t.kind { case ArrayDynamic, String: return true default: @@ -385,7 +378,7 @@ func findBoolLR(typeList []Type, index int, delta int) int { until := 0 for { curr := index + delta*until - if typeList[curr].abiTypeID == Bool { + if typeList[curr].kind == Bool { if curr != len(typeList)-1 && delta > 0 { until++ } else if curr > 0 && delta < 0 { @@ -403,7 +396,7 @@ func findBoolLR(typeList []Type, index int, delta int) int { // ByteLen method calculates the byte length of a static ABI type. func (t Type) ByteLen() (int, error) { - switch t.abiTypeID { + switch t.kind { case Address: return addressByteSize, nil case Byte: @@ -413,7 +406,7 @@ func (t Type) ByteLen() (int, error) { case Bool: return singleBoolSize, nil case ArrayStatic: - if t.childTypes[0].abiTypeID == Bool { + if t.childTypes[0].kind == Bool { byteLen := int(t.staticLength+7) / 8 return byteLen, nil } @@ -425,7 +418,7 @@ func (t Type) ByteLen() (int, error) { case Tuple: size := 0 for i := 0; i < len(t.childTypes); i++ { - if t.childTypes[i].abiTypeID == Bool { + if t.childTypes[i].kind == Bool { // search after bool after := findBoolLR(t.childTypes, i, 1) // shift the index diff --git a/abi/type_test.go b/abi/type_test.go index bc03e6a..62ee544 100644 --- a/abi/type_test.go +++ b/abi/type_test.go @@ -46,8 +46,8 @@ func TestMakeTypeValid(t *testing.T) { { input: makeDynamicArrayType( Type{ - abiTypeID: Uint, - bitSize: uint16(32), + kind: Uint, + bitSize: uint16(32), }, ), testType: "dynamic array", @@ -65,7 +65,7 @@ func TestMakeTypeValid(t *testing.T) { { input: makeStaticArrayType( Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: uint16(128), precision: uint16(10), }, @@ -88,21 +88,21 @@ func TestMakeTypeValid(t *testing.T) { // tuple type { input: Type{ - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ { - abiTypeID: Uint, - bitSize: uint16(32), + kind: Uint, + bitSize: uint16(32), }, { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ addressType, byteType, makeStaticArrayType(boolType, uint16(10)), makeDynamicArrayType( Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: uint16(256), precision: uint16(10), }, @@ -129,6 +129,8 @@ func TestMakeTypeValid(t *testing.T) { func TestMakeTypeInvalid(t *testing.T) { t.Parallel() + // zero value + require.Equal(t, "", Type{}.String()) // uint for i := 0; i <= 1000; i++ { randInput := rand.Uint32() % (1 << 16) @@ -188,14 +190,14 @@ func TestTypeFromStringValid(t *testing.T) { { input: "uint256[]", testType: "dynamic array", - expected: makeDynamicArrayType(Type{abiTypeID: Uint, bitSize: 256}), + expected: makeDynamicArrayType(Type{kind: Uint, bitSize: 256}), }, { input: "ufixed256x64[]", testType: "dynamic array", expected: makeDynamicArrayType( Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: 256, precision: 64, }, @@ -228,7 +230,7 @@ func TestTypeFromStringValid(t *testing.T) { testType: "static array", expected: makeStaticArrayType( makeDynamicArrayType( - Type{abiTypeID: Uint, bitSize: uint16(64)}, + Type{kind: Uint, bitSize: uint16(64)}, ), uint16(200), ), @@ -238,7 +240,7 @@ func TestTypeFromStringValid(t *testing.T) { input: "()", testType: "tuple type", expected: Type{ - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{}, staticLength: 0, }, @@ -247,21 +249,21 @@ func TestTypeFromStringValid(t *testing.T) { input: "(uint32,(address,byte,bool[10],ufixed256x10[]),byte[])", testType: "tuple type", expected: Type{ - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ { - abiTypeID: Uint, - bitSize: uint16(32), + kind: Uint, + bitSize: uint16(32), }, { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ addressType, byteType, makeStaticArrayType(boolType, uint16(10)), makeDynamicArrayType( Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: uint16(256), precision: uint16(10), }, @@ -278,24 +280,24 @@ func TestTypeFromStringValid(t *testing.T) { input: "(uint32,(address,byte,bool[10],(ufixed256x10[])))", testType: "tuple type", expected: Type{ - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ { - abiTypeID: Uint, - bitSize: uint16(32), + kind: Uint, + bitSize: uint16(32), }, { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ addressType, byteType, makeStaticArrayType(boolType, uint16(10)), { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ makeDynamicArrayType( Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: uint16(256), precision: uint16(10), }, @@ -314,30 +316,30 @@ func TestTypeFromStringValid(t *testing.T) { input: "((uint32),(address,(byte,bool[10],ufixed256x10[])))", testType: "tuple type", expected: Type{ - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ { - abiTypeID: Uint, - bitSize: uint16(32), + kind: Uint, + bitSize: uint16(32), }, }, staticLength: 1, }, { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ addressType, { - abiTypeID: Tuple, + kind: Tuple, childTypes: []Type{ byteType, makeStaticArrayType(boolType, uint16(10)), makeDynamicArrayType( Type{ - abiTypeID: Ufixed, + kind: Ufixed, bitSize: uint16(256), precision: uint16(10), }, @@ -449,7 +451,7 @@ func generateTupleType(baseTypes []Type, tupleTypes []Type) Type { resultTypes[i] = baseTypes[rand.Intn(len(baseTypes))] } } - return Type{abiTypeID: Tuple, childTypes: resultTypes, staticLength: uint16(tupleLen)} + return Type{kind: Tuple, childTypes: resultTypes, staticLength: uint16(tupleLen)} } func TestTypeMISC(t *testing.T) { @@ -548,10 +550,10 @@ func TestTypeMISC(t *testing.T) { testType.String()) } else { require.NoError(t, err, "byteLen test error on %s dynamic type, should not have error") - if testType.abiTypeID == Tuple { + if testType.kind == Tuple { sizeSum := 0 for i := 0; i < len(testType.childTypes); i++ { - if testType.childTypes[i].abiTypeID == Bool { + if testType.childTypes[i].kind == Bool { // search previous bool before := findBoolLR(testType.childTypes, i, -1) // search after bool @@ -572,8 +574,8 @@ func TestTypeMISC(t *testing.T) { require.Equal(t, sizeSum, byteLen, "%s do not match calculated byte length %d", testType.String(), sizeSum) - } else if testType.abiTypeID == ArrayStatic { - if testType.childTypes[0].abiTypeID == Bool { + } else if testType.kind == ArrayStatic { + if testType.childTypes[0].kind == Bool { expected := testType.staticLength / 8 if testType.staticLength%8 != 0 { expected++