accounts/abi: support custom int slice types

On solidity contract I have "uint32 []" type, when abigen creates Go
bindings - they are also "[]uint32" type on Go side. Even though it
looks like it should work - the actual type of the data coming from
the chain is of type " []*big.Int".

When executing contract function from Go side - getting unmarshal error:
abi: cannot unmarshal []*big.Int in to []uint32

The fix is to create array with the correct type

This fixed the issue reported in: https://github.com/ethereum/go-ethereum/issues/2802
This commit is contained in:
Thomas Bocek 2016-11-24 15:50:45 +01:00 committed by Péter Szilágyi
parent 808310a569
commit 972f0bd3db
No known key found for this signature in database
GPG Key ID: E9AE538CEDF8293D
2 changed files with 51 additions and 4 deletions

View File

@ -91,8 +91,31 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
// first we need to create a slice of the type // first we need to create a slice of the type
var refSlice reflect.Value var refSlice reflect.Value
switch elem.T { switch elem.T {
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int. case IntTy, UintTy, BoolTy: //we need to create the correct type of array otherwise we see the following issue;
//cannot unmarshal []*big.Int in to []uint32 as described in
//https://github.com/ethereum/go-ethereum/issues/2802
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)) refSlice = reflect.ValueOf([]*big.Int(nil))
}
case AddressTy: // address must be of slice Address case AddressTy: // address must be of slice Address
refSlice = reflect.ValueOf([]common.Address(nil)) refSlice = reflect.ValueOf([]common.Address(nil))
case HashTy: // hash must be of slice hash case HashTy: // hash must be of slice hash
@ -147,7 +170,27 @@ 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:
bigNum := common.BytesToBig(returnOutput)
switch t.Type.Kind {
case reflect.Uint8:
inter = uint8(bigNum.Uint64())
case reflect.Uint16:
inter = uint16(bigNum.Uint64())
case reflect.Uint32:
inter = uint32(bigNum.Uint64())
case reflect.Uint64:
inter = bigNum.Uint64()
case reflect.Int8:
inter = int8(bigNum.Int64())
case reflect.Int16:
inter = int16(bigNum.Int64())
case reflect.Int32:
inter = int32(bigNum.Int64())
case reflect.Int64:
inter = bigNum.Int64()
default:
inter = common.BytesToBig(returnOutput) inter = common.BytesToBig(returnOutput)
}
case BoolTy: case BoolTy:
inter = common.BytesToBig(returnOutput).Uint64() > 0 inter = common.BytesToBig(returnOutput).Uint64() > 0
case AddressTy: case AddressTy:

View File

@ -91,8 +91,12 @@ func NewType(t string) (typ Type, err error) {
} }
typ.Elem = &sliceType typ.Elem = &sliceType
typ.stringKind = sliceType.stringKind + t[len(res[1]):] typ.stringKind = sliceType.stringKind + t[len(res[1]):]
//Altough we know that this is an array, we cannot return as we don't
//know the type of the element, however, if it is still an array, then don't determine the type
if typ.Elem.IsArray {
return typ, nil return typ, nil
} }
}
// parse the type and size of the abi-type. // parse the type and size of the abi-type.
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0] parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]