From 2609e0a827c9810c1027425119e2760cf8e73132 Mon Sep 17 00:00:00 2001 From: RJ Catalano Date: Fri, 30 Jun 2017 12:29:40 -0500 Subject: [PATCH] accounts/abi: get rid of tests that don't test like they should and redo abi Signed-off-by: RJ Catalano --- accounts/abi/unpack.go | 228 ++++++++++++----------- accounts/abi/unpack_test.go | 347 ++++++++++++++---------------------- 2 files changed, 248 insertions(+), 327 deletions(-) diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index a76a57cd86..93322e93bc 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -25,90 +25,10 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// toGoSliceType parses the input and casts it to the proper slice defined by the ABI -// argument in T. -func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { - index := i * 32 - // The slice must, at very least be large enough for the index+32 which is exactly the size required - // for the [offset in output, size of offset]. - if index+32 > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32) - } - - elem := t.Type.Elem - - // this value will become our slice or our array, depending on the type - var refSlice reflect.Value - var slice []byte - var size int - var offset int - if t.Type.T == SliceTy { - // get the offset which determines the start of this array ... - offset = int(binary.BigEndian.Uint64(output[index+24 : index+32])) - if offset+32 > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) - } - - slice = output[offset:] - // ... starting with the size of the array in elements ... - size = int(binary.BigEndian.Uint64(slice[24:32])) - slice = slice[32:] - // ... and make sure that we've at the very least the amount of bytes - // available in the buffer. - if size*32 > len(slice) { - return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32) - } - - // reslice to match the required size - slice = slice[:size*32] - // declare our slice - refSlice = reflect.MakeSlice(reflect.SliceOf(elem.Type), size, size) - } else if t.Type.T == ArrayTy { - //get the number of elements in the array - size = t.Type.Size - // declare our slice - refSlice = reflect.New(reflect.ArrayOf(size, elem.Type)).Elem() - //check to make sure array size matches up - if index+32*size > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size) - } - //slice is there for a fixed amount of times - slice = output[index : index+size*32] - } - - for i := 0; i < size; i++ { - var ( - inter interface{} // interface type - returnOutput = slice[i*32 : i*32+32] // the return output - err error - ) - // set inter to the correct type (cast) - switch elem.T { - case IntTy, UintTy: - inter = readInteger(elem.Kind, returnOutput) - case BoolTy: - inter, err = readBool(returnOutput) - if err != nil { - return nil, err - } - case AddressTy: - inter = common.BytesToAddress(returnOutput) - case HashTy: - inter = common.BytesToHash(returnOutput) - case FixedBytesTy: - inter = returnOutput - default: - return nil, fmt.Errorf("abi: unsupported slice type passed in") - } - - //fmt.Printf("type: %T, value: %v\n", inter, inter) - //fmt.Printf("%v\n", elem.stringKind) - // append the item to our reflect slice - refSlice.Index(i).Set(reflect.ValueOf(inter)) - } - - // return the interface - return refSlice.Interface(), nil +type unpacker interface { + tupleUnpack(v interface{}, output []byte) error + singleUnpack(v interface{}, output []byte) error + tupleReturn() bool } func readInteger(kind reflect.Kind, b []byte) interface{} { @@ -152,58 +72,134 @@ func readBool(word []byte) (bool, error) { default: return false, errBadBool } +} +func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { + if t.T != FunctionTy { + return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array.") + } + if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { + err = fmt.Errorf("abi: got improperly encoded function type, got %v", word) + } else { + copy(funcTy[:], word[0:24]) + } + return +} + +func readFixedBytes(t Type, word []byte) (interface{}, error) { + if t.T != FixedBytesTy { + return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array.") + } + // convert + array := reflect.New(t.Type).Elem() + + reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) + return array.Interface(), nil + +} + +func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { + if start+32*size > len(output) { + return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) + } + + // this value will become our slice or our array, depending on the type + var refSlice reflect.Value + slice := output[start : start+size*32] + if t.T == SliceTy { + // declare our slice + refSlice = reflect.MakeSlice(t.Type, size, size) + } else if t.T == ArrayTy { + // declare our array + refSlice = reflect.New(t.Type).Elem() + } else { + return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") + } + + for i, j := start, 0; j*32 < len(slice); i, j = i+32, j+1 { + inter, err := toGoType(i, *t.Elem, output) + if err != nil { + return nil, err + } + // append the item to our reflect slice + refSlice.Index(j).Set(reflect.ValueOf(inter)) + } + + // return the interface + return refSlice.Interface(), nil } // toGoType parses the input and casts it to the proper type defined by the ABI // argument in T. -func toGoType(i int, t Argument, output []byte) (interface{}, error) { - // we need to treat slices differently - if t.Type.T == SliceTy || t.Type.T == ArrayTy { - return toGoSlice(i, t, output) - } - - index := i * 32 +func toGoType(index int, t Type, output []byte) (interface{}, error) { if index+32 > len(output) { return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) } // Parse the given index output and check whether we need to read // a different offset and length based on the type (i.e. string, bytes) - var returnOutput []byte - switch t.Type.T { - case StringTy, BytesTy: // variable arrays are written at the end of the return bytes - // parse offset from which we should start reading - offset := int(binary.BigEndian.Uint64(output[index+24 : index+32])) - if offset+32 > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32) - } - // parse the size up until we should be reading - size := int(binary.BigEndian.Uint64(output[offset+24 : offset+32])) - if offset+32+size > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size) - } + var ( + returnOutput []byte + i, j int + err error + ) - // get the bytes for this return value - returnOutput = output[offset+32 : offset+32+size] - default: + if t.requiresLengthPrefix() { + i, j, err = lengthPrefixPointsTo(index, output) + if err != nil { + return nil, err + } + } else { returnOutput = output[index : index+32] } - - // convert the bytes to whatever is specified by the ABI. - switch t.Type.T { + switch t.T { + case SliceTy: + return forEachUnpack(t, output, i, j) + case ArrayTy: + return forEachUnpack(t, output, i, t.Size) + case StringTy: // variable arrays are written at the end of the return bytes + return string(output[i : i+j]), nil case IntTy, UintTy: - return readInteger(t.Type.Kind, returnOutput), nil + return readInteger(t.Kind, returnOutput), nil case BoolTy: return readBool(returnOutput) case AddressTy: return common.BytesToAddress(returnOutput), nil case HashTy: return common.BytesToHash(returnOutput), nil - case BytesTy, FixedBytesTy, FunctionTy: - return returnOutput, nil - case StringTy: - return string(returnOutput), nil + case BytesTy: + return output[i : i+j], nil + case FixedBytesTy: + return readFixedBytes(t, returnOutput) + case FunctionTy: + return readFunctionType(t, returnOutput) + default: + return nil, fmt.Errorf("abi: unknown type %v", t.T) + } +} + +// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type. +func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { + offset := int(binary.BigEndian.Uint64(output[index+24 : index+32])) + if offset+32 > len(output) { + return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) + } + length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32])) + if offset+32+length > len(output) { + return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length) + } + start = offset + 32 + + //fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start) + return +} + +func bytesAreProper(output []byte) error { + if len(output) == 0 { + return fmt.Errorf("abi: unmarshalling empty output") + } else if len(output)%32 != 0 { + return fmt.Errorf("abi: improperly formatted output") + } else { + return nil } - return nil, fmt.Errorf("abi: unknown type %v", t.Type.T) } diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 6f25284e24..692bb40727 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -110,10 +110,24 @@ func TestSimpleMethodUnpack(t *testing.T) { { `[ { "type": "bytes32" } ]`, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), + [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + "fixedBytes32", + "", + }, + { + `[ { "type": "bytes" } ]`, + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000"), common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), "bytes", "", }, + { + `[ { "type": "bytes" } ]`, + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000"), + nil, + "fixedBytes32", + "abi: cannot unmarshal []uint8 in to [32]uint8", + }, { `[ { "type": "bytes32" } ]`, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), @@ -121,13 +135,6 @@ func TestSimpleMethodUnpack(t *testing.T) { "hash", "", }, - { - `[ { "type": "bytes32" } ]`, - common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), - common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), - "interface", - "", - }, { `[ { "type": "function" } ]`, common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"), @@ -193,6 +200,11 @@ func TestSimpleMethodUnpack(t *testing.T) { var v []byte err = abi.Unpack(&v, "method", test.marshalledOutput) outvar = v + case "fixedBytes32": + // this is a bit presumptive but will work for testing for now + var v [32]byte + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v case "hash": var v common.Hash err = abi.Unpack(&v, "method", test.marshalledOutput) @@ -201,8 +213,6 @@ func TestSimpleMethodUnpack(t *testing.T) { var v [24]byte err = abi.Unpack(&v, "method", test.marshalledOutput) outvar = v - case "interface": - err = abi.Unpack(&outvar, "method", test.marshalledOutput) default: t.Errorf("unsupported type '%v' please add it to the switch statement in this test", test.outVar) continue @@ -228,156 +238,163 @@ func TestSimpleMethodUnpack(t *testing.T) { } } } - func TestArraysAndSlicesUnpack(t *testing.T) { for i, test := range []struct { def string // definition of the **output** ABI params marshalledOutput []byte // evm return data expectedOut interface{} // the expected output - outVar interface{} // the output variable (e.g. uint32, *big.Int, etc) + outVar string // the output variable (e.g. uint32, *big.Int, etc) err string // empty or error if expected }{ { `[ { "type": "uint8[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []uint8{1, 2}, - []uint8{}, + "[]uint8", + "", + }, + { + `[ { "type": "uint8[][]" } ]`, + common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + [][]uint8{{1, 2}, {1, 2}}, + "[][]uint8", "", }, { `[ { "type": "uint8[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]uint8{1, 2}, - [2]uint8{}, + "[2]uint8", "", }, { `[ { "type": "uint16[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []uint16{1, 2}, - []uint16{}, + "[]uint16", "", }, { `[ { "type": "uint16[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]uint16{1, 2}, - [2]uint16{}, + "[2]uint16", "", }, { `[ { "type": "uint32[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []uint32{1, 2}, - []uint32{}, + "[]uint32", "", }, { `[ { "type": "uint32[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]uint32{1, 2}, - [2]uint32{}, + "[2]uint32", "", }, { `[ { "type": "uint64[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []uint64{1, 2}, - []uint64{}, + "[]uint64", "", }, { `[ { "type": "uint64[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]uint64{1, 2}, - [2]uint64{}, + "[2]uint64", "", }, { `[ { "type": "uint256[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []*big.Int{big.NewInt(1), big.NewInt(2)}, - []*big.Int{}, + "[]*big.Int", "", }, { `[ { "type": "uint256[3]" } ]`, append(pad([]byte{1}, 32, true), append(pad([]byte{2}, 32, true), pad([]byte{3}, 32, true)...)...), [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, - [3]*big.Int{}, + "[3]*big.Int", "", }, { `[ { "type": "int8[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []int8{1, 2}, - []int8{}, + "[]int8", "", }, { `[ { "type": "int8[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]int8{1, 2}, - [2]int8{}, + "[2]int8", "", }, { `[ { "type": "int16[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []int16{1, 2}, - []int16{}, + "[]int16", "", }, { `[ { "type": "int16[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]int16{1, 2}, - [2]int16{}, + "[2]int16", "", }, { `[ { "type": "int32[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []int32{1, 2}, - []int32{}, + "[]int32", "", }, { `[ { "type": "int32[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]int32{1, 2}, - [2]int32{}, + "[2]int32", "", }, { `[ { "type": "int64[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []int64{1, 2}, - []int64{}, + "[]int64", "", }, { `[ { "type": "int64[2]" } ]`, common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), [2]int64{1, 2}, - [2]int64{}, + "[2]int64", "", }, { `[ { "type": "int256[]" } ]`, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), []*big.Int{big.NewInt(1), big.NewInt(2)}, - []*big.Int{}, + "[]*big.Int", "", }, { `[ { "type": "int256[3]" } ]`, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"), [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, - [3]*big.Int{}, + "[3]*big.Int", "", }, } { + //t.Log(test.marshalledOutput) abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) abi, err := JSON(strings.NewReader(abiDefinition)) @@ -386,7 +403,88 @@ func TestArraysAndSlicesUnpack(t *testing.T) { continue } - err = abi.Unpack(&test.outVar, "method", test.marshalledOutput) + var outvar interface{} + switch test.outVar { + case "[][]uint8": + var v [][]uint8 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]uint8": + var v []uint8 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]uint8": + var v [2]uint8 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]uint16": + var v []uint16 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]uint16": + var v [2]uint16 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]uint32": + var v []uint32 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]uint32": + var v [2]uint32 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]uint64": + var v []uint64 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]uint64": + var v [2]uint64 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]int8": + var v []int8 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]int8": + var v [2]int8 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]int16": + var v []int16 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]int16": + var v [2]int16 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]int32": + var v []int32 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]int32": + var v [2]int32 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]int64": + var v []int64 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[2]int64": + var v [2]int64 + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[3]*big.Int": + var v [3]*big.Int + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + case "[]*big.Int": + var v []*big.Int + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v + default: + t.Errorf("unsupported type '%v' please add it to the switch statement in this test", test.outVar) + continue + } if err != nil && len(test.err) == 0 { t.Errorf("%d failed. Expected no err but got: %v", i, err) @@ -402,69 +500,14 @@ func TestArraysAndSlicesUnpack(t *testing.T) { } if err == nil { - if !reflect.DeepEqual(test.expectedOut, test.outVar) { - t.Errorf("%d failed. Output error: expected %v, got %v", i, test.expectedOut, test.outVar) + if !reflect.DeepEqual(test.expectedOut, outvar) { + t.Errorf("%d failed. Output error: expected %v, got %v", i, test.expectedOut, outvar) } } } } -func TestUnpackSetInterfaceSlice(t *testing.T) { - var ( - var1 = new(uint8) - var2 = new(uint8) - ) - out := []interface{}{var1, var2} - abi, err := JSON(strings.NewReader(`[{"type":"function", "name":"ints", "outputs":[{"type":"uint8"}, {"type":"uint8"}]}]`)) - if err != nil { - t.Fatal(err) - } - marshalledReturn := append(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")...) - err = abi.Unpack(&out, "ints", marshalledReturn) - if err != nil { - t.Fatal(err) - } - if *var1 != 1 { - t.Error("expected var1 to be 1, got", *var1) - } - if *var2 != 2 { - t.Error("expected var2 to be 2, got", *var2) - } - - out = []interface{}{var1} - err = abi.Unpack(&out, "ints", marshalledReturn) - - expErr := "abi: cannot marshal in to slices of unequal size (require: 2, got: 1)" - if err == nil || err.Error() != expErr { - t.Error("expected err:", expErr, "Got:", err) - } -} - -func TestUnpackSetInterfaceArrayOutput(t *testing.T) { - var ( - var1 = new([1]uint32) - var2 = new([1]uint32) - ) - out := []interface{}{var1, var2} - abi, err := JSON(strings.NewReader(`[{"type":"function", "name":"ints", "outputs":[{"type":"uint32[1]"}, {"type":"uint32[1]"}]}]`)) - if err != nil { - t.Fatal(err) - } - marshalledReturn := append(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")...) - err = abi.Unpack(&out, "ints", marshalledReturn) - if err != nil { - t.Fatal(err) - } - - if *var1 != [1]uint32{1} { - t.Error("expected var1 to be [1], got", *var1) - } - if *var2 != [1]uint32{2} { - t.Error("expected var2 to be [2], got", *var2) - } -} - func TestMultiReturnWithStruct(t *testing.T) { const definition = `[ { "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` @@ -518,101 +561,6 @@ func TestMultiReturnWithStruct(t *testing.T) { } } -func TestMultiReturnWithSlice(t *testing.T) { - const definition = `[ - { "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` - - abi, err := JSON(strings.NewReader(definition)) - if err != nil { - t.Fatal(err) - } - - // using buff to make the code readable - buff := new(bytes.Buffer) - buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) - buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) - buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005")) - stringOut := "hello" - buff.Write(common.RightPadBytes([]byte(stringOut), 32)) - - var inter []interface{} - err = abi.Unpack(&inter, "multi", buff.Bytes()) - if err != nil { - t.Error(err) - } - - if len(inter) != 2 { - t.Fatal("expected 2 results got", len(inter)) - } - - if num, ok := inter[0].(*big.Int); !ok || num.Cmp(big.NewInt(1)) != 0 { - t.Error("expected index 0 to be 1 got", num) - } - - if str, ok := inter[1].(string); !ok || str != stringOut { - t.Error("expected index 1 to be", stringOut, "got", str) - } -} - -func TestMarshalArrays(t *testing.T) { - const definition = `[ - { "name" : "bytes32", "constant" : false, "outputs": [ { "type": "bytes32" } ] }, - { "name" : "bytes10", "constant" : false, "outputs": [ { "type": "bytes10" } ] } - ]` - - abi, err := JSON(strings.NewReader(definition)) - if err != nil { - t.Fatal(err) - } - - output := common.LeftPadBytes([]byte{1}, 32) - - var bytes10 [10]byte - err = abi.Unpack(&bytes10, "bytes32", output) - if err == nil || err.Error() != "abi: cannot unmarshal src (len=32) in to dst (len=10)" { - t.Error("expected error or bytes32 not be assignable to bytes10:", err) - } - - var bytes32 [32]byte - err = abi.Unpack(&bytes32, "bytes32", output) - if err != nil { - t.Error("didn't expect error:", err) - } - if !bytes.Equal(bytes32[:], output) { - t.Error("expected bytes32[31] to be 1 got", bytes32[31]) - } - - type ( - B10 [10]byte - B32 [32]byte - ) - - var b10 B10 - err = abi.Unpack(&b10, "bytes32", output) - if err == nil || err.Error() != "abi: cannot unmarshal src (len=32) in to dst (len=10)" { - t.Error("expected error or bytes32 not be assignable to bytes10:", err) - } - - var b32 B32 - err = abi.Unpack(&b32, "bytes32", output) - if err != nil { - t.Error("didn't expect error:", err) - } - if !bytes.Equal(b32[:], output) { - t.Error("expected bytes32[31] to be 1 got", bytes32[31]) - } - - output[10] = 1 - var shortAssignLong [32]byte - err = abi.Unpack(&shortAssignLong, "bytes10", output) - if err != nil { - t.Error("didn't expect error:", err) - } - if !bytes.Equal(output, shortAssignLong[:]) { - t.Errorf("expected %x to be %x", shortAssignLong, output) - } -} - func TestUnmarshal(t *testing.T) { const definition = `[ { "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] }, @@ -685,11 +633,11 @@ func TestUnmarshal(t *testing.T) { t.Errorf("expected %x got %x", bytesOut, Bytes) } - // marshall dynamic bytes max length 63 + // marshall dynamic bytes max length 64 buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000003f")) - bytesOut = common.RightPadBytes([]byte("hello"), 63) + bytesOut = common.RightPadBytes([]byte("hello"), 64) buff.Write(bytesOut) err = abi.Unpack(&Bytes, "bytes", buff.Bytes()) @@ -697,8 +645,8 @@ func TestUnmarshal(t *testing.T) { t.Error(err) } - if !bytes.Equal(Bytes, bytesOut) { - t.Errorf("expected %x got %x", bytesOut, Bytes) + if !bytes.Equal(Bytes, bytesOut[:len(bytesOut)-1]) { + t.Errorf("expected %x got %x", bytesOut[:len(bytesOut)-1], Bytes) } // marshal dynamic bytes output empty @@ -750,29 +698,6 @@ func TestUnmarshal(t *testing.T) { t.Error("expected error") } - // marshal mixed bytes - buff.Reset() - buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) - fixed := common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001") - buff.Write(fixed) - buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) - bytesOut = common.RightPadBytes([]byte("hello"), 32) - buff.Write(bytesOut) - - var out []interface{} - err = abi.Unpack(&out, "mixedBytes", buff.Bytes()) - if err != nil { - t.Fatal("didn't expect error:", err) - } - - if !bytes.Equal(bytesOut, out[0].([]byte)) { - t.Errorf("expected %x, got %x", bytesOut, out[0]) - } - - if !bytes.Equal(fixed, out[1].([]byte)) { - t.Errorf("expected %x, got %x", fixed, out[1]) - } - buff.Reset() buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"))