Merge pull request #2435 from obscuren/abi-array-fixes
accounts/abi: refactored ABI package
This commit is contained in:
		
						commit
						0f722df2d9
					
				| @ -48,42 +48,6 @@ func JSON(reader io.Reader) (ABI, error) { | ||||
| 	return abi, nil | ||||
| } | ||||
| 
 | ||||
| // tests, tests whether the given input would result in a successful
 | ||||
| // call. Checks argument list count and matches input to `input`.
 | ||||
| func (abi ABI) pack(method Method, args ...interface{}) ([]byte, error) { | ||||
| 	// variable input is the output appended at the end of packed
 | ||||
| 	// output. This is used for strings and bytes types input.
 | ||||
| 	var variableInput []byte | ||||
| 
 | ||||
| 	var ret []byte | ||||
| 	for i, a := range args { | ||||
| 		input := method.Inputs[i] | ||||
| 		// pack the input
 | ||||
| 		packed, err := input.Type.pack(a) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("`%s` %v", method.Name, err) | ||||
| 		} | ||||
| 
 | ||||
| 		// check for a slice type (string, bytes, slice)
 | ||||
| 		if input.Type.T == StringTy || input.Type.T == BytesTy || input.Type.IsSlice { | ||||
| 			// calculate the offset
 | ||||
| 			offset := len(method.Inputs)*32 + len(variableInput) | ||||
| 			// set the offset
 | ||||
| 			ret = append(ret, packNum(reflect.ValueOf(offset), UintTy)...) | ||||
| 			// Append the packed output to the variable input. The variable input
 | ||||
| 			// will be appended at the end of the input.
 | ||||
| 			variableInput = append(variableInput, packed...) | ||||
| 		} else { | ||||
| 			// append the packed value to the input
 | ||||
| 			ret = append(ret, packed...) | ||||
| 		} | ||||
| 	} | ||||
| 	// append the variable input at the end of the packed input
 | ||||
| 	ret = append(ret, variableInput...) | ||||
| 
 | ||||
| 	return ret, nil | ||||
| } | ||||
| 
 | ||||
| // Pack the given method name to conform the ABI. Method call's data
 | ||||
| // will consist of method_id, args0, arg1, ... argN. Method id consists
 | ||||
| // of 4 bytes and arguments are all 32 bytes.
 | ||||
| @ -102,11 +66,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { | ||||
| 		} | ||||
| 		method = m | ||||
| 	} | ||||
| 	// Make sure arguments match up and pack them
 | ||||
