diff --git a/accounts/abi/type.go b/accounts/abi/type.go index d079212b3c..336c17e7b4 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -141,22 +141,24 @@ func checkForSlices(t string, structComponents ...unmarshalArg) (typ Type, found if strings.Count(t, "[") != 0 { i := strings.LastIndex(t, "[") - // recursively embed the type - var embeddedType Type - if len(structComponents) > 0 { - embeddedType, err = ParseStructType(t, structComponents...) - } else { - embeddedType, err = NewType(t[:i]) - } - if err != nil { - return Type{}, false, err - } // grab the last cell and create a type from there sliced := t[i:] // grab the slice size with regexp re := regexp.MustCompile("[0-9]+") intz := re.FindAllString(sliced, -1) + // recursively embed the type + var embeddedType Type + if len(structComponents) > 0 { + embeddedType, err = ParseStructType(t[:i], structComponents...) + typ.stringKind = embeddedType.String() + sliced + } else { + embeddedType, err = NewType(t[:i]) + typ.stringKind = t + } + if err != nil { + return Type{}, false, err + } if len(intz) == 0 { // is a slice typ.T = SliceTy @@ -188,12 +190,14 @@ func ParseStructType(t string, components ...unmarshalArg) (typ Type, err error) if typ, found, err = checkForSlices(t, components...); found == true || err != nil { return typ, err } - typ.stringKind = t + // need to concatenate the different type strings together + //typ.stringKind = t typ.T = StructTy typ.Kind = reflect.Struct // create the struct type var fields []reflect.StructField - for i, component := range components { + var typeStrings []string + for _, component := range components { // it's a embedded struct type var fieldType Type @@ -202,13 +206,14 @@ func ParseStructType(t string, components ...unmarshalArg) (typ Type, err error) } else { fieldType, err = NewType(component.Type) } - if err != nil { return Type{}, err } - fields[i] = reflect.StructField{Name: component.Name, Type: fieldType.Type, Tag: reflect.StructTag(fmt.Sprintf(`json:"%v"`, component.Name))} + typeStrings = append(typeStrings, fieldType.String()) + fields = append(fields, reflect.StructField{Name: strings.Title(component.Name), Type: fieldType.Type, Tag: reflect.StructTag(fmt.Sprintf(`json:"%v"`, component.Name))}) } typ.Type = reflect.StructOf(fields) + typ.stringKind = "(" + strings.Join(typeStrings, ",") + ")" return typ, nil } diff --git a/accounts/abi/type_test.go b/accounts/abi/type_test.go index e55af12939..5e875f94a5 100644 --- a/accounts/abi/type_test.go +++ b/accounts/abi/type_test.go @@ -107,6 +107,40 @@ func TestTypeRegexp(t *testing.T) { } } +// Sample structs for struct parsing test + +type ( + S struct { + A *big.Int + B []*big.Int + C []struct { + X *big.Int + Y *big.Int + } + } +) + +func TestStructParse(t *testing.T) { + + for i, test := range []struct { + input unmarshalArg + expectedOutput Type + }{ + { + unmarshalArg{Name: "s", Type: "tuple", Components: []unmarshalArg{unmarshalArg{Name: "a", Type: "uint256"}, unmarshalArg{Name: "b", Type: "uint256[]"}, unmarshalArg{Name: "c", Type: "tuple[]", Components: []unmarshalArg{unmarshalArg{Name: "x", Type: "uint256"}, unmarshalArg{Name: "y", Type: "uint256"}}}}}, + Type{Kind: reflect.Struct, T: StructTy, Type: reflect.TypeOf(S{}), stringKind: "(uint256,uint256[],(uint256,uint256)[])"}, + }, + } { + newStruct, err := ParseStructType(test.input.Name, test.input.Components...) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(newStruct, test.expectedOutput) { + t.Errorf("test %v: parsed type mismatch:\nGOT %v\nWANT %v ", i, newStruct, test.expectedOutput) + } + } +} + func TestTypeCheck(t *testing.T) { for i, test := range []struct { typ string