accounts/abi: add support for unpacking returned bytesN arrays

This commit is contained in:
Bas van Kervel 2017-10-04 15:08:59 +02:00
parent d78ad226c2
commit d37a347cc8
No known key found for this signature in database
GPG key ID: BFB23B252EF5812B
2 changed files with 65 additions and 0 deletions

View file

@ -77,6 +77,8 @@ func set(dst, src reflect.Value, output Argument) error {
switch { switch {
case dstType.AssignableTo(src.Type()): case dstType.AssignableTo(src.Type()):
dst.Set(src) dst.Set(src)
case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice:
return setSlice(dst, src, output)
case dstType.Kind() == reflect.Array && srcType.Kind() == reflect.Slice: case dstType.Kind() == reflect.Array && srcType.Kind() == reflect.Slice:
if dst.Len() < output.Type.SliceSize { 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()) return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len())
@ -91,3 +93,17 @@ func set(dst, src reflect.Value, output Argument) error {
} }
return nil return nil
} }
// setSlice attempts to assign src to dst when slices are not assignable by default
// e.g. src: [][]byte -> dst: [][15]byte
func setSlice(dst, src reflect.Value, output Argument) error {
slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len())
for i := 0; i < src.Len(); i++ {
v := src.Index(i)
reflect.Copy(slice.Index(i), v)
}
dst.Set(slice)
return nil
}

View file

@ -284,6 +284,55 @@ func TestUnpackSetInterfaceArrayOutput(t *testing.T) {
} }
} }
func TestUnpackSetDynamicArrayOutput(t *testing.T) {
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
if err != nil {
t.Fatal(err)
}
var (
marshalledReturn32 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783132333435363738393000000000000000000000000000000000000000003078303938373635343332310000000000000000000000000000000000000000")
marshalledReturn15 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783031323334350000000000000000000000000000000000000000000000003078393837363534000000000000000000000000000000000000000000000000")
out32 [][32]byte
out15 [][15]byte
)
// test 32
err = abi.Unpack(&out32, "testDynamicFixedBytes32", marshalledReturn32)
if err != nil {
t.Fatal(err)
}
if len(out32) != 2 {
t.Fatalf("expected array with 2 values, got %d", len(out32))
}
expected := common.Hex2Bytes("3078313233343536373839300000000000000000000000000000000000000000")
if bytes.Compare(out32[0][:], expected) != 0 {
t.Errorf("expected %x, got %x\n", expected, out32[0])
}
expected = common.Hex2Bytes("3078303938373635343332310000000000000000000000000000000000000000")
if bytes.Compare(out32[1][:], expected) != 0 {
t.Errorf("expected %x, got %x\n", expected, out32[1])
}
// test 15
err = abi.Unpack(&out15, "testDynamicFixedBytes32", marshalledReturn15)
if err != nil {
t.Fatal(err)
}
if len(out15) != 2 {
t.Fatalf("expected array with 2 values, got %d", len(out15))
}
expected = common.Hex2Bytes("307830313233343500000000000000")
if bytes.Compare(out15[0][:], expected) != 0 {
t.Errorf("expected %x, got %x\n", expected, out15[0])
}
expected = common.Hex2Bytes("307839383736353400000000000000")
if bytes.Compare(out15[1][:], expected) != 0 {
t.Errorf("expected %x, got %x\n", expected, out15[1])
}
}
func TestMultiReturnWithStruct(t *testing.T) { func TestMultiReturnWithStruct(t *testing.T) {
const definition = `[ const definition = `[
{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` { "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]`