From 2fab5dc246089769ecb85b7c26cb7bb7d033fb1d Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 18 Nov 2016 11:13:44 +0100 Subject: [PATCH 1/3] accounts/abi: Must copy arrays of arrays element wise --- accounts/abi/reflect.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 7970ba8ac1..c92c10b1be 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -81,7 +81,14 @@ func set(dst, src reflect.Value, output Argument) error { if dst.Len() < output.Type.SliceSize { return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len()) } - reflect.Copy(dst, src) + switch dstType.Elem().Kind() { + case reflect.Array: + for i := 0; i < dst.Len(); i++ { + reflect.Copy(dst.Index(i), src.Index(i)) + } + default: + reflect.Copy(dst, src) + } case dstType.Kind() == reflect.Interface: dst.Set(src) case dstType.Kind() == reflect.Ptr: From 7470129121cca94930e3fe610c5ffa1c5d573b85 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 18 Nov 2016 11:13:09 +0100 Subject: [PATCH 2/3] accounts/abi: Index output for slices and arrays correctly --- accounts/abi/abi.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 2efac1307d..fb9be71c56 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -274,12 +274,21 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) error { // struct will match named return values to the struct's field // names case reflect.Struct: + idx := 0 for i := 0; i < len(method.Outputs); i++ { - marshalledValue, err := toGoType(i, method.Outputs[i], output) + marshalledValue, err := toGoType(idx, method.Outputs[i], output) if err != nil { return err } reflectValue := reflect.ValueOf(marshalledValue) + kind := reflectValue.Type().Kind() + if (kind == reflect.Array || kind == reflect.Slice) && + reflectValue.Type().Elem().Kind() != reflect.Uint8 { + // This is a slice of something other than bytes. + idx += reflectValue.Len() + } else { + idx++ + } for j := 0; j < typ.NumField(); j++ { field := typ.Field(j) From 5fbce1ad39b439fbc81a5fe466a6208287d12b0a Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 18 Nov 2016 17:10:44 +0100 Subject: [PATCH 3/3] accounts/abi: Add test for unpacking arrays of arrays --- accounts/abi/abi_test.go | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 85e25f9ea8..08a910d7a1 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -930,7 +930,8 @@ func TestUnmarshal(t *testing.T) { { "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] }, { "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] }, { "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, - { "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` + { "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }, + { "name" : "arraysStruct", "constant" : true, "outputs": [ { "name": "a", "type": "bytes4[2]" }, { "name": "b", "type": "bytes20[2]" } ] }]` abi, err := JSON(strings.NewReader(definition)) if err != nil { @@ -1166,4 +1167,37 @@ func TestUnmarshal(t *testing.T) { if err == nil { t.Fatal("expected error:", err) } + + // marshal arrays of arrays + buff.Reset() + buff.Write(common.Hex2Bytes("0000000100000000000000000000000000000000000000000000000000000000")) // a[0] + buff.Write(common.Hex2Bytes("0000000200000000000000000000000000000000000000000000000000000000")) // a[1] + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000003000000000000000000000000")) // b[0] + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000004000000000000000000000000")) // b[1] + + var arraysStruct struct { + A [2][4]byte + B [2][20]byte + } + err = abi.Unpack(&arraysStruct, "arraysStruct", buff.Bytes()) + if err != nil { + t.Fatal("didn't expect error:", err) + } + + exp4 := [4]byte{0, 0, 0, 1} + if arraysStruct.A[0] != exp4 { + t.Errorf("expected %x, got %x", exp4, arraysStruct.A[0]) + } + exp4 = [4]byte{0, 0, 0, 2} + if arraysStruct.A[1] != exp4 { + t.Errorf("expected %x, got %x", exp4, arraysStruct.A[1]) + } + exp20 := [20]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3} + if arraysStruct.B[0] != exp20 { + t.Errorf("expected %x, got %x", exp20, arraysStruct.B[0]) + } + exp20 = [20]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4} + if arraysStruct.B[1] != exp20 { + t.Errorf("expected %x, got %x", exp20, arraysStruct.B[1]) + } }