Skip to content

Commit 758feae

Browse files
authored
Abi/dynamic types (#7)
1 parent fc490af commit 758feae

File tree

3 files changed

+113
-46
lines changed

3 files changed

+113
-46
lines changed

accounts/abi/argument.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,9 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
243243
// input offset is the bytes offset for packed output
244244
inputOffset := 0
245245
for _, abiArg := range abiArgs {
246-
if abiArg.Type.T == ArrayTy {
247-
inputOffset += 32 * abiArg.Type.Size
248-
} else {
249-
inputOffset += 32
250-
}
246+
inputOffset += getOffset(abiArg.Type)
251247
}
248+
252249
var ret []byte
253250
for i, a := range args {
254251
input := abiArgs[i]
@@ -257,14 +254,15 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
257254
if err != nil {
258255
return nil, err
259256
}
260-
// check for a slice type (string, bytes, slice)
261-
if input.Type.requiresLengthPrefix() {
262-
// calculate the offset
263-
offset := inputOffset + len(variableInput)
257+
// check for dynamic types)=
258+
if offsetRequired(input.Type) {
264259
// set the offset
265-
ret = append(ret, packNum(reflect.ValueOf(offset))...)
266-
// Append the packed output to the variable input. The variable input
267-
// will be appended at the end of the input.
260+
ret = append(ret, packNum(reflect.ValueOf(inputOffset))...)
261+
262+
// calculate next offset
263+
inputOffset += len(packed)
264+
265+
// append to variable input
268266
variableInput = append(variableInput, packed...)
269267
} else {
270268
// append the packed value to the input

accounts/abi/pack_test.go

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestPack(t *testing.T) {
4242
{
4343
"uint8[]",
4444
[]uint8{1, 2},
45-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
45+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
4646
},
4747
{
4848
"uint16",
@@ -52,7 +52,7 @@ func TestPack(t *testing.T) {
5252
{
5353
"uint16[]",
5454
[]uint16{1, 2},
55-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
55+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
5656
},
5757
{
5858
"uint32",
@@ -62,7 +62,7 @@ func TestPack(t *testing.T) {
6262
{
6363
"uint32[]",
6464
[]uint32{1, 2},
65-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
65+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
6666
},
6767
{
6868
"uint64",
@@ -72,7 +72,7 @@ func TestPack(t *testing.T) {
7272
{
7373
"uint64[]",
7474
[]uint64{1, 2},
75-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
75+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
7676
},
7777
{
7878
"uint256",
@@ -82,7 +82,7 @@ func TestPack(t *testing.T) {
8282
{
8383
"uint256[]",
8484
[]*big.Int{big.NewInt(1), big.NewInt(2)},
85-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
85+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
8686
},
8787
{
8888
"int8",
@@ -92,7 +92,7 @@ func TestPack(t *testing.T) {
9292
{
9393
"int8[]",
9494
[]int8{1, 2},
95-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
95+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
9696
},
9797
{
9898
"int16",
@@ -102,7 +102,7 @@ func TestPack(t *testing.T) {
102102
{
103103
"int16[]",
104104
[]int16{1, 2},
105-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
105+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
106106
},
107107
{
108108
"int32",
@@ -112,7 +112,7 @@ func TestPack(t *testing.T) {
112112
{
113113
"int32[]",
114114
[]int32{1, 2},
115-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
115+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
116116
},
117117
{
118118
"int64",
@@ -122,7 +122,7 @@ func TestPack(t *testing.T) {
122122
{
123123
"int64[]",
124124
[]int64{1, 2},
125-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
125+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
126126
},
127127
{
128128
"int256",
@@ -132,7 +132,7 @@ func TestPack(t *testing.T) {
132132
{
133133
"int256[]",
134134
[]*big.Int{big.NewInt(1), big.NewInt(2)},
135-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
135+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
136136
},
137137
{
138138
"bytes1",
@@ -308,18 +308,12 @@ func TestPack(t *testing.T) {
308308
//web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']);
309309
"address[]",
310310
[]common.Address{{1}, {2}},
311-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" +
312-
"0000000000000000000000000000000000000000000000000000000000000002" +
313-
"0000000000000000000000000100000000000000000000000000000000000000" +
314-
"0000000000000000000000000200000000000000000000000000000000000000"),
311+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"),
315312
},
316313
{
317314
"bytes32[]",
318315
[]common.Hash{{1}, {2}},
319-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + //offset: 32
320-
"0000000000000000000000000000000000000000000000000000000000000002" + //len: 2
321-
"0100000000000000000000000000000000000000000000000000000000000000" + // 1
322-
"0200000000000000000000000000000000000000000000000000000000000000"), // 2
316+
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"),
323317
},
324318
{
325319
"function",
@@ -329,31 +323,37 @@ func TestPack(t *testing.T) {
329323
{
330324
"string",
331325
"foobar",
332-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset: 32
333-
"0000000000000000000000000000000000000000000000000000000000000006" + // len: 6
334-
"666f6f6261720000000000000000000000000000000000000000000000000000"), // "foobar"
326+
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"),
335327
},
336328
{
337329
"string[]",
338330
[]string{"hello", "foobar"},
339-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32
340-
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
331+
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
341332
"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0
342333
"0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1
343334
"0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5
344335
"68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0]
345336
"0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6
346337
"666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1]
347338
},
339+
{
340+
"string[2]",
341+
[]string{"hello", "foobar"},
342+
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to hello
343+
"0000000000000000000000000000000000000000000000000000000000000080" + // offset to foobar
344+
"0000000000000000000000000000000000000000000000000000000000000005" + // length of hello
345+
"68656c6c6f000000000000000000000000000000000000000000000000000000" + // encoded foobar
346+
"0000000000000000000000000000000000000000000000000000000000000006" + // length of foobar
347+
"666f6f6261720000000000000000000000000000000000000000000000000000"), // encoded foobar
348+
},
348349
{
349350

350351
//web3.eth.abi.encodeParameter('bytes32[][]', [['0x0100000000000000000000000000000000000000000000000000000000000000',
351352
// '0x0200000000000000000000000000000000000000000000000000000000000000'],['0x0300000000000000000000000000000000000000000000000000000000000000',
352353
// '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]);
353354
"bytes32[][]",
354355
[][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}},
355-
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32
356-
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
356+
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2
357357
"0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0
358358
"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1
359359
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
@@ -365,6 +365,33 @@ func TestPack(t *testing.T) {
365365
"0500000000000000000000000000000000000000000000000000000000000000"), // array[2]
366366

367367
},
368+
369+
{
370+
"bytes32[][2]",
371+
[][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}},
372+
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0
373+
"00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1
374+
"0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2
375+
"0100000000000000000000000000000000000000000000000000000000000000" + // array[0]
376+
"0200000000000000000000000000000000000000000000000000000000000000" + // array[1]
377+
"0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3
378+
"0300000000000000000000000000000000000000000000000000000000000000" + // array[0]
379+
"0400000000000000000000000000000000000000000000000000000000000000" + // array[1]
380+
"0500000000000000000000000000000000000000000000000000000000000000"), // array[2]
381+
382+
},
383+
384+
{
385+
"bytes32[3][2]",
386+
[][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}},
387+
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0]
388+
"0200000000000000000000000000000000000000000000000000000000000000" + // array[1]
389+
"0300000000000000000000000000000000000000000000000000000000000000" + // array[2]
390+
"0300000000000000000000000000000000000000000000000000000000000000" + // array[0]
391+
"0400000000000000000000000000000000000000000000000000000000000000" + // array[1]
392+
"0500000000000000000000000000000000000000000000000000000000000000"), // array[2]
393+
394+
},
368395
} {
369396
typ, err := NewType(test.typ)
370397
if err != nil {

accounts/abi/type.go

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,27 +183,69 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
183183
return nil, err
184184
}
185185

186-
if t.T == SliceTy || t.T == ArrayTy {
187-
var packed []byte
186+
switch t.T {
187+
case SliceTy, ArrayTy:
188+
var ret []byte
188189

190+
if t.requiresLengthPrefix() {
191+
// append length
192+
ret = append(ret, packNum(reflect.ValueOf(v.Len()))...)
193+
}
194+
195+
// calculate offset if any
196+
offset := 0
197+
offsetReq := offsetRequired(*t.Elem)
198+
if offsetReq {
199+
offset = getOffset(*t.Elem) * v.Len()
200+
}
201+
202+
var tail []byte
189203
for i := 0; i < v.Len(); i++ {
190204
val, err := t.Elem.pack(v.Index(i))
191205
if err != nil {
192206
return nil, err
193207
}
194-
packed = append(packed, val...)
195-
}
196-
if t.T == SliceTy {
197-
return packBytesSlice(packed, v.Len()), nil
198-
} else if t.T == ArrayTy {
199-
return packed, nil
208+
209+
if !offsetReq {
210+
ret = append(ret, val...)
211+
continue
212+
}
213+
214+
ret = append(ret, packNum(reflect.ValueOf(offset))...)
215+
offset += len(val)
216+
tail = append(tail, val...)
200217
}
218+
219+
return append(ret, tail...), nil
220+
default:
221+
return packElement(t, v), nil
201222
}
202-
return packElement(t, v), nil
203223
}
204224

205225
// requireLengthPrefix returns whether the type requires any sort of length
206226
// prefixing.
207227
func (t Type) requiresLengthPrefix() bool {
208228
return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
209229
}
230+
231+
// offsetRequired returns true if the type is considered dynamic
232+
func offsetRequired(t Type) bool {
233+
// dynamic types
234+
// array is also a dynamic type if the array type is dynamic
235+
if t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) {
236+
return true
237+
}
238+
239+
return false
240+
}
241+
242+
// getOffset returns the offset to be added for t
243+
func getOffset(t Type) int {
244+
// if it is an array and there are no dynamic types
245+
// then the array is static type
246+
if t.T == ArrayTy && !offsetRequired(*t.Elem) {
247+
return 32 * t.Size
248+
}
249+
250+
return 32
251+
}

0 commit comments

Comments
 (0)