aboutsummaryrefslogtreecommitdiffstats
path: root/accounts
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2016-04-21 03:16:21 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2016-04-28 18:41:37 +0800
commite0dc45fce2276fcabae8dca61dc766f98dde23e2 (patch)
tree8f2b56cecb27315012af2fda4e31b9e96dd8d0cf /accounts
parent5127ec10cb84a615f4d5b314e4c3c102efefe4c9 (diff)
downloaddexon-e0dc45fce2276fcabae8dca61dc766f98dde23e2.tar.gz
dexon-e0dc45fce2276fcabae8dca61dc766f98dde23e2.tar.zst
dexon-e0dc45fce2276fcabae8dca61dc766f98dde23e2.zip
accounts/abi: fixed strict go-like unpacking
Diffstat (limited to 'accounts')
-rw-r--r--accounts/abi/abi.go31
-rw-r--r--accounts/abi/abi_test.go154
2 files changed, 158 insertions, 27 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index 82ea4a0d5..e7cf4aac7 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -180,12 +180,33 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
returnOutput = output[index : index+32]
}
- // cast bytes to abi return type
+ // convert the bytes to whatever is specified by the ABI.
switch t.Type.T {
- case IntTy:
- return common.BytesToBig(returnOutput), nil
- case UintTy:
- return common.BytesToBig(returnOutput), nil
+ case IntTy, UintTy:
+ bigNum := common.BytesToBig(returnOutput)
+
+ // If the type is a integer convert to the integer type
+ // specified by the ABI.
+ switch t.Type.Kind {
+ case reflect.Uint8:
+ return uint8(bigNum.Uint64()), nil
+ case reflect.Uint16:
+ return uint16(bigNum.Uint64()), nil
+ case reflect.Uint32:
+ return uint32(bigNum.Uint64()), nil
+ case reflect.Uint64:
+ return uint64(bigNum.Uint64()), nil
+ case reflect.Int8:
+ return uint8(bigNum.Int64()), nil
+ case reflect.Int16:
+ return uint16(bigNum.Int64()), nil
+ case reflect.Int32:
+ return uint32(bigNum.Int64()), nil
+ case reflect.Int64:
+ return uint64(bigNum.Int64()), nil
+ case reflect.Ptr:
+ return bigNum, nil
+ }
case BoolTy:
return common.BytesToBig(returnOutput).Uint64() > 0, nil
case AddressTy:
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index 323718a72..249d37dca 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -18,6 +18,7 @@ package abi
import (
"bytes"
+ "errors"
"fmt"
"log"
"math/big"
@@ -103,6 +104,137 @@ func TestTypeCheck(t *testing.T) {
}
}
+func TestSimpleMethodUnpack(t *testing.T) {
+ for i, test := range []struct {
+ def string // definition of the **output** ABI params
+ marshalledOutput []byte // evm return data
+ expectedOut interface{} // the expected output
+ outVar string // the output variable (e.g. uint32, *big.Int, etc)
+ err error // nil or error if expected
+ }{
+ {
+ `[ { "type": "uint32" } ]`,
+ pad([]byte{1}, 32, true),
+ uint32(1),
+ "uint32",
+ nil,
+ },
+ {
+ `[ { "type": "uint32" } ]`,
+ pad([]byte{1}, 32, true),
+ nil,
+ "uint16",
+ errors.New("abi: cannot unmarshal uint32 in to uint16"),
+ },
+ {
+ `[ { "type": "uint17" } ]`,
+ pad([]byte{1}, 32, true),
+ nil,
+ "uint16",
+ errors.New("abi: cannot unmarshal *big.Int in to uint16"),
+ },
+ {
+ `[ { "type": "uint17" } ]`,
+ pad([]byte{1}, 32, true),
+ big.NewInt(1),
+ "*big.Int",
+ nil,
+ },
+ {
+ `[ { "type": "address" } ]`,
+ pad(pad([]byte{1}, 20, false), 32, true),
+ common.Address{1},
+ "address",
+ nil,
+ },
+ {
+ `[ { "type": "bytes32" } ]`,
+ pad([]byte{1}, 32, false),
+ pad([]byte{1}, 32, false),
+ "bytes",
+ nil,
+ },
+ {
+ `[ { "type": "bytes32" } ]`,
+ pad([]byte{1}, 32, false),
+ pad([]byte{1}, 32, false),
+ "hash",
+ nil,
+ },
+ } {
+ abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
+ abi, err := JSON(strings.NewReader(abiDefinition))
+ if err != nil {
+ t.Errorf("%d failed. %v", i, err)
+ continue
+ }
+
+ var outvar interface{}
+ switch test.outVar {
+ case "uint8":
+ var v uint8
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "uint16":
+ var v uint16
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "uint32":
+ var v uint32
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "uint64":
+ var v uint64
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "*big.Int":
+ var v *big.Int
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "address":
+ var v common.Address
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "bytes":
+ var v []byte
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ case "hash":
+ var v common.Hash
+ err = abi.Unpack(&v, "method", test.marshalledOutput)
+ outvar = v
+ default:
+ t.Errorf("unsupported type '%v' please add it to the switch statement in this test", test.outVar)
+ continue
+ }
+
+ if err != nil && test.err == nil {
+ t.Errorf("%d failed. Expected no err but got: %v", i, err)
+ continue
+ }
+ if err == nil && test.err != nil {
+ t.Errorf("%d failed. Expected err: %v but got none", i, test.err)
+ continue
+ }
+ if err != nil && test.err != nil && err.Error() != test.err.Error() {
+ t.Errorf("%d failed. Expected err: '%v' got err: '%v'", i, test.err, err)
+ continue
+ }
+
+ if err == nil {
+ // bit of an ugly hack for hash type but I don't feel like finding a proper solution
+ if test.outVar == "hash" {
+ tmp := outvar.(common.Hash) // without assignment it's unaddressable
+ outvar = tmp[:]
+ }
+
+ if !reflect.DeepEqual(test.expectedOut, outvar) {
+ t.Errorf("%d failed. Output error: expected %v, got %v", i, test.expectedOut, outvar)
+ }
+ }
+ }
+}
+
func TestPack(t *testing.T) {
for i, test := range []struct {
typ string
@@ -354,28 +486,6 @@ func TestMethodSignature(t *testing.T) {
}
}
-func TestOldPack(t *testing.T) {
- abi, err := JSON(strings.NewReader(jsondata2))
- if err != nil {
- t.Error(err)
- t.FailNow()
- }
-
- sig := crypto.Keccak256([]byte("foo(uint32)"))[:4]
- sig = append(sig, make([]byte, 32)...)
- sig[35] = 10
-
- packed, err := abi.Pack("foo", uint32(10))
- if err != nil {
- t.Error(err)
- t.FailNow()
- }
-
- if !bytes.Equal(packed, sig) {
- t.Errorf("expected %x got %x", sig, packed)
- }
-}
-
func TestMultiPack(t *testing.T) {
abi, err := JSON(strings.NewReader(jsondata2))
if err != nil {