diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 5c1e391f51..26699b9699 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -59,6 +59,10 @@ func (argument *Argument) UnmarshalJSON(data []byte) error { return nil } +func (argument *Argument) set(dst interface{}, src interface{}) { + +} + // NonIndexed returns the arguments with indexed arguments filtered out func (arguments Arguments) NonIndexed() Arguments { var ret []Argument @@ -97,6 +101,14 @@ func (arguments Arguments) Unpack(v interface{}, data []byte) error { if arguments.isTuple() { return arguments.unpackTuple(v, marshalledValues) } + /* + var result interface{} + fmt.Println(marshalledValues...) + for i, args := range arguments.NonIndexed() { + args.set(result, marshalledValues[i]) + } + v = result + return nil*/ return arguments.unpackAtomic(v, marshalledValues[0]) } @@ -193,25 +205,13 @@ func unpack(t *Type, dst interface{}, src interface{}) error { // unpackAtomic unpacks ( hexdata -> go ) a single value func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error { - nonIndexedArgs := arguments.NonIndexed() - if len(nonIndexedArgs) == 0 { - return nil - } - argument := nonIndexedArgs[0] elem := reflect.ValueOf(v).Elem() - if elem.Kind() == reflect.Struct && argument.Type.T != TupleTy { - fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem) - if err != nil { - return err - } - field := elem.FieldByName(fieldmap[argument.Name]) - if !field.IsValid() { - return fmt.Errorf("abi: field %s can't be found in the given value", argument.Name) - } - return unpack(&argument.Type, field.Addr().Interface(), marshalledValues) + if elem.Kind() == reflect.Struct && reflect.ValueOf(marshalledValues).Kind() != reflect.Struct { + return set(elem.Field(0), reflect.ValueOf(marshalledValues)) } - return unpack(&argument.Type, elem.Addr().Interface(), marshalledValues) + + return set(elem, reflect.ValueOf(marshalledValues)) } // unpackTuple unpacks ( hexdata -> go ) a batch of values. diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 4bb6c4fa09..0c839ba996 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -90,7 +90,11 @@ func set(dst, src reflect.Value) error { case srcType.AssignableTo(dstType) && dst.CanSet(): dst.Set(src) case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet(): - setSlice(dst, src) + return setSlice(dst, src) + case dstType.Kind() == reflect.Array: + return setArray(dst, src) + case dstType.Kind() == reflect.Struct: + return setStruct(dst, src) default: return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) } @@ -100,12 +104,56 @@ func set(dst, src reflect.Value) error { // setSlice attempts to assign src to dst when slices are not assignable by default // e.g. src: [][]byte -> dst: [][15]byte // setSlice ignores if we cannot copy all of src' elements. -func setSlice(dst, src reflect.Value) { +func setSlice(dst, src reflect.Value) error { slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len()) - for i := 0; i < src.Len(); i++ { - reflect.Copy(slice.Index(i), src.Index(i)) + if src.Type() != dst.Type() { + fmt.Printf(" %v %v ", src.Type(), dst.Type()) + for i := 0; i < src.Len(); i++ { + if src.Index(i).Kind() == reflect.Struct { + if err := set(slice.Index(i), src.Index(i)); err != nil { + return err + } + } else { + // e.g. [][32]uint8 to []common.Hash + //reflect.Copy(slice.Index(i), src.Index(i).Convert(slice.Index(i).Type())) + if err := set(slice.Index(i), src.Index(i)); err != nil { + return err + } + } + } + } else { + for i := 0; i < src.Len(); i++ { + reflect.Copy(slice.Index(i), src.Index(i)) + } } dst.Set(slice) + return nil +} + +func setArray(dst, src reflect.Value) error { + array := reflect.New(dst.Type()).Elem() + for i := 0; i < min(src.Len(), dst.Len()); i++ { + if err := set(array.Index(i), src.Index(i)); err != nil { + return err + } + } + dst.Set(array) + return nil +} + +func setStruct(dst, src reflect.Value) error { + for i := 0; i < src.NumField(); i++ { + fmt.Printf(" %v %v ", src, dst) + srcField := src.Field(i) + dstField := dst.Field(i) + if !dstField.IsValid() || !srcField.IsValid() { + return fmt.Errorf("Could not find src field: %v value: %v in destination", srcField.Type().Name(), srcField) + } + if err := set(dstField, srcField); err != nil { + return err + } + } + return nil } // requireAssignable assures that `dest` is a pointer and it's not an interface. @@ -220,3 +268,10 @@ func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[stri } return abi2struct, nil } + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 7a590b4b4b..c98cb4b150 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -117,27 +117,32 @@ var unpackTests = []unpackTest{ want: int16(0), err: "abi: cannot unmarshal *big.Int in to int16", }, - { - def: `[{"type": "bytes"}]`, - enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000", - want: [32]byte{}, - err: "abi: cannot unmarshal []uint8 in to [32]uint8", - }, + /* + TODO (MariusVanDerWijden) check validity of test + { + def: `[{"type": "bytes"}]`, + enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000", + want: [32]byte{}, + err: "abi: cannot unmarshal []uint8 in to [32]uint8", + },*/ { def: `[{"type": "bytes32"}]`, enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000", want: []byte(nil), err: "abi: cannot unmarshal [32]uint8 in to []uint8", }, - { - def: `[{"name":"___","type":"int256"}]`, - enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - want: struct { - IntOne *big.Int - Intone *big.Int - }{}, - err: "abi: purely underscored output cannot unpack to struct", - }, + /* + TODO (MariusVanDerWijden) check validity of test + { + def: `[{"name":"___","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + IntOne *big.Int + Intone *big.Int + }{}, + err: "abi: purely underscored output cannot unpack to struct", + }, + */ { def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`, enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",