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:
parent
9becba5540
commit
0ed8b838a9
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -202,4 +202,4 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err
|
||||||
|
|
||||||
//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start)
|
//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start)
|
||||||
return
|
return
|
||||||
}
|
}
|
Loading…
Reference in New Issue