accounts/abi: add support for function types (#3405)

This commit is contained in:
RJ 2017-01-05 04:46:44 -06:00 committed by Felix Lange
parent 06b381d1c9
commit 2126d81488
4 changed files with 24 additions and 4 deletions

View File

@ -169,7 +169,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
// argument in T. // argument in T.
func toGoType(i int, t Argument, output []byte) (interface{}, error) { func toGoType(i int, t Argument, output []byte) (interface{}, error) {
// we need to treat slices differently // we need to treat slices differently
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy { if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy {
return toGoSlice(i, t, output) return toGoSlice(i, t, output)
} }
@ -233,7 +233,7 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
return common.BytesToAddress(returnOutput), nil return common.BytesToAddress(returnOutput), nil
case HashTy: case HashTy:
return common.BytesToHash(returnOutput), nil return common.BytesToHash(returnOutput), nil
case BytesTy, FixedBytesTy: case BytesTy, FixedBytesTy, FunctionTy:
return returnOutput, nil return returnOutput, nil
case StringTy: case StringTy:
return string(returnOutput), nil return string(returnOutput), nil

View File

@ -81,6 +81,7 @@ func TestTypeCheck(t *testing.T) {
{"bytes", common.Hash{1}, ""}, {"bytes", common.Hash{1}, ""},
{"string", "hello world", ""}, {"string", "hello world", ""},
{"bytes32[]", [][32]byte{[32]byte{}}, ""}, {"bytes32[]", [][32]byte{[32]byte{}}, ""},
{"function", [24]byte{}, ""},
} { } {
typ, err := NewType(test.typ) typ, err := NewType(test.typ)
if err != nil { if err != nil {
@ -197,6 +198,13 @@ func TestSimpleMethodUnpack(t *testing.T) {
"interface", "interface",
"", "",
}, },
{
`[ { "type": "function" } ]`,
pad([]byte{1}, 32, false),
[24]byte{1},
"function",
"",
},
} { } {
abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(abiDefinition)) abi, err := JSON(strings.NewReader(abiDefinition))
@ -255,6 +263,10 @@ func TestSimpleMethodUnpack(t *testing.T) {
var v common.Hash var v common.Hash
err = abi.Unpack(&v, "method", test.marshalledOutput) err = abi.Unpack(&v, "method", test.marshalledOutput)
outvar = v outvar = v
case "function":
var v [24]byte
err = abi.Unpack(&v, "method", test.marshalledOutput)
outvar = v
case "interface": case "interface":
err = abi.Unpack(&outvar, "method", test.marshalledOutput) err = abi.Unpack(&outvar, "method", test.marshalledOutput)
default: default:
@ -333,6 +345,7 @@ func TestPack(t *testing.T) {
{"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})}, {"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))}, {"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))}, {"bytes32[]", []common.Hash{common.Hash{1}, common.Hash{2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))},
{"function", [24]byte{1}, pad([]byte{1}, 32, false)},
} { } {
typ, err := NewType(test.typ) typ, err := NewType(test.typ)
if err != nil { if err != nil {

View File

@ -54,7 +54,7 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
reflectValue = mustArrayToByteSlice(reflectValue) reflectValue = mustArrayToByteSlice(reflectValue)
} }
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()) return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
case FixedBytesTy: case FixedBytesTy, FunctionTy:
if reflectValue.Kind() == reflect.Array { if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue) reflectValue = mustArrayToByteSlice(reflectValue)
} }

View File

@ -34,6 +34,7 @@ const (
BytesTy BytesTy
HashTy HashTy
FixedpointTy FixedpointTy
FunctionTy
) )
// Type is the reflection of the supported argument type // Type is the reflection of the supported argument type
@ -148,6 +149,12 @@ func NewType(t string) (typ Type, err error) {
typ.T = FixedBytesTy typ.T = FixedBytesTy
typ.SliceSize = varSize typ.SliceSize = varSize
} }
case "function":
sliceType, _ := NewType("uint8")
typ.Elem = &sliceType
typ.IsArray = true
typ.T = FunctionTy
typ.SliceSize = 24
default: default:
return Type{}, fmt.Errorf("unsupported arg type: %s", t) return Type{}, fmt.Errorf("unsupported arg type: %s", t)
} }
@ -168,7 +175,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
return nil, err return nil, err
} }
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy { if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy {
var packed []byte var packed []byte
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {