浏览代码

accounts/abi: add support for unpacking returned bytesN arrays (#15242)

bas-vk 6 年之前
父节点
当前提交
7df52e324c
共有 2 个文件被更改,包括 64 次插入0 次删除
  1. 15 0
      accounts/abi/reflect.go
  2. 49 0
      accounts/abi/unpack_test.go

+ 15 - 0
accounts/abi/reflect.go

@@ -77,6 +77,8 @@ func set(dst, src reflect.Value, output Argument) error {
 	switch {
 	switch {
 	case dstType.AssignableTo(srcType):
 	case dstType.AssignableTo(srcType):
 		dst.Set(src)
 		dst.Set(src)
+	case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice:
+		return setSlice(dst, src, output)
 	case dstType.Kind() == reflect.Interface:
 	case dstType.Kind() == reflect.Interface:
 		dst.Set(src)
 		dst.Set(src)
 	case dstType.Kind() == reflect.Ptr:
 	case dstType.Kind() == reflect.Ptr:
@@ -87,6 +89,19 @@ func set(dst, src reflect.Value, output Argument) error {
 	return nil
 	return nil
 }
 }
 
 
+// setSlice attempts to assign src to dst when slices are not assignable by default
+// e.g. src: [][]byte -> dst: [][15]byte
+func setSlice(dst, src reflect.Value, output Argument) error {
+	slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len())
+	for i := 0; i < src.Len(); i++ {
+		v := src.Index(i)
+		reflect.Copy(slice.Index(i), v)
+	}
+
+	dst.Set(slice)
+	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.
 func requireAssignable(dst, src reflect.Value) error {
 func requireAssignable(dst, src reflect.Value) error {
 	if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface {
 	if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface {

+ 49 - 0
accounts/abi/unpack_test.go

@@ -364,6 +364,55 @@ func TestUnpack(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestUnpackSetDynamicArrayOutput(t *testing.T) {
+	abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var (
+		marshalledReturn32 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783132333435363738393000000000000000000000000000000000000000003078303938373635343332310000000000000000000000000000000000000000")
+		marshalledReturn15 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783031323334350000000000000000000000000000000000000000000000003078393837363534000000000000000000000000000000000000000000000000")
+
+		out32 [][32]byte
+		out15 [][15]byte
+	)
+
+	// test 32
+	err = abi.Unpack(&out32, "testDynamicFixedBytes32", marshalledReturn32)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(out32) != 2 {
+		t.Fatalf("expected array with 2 values, got %d", len(out32))
+	}
+	expected := common.Hex2Bytes("3078313233343536373839300000000000000000000000000000000000000000")
+	if !bytes.Equal(out32[0][:], expected) {
+		t.Errorf("expected %x, got %x\n", expected, out32[0])
+	}
+	expected = common.Hex2Bytes("3078303938373635343332310000000000000000000000000000000000000000")
+	if !bytes.Equal(out32[1][:], expected) {
+		t.Errorf("expected %x, got %x\n", expected, out32[1])
+	}
+
+	// test 15
+	err = abi.Unpack(&out15, "testDynamicFixedBytes32", marshalledReturn15)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(out15) != 2 {
+		t.Fatalf("expected array with 2 values, got %d", len(out15))
+	}
+	expected = common.Hex2Bytes("307830313233343500000000000000")
+	if !bytes.Equal(out15[0][:], expected) {
+		t.Errorf("expected %x, got %x\n", expected, out15[0])
+	}
+	expected = common.Hex2Bytes("307839383736353400000000000000")
+	if !bytes.Equal(out15[1][:], expected) {
+		t.Errorf("expected %x, got %x\n", expected, out15[1])
+	}
+}
+
 type methodMultiOutput struct {
 type methodMultiOutput struct {
 	Int    *big.Int
 	Int    *big.Int
 	String string
 	String string