mirror of https://github.com/status-im/op-geth.git
accounts/abi: fixed return tuple and string, bytes return type parsing
Removed old unmarshalling of return types: `abi.Call(...).([]byte)`. This is now replaced by a new syntax: ``` var a []byte err := abi.Call(&a, ...) ``` It also addresses a few issues with Bytes and Strings and can also handle both fixed and arbitrary sized byte slices, including strings.
This commit is contained in:
parent
856b9e9c50
commit
ecc876cec0
|
@ -20,11 +20,10 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Executer is an executer method for performing state executions. It takes one
|
// Executer is an executer method for performing state executions. It takes one
|
||||||
|
@ -101,52 +100,143 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// toGoType parses the input and casts it to the proper type defined by the ABI
|
// toGoType parses the input and casts it to the proper type defined by the ABI
|
||||||
// argument in t.
|
// argument in T.
|
||||||
func toGoType(t Argument, input []byte) interface{} {
|
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
|
index := i * 32
|
||||||
|
|
||||||
|
if index+32 > len(output) {
|
||||||
|
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the given index output and check whether we need to read
|
||||||
|
// a different offset and length based on the type (i.e. string, bytes)
|
||||||
|
var returnOutput []byte
|
||||||
|
switch t.Type.T {
|
||||||
|
case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
|
||||||
|
// parse offset from which we should start reading
|
||||||
|
offset := int(common.BytesToBig(output[index : index+32]).Uint64())
|
||||||
|
if offset+32 > len(output) {
|
||||||
|
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
|
||||||
|
}
|
||||||
|
// parse the size up until we should be reading
|
||||||
|
size := int(common.BytesToBig(output[offset : offset+32]).Uint64())
|
||||||
|
if offset+32+size > len(output) {
|
||||||
|
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the bytes for this return value
|
||||||
|
returnOutput = output[offset+32 : offset+32+size]
|
||||||
|
default:
|
||||||
|
returnOutput = output[index : index+32]
|
||||||
|
}
|
||||||
|
|
||||||
|
// cast bytes to abi return type
|
||||||
switch t.Type.T {
|
switch t.Type.T {
|
||||||
case IntTy:
|
case IntTy:
|
||||||
return common.BytesToBig(input)
|
return common.BytesToBig(returnOutput), nil
|
||||||
case UintTy:
|
case UintTy:
|
||||||
return common.BytesToBig(input)
|
return common.BytesToBig(returnOutput), nil
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
return common.BytesToBig(input).Uint64() > 0
|
return common.BytesToBig(returnOutput).Uint64() > 0, nil
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
return common.BytesToAddress(input)
|
return common.BytesToAddress(returnOutput), nil
|
||||||
case HashTy:
|
case HashTy:
|
||||||
return common.BytesToHash(input)
|
return common.BytesToHash(returnOutput), nil
|
||||||
|
case BytesTy, FixedBytesTy:
|
||||||
|
return returnOutput, nil
|
||||||
|
case StringTy:
|
||||||
|
return string(returnOutput), nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil, fmt.Errorf("abi: unknown type %v", t.Type.T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call executes a call and attemps to parse the return values and returns it as
|
// Call will unmarshal the output of the call in v. It will return an error if
|
||||||
// an interface. It uses the executer method to perform the actual call since
|
// invalid type is given or if the output is too short to conform to the ABI
|
||||||
// the abi knows nothing of the lower level calling mechanism.
|
// spec.
|
||||||
//
|
//
|
||||||
// Call supports all abi types and includes multiple return values. When only
|
// Call supports all of the available types and accepts a struct or an interface
|
||||||
// one item is returned a single interface{} will be returned, if a contract
|
// slice if the return is a tuple.
|
||||||
// method returns multiple values an []interface{} slice is returned.
|
func (abi ABI) Call(executer Executer, v interface{}, name string, args ...interface{}) error {
|
||||||
func (abi ABI) Call(executer Executer, name string, args ...interface{}) interface{} {
|
|
||||||
callData, err := abi.Pack(name, args...)
|
callData, err := abi.Pack(name, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Debug).Infoln("pack error:", err)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return abi.unmarshal(v, name, executer(callData))
|
||||||
|
}
|
||||||
|
|
||||||
|
var interSlice = reflect.TypeOf([]interface{}{})
|
||||||
|
|
||||||
|
// unmarshal output in v according to the abi specification
|
||||||
|
func (abi ABI) unmarshal(v interface{}, name string, output []byte) error {
|
||||||
|
var method = abi.Methods[name]
|
||||||
|
|
||||||
|
if len(output) == 0 {
|
||||||
|
return fmt.Errorf("abi: unmarshalling empty output")
|
||||||
|
}
|
||||||
|
|
||||||
|
value := reflect.ValueOf(v).Elem()
|
||||||
|
typ := value.Type()
|
||||||
|
|
||||||
|
if len(method.Outputs) > 1 {
|
||||||
|
switch value.Kind() {
|
||||||
|
// struct will match named return values to the struct's field
|
||||||
|
// names
|
||||||
|
case reflect.Struct:
|
||||||
|
for i := 0; i < len(method.Outputs); i++ {
|
||||||
|
marshalledValue, err := toGoType(i, method.Outputs[i], output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reflectValue := reflect.ValueOf(marshalledValue)
|
||||||
|
|
||||||
|
for j := 0; j < typ.NumField(); j++ {
|
||||||
|
field := typ.Field(j)
|
||||||
|
// TODO read tags: `abi:"fieldName"`
|
||||||
|
if field.Name == strings.ToUpper(method.Outputs[i].Name[:1])+method.Outputs[i].Name[1:] {
|
||||||
|
if field.Type.AssignableTo(reflectValue.Type()) {
|
||||||
|
value.Field(j).Set(reflectValue)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("abi: cannot unmarshal %v in to %v", field.Type, reflectValue.Type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if !value.Type().AssignableTo(interSlice) {
|
||||||
|
return fmt.Errorf("abi: cannot marshal tuple in to slice %T (only []interface{} is supported)", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new slice and start appending the unmarshalled
|
||||||
|
// values to the new interface slice.
|
||||||
|
z := reflect.MakeSlice(typ, 0, len(method.Outputs))
|
||||||
|
for i := 0; i < len(method.Outputs); i++ {
|
||||||
|
marshalledValue, err := toGoType(i, method.Outputs[i], output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z = reflect.Append(z, reflect.ValueOf(marshalledValue))
|
||||||
|
}
|
||||||
|
value.Set(z)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
marshalledValue, err := toGoType(0, method.Outputs[0], output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reflectValue := reflect.ValueOf(marshalledValue)
|
||||||
|
if typ.AssignableTo(reflectValue.Type()) {
|
||||||
|
value.Set(reflectValue)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("abi: cannot unmarshal %v in to %v", reflectValue.Type(), value.Type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
output := executer(callData)
|
|
||||||
|
|
||||||
method := abi.Methods[name]
|
|
||||||
ret := make([]interface{}, int(math.Max(float64(len(method.Outputs)), float64(len(output)/32))))
|
|
||||||
for i := 0; i < len(ret); i += 32 {
|
|
||||||
index := i / 32
|
|
||||||
ret[index] = toGoType(method.Outputs[index], output[i:i+32])
|
|
||||||
}
|
|
||||||
|
|
||||||
// return single interface
|
|
||||||
if len(ret) == 1 {
|
|
||||||
return ret[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (abi *ABI) UnmarshalJSON(data []byte) error {
|
func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||||
|
|
|
@ -394,6 +394,7 @@ func TestBytes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func TestReturn(t *testing.T) {
|
func TestReturn(t *testing.T) {
|
||||||
const definition = `[
|
const definition = `[
|
||||||
{ "type" : "function", "name" : "balance", "const" : true, "inputs" : [], "outputs" : [ { "name": "", "type": "hash" } ] },
|
{ "type" : "function", "name" : "balance", "const" : true, "inputs" : [], "outputs" : [ { "name": "", "type": "hash" } ] },
|
||||||
|
@ -422,6 +423,7 @@ func TestReturn(t *testing.T) {
|
||||||
t.Errorf("expected type common.Address, got %T", r)
|
t.Errorf("expected type common.Address, got %T", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func TestDefaultFunctionParsing(t *testing.T) {
|
func TestDefaultFunctionParsing(t *testing.T) {
|
||||||
const definition = `[{ "name" : "balance" }]`
|
const definition = `[{ "name" : "balance" }]`
|
||||||
|
@ -458,3 +460,234 @@ func TestBareEvents(t *testing.T) {
|
||||||
t.Error("expected 'name' event to be present")
|
t.Error("expected 'name' event to be present")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMultiReturnWithStruct(t *testing.T) {
|
||||||
|
const definition = `[
|
||||||
|
{ "name" : "multi", "const" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]`
|
||||||
|
|
||||||
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// using buff to make the code readable
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
|
||||||
|
stringOut := "hello"
|
||||||
|
buff.Write(common.RightPadBytes([]byte(stringOut), 32))
|
||||||
|
|
||||||
|
var inter struct {
|
||||||
|
Int *big.Int
|
||||||
|
String string
|
||||||
|
}
|
||||||
|
err = abi.unmarshal(&inter, "multi", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inter.Int == nil || inter.Int.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Error("expected Int to be 1 got", inter.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inter.String != stringOut {
|
||||||
|
t.Error("expected String to be", stringOut, "got", inter.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
var reversed struct {
|
||||||
|
String string
|
||||||
|
Int *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
err = abi.unmarshal(&reversed, "multi", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reversed.Int == nil || reversed.Int.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Error("expected Int to be 1 got", reversed.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reversed.String != stringOut {
|
||||||
|
t.Error("expected String to be", stringOut, "got", reversed.String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultiReturnWithSlice(t *testing.T) {
|
||||||
|
const definition = `[
|
||||||
|
{ "name" : "multi", "const" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]`
|
||||||
|
|
||||||
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// using buff to make the code readable
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
|
||||||
|
stringOut := "hello"
|
||||||
|
buff.Write(common.RightPadBytes([]byte(stringOut), 32))
|
||||||
|
|
||||||
|
var inter []interface{}
|
||||||
|
err = abi.unmarshal(&inter, "multi", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(inter) != 2 {
|
||||||
|
t.Fatal("expected 2 results got", len(inter))
|
||||||
|
}
|
||||||
|
|
||||||
|
if num, ok := inter[0].(*big.Int); !ok || num.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Error("expected index 0 to be 1 got", num)
|
||||||
|
}
|
||||||
|
|
||||||
|
if str, ok := inter[1].(string); !ok || str != stringOut {
|
||||||
|
t.Error("expected index 1 to be", stringOut, "got", str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshal(t *testing.T) {
|
||||||
|
const definition = `[
|
||||||
|
{ "name" : "int", "const" : false, "outputs": [ { "type": "uint256" } ] },
|
||||||
|
{ "name" : "bool", "const" : false, "outputs": [ { "type": "bool" } ] },
|
||||||
|
{ "name" : "bytes", "const" : false, "outputs": [ { "type": "bytes" } ] },
|
||||||
|
{ "name" : "multi", "const" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
|
||||||
|
{ "name" : "mixedBytes", "const" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]`
|
||||||
|
|
||||||
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal int
|
||||||
|
var Int *big.Int
|
||||||
|
err = abi.unmarshal(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if Int == nil || Int.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Error("expected Int to be 1 got", Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal bool
|
||||||
|
var Bool bool
|
||||||
|
err = abi.unmarshal(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !Bool {
|
||||||
|
t.Error("expected Bool to be true")
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal dynamic bytes max length 32
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
bytesOut := common.RightPadBytes([]byte("hello"), 32)
|
||||||
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
|
var Bytes []byte
|
||||||
|
err = abi.unmarshal(&Bytes, "bytes", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(Bytes, bytesOut) {
|
||||||
|
t.Errorf("expected %x got %x", bytesOut, Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshall dynamic bytes max length 64
|
||||||
|
buff.Reset()
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
|
||||||
|
bytesOut = common.RightPadBytes([]byte("hello"), 64)
|
||||||
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
|
err = abi.unmarshal(&Bytes, "bytes", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(Bytes, bytesOut) {
|
||||||
|
t.Errorf("expected %x got %x", bytesOut, Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshall dynamic bytes max length 63
|
||||||
|
buff.Reset()
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000003f"))
|
||||||
|
bytesOut = common.RightPadBytes([]byte("hello"), 63)
|
||||||
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
|
err = abi.unmarshal(&Bytes, "bytes", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(Bytes, bytesOut) {
|
||||||
|
t.Errorf("expected %x got %x", bytesOut, Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal dynamic bytes output empty
|
||||||
|
err = abi.unmarshal(&Bytes, "bytes", nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal dynamic bytes length 5
|
||||||
|
buff.Reset()
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
|
||||||
|
buff.Write(common.RightPadBytes([]byte("hello"), 32))
|
||||||
|
|
||||||
|
err = abi.unmarshal(&Bytes, "bytes", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(Bytes, []byte("hello")) {
|
||||||
|
t.Errorf("expected %x got %x", bytesOut, Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal error
|
||||||
|
buff.Reset()
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
err = abi.unmarshal(&Bytes, "bytes", buff.Bytes())
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = abi.unmarshal(&Bytes, "multi", make([]byte, 64))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal mixed bytes
|
||||||
|
buff.Reset()
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
|
||||||
|
fixed := common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")
|
||||||
|
buff.Write(fixed)
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
|
bytesOut = common.RightPadBytes([]byte("hello"), 32)
|
||||||
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
|
var out []interface{}
|
||||||
|
err = abi.unmarshal(&out, "mixedBytes", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("didn't expect error:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(bytesOut, out[0].([]byte)) {
|
||||||
|
t.Errorf("expected %x, got %x", bytesOut, out[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(fixed, out[1].([]byte)) {
|
||||||
|
t.Errorf("expected %x, got %x", fixed, out[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,8 +29,11 @@ const (
|
||||||
IntTy byte = iota
|
IntTy byte = iota
|
||||||
UintTy
|
UintTy
|
||||||
BoolTy
|
BoolTy
|
||||||
|
StringTy
|
||||||
SliceTy
|
SliceTy
|
||||||
AddressTy
|
AddressTy
|
||||||
|
FixedBytesTy
|
||||||
|
BytesTy
|
||||||
HashTy
|
HashTy
|
||||||
RealTy
|
RealTy
|
||||||
)
|
)
|
||||||
|
@ -118,6 +121,7 @@ func NewType(t string) (typ Type, err error) {
|
||||||
typ.T = UintTy
|
typ.T = UintTy
|
||||||
case "bool":
|
case "bool":
|
||||||
typ.Kind = reflect.Bool
|
typ.Kind = reflect.Bool
|
||||||
|
typ.T = BoolTy
|
||||||
case "real": // TODO
|
case "real": // TODO
|
||||||
typ.Kind = reflect.Invalid
|
typ.Kind = reflect.Invalid
|
||||||
case "address":
|
case "address":
|
||||||
|
@ -128,6 +132,7 @@ func NewType(t string) (typ Type, err error) {
|
||||||
case "string":
|
case "string":
|
||||||
typ.Kind = reflect.String
|
typ.Kind = reflect.String
|
||||||
typ.Size = -1
|
typ.Size = -1
|
||||||
|
typ.T = StringTy
|
||||||
if vsize > 0 {
|
if vsize > 0 {
|
||||||
typ.Size = 32
|
typ.Size = 32
|
||||||
}
|
}
|
||||||
|
@ -140,6 +145,11 @@ func NewType(t string) (typ Type, err error) {
|
||||||
typ.Kind = reflect.Slice
|
typ.Kind = reflect.Slice
|
||||||
typ.Type = byte_ts
|
typ.Type = byte_ts
|
||||||
typ.Size = vsize
|
typ.Size = vsize
|
||||||
|
if vsize == 0 {
|
||||||
|
typ.T = BytesTy
|
||||||
|
} else {
|
||||||
|
typ.T = FixedBytesTy
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue