accounts/abi: simplify reflection logic (#21058)
* accounts/abi: simplified reflection logic * accounts/abi: simplified reflection logic * accounts/abi: removed unpack * accounts/abi: removed comments * accounts/abi: removed uneccessary complications * accounts/abi: minor changes in error messages * accounts/abi: removed unnused code * accounts/abi: fixed indexed argument unpacking * accounts/abi: removed superfluous test cases This commit removes two test cases. The first one is trivially invalid as we have the same test cases as passing in packing_test.go L375. The second one passes now, because we don't need the mapArgNamesToStructFields in unpack_atomic anymore. Checking for purely underscored arg names generally should not be something we do as the abi/contract is generally out of the control of the user. * accounts/abi: removed comments, debug println * accounts/abi: added commented out code * accounts/abi: addressed comments * accounts/abi: remove unnecessary dst.CanSet check * accounts/abi: added dst.CanSet checks
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							677724af0c
						
					
				
				
					commit
					f3f1e59eea
				
			@@ -122,149 +122,55 @@ func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// unpack sets the unmarshalled value to go format.
 | 
			
		||||
// Note the dst here must be settable.
 | 
			
		||||
func unpack(t *Type, dst interface{}, src interface{}) error {
 | 
			
		||||
	var (
 | 
			
		||||
		dstVal = reflect.ValueOf(dst).Elem()
 | 
			
		||||
		srcVal = reflect.ValueOf(src)
 | 
			
		||||
	)
 | 
			
		||||
	tuple, typ := false, t
 | 
			
		||||
	for {
 | 
			
		||||
		if typ.T == SliceTy || typ.T == ArrayTy {
 | 
			
		||||
			typ = typ.Elem
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		tuple = typ.T == TupleTy
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
	if !tuple {
 | 
			
		||||
		return set(dstVal, srcVal)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dereferences interface or pointer wrapper
 | 
			
		||||
	dstVal = indirectInterfaceOrPtr(dstVal)
 | 
			
		||||
 | 
			
		||||
	switch t.T {
 | 
			
		||||
	case TupleTy:
 | 
			
		||||
		if dstVal.Kind() != reflect.Struct {
 | 
			
		||||
			return fmt.Errorf("abi: invalid dst value for unpack, want struct, got %s", dstVal.Kind())
 | 
			
		||||
		}
 | 
			
		||||
		fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, dstVal)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for i, elem := range t.TupleElems {
 | 
			
		||||
			fname := fieldmap[t.TupleRawNames[i]]
 | 
			
		||||
			field := dstVal.FieldByName(fname)
 | 
			
		||||
			if !field.IsValid() {
 | 
			
		||||
				return fmt.Errorf("abi: field %s can't found in the given value", t.TupleRawNames[i])
 | 
			
		||||
			}
 | 
			
		||||
			if err := unpack(elem, field.Addr().Interface(), srcVal.Field(i).Interface()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	case SliceTy:
 | 
			
		||||
		if dstVal.Kind() != reflect.Slice {
 | 
			
		||||
			return fmt.Errorf("abi: invalid dst value for unpack, want slice, got %s", dstVal.Kind())
 | 
			
		||||
		}
 | 
			
		||||
		slice := reflect.MakeSlice(dstVal.Type(), srcVal.Len(), srcVal.Len())
 | 
			
		||||
		for i := 0; i < slice.Len(); i++ {
 | 
			
		||||
			if err := unpack(t.Elem, slice.Index(i).Addr().Interface(), srcVal.Index(i).Interface()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		dstVal.Set(slice)
 | 
			
		||||
	case ArrayTy:
 | 
			
		||||
		if dstVal.Kind() != reflect.Array {
 | 
			
		||||
			return fmt.Errorf("abi: invalid dst value for unpack, want array, got %s", dstVal.Kind())
 | 
			
		||||
		}
 | 
			
		||||
		array := reflect.New(dstVal.Type()).Elem()
 | 
			
		||||
		for i := 0; i < array.Len(); i++ {
 | 
			
		||||
			if err := unpack(t.Elem, array.Index(i).Addr().Interface(), srcVal.Index(i).Interface()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		dstVal.Set(array)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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()
 | 
			
		||||
	dst := reflect.ValueOf(v).Elem()
 | 
			
		||||
	src := reflect.ValueOf(marshalledValues)
 | 
			
		||||
 | 
			
		||||
	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 dst.Kind() == reflect.Struct && src.Kind() != reflect.Struct {
 | 
			
		||||
		return set(dst.Field(0), src)
 | 
			
		||||
	}
 | 
			
		||||
	return unpack(&argument.Type, elem.Addr().Interface(), marshalledValues)
 | 
			
		||||
	return set(dst, src)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// unpackTuple unpacks ( hexdata -> go ) a batch of values.
 | 
			
		||||
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
 | 
			
		||||
	var (
 | 
			
		||||
		value          = reflect.ValueOf(v).Elem()
 | 
			
		||||
		typ            = value.Type()
 | 
			
		||||
		kind           = value.Kind()
 | 
			
		||||
		nonIndexedArgs = arguments.NonIndexed()
 | 
			
		||||
	)
 | 
			
		||||
	if err := requireUnpackKind(value, len(nonIndexedArgs), arguments); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	value := reflect.ValueOf(v).Elem()
 | 
			
		||||
	nonIndexedArgs := arguments.NonIndexed()
 | 
			
		||||
 | 
			
		||||
	// If the interface is a struct, get of abi->struct_field mapping
 | 
			
		||||
	var abi2struct map[string]string
 | 
			
		||||
	if kind == reflect.Struct {
 | 
			
		||||
	switch value.Kind() {
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		argNames := make([]string, len(nonIndexedArgs))
 | 
			
		||||
		for i, arg := range nonIndexedArgs {
 | 
			
		||||
			argNames[i] = arg.Name
 | 
			
		||||
		}
 | 
			
		||||
		var err error
 | 
			
		||||
		if abi2struct, err = mapArgNamesToStructFields(argNames, value); err != nil {
 | 
			
		||||
		abi2struct, err := mapArgNamesToStructFields(argNames, value)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i, arg := range nonIndexedArgs {
 | 
			
		||||
		switch kind {
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
		for i, arg := range nonIndexedArgs {
 | 
			
		||||
			field := value.FieldByName(abi2struct[arg.Name])
 | 
			
		||||
			if !field.IsValid() {
 | 
			
		||||
				return fmt.Errorf("abi: field %s can't be found in the given value", arg.Name)
 | 
			
		||||
			}
 | 
			
		||||
			if err := unpack(&arg.Type, field.Addr().Interface(), marshalledValues[i]); err != nil {
 | 
			
		||||
			if err := set(field, reflect.ValueOf(marshalledValues[i])); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Slice, reflect.Array:
 | 
			
		||||
			if value.Len() < i {
 | 
			
		||||
				return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len())
 | 
			
		||||
			}
 | 
			
		||||
			v := value.Index(i)
 | 
			
		||||
			if err := requireAssignable(v, reflect.ValueOf(marshalledValues[i])); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if err := unpack(&arg.Type, v.Addr().Interface(), marshalledValues[i]); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ)
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Slice, reflect.Array:
 | 
			
		||||
		if value.Len() < len(marshalledValues) {
 | 
			
		||||
			return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len())
 | 
			
		||||
		}
 | 
			
		||||
		for i := range nonIndexedArgs {
 | 
			
		||||
			if err := set(value.Index(i), reflect.ValueOf(marshalledValues[i])); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", value.Type())
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user