Skip to content

Commit 88cc1ca

Browse files
authored
Merge pull request ethereum#3533 from karalabe/modum-io-develop-2
accounts/abi: support custom int slice types
2 parents 808310a + 1bd9769 commit 88cc1ca

File tree

4 files changed

+93
-17
lines changed

4 files changed

+93
-17
lines changed

accounts/abi/abi.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,30 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
9191
// first we need to create a slice of the type
9292
var refSlice reflect.Value
9393
switch elem.T {
94-
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int.
95-
refSlice = reflect.ValueOf([]*big.Int(nil))
94+
case IntTy, UintTy, BoolTy:
95+
// create a new reference slice matching the element type
96+
switch t.Type.Kind {
97+
case reflect.Bool:
98+
refSlice = reflect.ValueOf([]bool(nil))
99+
case reflect.Uint8:
100+
refSlice = reflect.ValueOf([]uint8(nil))
101+
case reflect.Uint16:
102+
refSlice = reflect.ValueOf([]uint16(nil))
103+
case reflect.Uint32:
104+
refSlice = reflect.ValueOf([]uint32(nil))
105+
case reflect.Uint64:
106+
refSlice = reflect.ValueOf([]uint64(nil))
107+
case reflect.Int8:
108+
refSlice = reflect.ValueOf([]int8(nil))
109+
case reflect.Int16:
110+
refSlice = reflect.ValueOf([]int16(nil))
111+
case reflect.Int32:
112+
refSlice = reflect.ValueOf([]int32(nil))
113+
case reflect.Int64:
114+
refSlice = reflect.ValueOf([]int64(nil))
115+
default:
116+
refSlice = reflect.ValueOf([]*big.Int(nil))
117+
}
96118
case AddressTy: // address must be of slice Address
97119
refSlice = reflect.ValueOf([]common.Address(nil))
98120
case HashTy: // hash must be of slice hash
@@ -147,7 +169,27 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
147169
// set inter to the correct type (cast)
148170
switch elem.T {
149171
case IntTy, UintTy:
150-
inter = common.BytesToBig(returnOutput)
172+
bigNum := common.BytesToBig(returnOutput)
173+
switch t.Type.Kind {
174+
case reflect.Uint8:
175+
inter = uint8(bigNum.Uint64())
176+
case reflect.Uint16:
177+
inter = uint16(bigNum.Uint64())
178+
case reflect.Uint32:
179+
inter = uint32(bigNum.Uint64())
180+
case reflect.Uint64:
181+
inter = bigNum.Uint64()
182+
case reflect.Int8:
183+
inter = int8(bigNum.Int64())
184+
case reflect.Int16:
185+
inter = int16(bigNum.Int64())
186+
case reflect.Int32:
187+
inter = int32(bigNum.Int64())
188+
case reflect.Int64:
189+
inter = bigNum.Int64()
190+
default:
191+
inter = common.BytesToBig(returnOutput)
192+
}
151193
case BoolTy:
152194
inter = common.BytesToBig(returnOutput).Uint64() > 0
153195
case AddressTy:

accounts/abi/abi_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,30 @@ func TestUnpackSetInterfaceSlice(t *testing.T) {
332332
}
333333
}
334334

335+
func TestUnpackSetInterfaceArrayOutput(t *testing.T) {
336+
var (
337+
var1 = new([1]uint32)
338+
var2 = new([1]uint32)
339+
)
340+
out := []interface{}{var1, var2}
341+
abi, err := JSON(strings.NewReader(`[{"type":"function", "name":"ints", "outputs":[{"type":"uint32[1]"}, {"type":"uint32[1]"}]}]`))
342+
if err != nil {
343+
t.Fatal(err)
344+
}
345+
marshalledReturn := append(pad([]byte{1}, 32, true), pad([]byte{2}, 32, true)...)
346+
err = abi.Unpack(&out, "ints", marshalledReturn)
347+
if err != nil {
348+
t.Fatal(err)
349+
}
350+
351+
if *var1 != [1]uint32{1} {
352+
t.Error("expected var1 to be [1], got", *var1)
353+
}
354+
if *var2 != [1]uint32{2} {
355+
t.Error("expected var2 to be [2], got", *var2)
356+
}
357+
}
358+
335359
func TestPack(t *testing.T) {
336360
for i, test := range []struct {
337361
typ string

accounts/abi/type.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ func NewType(t string) (typ Type, err error) {
9191
}
9292
typ.Elem = &sliceType
9393
typ.stringKind = sliceType.stringKind + t[len(res[1]):]
94-
return typ, nil
94+
// Altough we know that this is an array, we cannot return
95+
// as we don't know the type of the element, however, if it
96+
// is still an array, then don't determine the type.
97+
if typ.Elem.IsArray || typ.Elem.IsSlice {
98+
return typ, nil
99+
}
95100
}
96101

97102
// parse the type and size of the abi-type.
@@ -112,7 +117,12 @@ func NewType(t string) (typ Type, err error) {
112117
varSize = 256
113118
t += "256"
114119
}
115-
typ.stringKind = t
120+
121+
// only set stringKind if not array or slice, as for those,
122+
// the correct string type has been set
123+
if !(typ.IsArray || typ.IsSlice) {
124+
typ.stringKind = t
125+
}
116126

117127
switch varType {
118128
case "int":

accounts/abi/type_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,29 @@ func TestTypeRegexp(t *testing.T) {
3434
{"int", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
3535
{"int8", Type{Kind: reflect.Int8, Type: big_t, Size: 8, T: IntTy, stringKind: "int8"}},
3636
{"int256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
37-
{"int[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}},
38-
{"int[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}},
39-
{"int32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}},
40-
{"int32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}},
37+
{"int[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}},
38+
{"int[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}},
39+
{"int32[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}},
40+
{"int32[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}},
4141
{"uint", Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}},
4242
{"uint8", Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}},
4343
{"uint256", Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}},
44-
{"uint[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}},
45-
{"uint[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}},
46-
{"uint32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}},
47-
{"uint32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}},
44+
{"uint[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}},
45+
{"uint[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}},
46+
{"uint32[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Uint32, Type: ubig_t, Size: 32, T: UintTy, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}},
47+
{"uint32[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Uint32, Type: ubig_t, Size: 32, T: UintTy, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}},
4848
{"bytes", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}},
4949
{"bytes32", Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}},
5050
{"bytes[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[]"}},
5151
{"bytes[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[2]"}},
5252
{"bytes32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}, stringKind: "bytes32[]"}},
5353
{"bytes32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}, stringKind: "bytes32[2]"}},
5454
{"string", Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}},
55-
{"string[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}, stringKind: "string[]"}},
56-
{"string[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}, stringKind: "string[2]"}},
55+
{"string[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.String, T: StringTy, Size: -1, Elem: &Type{Kind: reflect.String, T: StringTy, Size: -1, stringKind: "string"}, stringKind: "string[]"}},
56+
{"string[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.String, T: StringTy, Size: -1, Elem: &Type{Kind: reflect.String, T: StringTy, Size: -1, stringKind: "string"}, stringKind: "string[2]"}},
5757
{"address", Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}},
58-
{"address[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}},
59-
{"address[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}},
58+
{"address[]", Type{IsSlice: true, SliceSize: -1,Kind: reflect.Array, Type:address_t, T: AddressTy, Size:20, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}},
59+
{"address[2]", Type{IsArray: true, SliceSize: 2,Kind: reflect.Array, Type:address_t, T: AddressTy, Size:20, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}},
6060

6161
// TODO when fixed types are implemented properly
6262
// {"fixed", Type{}},

0 commit comments

Comments
 (0)