Skip to content

Commit 0f722df

Browse files
committed
Merge pull request #2435 from obscuren/abi-array-fixes
accounts/abi: refactored ABI package
2 parents 1b77d50 + 4880868 commit 0f722df

File tree

8 files changed

+733
-362
lines changed

8 files changed

+733
-362
lines changed

accounts/abi/abi.go

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -48,42 +48,6 @@ func JSON(reader io.Reader) (ABI, error) {
4848
return abi, nil
4949
}
5050

51-
// tests, tests whether the given input would result in a successful
52-
// call. Checks argument list count and matches input to `input`.
53-
func (abi ABI) pack(method Method, args ...interface{}) ([]byte, error) {
54-
// variable input is the output appended at the end of packed
55-
// output. This is used for strings and bytes types input.
56-
var variableInput []byte
57-
58-
var ret []byte
59-
for i, a := range args {
60-
input := method.Inputs[i]
61-
// pack the input
62-
packed, err := input.Type.pack(a)
63-
if err != nil {
64-
return nil, fmt.Errorf("`%s` %v", method.Name, err)
65-
}
66-
67-
// check for a slice type (string, bytes, slice)
68-
if input.Type.T == StringTy || input.Type.T == BytesTy || input.Type.IsSlice {
69-
// calculate the offset
70-
offset := len(method.Inputs)*32 + len(variableInput)
71-
// set the offset
72-
ret = append(ret, packNum(reflect.ValueOf(offset), UintTy)...)
73-
// Append the packed output to the variable input. The variable input
74-
// will be appended at the end of the input.
75-
variableInput = append(variableInput, packed...)
76-
} else {
77-
// append the packed value to the input
78-
ret = append(ret, packed...)
79-
}
80-
}
81-
// append the variable input at the end of the packed input
82-
ret = append(ret, variableInput...)
83-
84-
return ret, nil
85-
}
86-
8751
// Pack the given method name to conform the ABI. Method call's data
8852
// will consist of method_id, args0, arg1, ... argN. Method id consists
8953
// of 4 bytes and arguments are all 32 bytes.
@@ -102,11 +66,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
10266
}
10367
method = m
10468
}
105-
// Make sure arguments match up and pack them
106-
if len(args) != len(method.Inputs) {
107-
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))
108-
}
109-
arguments, err := abi.pack(method, args...)
69+
arguments, err := method.pack(method, args...)
11070
if err != nil {
11171
return nil, err
11272
}
@@ -126,18 +86,21 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
12686
if index+32 > len(output) {
12787
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32)
12888
}
89+
elem := t.Type.Elem
12990

13091
// first we need to create a slice of the type
13192
var refSlice reflect.Value
132-
switch t.Type.T {
93+
switch elem.T {
13394
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int.
13495
refSlice = reflect.ValueOf([]*big.Int(nil))
13596
case AddressTy: // address must be of slice Address
13697
refSlice = reflect.ValueOf([]common.Address(nil))
13798
case HashTy: // hash must be of slice hash
13899
refSlice = reflect.ValueOf([]common.Hash(nil))
100+
case FixedBytesTy:
101+
refSlice = reflect.ValueOf([]byte(nil))
139102
default: // no other types are supported
140-
return nil, fmt.Errorf("abi: unsupported slice type %v", t.Type.T)
103+
return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
141104
}
142105
// get the offset which determines the start of this array ...
143106
offset := int(common.BytesToBig(output[index : index+32]).Uint64())
@@ -164,7 +127,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
164127
)
165128

166129
// set inter to the correct type (cast)
167-
switch t.Type.T {
130+
switch elem.T {
168131
case IntTy, UintTy:
169132
inter = common.BytesToBig(returnOutput)
170133
case BoolTy:
@@ -186,7 +149,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
186149
// argument in T.
187150
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
188151
// we need to treat slices differently
189-
if t.Type.IsSlice {
152+
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy {
190153
return toGoSlice(i, t, output)
191154
}
192155

@@ -217,12 +180,33 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
217180
returnOutput = output[index : index+32]
218181
}
219182

220-
// cast bytes to abi return type
183+
// convert the bytes to whatever is specified by the ABI.
221184
switch t.Type.T {
222-
case IntTy:
223-
return common.BytesToBig(returnOutput), nil
224-
case UintTy:
225-
return common.BytesToBig(returnOutput), nil
185+
case IntTy, UintTy:
186+
bigNum := common.BytesToBig(returnOutput)
187+
188+
// If the type is a integer convert to the integer type
189+
// specified by the ABI.
190+
switch t.Type.Kind {
191+
case reflect.Uint8:
192+
return uint8(bigNum.Uint64()), nil
193+
case reflect.Uint16:
194+
return uint16(bigNum.Uint64()), nil
195+
case reflect.Uint32:
196+
return uint32(bigNum.Uint64()), nil
197+
case reflect.Uint64:
198+
return uint64(bigNum.Uint64()), nil
199+
case reflect.Int8:
200+
return int8(bigNum.Int64()), nil
201+
case reflect.Int16:
202+
return int16(bigNum.Int64()), nil
203+
case reflect.Int32:
204+
return int32(bigNum.Int64()), nil
205+
case reflect.Int64:
206+
return int64(bigNum.Int64()), nil
207+
case reflect.Ptr:
208+
return bigNum, nil
209+
}
226210
case BoolTy:
227211
return common.BytesToBig(returnOutput).Uint64() > 0, nil
228212
case AddressTy:
@@ -328,10 +312,12 @@ func set(dst, src reflect.Value, output Argument) error {
328312
return fmt.Errorf("abi: cannot unmarshal %v in to array of elem %v", src.Type(), dstType.Elem())
329313
}
330314

331-
if dst.Len() < output.Type.Size {
332-
return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.Size, dst.Len())
315+
if dst.Len() < output.Type.SliceSize {
316+
return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len())
333317
}
334318
reflect.Copy(dst, src)
319+
case dstType.Kind() == reflect.Interface:
320+
dst.Set(src)
335321
default:
336322
return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type())
337323
}

0 commit comments

Comments
 (0)