accounts/abi: simplified reflection logic

This commit is contained in:
Marius van der Wijden 2020-05-07 15:52:51 +02:00
parent 46698d7931
commit a10793e412
3 changed files with 95 additions and 35 deletions

View file

@ -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
if elem.Kind() == reflect.Struct && reflect.ValueOf(marshalledValues).Kind() != reflect.Struct {
return set(elem.Field(0), reflect.ValueOf(marshalledValues))
}
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)
}
return unpack(&argument.Type, elem.Addr().Interface(), marshalledValues)
return set(elem, reflect.ValueOf(marshalledValues))
}
// unpackTuple unpacks ( hexdata -> go ) a batch of values.

View file

@ -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())
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
}

View file

@ -117,18 +117,22 @@ var unpackTests = []unpackTest{
want: int16(0),
err: "abi: cannot unmarshal *big.Int in to int16",
},
/*
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",
},
/*
TODO (MariusVanDerWijden) check validity of test
{
def: `[{"name":"___","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
@ -138,6 +142,7 @@ var unpackTests = []unpackTest{
}{},
err: "abi: purely underscored output cannot unpack to struct",
},
*/
{
def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",