Beispiel #1
0
// packElement packs the given reflect value according to the abi specification in
// t.
func packElement(t Type, reflectValue reflect.Value) []byte {
	switch t.T {
	case IntTy, UintTy:
		return packNum(reflectValue)
	case StringTy:
		return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len())
	case AddressTy:
		if reflectValue.Kind() == reflect.Array {
			reflectValue = mustArrayToByteSlice(reflectValue)
		}

		return common.LeftPadBytes(reflectValue.Bytes(), 32)
	case BoolTy:
		if reflectValue.Bool() {
			return common.LeftPadBytes(common.Big1.Bytes(), 32)
		} else {
			return common.LeftPadBytes(common.Big0.Bytes(), 32)
		}
	case BytesTy:
		if reflectValue.Kind() == reflect.Array {
			reflectValue = mustArrayToByteSlice(reflectValue)
		}
		return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
	case FixedBytesTy:
		if reflectValue.Kind() == reflect.Array {
			reflectValue = mustArrayToByteSlice(reflectValue)
		}

		return common.RightPadBytes(reflectValue.Bytes(), 32)
	}
	panic("abi: fatal error")
}
Beispiel #2
0
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(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
	buff.Write(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)
	}
}
Beispiel #3
0
func TestMultiReturnWithStruct(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(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
	stringOut := "hello"
	buff.Write(common.RightPadBytes([]byte(stringOut), 32))

	var inter struct {
		Int    *big.Int
		String string
	}
	err = abi.Unpack(&inter, "multi", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	if inter.Int == nil || inter.Int.Cmp(big.NewInt(1)) != 0 {
		t.Error("expected Int to be 1 got", inter.Int)
	}

	if inter.String != stringOut {
		t.Error("expected String to be", stringOut, "got", inter.String)
	}

	var reversed struct {
		String string
		Int    *big.Int
	}

	err = abi.Unpack(&reversed, "multi", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	if reversed.Int == nil || reversed.Int.Cmp(big.NewInt(1)) != 0 {
		t.Error("expected Int to be 1 got", reversed.Int)
	}

	if reversed.String != stringOut {
		t.Error("expected String to be", stringOut, "got", reversed.String)
	}
}
Beispiel #4
0
func TestUnmarshal(t *testing.T) {
	const definition = `[
	{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
	{ "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
	{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
	{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
	{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
	{ "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" } ] }]`

	abi, err := JSON(strings.NewReader(definition))
	if err != nil {
		t.Fatal(err)
	}
	buff := new(bytes.Buffer)

	// marshal int
	var Int *big.Int
	err = abi.Unpack(&Int, "int", Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
	if err != nil {
		t.Error(err)
	}

	if Int == nil || Int.Cmp(big.NewInt(1)) != 0 {
		t.Error("expected Int to be 1 got", Int)
	}

	// marshal bool
	var Bool bool
	err = abi.Unpack(&Bool, "bool", Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
	if err != nil {
		t.Error(err)
	}

	if !Bool {
		t.Error("expected Bool to be true")
	}

	// marshal dynamic bytes max length 32
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
	bytesOut := common.RightPadBytes([]byte("hello"), 32)
	buff.Write(bytesOut)

	var Bytes []byte
	err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	if !bytes.Equal(Bytes, bytesOut) {
		t.Errorf("expected %x got %x", bytesOut, Bytes)
	}

	// marshall dynamic bytes max length 64
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
	bytesOut = common.RightPadBytes([]byte("hello"), 64)
	buff.Write(bytesOut)

	err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	if !bytes.Equal(Bytes, bytesOut) {
		t.Errorf("expected %x got %x", bytesOut, Bytes)
	}

	// marshall dynamic bytes max length 63
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
	buff.Write(Hex2Bytes("000000000000000000000000000000000000000000000000000000000000003f"))
	bytesOut = common.RightPadBytes([]byte("hello"), 63)
	buff.Write(bytesOut)

	err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	if !bytes.Equal(Bytes, bytesOut) {
		t.Errorf("expected %x got %x", bytesOut, Bytes)
	}

	// marshal dynamic bytes output empty
	err = abi.Unpack(&Bytes, "bytes", nil)
	if err == nil {
		t.Error("expected error")
	}

	// marshal dynamic bytes length 5
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
	buff.Write(common.RightPadBytes([]byte("hello"), 32))

	err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	if !bytes.Equal(Bytes, []byte("hello")) {
		t.Errorf("expected %x got %x", bytesOut, Bytes)
	}

	// marshal dynamic bytes length 5
	buff.Reset()
	buff.Write(common.RightPadBytes([]byte("hello"), 32))

	var hash Hash
	err = abi.Unpack(&hash, "fixed", buff.Bytes())
	if err != nil {
		t.Error(err)
	}

	helloHash := BytesToHash(common.RightPadBytes([]byte("hello"), 32))
	if hash != helloHash {
		t.Errorf("Expected %x to equal %x", hash, helloHash)
	}

	// marshal error
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
	err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
	if err == nil {
		t.Error("expected error")
	}

	err = abi.Unpack(&Bytes, "multi", make([]byte, 64))
	if err == nil {
		t.Error("expected error")
	}

	// marshal mixed bytes
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
	fixed := Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")
	buff.Write(fixed)
	buff.Write(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(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
	// marshal int array
	var intArray [3]*big.Int
	err = abi.Unpack(&intArray, "intArraySingle", buff.Bytes())
	if err != nil {
		t.Error(err)
	}
	var testAgainstIntArray [3]*big.Int
	testAgainstIntArray[0] = big.NewInt(1)
	testAgainstIntArray[1] = big.NewInt(2)
	testAgainstIntArray[2] = big.NewInt(3)

	for i, Int := range intArray {
		if Int.Cmp(testAgainstIntArray[i]) != 0 {
			t.Error("expected %v, got %v", testAgainstIntArray[i], Int)
		}
	}

	// marshal address slice
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) // offset
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size
	buff.Write(Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))

	var outAddr []Address
	err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes())
	if err != nil {
		t.Fatal("didn't expect error:", err)
	}

	if len(outAddr) != 1 {
		t.Fatal("expected 1 item, got", len(outAddr))
	}

	if outAddr[0] != (Address{1}) {
		t.Errorf("expected %x, got %x", Address{1}, outAddr[0])
	}

	// marshal multiple address slice
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) // offset
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000080")) // offset
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size
	buff.Write(Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // size
	buff.Write(Hex2Bytes("0000000000000000000000000200000000000000000000000000000000000000"))
	buff.Write(Hex2Bytes("0000000000000000000000000300000000000000000000000000000000000000"))

	var outAddrStruct struct {
		A []Address
		B []Address
	}
	err = abi.Unpack(&outAddrStruct, "addressSliceDouble", buff.Bytes())
	if err != nil {
		t.Fatal("didn't expect error:", err)
	}

	if len(outAddrStruct.A) != 1 {
		t.Fatal("expected 1 item, got", len(outAddrStruct.A))
	}

	if outAddrStruct.A[0] != (Address{1}) {
		t.Errorf("expected %x, got %x", Address{1}, outAddrStruct.A[0])
	}

	if len(outAddrStruct.B) != 2 {
		t.Fatal("expected 1 item, got", len(outAddrStruct.B))
	}

	if outAddrStruct.B[0] != (Address{2}) {
		t.Errorf("expected %x, got %x", Address{2}, outAddrStruct.B[0])
	}
	if outAddrStruct.B[1] != (Address{3}) {
		t.Errorf("expected %x, got %x", Address{3}, outAddrStruct.B[1])
	}

	// marshal invalid address slice
	buff.Reset()
	buff.Write(Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100"))

	err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes())
	if err == nil {
		t.Fatal("expected error:", err)
	}
}
Beispiel #5
0
func TestInputVariableInputLength(t *testing.T) {
	const definition = `[
	{ "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
	{ "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
	{ "type" : "function", "name" : "strTwo", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] }
	]`

	abi, err := JSON(strings.NewReader(definition))
	if err != nil {
		t.Fatal(err)
	}

	// test one string
	strin := "hello world"
	strpack, err := abi.Pack("strOne", strin)
	if err != nil {
		t.Error(err)
	}

	offset := make([]byte, 32)
	offset[31] = 32
	length := make([]byte, 32)
	length[31] = byte(len(strin))
	value := common.RightPadBytes([]byte(strin), 32)
	exp := append(offset, append(length, value...)...)

	// ignore first 4 bytes of the output. This is the function identifier
	strpack = strpack[4:]
	if !bytes.Equal(strpack, exp) {
		t.Errorf("expected %x, got %x\n", exp, strpack)
	}

	// test one bytes
	btspack, err := abi.Pack("bytesOne", []byte(strin))
	if err != nil {
		t.Error(err)
	}
	// ignore first 4 bytes of the output. This is the function identifier
	btspack = btspack[4:]
	if !bytes.Equal(btspack, exp) {
		t.Errorf("expected %x, got %x\n", exp, btspack)
	}

	//  test two strings
	str1 := "hello"
	str2 := "world"
	str2pack, err := abi.Pack("strTwo", str1, str2)
	if err != nil {
		t.Error(err)
	}

	offset1 := make([]byte, 32)
	offset1[31] = 64
	length1 := make([]byte, 32)
	length1[31] = byte(len(str1))
	value1 := common.RightPadBytes([]byte(str1), 32)

	offset2 := make([]byte, 32)
	offset2[31] = 128
	length2 := make([]byte, 32)
	length2[31] = byte(len(str2))
	value2 := common.RightPadBytes([]byte(str2), 32)

	exp2 := append(offset1, offset2...)
	exp2 = append(exp2, append(length1, value1...)...)
	exp2 = append(exp2, append(length2, value2...)...)

	// ignore first 4 bytes of the output. This is the function identifier
	str2pack = str2pack[4:]
	if !bytes.Equal(str2pack, exp2) {
		t.Errorf("expected %x, got %x\n", exp, str2pack)
	}

	// test two strings, first > 32, second < 32
	str1 = strings.Repeat("a", 33)
	str2pack, err = abi.Pack("strTwo", str1, str2)
	if err != nil {
		t.Error(err)
	}

	offset1 = make([]byte, 32)
	offset1[31] = 64
	length1 = make([]byte, 32)
	length1[31] = byte(len(str1))
	value1 = common.RightPadBytes([]byte(str1), 64)
	offset2[31] = 160

	exp2 = append(offset1, offset2...)
	exp2 = append(exp2, append(length1, value1...)...)
	exp2 = append(exp2, append(length2, value2...)...)

	// ignore first 4 bytes of the output. This is the function identifier
	str2pack = str2pack[4:]
	if !bytes.Equal(str2pack, exp2) {
		t.Errorf("expected %x, got %x\n", exp, str2pack)
	}

	// test two strings, first > 32, second >32
	str1 = strings.Repeat("a", 33)
	str2 = strings.Repeat("a", 33)
	str2pack, err = abi.Pack("strTwo", str1, str2)
	if err != nil {
		t.Error(err)
	}

	offset1 = make([]byte, 32)
	offset1[31] = 64
	length1 = make([]byte, 32)
	length1[31] = byte(len(str1))
	value1 = common.RightPadBytes([]byte(str1), 64)

	offset2 = make([]byte, 32)
	offset2[31] = 160
	length2 = make([]byte, 32)
	length2[31] = byte(len(str2))
	value2 = common.RightPadBytes([]byte(str2), 64)

	exp2 = append(offset1, offset2...)
	exp2 = append(exp2, append(length1, value1...)...)
	exp2 = append(exp2, append(length2, value2...)...)

	// ignore first 4 bytes of the output. This is the function identifier
	str2pack = str2pack[4:]
	if !bytes.Equal(str2pack, exp2) {
		t.Errorf("expected %x, got %x\n", exp, str2pack)
	}
}
Beispiel #6
0
// quick helper padding
func pad(input []byte, size int, left bool) []byte {
	if left {
		return common.LeftPadBytes(input, size)
	}
	return common.RightPadBytes(input, size)
}
Beispiel #7
0
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
// bytes slice
func packBytesSlice(bytes []byte, l int) []byte {
	len := packNum(reflect.ValueOf(l))
	return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
}
Beispiel #8
0
func packInterfaceValue(typ Type, val string) (interface{}, error) {
	if typ.IsArray || typ.IsSlice {

		//check for fixed byte types and bytes types
		if typ.T == BytesTy {
			bytez := bytes.NewBufferString(val)
			return common.RightPadBytes(bytez.Bytes(), bytez.Len()%32), nil
		} else if typ.T == FixedBytesTy {
			bytez := bytes.NewBufferString(val)
			return common.RightPadBytes(bytez.Bytes(), typ.SliceSize), nil
		} else if typ.Elem.T == BytesTy || typ.Elem.T == FixedBytesTy {
			val = strings.Trim(val, "[]")
			arr := strings.Split(val, ",")
			var sliceOfFixedBytes [][]byte
			for _, str := range arr {
				bytez := bytes.NewBufferString(str)
				sliceOfFixedBytes = append(sliceOfFixedBytes, common.RightPadBytes(bytez.Bytes(), 32))
			}
			return sliceOfFixedBytes, nil
		} else {
			val = strings.Trim(val, "[]")
			arr := strings.Split(val, ",")
			var values interface{}

			for i := 0; i < typ.SliceSize; i++ {
				value, err := packInterfaceValue(*typ.Elem, arr[i])
				if err != nil {
					return nil, err
				}
				if value == nil {
					return nil, nil
				}
				//var bigIntValue = (*big.Int)(nil)
				switch value := value.(type) {
				case string:
					var ok bool
					if values, ok = values.([]string); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]string), value)
				case bool:
					var ok bool
					if values, ok = values.([]bool); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]bool), value)
				case uint8:
					var ok bool
					if values, ok = values.([]uint8); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]uint8), value)
				case uint16:
					var ok bool
					if values, ok = values.([]uint16); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]uint16), value)
				case uint32:
					var ok bool
					if values, ok = values.([]uint32); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]uint32), value)
				case uint64:
					var ok bool
					if values, ok = values.([]uint64); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]uint64), value)
				case int8:
					var ok bool
					if values, ok = values.([]int8); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]int8), value)
				case int16:
					var ok bool
					if values, ok = values.([]int16); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]int16), value)
				case int32:
					var ok bool
					if values, ok = values.([]uint32); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]int32), value)
				case int64:
					var ok bool
					if values, ok = values.([]uint64); ok {
						fmt.Printf("n=%#v\n", value)
					}
					values = append(values.([]int64), value)
				case *big.Int:
					var ok bool
					if values, ok = values.([]*big.Int); ok {
						fmt.Printf("n=%#v\n", value)
					}

					values = append(values.([]*big.Int), value)
				case Address:
					var ok bool
					if values, ok = values.([]Address); ok {
						fmt.Printf("n=%#v\n", value)
					}

					values = append(values.([]Address), value)
				}
			}
			return values, nil
		}
	} else {
		switch typ.T {
		case IntTy:
			switch typ.Size {
			case 8:
				val, err := strconv.ParseInt(val, 10, 8)
				if err != nil {
					return nil, err
				}
				return int8(val), nil
			case 16:
				val, err := strconv.ParseInt(val, 10, 16)
				if err != nil {
					return nil, err
				}
				return int16(val), nil
			case 32:
				val, err := strconv.ParseInt(val, 10, 32)
				if err != nil {
					return nil, err
				}
				return int32(val), nil
			case 64:
				val, err := strconv.ParseInt(val, 10, 64)
				if err != nil {
					return nil, err
				}
				return int64(val), nil
			default:
				val, set := big.NewInt(0).SetString(val, 10)
				if set != true {
					return nil, fmt.Errorf("Could not set to big int")
				}
				return val, nil
			}
		case UintTy:
			switch typ.Size {
			case 8:
				val, err := strconv.ParseUint(val, 10, 8)
				if err != nil {
					return nil, err
				}
				return uint8(val), nil
			case 16:
				val, err := strconv.ParseUint(val, 10, 16)
				if err != nil {
					return nil, err
				}
				return uint16(val), nil
			case 32:
				val, err := strconv.ParseUint(val, 10, 32)
				if err != nil {
					return nil, err
				}
				return uint32(val), nil
			case 64:
				val, err := strconv.ParseUint(val, 10, 64)
				if err != nil {
					return nil, err
				}
				return uint64(val), nil
			default:
				val, set := big.NewInt(0).SetString(val, 10)
				if set != true {
					return nil, fmt.Errorf("Could not set to big int")
				}
				return val, nil
			}
		case BoolTy:
			return strconv.ParseBool(val)
		case StringTy:
			return val, nil
		case AddressTy:
			return HexToAddress(val), nil
		default:
			return nil, fmt.Errorf("Could not get valid type from input")
		}
	}
}