| 	if len(args) != len(method.Inputs) { | ||||
| 		return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs)) | ||||
| 	} | ||||
| 	arguments, err := abi.pack(method, args...) | ||||
| 	arguments, err := method.pack(method, args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -126,18 +86,21 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { | ||||
| 	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 | ||||
| 
 | ||||
| 	// first we need to create a slice of the type
 | ||||
| 	var refSlice reflect.Value | ||||
| 	switch t.Type.T { | ||||
| 	switch elem.T { | ||||
| 	case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int.
 | ||||
| 		refSlice = reflect.ValueOf([]*big.Int(nil)) | ||||
| 	case AddressTy: // address must be of slice Address
 | ||||
| 		refSlice = reflect.ValueOf([]common.Address(nil)) | ||||
| 	case HashTy: // hash must be of slice hash
 | ||||
| 		refSlice = reflect.ValueOf([]common.Hash(nil)) | ||||
| 	case FixedBytesTy: | ||||
| 		refSlice = reflect.ValueOf([]byte(nil)) | ||||
| 	default: // no other types are supported
 | ||||
| 		return nil, fmt.Errorf("abi: unsupported slice type %v", t.Type.T) | ||||
| 		return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T) | ||||
| 	} | ||||
| 	// get the offset which determines the start of this array ...
 | ||||
| 	offset := int(common.BytesToBig(output[index : index+32]).Uint64()) | ||||
| @ -164,7 +127,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { | ||||
| 		) | ||||
| 
 | ||||
| 		// set inter to the correct type (cast)
 | ||||
| 		switch t.Type.T { | ||||
| 		switch elem.T { | ||||
| 		case IntTy, UintTy: | ||||
| 			inter = common.BytesToBig(returnOutput) | ||||
| 		case BoolTy: | ||||
| @ -186,7 +149,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { | ||||
| // argument in T.
 | ||||
| func toGoType(i int, t Argument, output []byte) (interface{}, error) { | ||||
| 	// we need to treat slices differently
 | ||||
| 	if t.Type.IsSlice { | ||||
| 	if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy { | ||||
| 		return toGoSlice(i, t, output) | ||||
| 	} | ||||
| 
 | ||||
| @ -217,12 +180,33 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) { | ||||
| 		returnOutput = output[index : index+32] | ||||
| 	} | ||||
| 
 | ||||
| 	// cast bytes to abi return type
 | ||||
| 	// convert the bytes to whatever is specified by the ABI.
 | ||||
| 	switch t.Type.T { | ||||
| 	case IntTy: | ||||
| 		return common.BytesToBig(returnOutput), nil | ||||
| 	case UintTy: | ||||
| 		return common.BytesToBig(returnOutput), nil | ||||
| 	case IntTy, UintTy: | ||||
| 		bigNum := common.BytesToBig(returnOutput) | ||||
| 
 | ||||
| 		// If the type is a integer convert to the integer type
 | ||||
| 		// specified by the ABI.
 | ||||
| 		switch t.Type.Kind { | ||||
| 		case reflect.Uint8: | ||||
| 			return uint8(bigNum.Uint64()), nil | ||||
| 		case reflect.Uint16: | ||||
| 			return uint16(bigNum.Uint64()), nil | ||||
| 		case reflect.Uint32: | ||||
| 			return uint32(bigNum.Uint64()), nil | ||||
| 		case reflect.Uint64: | ||||
| 			return uint64(bigNum.Uint64()), nil | ||||
| 		case reflect.Int8: | ||||
| 			return int8(bigNum.Int64()), nil | ||||
| 		case reflect.Int16: | ||||
| 			return int16(bigNum.Int64()), nil | ||||
| 		case reflect.Int32: | ||||
| 			return int32(bigNum.Int64()), nil | ||||
| 		case reflect.Int64: | ||||
| 			return int64(bigNum.Int64()), nil | ||||
| 		case reflect.Ptr: | ||||
| 			return bigNum, nil | ||||
| 		} | ||||
| 	case BoolTy: | ||||
| 		return common.BytesToBig(returnOutput).Uint64() > 0, nil | ||||
| 	case AddressTy: | ||||
| @ -328,10 +312,12 @@ func set(dst, src reflect.Value, output Argument) error { | ||||
| 			return fmt.Errorf("abi: cannot unmarshal %v in to array of elem %v", src.Type(), dstType.Elem()) | ||||
| 		} | ||||
| 
 | ||||
| 		if dst.Len() < output.Type.Size { | ||||
| 			return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.Size, dst.Len()) | ||||
| 		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) | ||||
| 	case dstType.Kind() == reflect.Interface: | ||||
| 		dst.Set(src) | ||||
| 	default: | ||||
| 		return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) | ||||
| 	} | ||||
|  | ||||
| @ -29,66 +29,391 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| ) | ||||
| 
 | ||||
| // formatSilceOutput add padding to the value and adds a size
 | ||||
| func formatSliceOutput(v ...[]byte) []byte { | ||||
| 	off := common.LeftPadBytes(big.NewInt(int64(len(v))).Bytes(), 32) | ||||
| 	output := append(off, make([]byte, 0, len(v)*32)...) | ||||
| 
 | ||||
| 	for _, value := range v { | ||||
| 		output = append(output, common.LeftPadBytes(value, 32)...) | ||||
| 	} | ||||
| 	return output | ||||
| } | ||||
| 
 | ||||
| // quick helper padding
 | ||||
| func pad(input []byte, size int, left bool) []byte { | ||||
| 	if left { | ||||
| 		return common.LeftPadBytes(input, size) | ||||
| 	} | ||||
| 	return common.RightPadBytes(input, size) | ||||
| } | ||||
| 
 | ||||
| func TestTypeCheck(t *testing.T) { | ||||
| 	for i, test := range []struct { | ||||
| 		typ   string | ||||
| 		input interface{} | ||||
| 		err   string | ||||
| 	}{ | ||||
| 		{"uint", big.NewInt(1), ""}, | ||||
| 		{"int", big.NewInt(1), ""}, | ||||
| 		{"uint30", big.NewInt(1), ""}, | ||||
| 		{"uint30", uint8(1), "abi: cannot use uint8 as type ptr as argument"}, | ||||
| 		{"uint16", uint16(1), ""}, | ||||
| 		{"uint16", uint8(1), "abi: cannot use uint8 as type uint16 as argument"}, | ||||
| 		{"uint16[]", []uint16{1, 2, 3}, ""}, | ||||
| 		{"uint16[]", [3]uint16{1, 2, 3}, ""}, | ||||
| 		{"uint16[]", []uint32{1, 2, 3}, "abi: cannot use []uint32 as type []uint16 as argument"}, | ||||
| 		{"uint16[3]", [3]uint32{1, 2, 3}, "abi: cannot use [3]uint32 as type [3]uint16 as argument"}, | ||||
| 		{"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, | ||||
| 		{"uint16[3]", []uint16{1, 2, 3}, ""}, | ||||
| 		{"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, | ||||
| 		{"address[]", []common.Address{common.Address{1}}, ""}, | ||||
| 		{"address[1]", []common.Address{common.Address{1}}, ""}, | ||||
| 		{"address[1]", [1]common.Address{common.Address{1}}, ""}, | ||||
| 		{"address[2]", [1]common.Address{common.Address{1}}, "abi: cannot use [1]array as type [2]array as argument"}, | ||||
| 		{"bytes32", [32]byte{}, ""}, | ||||
| 		{"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"}, | ||||
| 		{"bytes32", common.Hash{1}, ""}, | ||||
| 		{"bytes31", [31]byte{}, ""}, | ||||
| 		{"bytes31", [32]byte{}, "abi: cannot use [32]uint8 as type [31]uint8 as argument"}, | ||||
| 		{"bytes", []byte{0, 1}, ""}, | ||||
| 		{"bytes", [2]byte{0, 1}, ""}, | ||||
| 		{"bytes", common.Hash{1}, ""}, | ||||
| 		{"string", "hello world", ""}, | ||||
| 		{"bytes32[]", [][32]byte{[32]byte{}}, ""}, | ||||
| 	} { | ||||
| 		typ, err := NewType(test.typ) | ||||
| 		if err != nil { | ||||
| 			t.Fatal("unexpected parse error:", err) | ||||
| 		} | ||||
| 
 | ||||
| 		err = typeCheck(typ, reflect.ValueOf(test.input)) | ||||
| 		if err != nil && len(test.err) == 0 { | ||||
| 			t.Errorf("%d failed. Expected no err but got: %v", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if err == nil && len(test.err) != 0 { | ||||
| 			t.Errorf("%d failed. Expected err: %v but got none", i, test.err) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if err != nil && len(test.err) != 0 && err.Error() != test.err { | ||||
| 			t.Errorf("%d failed. Expected err: '%v' got err: '%v'", i, test.err, err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestSimpleMethodUnpack(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           string      // the output variable (e.g. uint32, *big.Int, etc)
 | ||||
| 		err              string      // empty or error if expected
 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			`[ { "type": "uint32" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			uint32(1), | ||||
| 			"uint32", | ||||
| 			"", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "uint32" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			nil, | ||||
| 			"uint16", | ||||
| 			"abi: cannot unmarshal uint32 in to uint16", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "uint17" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			nil, | ||||
| 			"uint16", | ||||
| 			"abi: cannot unmarshal *big.Int in to uint16", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "uint17" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			big.NewInt(1), | ||||
| 			"*big.Int", | ||||
| 			"", | ||||
| 		}, | ||||
| 
 | ||||
| 		{ | ||||
| 			`[ { "type": "int32" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			int32(1), | ||||
| 			"int32", | ||||
| 			"", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "int32" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			nil, | ||||
| 			"int16", | ||||
| 			"abi: cannot unmarshal int32 in to int16", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "int17" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			nil, | ||||
| 			"int16", | ||||
| 			"abi: cannot unmarshal *big.Int in to int16", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "int17" } ]`, | ||||
| 			pad([]byte{1}, 32, true), | ||||
| 			big.NewInt(1), | ||||
| 			"*big.Int", | ||||
| 			"", | ||||
| 		}, | ||||
| 
 | ||||
| 		{ | ||||
| 			`[ { "type": "address" } ]`, | ||||
| 			pad(pad([]byte{1}, 20, false), 32, true), | ||||
| 			common.Address{1}, | ||||
| 			"address", | ||||
| 			"", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "bytes32" } ]`, | ||||
| 			pad([]byte{1}, 32, false), | ||||
| 			pad([]byte{1}, 32, false), | ||||
| 			"bytes", | ||||
| 			"", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "bytes32" } ]`, | ||||
| 			pad([]byte{1}, 32, false), | ||||
| 			pad([]byte{1}, 32, false), | ||||
| 			"hash", | ||||
| 			"", | ||||
| 		}, | ||||
| 		{ | ||||
| 			`[ { "type": "bytes32" } ]`, | ||||
| 			pad([]byte{1}, 32, false), | ||||
| 			pad([]byte{1}, 32, false), | ||||
| 			"interface", | ||||
| 			"", | ||||
| 		}, | ||||
| 	} { | ||||
| 		abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) | ||||
| 		abi, err := JSON(strings.NewReader(abiDefinition)) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d failed. %v", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		var outvar interface{} | ||||
| 		switch test.outVar { | ||||
| 		case "uint8": | ||||
| 			var v 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 "uint32": | ||||
| 			var v 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 "int8": | ||||
| 			var v 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 "int32": | ||||
| 			var v 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 "*big.Int": | ||||
| 			var v *big.Int | ||||
| 			err = abi.Unpack(&v, "method", test.marshalledOutput) | ||||
| 			outvar = v | ||||
| 		case "address": | ||||
| 			var v common.Address | ||||
| 			err = abi.Unpack(&v, "method", test.marshalledOutput) | ||||
| 			outvar = v | ||||
| 		case "bytes": | ||||
| 			var v []byte | ||||
| 			err = abi.Unpack(&v, "method", test.marshalledOutput) | ||||
| 			outvar = v | ||||
| 		case "hash": | ||||
| 			var v common.Hash | ||||
| 			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 | ||||
| 		} | ||||
| 
 | ||||
| 		if err != nil && len(test.err) == 0 { | ||||
| 			t.Errorf("%d failed. Expected no err but got: %v", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if err == nil && len(test.err) != 0 { | ||||
| 			t.Errorf("%d failed. Expected err: %v but got none", i, test.err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if err != nil && len(test.err) != 0 && err.Error() != test.err { | ||||
| 			t.Errorf("%d failed. Expected err: '%v' got err: '%v'", i, test.err, err) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if err == nil { | ||||
| 			// bit of an ugly hack for hash type but I don't feel like finding a proper solution
 | ||||
| 			if test.outVar == "hash" { | ||||
| 				tmp := outvar.(common.Hash) // without assignment it's unaddressable
 | ||||
| 				outvar = tmp[:] | ||||
| 			} | ||||
| 
 | ||||
| 			if !reflect.DeepEqual(test.expectedOut, outvar) { | ||||
| 				t.Errorf("%d failed. Output error: expected %v, got %v", i, test.expectedOut, outvar) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestPack(t *testing.T) { | ||||
| 	for i, test := range []struct { | ||||
| 		typ string | ||||
| 
 | ||||
| 		input  interface{} | ||||
| 		output []byte | ||||
| 	}{ | ||||
| 		{"uint16", uint16(2), pad([]byte{2}, 32, true)}, | ||||
| 		{"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})}, | ||||
| 		{"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)}, | ||||
| 		{"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})}, | ||||
| 		{"address[]", []common.Address{common.Address{1}, common.Address{2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))}, | ||||
| 		{"bytes32[]", []common.Hash{common.Hash{1}, common.Hash{2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))}, | ||||
| 	} { | ||||
| 		typ, err := NewType(test.typ) | ||||
| 		if err != nil { | ||||
| 			t.Fatal("unexpected parse error:", err) | ||||
| 		} | ||||
| 
 | ||||
| 		output, err := typ.pack(reflect.ValueOf(test.input)) | ||||
| 		if err != nil { | ||||
| 			t.Fatal("unexpected pack error:", err) | ||||
| 		} | ||||
| 
 | ||||
| 		if !bytes.Equal(output, test.output) { | ||||
| 			t.Errorf("%d failed. Expected bytes: '%x' Got: '%x'", i, test.output, output) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestMethodPack(t *testing.T) { | ||||
| 	abi, err := JSON(strings.NewReader(jsondata2)) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	sig := abi.Methods["slice"].Id() | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 
 | ||||
| 	packed, err := abi.Pack("slice", []uint32{1, 2}) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| 
 | ||||
| 	var addrA, addrB = common.Address{1}, common.Address{2} | ||||
| 	sig = abi.Methods["sliceAddress"].Id() | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) | ||||
| 
 | ||||
| 	packed, err = abi.Pack("sliceAddress", []common.Address{addrA, addrB}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| 
 | ||||
| 	var addrC, addrD = common.Address{3}, common.Address{4} | ||||
| 	sig = abi.Methods["sliceMultiAddress"].Id() | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrC[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrD[:], 32)...) | ||||
| 
 | ||||
| 	packed, err = abi.Pack("sliceMultiAddress", []common.Address{addrA, addrB}, []common.Address{addrC, addrD}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| 
 | ||||
| 	sig = abi.Methods["slice256"].Id() | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 
 | ||||
| 	packed, err = abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)}) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const jsondata = ` | ||||
| [ | ||||
| 	{ "type" : "function", "name" : "balance", "const" : true }, | ||||
| 	{ "type" : "function", "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] } | ||||
| 	{ "type" : "function", "name" : "balance", "constant" : true }, | ||||
| 	{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] } | ||||
| ]` | ||||
| 
 | ||||
| const jsondata2 = ` | ||||
| [ | ||||
| 	{ "type" : "function", "name" : "balance", "const" : true }, | ||||
| 	{ "type" : "function", "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, | ||||
| 	{ "type" : "function", "name" : "test", "const" : false, "inputs" : [ { "name" : "number", "type" : "uint32" } ] }, | ||||
| 	{ "type" : "function", "name" : "string", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, | ||||
| 	{ "type" : "function", "name" : "bool", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, | ||||
| 	{ "type" : "function", "name" : "address", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, | ||||
| 	{ "type" : "function", "name" : "string32", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "string32" } ] }, | ||||
| 	{ "type" : "function", "name" : "uint64[2]", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] }, | ||||
| 	{ "type" : "function", "name" : "uint64[]", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] }, | ||||
| 	{ "type" : "function", "name" : "foo", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] }, | ||||
| 	{ "type" : "function", "name" : "bar", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] }, | ||||
| 	{ "type" : "function", "name" : "slice", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, | ||||
| 	{ "type" : "function", "name" : "slice256", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, | ||||
| 	{ "type" : "function", "name" : "sliceAddress", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, | ||||
| 	{ "type" : "function", "name" : "sliceMultiAddress", "const" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] } | ||||
| 	{ "type" : "function", "name" : "balance", "constant" : true }, | ||||
| 	{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }, | ||||
| 	{ "type" : "function", "name" : "test", "constant" : false, "inputs" : [ { "name" : "number", "type" : "uint32" } ] }, | ||||
| 	{ "type" : "function", "name" : "string", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "string" } ] }, | ||||
| 	{ "type" : "function", "name" : "bool", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "bool" } ] }, | ||||
| 	{ "type" : "function", "name" : "address", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address" } ] }, | ||||
| 	{ "type" : "function", "name" : "uint64[2]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] }, | ||||
| 	{ "type" : "function", "name" : "uint64[]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] }, | ||||
| 	{ "type" : "function", "name" : "foo", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] }, | ||||
| 	{ "type" : "function", "name" : "bar", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] }, | ||||
| 	{ "type" : "function", "name" : "slice", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, | ||||
| 	{ "type" : "function", "name" : "slice256", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, | ||||
| 	{ "type" : "function", "name" : "sliceAddress", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, | ||||
| 	{ "type" : "function", "name" : "sliceMultiAddress", "constant" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] } | ||||
| ]` | ||||
| 
 | ||||
| func TestType(t *testing.T) { | ||||
| 	typ, err := NewType("uint32") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	if typ.Kind != reflect.Uint { | ||||
| 		t.Error("expected uint32 to have kind Ptr") | ||||
| 	} | ||||
| 
 | ||||
| 	typ, err = NewType("uint32[]") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	if !typ.IsSlice { | ||||
| 		t.Error("expected uint32[] to be slice") | ||||
| 	} | ||||
| 	if typ.Type != ubig_t { | ||||
| 		t.Error("expcted uith32[] to have type uint64") | ||||
| 	} | ||||
| 
 | ||||
| 	typ, err = NewType("uint32[2]") | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	if !typ.IsSlice { | ||||
| 		t.Error("expected uint32[2] to be slice") | ||||
| 	} | ||||
| 	if typ.Type != ubig_t { | ||||
| 		t.Error("expcted uith32[2] to have type uint64") | ||||
| 	} | ||||
| 	if typ.SliceSize != 2 { | ||||
| 		t.Error("expected uint32[2] to have a size of 2") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestReader(t *testing.T) { | ||||
| 	Uint256, _ := NewType("uint256") | ||||
| 	exp := ABI{ | ||||
| @ -164,21 +489,6 @@ func TestTestString(t *testing.T) { | ||||
| 	if _, err := abi.Pack("string", "hello world"); err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	str10 := string(make([]byte, 10)) | ||||
| 	if _, err := abi.Pack("string32", str10); err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	str32 := string(make([]byte, 32)) | ||||
| 	if _, err := abi.Pack("string32", str32); err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	str33 := string(make([]byte, 33)) | ||||
| 	if _, err := abi.Pack("string32", str33); err == nil { | ||||
| 		t.Error("expected str33 to throw out of bound error") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestTestBool(t *testing.T) { | ||||
| @ -210,26 +520,10 @@ func TestTestSlice(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestImplicitTypeCasts(t *testing.T) { | ||||
| 	abi, err := JSON(strings.NewReader(jsondata2)) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		t.FailNow() | ||||
| 	} | ||||
| 
 | ||||
| 	slice := make([]uint8, 2) | ||||
| 	_, err = abi.Pack("uint64[2]", slice) | ||||
| 	expStr := "`uint64[2]` abi: cannot use type uint8 as type uint64" | ||||
| 	if err.Error() != expStr { | ||||
| 		t.Errorf("expected %v, got %v", expStr, err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestMethodSignature(t *testing.T) { | ||||
| 	String, _ := NewType("string") | ||||
| 	String32, _ := NewType("string32") | ||||
| 	m := Method{"foo", false, []Argument{Argument{"bar", String32, false}, Argument{"baz", String, false}}, nil} | ||||
| 	exp := "foo(string32,string)" | ||||
| 	m := Method{"foo", false, []Argument{Argument{"bar", String, false}, Argument{"baz", String, false}}, nil} | ||||
| 	exp := "foo(string,string)" | ||||
| 	if m.Sig() != exp { | ||||
| 		t.Error("signature mismatch", exp, "!=", m.Sig()) | ||||
| 	} | ||||
| @ -247,28 +541,6 @@ func TestMethodSignature(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestPack(t *testing.T) { | ||||
| 	abi, err := JSON(strings.NewReader(jsondata2)) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		t.FailNow() | ||||
| 	} | ||||
| 
 | ||||
| 	sig := crypto.Keccak256([]byte("foo(uint32)"))[:4] | ||||
| 	sig = append(sig, make([]byte, 32)...) | ||||
| 	sig[35] = 10 | ||||
| 
 | ||||
| 	packed, err := abi.Pack("foo", uint32(10)) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		t.FailNow() | ||||
| 	} | ||||
| 
 | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestMultiPack(t *testing.T) { | ||||
| 	abi, err := JSON(strings.NewReader(jsondata2)) | ||||
| 	if err != nil { | ||||
| @ -292,77 +564,6 @@ func TestMultiPack(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestPackSlice(t *testing.T) { | ||||
| 	abi, err := JSON(strings.NewReader(jsondata2)) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 		t.FailNow() | ||||
| 	} | ||||
| 
 | ||||
| 	sig := crypto.Keccak256([]byte("slice(uint32[2])"))[:4] | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 
 | ||||
| 	packed, err := abi.Pack("slice", []uint32{1, 2}) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| 
 | ||||
| 	var addrA, addrB = common.Address{1}, common.Address{2} | ||||
| 	sig = abi.Methods["sliceAddress"].Id() | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) | ||||
| 
 | ||||
| 	packed, err = abi.Pack("sliceAddress", []common.Address{addrA, addrB}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| 
 | ||||
| 	var addrC, addrD = common.Address{3}, common.Address{4} | ||||
| 	sig = abi.Methods["sliceMultiAddress"].Id() | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrC[:], 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes(addrD[:], 32)...) | ||||
| 
 | ||||
| 	packed, err = abi.Pack("sliceMultiAddress", []common.Address{addrA, addrB}, []common.Address{addrC, addrD}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| 
 | ||||
| 	sig = crypto.Keccak256([]byte("slice256(uint256[2])"))[:4] | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) | ||||
| 	sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) | ||||
| 
 | ||||
| 	packed, err = abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)}) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !bytes.Equal(packed, sig) { | ||||
| 		t.Errorf("expected %x got %x", sig, packed) | ||||
| 	} | ||||
| } | ||||
| func ExampleJSON() { | ||||
| 	const definition = `[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBar","outputs":[{"name":"","type":"bool"}],"type":"function"}]` | ||||
| 
 | ||||
| @ -382,9 +583,9 @@ func ExampleJSON() { | ||||
| 
 | ||||
| func TestInputVariableInputLength(t *testing.T) { | ||||
| 	const definition = `[ | ||||
| 	{ "type" : "function", "name" : "strOne", "const" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] }, | ||||
| 	{ "type" : "function", "name" : "bytesOne", "const" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] }, | ||||
| 	{ "type" : "function", "name" : "strTwo", "const" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] } | ||||
| 	{ "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)) | ||||
| @ -546,7 +747,7 @@ func TestBareEvents(t *testing.T) { | ||||
| 
 | ||||
| func TestMultiReturnWithStruct(t *testing.T) { | ||||
| 	const definition = `[ | ||||
| 	{ "name" : "multi", "const" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` | ||||
| 	{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` | ||||
| 
 | ||||
| 	abi, err := JSON(strings.NewReader(definition)) | ||||
| 	if err != nil { | ||||
| @ -599,7 +800,7 @@ func TestMultiReturnWithStruct(t *testing.T) { | ||||
| 
 | ||||
| func TestMultiReturnWithSlice(t *testing.T) { | ||||
| 	const definition = `[ | ||||
| 	{ "name" : "multi", "const" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` | ||||
| 	{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` | ||||
| 
 | ||||
| 	abi, err := JSON(strings.NewReader(definition)) | ||||
| 	if err != nil { | ||||
| @ -635,8 +836,8 @@ func TestMultiReturnWithSlice(t *testing.T) { | ||||
| 
 | ||||
| func TestMarshalArrays(t *testing.T) { | ||||
| 	const definition = `[ | ||||
| 	{ "name" : "bytes32", "const" : false, "outputs": [ { "type": "bytes32" } ] }, | ||||
| 	{ "name" : "bytes10", "const" : false, "outputs": [ { "type": "bytes10" } ] } | ||||
| 	{ "name" : "bytes32", "constant" : false, "outputs": [ { "type": "bytes32" } ] }, | ||||
| 	{ "name" : "bytes10", "constant" : false, "outputs": [ { "type": "bytes10" } ] } | ||||
| 	]` | ||||
| 
 | ||||
| 	abi, err := JSON(strings.NewReader(definition)) | ||||
| @ -694,14 +895,14 @@ func TestMarshalArrays(t *testing.T) { | ||||
| 
 | ||||
| func TestUnmarshal(t *testing.T) { | ||||
| 	const definition = `[ | ||||
| 	{ "name" : "int", "const" : false, "outputs": [ { "type": "uint256" } ] }, | ||||
| 	{ "name" : "bool", "const" : false, "outputs": [ { "type": "bool" } ] }, | ||||
| 	{ "name" : "bytes", "const" : false, "outputs": [ { "type": "bytes" } ] }, | ||||
| 	{ "name" : "fixed", "const" : false, "outputs": [ { "type": "bytes32" } ] }, | ||||
| 	{ "name" : "multi", "const" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] }, | ||||
| 	{ "name" : "addressSliceSingle", "const" : false, "outputs": [ { "type": "address[]" } ] }, | ||||
| 	{ "name" : "addressSliceDouble", "const" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, | ||||
| 	{ "name" : "mixedBytes", "const" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` | ||||
| 	{ "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" : "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 { | ||||
|  | ||||
							
								
								
									
										79
									
								
								accounts/abi/error.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								accounts/abi/error.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| // Copyright 2016 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package abi | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| ) | ||||
| 
 | ||||
| // formatSliceString formats the reflection kind with the given slice size
 | ||||
| // and returns a formatted string representation.
 | ||||
| func formatSliceString(kind reflect.Kind, sliceSize int) string { | ||||
| 	if sliceSize == -1 { | ||||
| 		return fmt.Sprintf("[]%v", kind) | ||||
| 	} | ||||
| 	return fmt.Sprintf("[%d]%v", sliceSize, kind) | ||||
| } | ||||
| 
 | ||||
| // sliceTypeCheck checks that the given slice can by assigned to the reflection
 | ||||
| // type in t.
 | ||||
| func sliceTypeCheck(t Type, val reflect.Value) error { | ||||
| 	if val.Kind() != reflect.Slice && val.Kind() != reflect.Array { | ||||
| 		return typeErr(formatSliceString(t.Kind, t.SliceSize), val.Type()) | ||||
| 	} | ||||
| 	if t.IsArray && val.Len() != t.SliceSize { | ||||
| 		return typeErr(formatSliceString(t.Elem.Kind, t.SliceSize), formatSliceString(val.Type().Elem().Kind(), val.Len())) | ||||
| 	} | ||||
| 
 | ||||
| 	if t.Elem.IsSlice { | ||||
| 		if val.Len() > 0 { | ||||
| 			return sliceTypeCheck(*t.Elem, val.Index(0)) | ||||
| 		} | ||||
| 	} else if t.Elem.IsArray { | ||||
| 		return sliceTypeCheck(*t.Elem, val.Index(0)) | ||||
| 	} | ||||
| 
 | ||||
| 	if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.Kind { | ||||
| 		return typeErr(formatSliceString(t.Elem.Kind, t.SliceSize), val.Type()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // typeCheck checks that the given reflection value can be assigned to the reflection
 | ||||
| // type in t.
 | ||||
| func typeCheck(t Type, value reflect.Value) error { | ||||
| 	if t.IsSlice || t.IsArray { | ||||
| 		return sliceTypeCheck(t, value) | ||||
| 	} | ||||
| 
 | ||||
| 	// Check base type validity. Element types will be checked later on.
 | ||||
| 	if t.Kind != value.Kind() { | ||||
| 		return typeErr(t.Kind, value.Kind()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // varErr returns a formatted error.
 | ||||
| func varErr(expected, got reflect.Kind) error { | ||||
| 	return typeErr(expected, got) | ||||
| } | ||||
| 
 | ||||
| // typeErr returns a formatted type casting error.
 | ||||
| func typeErr(expected, got interface{}) error { | ||||
| 	return fmt.Errorf("abi: cannot use %v as type %v as argument", got, expected) | ||||
| } | ||||
| @ -18,6 +18,7 @@ package abi | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| @ -38,6 +39,44 @@ type Method struct { | ||||
| 	Outputs []Argument | ||||
| } | ||||
| 
 | ||||
| func (m Method) pack(method Method, args ...interface{}) ([]byte, error) { | ||||
| 	// Make sure arguments match up and pack them
 | ||||
| 	if len(args) != len(method.Inputs) { | ||||
| 		return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs)) | ||||
| 	} | ||||
| 	// variable input is the output appended at the end of packed
 | ||||
| 	// output. This is used for strings and bytes types input.
 | ||||
| 	var variableInput []byte | ||||
| 
 | ||||
| 	var ret []byte | ||||
| 	for i, a := range args { | ||||
| 		input := method.Inputs[i] | ||||
| 		// pack the input
 | ||||
| 		packed, err := input.Type.pack(reflect.ValueOf(a)) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("`%s` %v", method.Name, err) | ||||
| 		} | ||||
| 
 | ||||
| 		// check for a slice type (string, bytes, slice)
 | ||||
| 		if input.Type.requiresLengthPrefix() { | ||||
| 			// calculate the offset
 | ||||
| 			offset := len(method.Inputs)*32 + len(variableInput) | ||||
| 			// set the offset
 | ||||
| 			ret = append(ret, packNum(reflect.ValueOf(offset), UintTy)...) | ||||
| 			// Append the packed output to the variable input. The variable input
 | ||||
| 			// will be appended at the end of the input.
 | ||||
| 			variableInput = append(variableInput, packed...) | ||||
| 		} else { | ||||
| 			// append the packed value to the input
 | ||||
| 			ret = append(ret, packed...) | ||||
| 		} | ||||
| 	} | ||||
| 	// append the variable input at the end of the packed input
 | ||||
| 	ret = append(ret, variableInput...) | ||||
| 
 | ||||
| 	return ret, nil | ||||
| } | ||||
| 
 | ||||
| // Sig returns the methods string signature according to the ABI spec.
 | ||||
| //
 | ||||
| // Example
 | ||||
|  | ||||
| @ -24,8 +24,8 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	big_t     = reflect.TypeOf(&big.Int{}) | ||||
| 	ubig_t    = reflect.TypeOf(&big.Int{}) | ||||
| 	big_t     = reflect.TypeOf(big.Int{}) | ||||
| 	ubig_t    = reflect.TypeOf(big.Int{}) | ||||
| 	byte_t    = reflect.TypeOf(byte(0)) | ||||
| 	byte_ts   = reflect.TypeOf([]byte(nil)) | ||||
| 	uint_t    = reflect.TypeOf(uint(0)) | ||||
|  | ||||
							
								
								
									
										65
									
								
								accounts/abi/packing.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								accounts/abi/packing.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| // Copyright 2016 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package abi | ||||
| 
 | ||||
| import ( | ||||
| 	"reflect" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| // 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), UintTy) | ||||
| 	return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...) | ||||
| } | ||||
| 
 | ||||
| // 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, t.T) | ||||
| 	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") | ||||
| } | ||||
							
								
								
									
										64
									
								
								accounts/abi/reflect.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								accounts/abi/reflect.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| // Copyright 2016 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package abi | ||||
| 
 | ||||
| import "reflect" | ||||
| 
 | ||||
| // indirect recursively dereferences the value until it either gets the value
 | ||||
| // or finds a big.Int
 | ||||
| func indirect(v reflect.Value) reflect.Value { | ||||
| 	if v.Kind() == reflect.Ptr && v.Elem().Type() != big_t { | ||||
| 		return indirect(v.Elem()) | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
| 
 | ||||
| // reflectIntKind returns the reflect using the given size and
 | ||||
| // unsignedness.
 | ||||
| func reflectIntKind(unsigned bool, size int) reflect.Kind { | ||||
| 	switch size { | ||||
| 	case 8: | ||||
| 		if unsigned { | ||||
| 			return reflect.Uint8 | ||||
| 		} | ||||
| 		return reflect.Int8 | ||||
| 	case 16: | ||||
| 		if unsigned { | ||||
| 			return reflect.Uint16 | ||||
| 		} | ||||
| 		return reflect.Int16 | ||||
| 	case 32: | ||||
| 		if unsigned { | ||||
| 			return reflect.Uint32 | ||||
| 		} | ||||
| 		return reflect.Int32 | ||||
| 	case 64: | ||||
| 		if unsigned { | ||||
| 			return reflect.Uint64 | ||||
| 		} | ||||
| 		return reflect.Int64 | ||||
| 	} | ||||
| 	return reflect.Ptr | ||||
| } | ||||
| 
 | ||||
| // mustArrayToBytesSlice creates a new byte slice with the exact same size as value
 | ||||
| // and copies the bytes in value to the new slice.
 | ||||
| func mustArrayToByteSlice(value reflect.Value) reflect.Value { | ||||
| 	slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len()) | ||||
| 	reflect.Copy(slice, value) | ||||
| 	return slice | ||||
| } | ||||
| @ -21,8 +21,6 @@ import ( | ||||
| 	"reflect" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| @ -40,53 +38,60 @@ const ( | ||||
| 
 | ||||
| // Type is the reflection of the supported argument type
 | ||||
| type Type struct { | ||||
| 	IsSlice   bool | ||||
| 	SliceSize int | ||||
| 	IsSlice, IsArray bool | ||||
| 	SliceSize        int | ||||
| 
 | ||||
| 	Elem *Type | ||||
| 
 | ||||
| 	Kind reflect.Kind | ||||
| 	Type reflect.Type | ||||
| 	Size int | ||||
| 	T    byte // Our own type checking
 | ||||
| 
 | ||||
| 	Kind       reflect.Kind | ||||
| 	Type       reflect.Type | ||||
| 	Size       int | ||||
| 	T          byte   // Our own type checking
 | ||||
| 	stringKind string // holds the unparsed string for deriving signatures
 | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	// fullTypeRegex parses the abi types
 | ||||
| 	//
 | ||||
| 	// Types can be in the format of:
 | ||||
| 	//
 | ||||
| 	// 	Input  = Type [ "[" [ Number ] "]" ] Name .
 | ||||
| 	// 	Type   = [ "u" ] "int" [ Number ] .
 | ||||
| 	//
 | ||||
| 	// Examples:
 | ||||
| 	//
 | ||||
| 	//      string     int       uint       real
 | ||||
| 	//      string32   int8      uint8      uint[]
 | ||||
| 	//      address    int256    uint256    real[2]
 | ||||
| 	fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?") | ||||
| 	typeRegex     = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?") | ||||
| 	// typeRegex parses the abi sub types
 | ||||
| 	typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?") | ||||
| ) | ||||
| 
 | ||||
| // NewType returns a fully parsed Type given by the input string or an error if it  can't be parsed.
 | ||||
| //
 | ||||
| // Strings can be in the format of:
 | ||||
| //
 | ||||
| // 	Input  = Type [ "[" [ Number ] "]" ] Name .
 | ||||
| // 	Type   = [ "u" ] "int" [ Number ] .
 | ||||
| //
 | ||||
| // Examples:
 | ||||
| //
 | ||||
| //      string     int       uint       real
 | ||||
| //      string32   int8      uint8      uint[]
 | ||||
| //      address    int256    uint256    real[2]
 | ||||
| // NewType creates a new reflection type of abi type given in t.
 | ||||
| func NewType(t string) (typ Type, err error) { | ||||
| 	// 1. full string 2. type 3. (opt.) is slice 4. (opt.) size
 | ||||
| 	// parse the full representation of the abi-type definition; including:
 | ||||
| 	// * full string
 | ||||
| 	// * type
 | ||||
| 	// 	* is slice
 | ||||
| 	//	* slice size
 | ||||
| 	res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0] | ||||
| 
 | ||||
| 	// check if type is slice and parse type.
 | ||||
| 	switch { | ||||
| 	case res[3] != "": | ||||
| 		// err is ignored. Already checked for number through the regexp
 | ||||
| 		typ.SliceSize, _ = strconv.Atoi(res[3]) | ||||
| 		typ.IsSlice = true | ||||
| 		typ.IsArray = true | ||||
| 	case res[2] != "": | ||||
| 		typ.IsSlice, typ.SliceSize = true, -1 | ||||
| 	case res[0] == "": | ||||
| 		return Type{}, fmt.Errorf("abi: type parse error: %s", t) | ||||
| 	} | ||||
| 	if typ.IsArray || typ.IsSlice { | ||||
| 		sliceType, err := NewType(res[1]) | ||||
| 		if err != nil { | ||||
| 			return Type{}, err | ||||
| 		} | ||||
| 		typ.Elem = &sliceType | ||||
| 		typ.stringKind = sliceType.stringKind + t[len(res[1]):] | ||||
| 		return typ, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// parse the type and size of the abi-type.
 | ||||
| 	parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0] | ||||
| @ -106,24 +111,24 @@ func NewType(t string) (typ Type, err error) { | ||||
| 		varSize = 256 | ||||
| 		t += "256" | ||||
| 	} | ||||
| 	typ.stringKind = t | ||||
| 
 | ||||
| 	switch varType { | ||||
| 	case "int": | ||||
| 		typ.Kind = reflect.Int | ||||
| 		typ.Kind = reflectIntKind(false, varSize) | ||||
| 		typ.Type = big_t | ||||
| 		typ.Size = varSize | ||||
| 		typ.T = IntTy | ||||
| 	case "uint": | ||||
| 		typ.Kind = reflect.Uint | ||||
| 		typ.Kind = reflectIntKind(true, varSize) | ||||
| 		typ.Type = ubig_t | ||||
| 		typ.Size = varSize | ||||
| 		typ.T = UintTy | ||||
| 	case "bool": | ||||
| 		typ.Kind = reflect.Bool | ||||
| 		typ.T = BoolTy | ||||
| 	case "real": // TODO
 | ||||
| 		typ.Kind = reflect.Invalid | ||||
| 	case "address": | ||||
| 		typ.Kind = reflect.Array | ||||
| 		typ.Type = address_t | ||||
| 		typ.Size = 20 | ||||
| 		typ.T = AddressTy | ||||
| @ -131,123 +136,55 @@ func NewType(t string) (typ Type, err error) { | ||||
| 		typ.Kind = reflect.String | ||||
| 		typ.Size = -1 | ||||
| 		typ.T = StringTy | ||||
| 		if varSize > 0 { | ||||
| 			typ.Size = 32 | ||||
| 		} | ||||
| 	case "hash": | ||||
| 		typ.Kind = reflect.Array | ||||
| 		typ.Size = 32 | ||||
| 		typ.Type = hash_t | ||||
| 		typ.T = HashTy | ||||
| 	case "bytes": | ||||
| 		typ.Kind = reflect.Array | ||||
| 		typ.Type = byte_ts | ||||
| 		typ.Size = varSize | ||||
| 		sliceType, _ := NewType("uint8") | ||||
| 		typ.Elem = &sliceType | ||||
| 		if varSize == 0 { | ||||
| 			typ.IsSlice = true | ||||
| 			typ.T = BytesTy | ||||
| 			typ.SliceSize = -1 | ||||
| 		} else { | ||||
| 			typ.IsArray = true | ||||
| 			typ.T = FixedBytesTy | ||||
| 			typ.SliceSize = varSize | ||||
| 		} | ||||
| 	default: | ||||
| 		return Type{}, fmt.Errorf("unsupported arg type: %s", t) | ||||
| 	} | ||||
| 	typ.stringKind = t | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // String implements Stringer
 | ||||
| func (t Type) String() (out string) { | ||||
| 	return t.stringKind | ||||
| } | ||||
| 
 | ||||
| // 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), UintTy) | ||||
| 	return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...) | ||||
| } | ||||
| func (t Type) pack(v reflect.Value) ([]byte, error) { | ||||
| 	// dereference pointer first if it's a pointer
 | ||||
| 	v = indirect(v) | ||||
| 
 | ||||
| // Test the given input parameter `v` and checks if it matches certain
 | ||||
| // criteria
 | ||||
| // * Big integers are checks for ptr types and if the given value is
 | ||||
| //   assignable
 | ||||
| // * Integer are checked for size
 | ||||
| // * Strings, addresses and bytes are checks for type and size
 | ||||
| func (t Type) pack(v interface{}) ([]byte, error) { | ||||
| 	value := reflect.ValueOf(v) | ||||
| 	switch kind := value.Kind(); kind { | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 		// check input is unsigned
 | ||||
| 		if t.Type != ubig_t { | ||||
| 			return nil, fmt.Errorf("abi: type mismatch: %s for %T", t.Type, v) | ||||
| 		} | ||||
| 
 | ||||
| 		// no implicit type casting
 | ||||
| 		if int(value.Type().Size()*8) != t.Size { | ||||
| 			return nil, fmt.Errorf("abi: cannot use type %T as type uint%d", v, t.Size) | ||||
| 		} | ||||
| 
 | ||||
| 		return packNum(value, t.T), nil | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		if t.Type != ubig_t { | ||||
| 			return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v) | ||||
| 		} | ||||
| 
 | ||||
| 		// no implicit type casting
 | ||||
| 		if int(value.Type().Size()*8) != t.Size { | ||||
| 			return nil, fmt.Errorf("abi: cannot use type %T as type uint%d", v, t.Size) | ||||
| 		} | ||||
| 		return packNum(value, t.T), nil | ||||
| 	case reflect.Ptr: | ||||
| 		// If the value is a ptr do a assign check (only used by
 | ||||
| 		// big.Int for now)
 | ||||
| 		if t.Type == ubig_t && value.Type() != ubig_t { | ||||
| 			return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v) | ||||
| 		} | ||||
| 		return packNum(value, t.T), nil | ||||
| 	case reflect.String: | ||||
| 		if t.Size > -1 && value.Len() > t.Size { | ||||
| 			return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size) | ||||
| 		} | ||||
| 
 | ||||
| 		return packBytesSlice([]byte(value.String()), value.Len()), nil | ||||
| 	case reflect.Slice: | ||||
| 		// Byte slice is a special case, it gets treated as a single value
 | ||||
| 		if t.T == BytesTy { | ||||
| 			return packBytesSlice(value.Bytes(), value.Len()), nil | ||||
| 		} | ||||
| 
 | ||||
| 		if t.SliceSize > -1 && value.Len() > t.SliceSize { | ||||
| 			return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size) | ||||
| 		} | ||||
| 
 | ||||
| 		// Signed / Unsigned check
 | ||||
| 		if value.Type() == big_t && (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) { | ||||
| 			return nil, fmt.Errorf("slice of incompatible types.") | ||||
| 		} | ||||
| 	if err := typeCheck(t, v); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy { | ||||
| 		var packed []byte | ||||
| 		for i := 0; i < value.Len(); i++ { | ||||
| 			val, err := t.pack(value.Index(i).Interface()) | ||||
| 		for i := 0; i < v.Len(); i++ { | ||||
| 			val, err := t.Elem.pack(v.Index(i)) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			packed = append(packed, val...) | ||||
| 		} | ||||
| 		return packBytesSlice(packed, value.Len()), nil | ||||
| 	case reflect.Bool: | ||||
| 		if value.Bool() { | ||||
| 			return common.LeftPadBytes(common.Big1.Bytes(), 32), nil | ||||
| 		} else { | ||||
| 			return common.LeftPadBytes(common.Big0.Bytes(), 32), nil | ||||
| 		} | ||||
| 	case reflect.Array: | ||||
| 		if v, ok := value.Interface().(common.Address); ok { | ||||
| 			return common.LeftPadBytes(v[:], 32), nil | ||||
| 		} else if v, ok := value.Interface().(common.Hash); ok { | ||||
| 			return v[:], nil | ||||
| 		} | ||||
| 		return packBytesSlice(packed, v.Len()), nil | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, fmt.Errorf("ABI: bad input given %v", value.Kind()) | ||||
| 	return packElement(t, v), nil | ||||
| } | ||||
| 
 | ||||
| // requireLengthPrefix returns whether the type requires any sort of length
 | ||||
| // prefixing.
 | ||||
| func (t Type) requiresLengthPrefix() bool { | ||||
| 	return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice || t.IsArray) | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user