Эх сурвалжийг харах

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
Robert Zaremba 8 жил өмнө
parent
commit
0ed8b838a9

+ 10 - 0
accounts/abi/argument.go

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

+ 10 - 13
accounts/abi/event.go

@@ -59,16 +59,19 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
 	var (
 		value = valueOf.Elem()
 		typ   = value.Type()
+		kind  = value.Kind()
 	)
-
-	if value.Kind() != reflect.Struct {
-		return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
+	if err := requireUnpackKind(value, typ, kind, e.Inputs, true); err != nil {
+		return err
 	}
 
+	// `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
 	for _, input := range e.Inputs {
 		if input.Indexed {
-			// can't read, continue
+			// Indexed arguments are not packed into data
 			continue
 		}
 		i++
@@ -83,7 +86,7 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
 		}
 		reflectValue := reflect.ValueOf(marshalledValue)
 
-		switch value.Kind() {
+		switch kind {
 		case reflect.Struct:
 			for j := 0; j < typ.NumField(); j++ {
 				field := typ.Field(j)
@@ -95,19 +98,13 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
 				}
 			}
 		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)
-			if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
-				return fmt.Errorf("abi: cannot unmarshal %v in to %v", v.Type(), reflectValue.Type())
+			if err := requireAssignable(v, reflectValue); err != nil {
+				return err
 			}
-			reflectValue := reflect.ValueOf(marshalledValue)
 			if err := set(v.Elem(), reflectValue, input); err != nil {
 				return err
 			}
-		default:
-			return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
 		}
 	}
 	return nil

+ 7 - 9
accounts/abi/method.go

@@ -101,7 +101,11 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error {
 	var (
 		value = valueOf.Elem()
 		typ   = value.Type()
+		kind  = value.Kind()
 	)
+	if err := requireUnpackKind(value, typ, kind, method.Outputs, false); err != nil {
+		return err
+	}
 
 	j := 0
 	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)
 
-		switch value.Kind() {
+		switch kind {
 		case reflect.Struct:
 			for j := 0; j < typ.NumField(); j++ {
 				field := typ.Field(j)
@@ -129,19 +133,13 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error {
 				}
 			}
 		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)
-			if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
-				return fmt.Errorf("abi: cannot unmarshal %v in to %v", v.Type(), reflectValue.Type())
+			if err := requireAssignable(v, reflectValue); err != nil {
+				return err
 			}
-			reflectValue := reflect.ValueOf(marshalledValue)
 			if err := set(v.Elem(), reflectValue, method.Outputs[i]); err != nil {
 				return err
 			}
-		default:
-			return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
 		}
 	}
 	return nil

+ 8 - 0
accounts/abi/reflect.go

@@ -85,3 +85,11 @@ func set(dst, src reflect.Value, output Argument) error {
 	}
 	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
+}

+ 1 - 1
accounts/abi/unpack.go

@@ -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)
 	return
-}
+}