mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-15 16:33:47 +00:00
accounts/abi: make a better slicing scheme
Signed-off-by: RJ Catalano <rj@monax.io>
This commit is contained in:
parent
41318f3776
commit
93f3e15c34
2 changed files with 198 additions and 43 deletions
|
|
@ -34,49 +34,15 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
if index+32 > len(output) {
|
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)
|
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
|
elem := t.Type.Elem
|
||||||
|
|
||||||
// first we need to create a slice of the type
|
// this value will become our slice or our array, depending on the type
|
||||||
var refSlice reflect.Value
|
var refSlice reflect.Value
|
||||||
switch elem.T {
|
|
||||||
case IntTy, UintTy, BoolTy:
|
|
||||||
// create a new reference slice matching the element type
|
|
||||||
switch t.Type.Kind {
|
|
||||||
case reflect.Bool:
|
|
||||||
refSlice = reflect.ValueOf([]bool(nil))
|
|
||||||
case reflect.Uint8:
|
|
||||||
refSlice = reflect.ValueOf([]uint8(nil))
|
|
||||||
case reflect.Uint16:
|
|
||||||
refSlice = reflect.ValueOf([]uint16(nil))
|
|
||||||
case reflect.Uint32:
|
|
||||||
refSlice = reflect.ValueOf([]uint32(nil))
|
|
||||||
case reflect.Uint64:
|
|
||||||
refSlice = reflect.ValueOf([]uint64(nil))
|
|
||||||
case reflect.Int8:
|
|
||||||
refSlice = reflect.ValueOf([]int8(nil))
|
|
||||||
case reflect.Int16:
|
|
||||||
refSlice = reflect.ValueOf([]int16(nil))
|
|
||||||
case reflect.Int32:
|
|
||||||
refSlice = reflect.ValueOf([]int32(nil))
|
|
||||||
case reflect.Int64:
|
|
||||||
refSlice = reflect.ValueOf([]int64(nil))
|
|
||||||
default:
|
|
||||||
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", elem.T)
|
|
||||||
}
|
|
||||||
|
|
||||||
var slice []byte
|
var slice []byte
|
||||||
var size int
|
var size int
|
||||||
var offset int
|
var offset int
|
||||||
if t.Type.IsSlice {
|
if t.Type.T == SliceTy {
|
||||||
// get the offset which determines the start of this array ...
|
// get the offset which determines the start of this array ...
|
||||||
offset = int(binary.BigEndian.Uint64(output[index+24 : index+32]))
|
offset = int(binary.BigEndian.Uint64(output[index+24 : index+32]))
|
||||||
if offset+32 > len(output) {
|
if offset+32 > len(output) {
|
||||||
|
|
@ -95,10 +61,13 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
|
|
||||||
// reslice to match the required size
|
// reslice to match the required size
|
||||||
slice = slice[:size*32]
|
slice = slice[:size*32]
|
||||||
} else if t.Type.IsArray {
|
// 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
|
//get the number of elements in the array
|
||||||
size = t.Type.SliceSize
|
size = t.Type.Size
|
||||||
|
// declare our slice
|
||||||
|
refSlice = reflect.New(reflect.ArrayOf(size, elem.Type)).Elem()
|
||||||
//check to make sure array size matches up
|
//check to make sure array size matches up
|
||||||
if index+32*size > len(output) {
|
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)
|
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)
|
||||||
|
|
@ -116,7 +85,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// set inter to the correct type (cast)
|
// set inter to the correct type (cast)
|
||||||
switch elem.T {
|
switch elem.T {
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
inter = readInteger(t.Type.Kind, returnOutput)
|
inter = readInteger(elem.Kind, returnOutput)
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
inter, err = readBool(returnOutput)
|
inter, err = readBool(returnOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -128,9 +97,14 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
inter = common.BytesToHash(returnOutput)
|
inter = common.BytesToHash(returnOutput)
|
||||||
case FixedBytesTy:
|
case FixedBytesTy:
|
||||||
inter = returnOutput
|
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
|
// append the item to our reflect slice
|
||||||
refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
|
refSlice.Index(i).Set(reflect.ValueOf(inter))
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the interface
|
// return the interface
|
||||||
|
|
@ -185,7 +159,7 @@ func readBool(word []byte) (bool, 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 && t.Type.T != FunctionTy {
|
if t.Type.T == SliceTy || t.Type.T == ArrayTy {
|
||||||
return toGoSlice(i, t, output)
|
return toGoSlice(i, t, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,187 @@ 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)
|
||||||
|
err string // empty or error if expected
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
`[ { "type": "uint8[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]uint8{1, 2},
|
||||||
|
[]uint8{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint8[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]uint8{1, 2},
|
||||||
|
[2]uint8{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint16[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]uint16{1, 2},
|
||||||
|
[]uint16{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint16[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]uint16{1, 2},
|
||||||
|
[2]uint16{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint32[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]uint32{1, 2},
|
||||||
|
[]uint32{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint32[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]uint32{1, 2},
|
||||||
|
[2]uint32{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint64[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]uint64{1, 2},
|
||||||
|
[]uint64{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint64[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]uint64{1, 2},
|
||||||
|
[2]uint64{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "uint256[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]*big.Int{big.NewInt(1), big.NewInt(2)},
|
||||||
|
[]*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{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int8[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]int8{1, 2},
|
||||||
|
[]int8{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int8[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]int8{1, 2},
|
||||||
|
[2]int8{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int16[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]int16{1, 2},
|
||||||
|
[]int16{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int16[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]int16{1, 2},
|
||||||
|
[2]int16{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int32[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]int32{1, 2},
|
||||||
|
[]int32{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int32[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]int32{1, 2},
|
||||||
|
[2]int32{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int64[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]int64{1, 2},
|
||||||
|
[]int64{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int64[2]" } ]`,
|
||||||
|
common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[2]int64{1, 2},
|
||||||
|
[2]int64{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int256[]" } ]`,
|
||||||
|
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
|
||||||
|
[]*big.Int{big.NewInt(1), big.NewInt(2)},
|
||||||
|
[]*big.Int{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "int256[3]" } ]`,
|
||||||
|
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"),
|
||||||
|
[3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
|
||||||
|
[3]*big.Int{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
err = abi.Unpack(&test.outVar, "method", test.marshalledOutput)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if !reflect.DeepEqual(test.expectedOut, test.outVar) {
|
||||||
|
t.Errorf("%d failed. Output error: expected %v, got %v", i, test.expectedOut, test.outVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnpackSetInterfaceSlice(t *testing.T) {
|
func TestUnpackSetInterfaceSlice(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
var1 = new(uint8)
|
var1 = new(uint8)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue