Abi/dynamic types (#7)

This commit is contained in:
Vedhavyas Singareddi 2018-11-07 17:23:45 +01:00 committed by GitHub
parent fc490afef7
commit 758feaeb58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 46 deletions

View file

@ -243,12 +243,9 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
// input offset is the bytes offset for packed output // input offset is the bytes offset for packed output
inputOffset := 0 inputOffset := 0
for _, abiArg := range abiArgs { for _, abiArg := range abiArgs {
if abiArg.Type.T == ArrayTy { inputOffset += getOffset(abiArg.Type)
inputOffset += 32 * abiArg.Type.Size
} else {
inputOffset += 32
}
} }
var ret []byte var ret []byte
for i, a := range args { for i, a := range args {
input := abiArgs[i] input := abiArgs[i]
@ -257,14 +254,15 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// check for a slice type (string, bytes, slice) // check for dynamic types)=
if input.Type.requiresLengthPrefix() { if offsetRequired(input.Type) {
// calculate the offset
offset := inputOffset + len(variableInput)
// set the offset // set the offset
ret = append(ret, packNum(reflect.ValueOf(offset))...) ret = append(ret, packNum(reflect.ValueOf(inputOffset))...)
// Append the packed output to the variable input. The variable input
// will be appended at the end of the input. // calculate next offset
inputOffset += len(packed)
// append to variable input
variableInput = append(variableInput, packed...) variableInput = append(variableInput, packed...)
} else { } else {
// append the packed value to the input // append the packed value to the input

View file

@ -42,7 +42,7 @@ func TestPack(t *testing.T) {
{ {
"uint8[]", "uint8[]",
[]uint8{1, 2}, []uint8{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"uint16", "uint16",
@ -52,7 +52,7 @@ func TestPack(t *testing.T) {
{ {
"uint16[]", "uint16[]",
[]uint16{1, 2}, []uint16{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"uint32", "uint32",
@ -62,7 +62,7 @@ func TestPack(t *testing.T) {
{ {
"uint32[]", "uint32[]",
[]uint32{1, 2}, []uint32{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"uint64", "uint64",
@ -72,7 +72,7 @@ func TestPack(t *testing.T) {
{ {
"uint64[]", "uint64[]",
[]uint64{1, 2}, []uint64{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"uint256", "uint256",
@ -82,7 +82,7 @@ func TestPack(t *testing.T) {
{ {
"uint256[]", "uint256[]",
[]*big.Int{big.NewInt(1), big.NewInt(2)}, []*big.Int{big.NewInt(1), big.NewInt(2)},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"int8", "int8",
@ -92,7 +92,7 @@ func TestPack(t *testing.T) {
{ {
"int8[]", "int8[]",
[]int8{1, 2}, []int8{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"int16", "int16",
@ -102,7 +102,7 @@ func TestPack(t *testing.T) {
{ {
"int16[]", "int16[]",
[]int16{1, 2}, []int16{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"int32", "int32",
@ -112,7 +112,7 @@ func TestPack(t *testing.T) {
{ {
"int32[]", "int32[]",
[]int32{1, 2}, []int32{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"int64", "int64",
@ -122,7 +122,7 @@ func TestPack(t *testing.T) {
{ {
"int64[]", "int64[]",
[]int64{1, 2}, []int64{1, 2},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"int256", "int256",
@ -132,7 +132,7 @@ func TestPack(t *testing.T) {
{ {
"int256[]", "int256[]",
[]*big.Int{big.NewInt(1), big.NewInt(2)}, []*big.Int{big.NewInt(1), big.NewInt(2)},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
}, },
{ {
"bytes1", "bytes1",
@ -308,18 +308,12 @@ func TestPack(t *testing.T) {
//web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']); //web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']);
"address[]", "address[]",
[]common.Address{{1}, {2}}, []common.Address{{1}, {2}},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000100000000000000000000000000000000000000" +
"0000000000000000000000000200000000000000000000000000000000000000"),
}, },
{ {
"bytes32[]", "bytes32[]",
[]common.Hash{{1}, {2}}, []common.Hash{{1}, {2}},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + //offset: 32 common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"),
"0000000000000000000000000000000000000000000000000000000000000002" + //len: 2
"0100000000000000000000000000000000000000000000000000000000000000" + // 1
"0200000000000000000000000000000000000000000000000000000000000000"), // 2
}, },
{ {
"function", "function",
@ -329,15 +323,12 @@ func TestPack(t *testing.T) {
{ {
"string", "string",
"foobar", "foobar",
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset: 32 common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"),
"0000000000000000000000000000000000000000000000000000000000000006" + // len: 6
"666f6f6261720000000000000000000000000000000000000000000000000000"), // "foobar"
}, },
{ {
"string[]", "string[]",
[]string{"hello", "foobar"}, []string{"hello", "foobar"},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0
"0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1 "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1
"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
@ -345,6 +336,16 @@ func TestPack(t *testing.T) {
"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
"666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1] "666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1]
}, },
{
"string[2]",
[]string{"hello", "foobar"},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to hello
"0000000000000000000000000000000000000000000000000000000000000080" + // offset to foobar
"0000000000000000000000000000000000000000000000000000000000000005" + // length of hello
"68656c6c6f000000000000000000000000000000000000000000000000000000" + // encoded foobar
"0000000000000000000000000000000000000000000000000000000000000006" + // length of foobar
"666f6f6261720000000000000000000000000000000000000000000000000000"), // encoded foobar
},
{ {
//web3.eth.abi.encodeParameter('bytes32[][]', [['0x0100000000000000000000000000000000000000000000000000000000000000', //web3.eth.abi.encodeParameter('bytes32[][]', [['0x0100000000000000000000000000000000000000000000000000000000000000',
@ -352,8 +353,7 @@ func TestPack(t *testing.T) {
// '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]); // '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]);
"bytes32[][]", "bytes32[][]",
[][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0
"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
@ -365,6 +365,33 @@ func TestPack(t *testing.T) {
"0500000000000000000000000000000000000000000000000000000000000000"), // array[2] "0500000000000000000000000000000000000000000000000000000000000000"), // array[2]
}, },
{
"bytes32[][2]",
[][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}},
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0
"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
"0100000000000000000000000000000000000000000000000000000000000000" + // array[0]
"0200000000000000000000000000000000000000000000000000000000000000" + // array[1]
"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
"0300000000000000000000000000000000000000000000000000000000000000" + // array[0]
"0400000000000000000000000000000000000000000000000000000000000000" + // array[1]
"0500000000000000000000000000000000000000000000000000000000000000"), // array[2]
},
{
"bytes32[3][2]",
[][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0]
"0200000000000000000000000000000000000000000000000000000000000000" + // array[1]
"0300000000000000000000000000000000000000000000000000000000000000" + // array[2]
"0300000000000000000000000000000000000000000000000000000000000000" + // array[0]
"0400000000000000000000000000000000000000000000000000000000000000" + // array[1]
"0500000000000000000000000000000000000000000000000000000000000000"), // array[2]
},
} { } {
typ, err := NewType(test.typ) typ, err := NewType(test.typ)
if err != nil { if err != nil {

View file

@ -183,23 +183,43 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
return nil, err return nil, err
} }
if t.T == SliceTy || t.T == ArrayTy { switch t.T {
var packed []byte case SliceTy, ArrayTy:
var ret []byte
if t.requiresLengthPrefix() {
// append length
ret = append(ret, packNum(reflect.ValueOf(v.Len()))...)
}
// calculate offset if any
offset := 0
offsetReq := offsetRequired(*t.Elem)
if offsetReq {
offset = getOffset(*t.Elem) * v.Len()
}
var tail []byte
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {
val, err := t.Elem.pack(v.Index(i)) val, err := t.Elem.pack(v.Index(i))
if err != nil { if err != nil {
return nil, err return nil, err
} }
packed = append(packed, val...)
} if !offsetReq {
if t.T == SliceTy { ret = append(ret, val...)
return packBytesSlice(packed, v.Len()), nil continue
} else if t.T == ArrayTy {
return packed, nil
} }
ret = append(ret, packNum(reflect.ValueOf(offset))...)
offset += len(val)
tail = append(tail, val...)
} }
return append(ret, tail...), nil
default:
return packElement(t, v), nil return packElement(t, v), nil
}
} }
// requireLengthPrefix returns whether the type requires any sort of length // requireLengthPrefix returns whether the type requires any sort of length
@ -207,3 +227,25 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
func (t Type) requiresLengthPrefix() bool { func (t Type) requiresLengthPrefix() bool {
return t.T == StringTy || t.T == BytesTy || t.T == SliceTy return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
} }
// offsetRequired returns true if the type is considered dynamic
func offsetRequired(t Type) bool {
// dynamic types
// array is also a dynamic type if the array type is dynamic
if t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) {
return true
}
return false
}
// getOffset returns the offset to be added for t
func getOffset(t Type) int {
// if it is an array and there are no dynamic types
// then the array is static type
if t.T == ArrayTy && !offsetRequired(*t.Elem) {
return 32 * t.Size
}
return 32
}