forked from cerc-io/plugeth
accounts/abi: fixed strict go-like unpacking
This commit is contained in:
parent
5127ec10cb
commit
e0dc45fce2
@ -180,12 +180,33 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
|||||||
returnOutput = output[index : index+32]
|
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 {
|
switch t.Type.T {
|
||||||
case IntTy:
|
case IntTy, UintTy:
|
||||||
return common.BytesToBig(returnOutput), nil
|
bigNum := common.BytesToBig(returnOutput)
|
||||||
case UintTy:
|
|
||||||
return common.BytesToBig(returnOutput), nil
|
// 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:
|
case BoolTy:
|
||||||
return common.BytesToBig(returnOutput).Uint64() > 0, nil
|
return common.BytesToBig(returnOutput).Uint64() > 0, nil
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
|
@ -18,6 +18,7 @@ package abi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"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) {
|
func TestPack(t *testing.T) {
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
typ string
|
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) {
|
func TestMultiPack(t *testing.T) {
|
||||||
abi, err := JSON(strings.NewReader(jsondata2))
|
abi, err := JSON(strings.NewReader(jsondata2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user