From 7df52e324c1393f9dad3daa8c724782f4ade5b42 Mon Sep 17 00:00:00 2001 From: bas-vk Date: Sat, 22 Dec 2018 11:26:49 +0100 Subject: [PATCH] accounts/abi: add support for unpacking returned bytesN arrays (#15242) --- accounts/abi/reflect.go | 15 ++++++++++++ accounts/abi/unpack_test.go | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 0193517a4..6ec79a12f 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -77,6 +77,8 @@ func set(dst, src reflect.Value, output Argument) error { switch { case dstType.AssignableTo(srcType): dst.Set(src) + case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice: + return setSlice(dst, src, output) case dstType.Kind() == reflect.Interface: dst.Set(src) case dstType.Kind() == reflect.Ptr: @@ -87,6 +89,19 @@ func set(dst, src reflect.Value, output Argument) error { 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. func requireAssignable(dst, src reflect.Value) error { if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface { diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 29ed4522c..de7953770 100644 --- a/accounts/abi/unpack_test.go +++ b/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 { Int *big.Int String string