mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
accounts/abi: simplified reflection logic
This commit is contained in:
parent
46698d7931
commit
a10793e412
3 changed files with 95 additions and 35 deletions
|
|
@ -59,6 +59,10 @@ func (argument *Argument) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (argument *Argument) set(dst interface{}, src interface{}) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// NonIndexed returns the arguments with indexed arguments filtered out
|
// NonIndexed returns the arguments with indexed arguments filtered out
|
||||||
func (arguments Arguments) NonIndexed() Arguments {
|
func (arguments Arguments) NonIndexed() Arguments {
|
||||||
var ret []Argument
|
var ret []Argument
|
||||||
|
|
@ -97,6 +101,14 @@ func (arguments Arguments) Unpack(v interface{}, data []byte) error {
|
||||||
if arguments.isTuple() {
|
if arguments.isTuple() {
|
||||||
return arguments.unpackTuple(v, marshalledValues)
|
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])
|
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
|
// unpackAtomic unpacks ( hexdata -> go ) a single value
|
||||||
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error {
|
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()
|
elem := reflect.ValueOf(v).Elem()
|
||||||
|
|
||||||
if elem.Kind() == reflect.Struct && argument.Type.T != TupleTy {
|
if elem.Kind() == reflect.Struct && reflect.ValueOf(marshalledValues).Kind() != reflect.Struct {
|
||||||
fieldmap, err := mapArgNamesToStructFields([]string{argument.Name}, elem)
|
return set(elem.Field(0), reflect.ValueOf(marshalledValues))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
field := elem.FieldByName(fieldmap[argument.Name])
|
|
||||||
if !field.IsValid() {
|
return set(elem, reflect.ValueOf(marshalledValues))
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpackTuple unpacks ( hexdata -> go ) a batch of values.
|
// unpackTuple unpacks ( hexdata -> go ) a batch of values.
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,11 @@ func set(dst, src reflect.Value) error {
|
||||||
case srcType.AssignableTo(dstType) && dst.CanSet():
|
case srcType.AssignableTo(dstType) && dst.CanSet():
|
||||||
dst.Set(src)
|
dst.Set(src)
|
||||||
case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet():
|
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:
|
default:
|
||||||
return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type())
|
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
|
// setSlice attempts to assign src to dst when slices are not assignable by default
|
||||||
// e.g. src: [][]byte -> dst: [][15]byte
|
// e.g. src: [][]byte -> dst: [][15]byte
|
||||||
// setSlice ignores if we cannot copy all of src' elements.
|
// 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())
|
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++ {
|
for i := 0; i < src.Len(); i++ {
|
||||||
reflect.Copy(slice.Index(i), src.Index(i))
|
reflect.Copy(slice.Index(i), src.Index(i))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
dst.Set(slice)
|
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.
|
// 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
|
return abi2struct, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,18 +117,22 @@ var unpackTests = []unpackTest{
|
||||||
want: int16(0),
|
want: int16(0),
|
||||||
err: "abi: cannot unmarshal *big.Int in to int16",
|
err: "abi: cannot unmarshal *big.Int in to int16",
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
|
TODO (MariusVanDerWijden) check validity of test
|
||||||
{
|
{
|
||||||
def: `[{"type": "bytes"}]`,
|
def: `[{"type": "bytes"}]`,
|
||||||
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
|
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
|
||||||
want: [32]byte{},
|
want: [32]byte{},
|
||||||
err: "abi: cannot unmarshal []uint8 in to [32]uint8",
|
err: "abi: cannot unmarshal []uint8 in to [32]uint8",
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
def: `[{"type": "bytes32"}]`,
|
def: `[{"type": "bytes32"}]`,
|
||||||
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
|
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
|
||||||
want: []byte(nil),
|
want: []byte(nil),
|
||||||
err: "abi: cannot unmarshal [32]uint8 in to []uint8",
|
err: "abi: cannot unmarshal [32]uint8 in to []uint8",
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
|
TODO (MariusVanDerWijden) check validity of test
|
||||||
{
|
{
|
||||||
def: `[{"name":"___","type":"int256"}]`,
|
def: `[{"name":"___","type":"int256"}]`,
|
||||||
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
|
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
|
||||||
|
|
@ -138,6 +142,7 @@ var unpackTests = []unpackTest{
|
||||||
}{},
|
}{},
|
||||||
err: "abi: purely underscored output cannot unpack to struct",
|
err: "abi: purely underscored output cannot unpack to struct",
|
||||||
},
|
},
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`,
|
def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`,
|
||||||
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
|
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue