accounts/abi: fix event unpack into slice

+ The event slice unpacker doesn't correctly extract element from the
slice. The indexed arguments are not ignored as they should be
(the data offset should not include the indexed arguments).

+ The `Elem()` call in the slice unpack doesn't work.
The Slice related tests fails because of that.

+ the check in the loop are suboptimal and have been extracted
out of the loop.

+ extracted common code from event and method tupleUnpack
This commit is contained in:
Robert Zaremba 2017-11-10 02:30:26 +01:00 committed by Martin Holst Swende
parent 9becba5540
commit 0ed8b838a9
No known key found for this signature in database
GPG Key ID: 683B438C05A5DDF0
5 changed files with 36 additions and 23 deletions

View File

@ -49,3 +49,13 @@ func (a *Argument) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func countNonIndexedArguments(args []Argument) int {
out := 0
for i := range args {
if !args[i].Indexed {
out++
}
}
return out
}

View File

@ -59,16 +59,19 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
var ( var (
value = valueOf.Elem() value = valueOf.Elem()
typ = value.Type() typ = value.Type()
kind = value.Kind()
) )
if err := requireUnpackKind(value, typ, kind, e.Inputs, true); err != nil {
if value.Kind() != reflect.Struct { return err
return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
} }
// `i` counts the nonindexed arguments.
// `j` counts the number of complex types.
// both `i` and `j` are used to to correctly compute `data` offset.
i, j := -1, 0 i, j := -1, 0
for _, input := range e.Inputs { for _, input := range e.Inputs {
if input.Indexed { if input.Indexed {
// can't read, continue // Indexed arguments are not packed into data
continue continue
} }
i++ i++
@ -83,7 +86,7 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
} }
reflectValue := reflect.ValueOf(marshalledValue) reflectValue := reflect.ValueOf(marshalledValue)
switch value.Kind() { switch kind {
case reflect.Struct: case reflect.Struct:
for j := 0; j < typ.NumField(); j++ { for j := 0; j < typ.NumField(); j++ {
field := typ.Field(j) field := typ.Field(j)
@ -95,19 +98,13 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
} }
} }
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
if value.Len() < i {
return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", i, value.Len())
}
v := value.Index(i) v := value.Index(i)
if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface { if err := requireAssignable(v, reflectValue); err != nil {
return fmt.Errorf("abi: cannot unmarshal %v in to %v", v.Type(), reflectValue.Type()) return err
} }
reflectValue := reflect.ValueOf(marshalledValue)
if err := set(v.Elem(), reflectValue, input); err != nil { if err := set(v.Elem(), reflectValue, input); err != nil {
return err return err
} }
default:
return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
} }
} }
return nil return nil

View File

@ -101,7 +101,11 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error {
var ( var (
value = valueOf.Elem() value = valueOf.Elem()
typ = value.Type() typ = value.Type()
kind = value.Kind()
) )
if err := requireUnpackKind(value, typ, kind, method.Outputs, false); err != nil {
return err
}
j := 0 j := 0
for i := 0; i < len(method.Outputs); i++ { for i := 0; i < len(method.Outputs); i++ {
@ -117,7 +121,7 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error {
} }
reflectValue := reflect.ValueOf(marshalledValue) reflectValue := reflect.ValueOf(marshalledValue)
switch value.Kind() { switch kind {
case reflect.Struct: case reflect.Struct:
for j := 0; j < typ.NumField(); j++ { for j := 0; j < typ.NumField(); j++ {
field := typ.Field(j) field := typ.Field(j)
@ -129,19 +133,13 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error {
} }
} }
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
if value.Len() < i {
return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(method.Outputs), value.Len())
}
v := value.Index(i) v := value.Index(i)
if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface { if err := requireAssignable(v, reflectValue); err != nil {
return fmt.Errorf("abi: cannot unmarshal %v in to %v", v.Type(), reflectValue.Type()) return err
} }
reflectValue := reflect.ValueOf(marshalledValue)
if err := set(v.Elem(), reflectValue, method.Outputs[i]); err != nil { if err := set(v.Elem(), reflectValue, method.Outputs[i]); err != nil {
return err return err
} }
default:
return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
} }
} }
return nil return nil

View File

@ -85,3 +85,11 @@ func set(dst, src reflect.Value, output Argument) error {
} }
return nil return nil
} }
// requireAssignable assures that `dest` is a pointer and it's not an interface.
func requireAssignable(dst, src reflect.Value) error {
if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface {
return fmt.Errorf("abi: cannot unmarshal %v into %v", src.Type(), dst.Type())
}
return nil
}