github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/cmd/contract/parse.go (about)

     1  // Copyright (c) 2020 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package contract
     7  
     8  import (
     9  	"encoding/hex"
    10  	"encoding/json"
    11  	"fmt"
    12  	"math/big"
    13  	"reflect"
    14  	"strconv"
    15  	"strings"
    16  
    17  	"github.com/ethereum/go-ethereum/accounts/abi"
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/iotexproject/iotex-address/address"
    20  	"github.com/pkg/errors"
    21  
    22  	"github.com/iotexproject/iotex-core/ioctl/output"
    23  	"github.com/iotexproject/iotex-core/pkg/util/addrutil"
    24  )
    25  
    26  // ErrInvalidArg indicates argument is invalid
    27  var (
    28  	ErrInvalidArg = errors.New("invalid argument")
    29  )
    30  
    31  func parseAbi(abiBytes []byte) (*abi.ABI, error) {
    32  	parsedAbi, err := abi.JSON(strings.NewReader(string(abiBytes)))
    33  	if err != nil {
    34  		return nil, output.NewError(output.SerializationError, "failed to unmarshal abi", err)
    35  	}
    36  	return &parsedAbi, nil
    37  }
    38  
    39  func parseInput(rowInput string) (map[string]interface{}, error) {
    40  	var input map[string]interface{}
    41  	if err := json.Unmarshal([]byte(rowInput), &input); err != nil {
    42  		return nil, output.NewError(output.SerializationError, "failed to unmarshal arguments", err)
    43  	}
    44  	return input, nil
    45  }
    46  
    47  // ParseOutput parse contract output data
    48  func ParseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) {
    49  	resultBytes, err := hex.DecodeString(result)
    50  	if err != nil {
    51  		return "", output.NewError(output.ConvertError, "failed to decode result", err)
    52  	}
    53  
    54  	var (
    55  		outputArgs = targetAbi.Methods[targetMethod].Outputs
    56  		tupleStr   = make([]string, 0, len(outputArgs))
    57  	)
    58  
    59  	v, err := targetAbi.Unpack(targetMethod, resultBytes)
    60  	if err != nil {
    61  		return "", output.NewError(output.SerializationError, "failed to parse output", err)
    62  	}
    63  
    64  	if len(outputArgs) == 1 {
    65  		elemStr, _ := parseOutputArgument(v[0], &outputArgs[0].Type)
    66  		return elemStr, nil
    67  	}
    68  
    69  	for i, field := range v {
    70  		elemStr, _ := parseOutputArgument(field, &outputArgs[i].Type)
    71  		tupleStr = append(tupleStr, outputArgs[i].Name+":"+elemStr)
    72  	}
    73  	return "{" + strings.Join(tupleStr, " ") + "}", nil
    74  }
    75  
    76  // parseInputArgument parses input's argument as golang variable
    77  func parseInputArgument(t *abi.Type, arg interface{}) (interface{}, error) {
    78  	switch t.T {
    79  	default:
    80  		return nil, ErrInvalidArg
    81  
    82  	case abi.BoolTy:
    83  		if reflect.TypeOf(arg).Kind() != reflect.Bool {
    84  			return nil, ErrInvalidArg
    85  		}
    86  
    87  	case abi.StringTy:
    88  		if reflect.TypeOf(arg).Kind() != reflect.String {
    89  			return nil, ErrInvalidArg
    90  		}
    91  
    92  	case abi.SliceTy:
    93  		if reflect.TypeOf(arg).Kind() != reflect.Slice {
    94  			return nil, ErrInvalidArg
    95  		}
    96  
    97  		slice := reflect.MakeSlice(t.GetType(), 0, t.Size)
    98  
    99  		s := reflect.ValueOf(arg)
   100  		for i := 0; i < s.Len(); i++ {
   101  			ele, err := parseInputArgument(t.Elem, s.Index(i).Interface())
   102  			if err != nil {
   103  				return nil, err
   104  			}
   105  			slice = reflect.Append(slice, reflect.ValueOf(ele))
   106  		}
   107  
   108  		arg = slice.Interface()
   109  
   110  	case abi.ArrayTy:
   111  		if reflect.TypeOf(arg).Kind() != reflect.Slice {
   112  			return nil, ErrInvalidArg
   113  		}
   114  
   115  		arrayType := reflect.ArrayOf(t.Size, t.Elem.GetType())
   116  		array := reflect.New(arrayType).Elem()
   117  
   118  		s := reflect.ValueOf(arg)
   119  		for i := 0; i < s.Len(); i++ {
   120  			ele, err := parseInputArgument(t.Elem, s.Index(i).Interface())
   121  			if err != nil {
   122  				return nil, err
   123  			}
   124  			array.Index(i).Set(reflect.ValueOf(ele))
   125  		}
   126  
   127  		arg = array.Interface()
   128  
   129  	// support both of Ether address & IoTeX address input
   130  	case abi.AddressTy:
   131  		var err error
   132  		addrString, ok := arg.(string)
   133  		if !ok {
   134  			return nil, ErrInvalidArg
   135  		}
   136  
   137  		if common.IsHexAddress(addrString) {
   138  			arg = common.HexToAddress(addrString)
   139  		} else {
   140  			arg, err = addrutil.IoAddrToEvmAddr(addrString)
   141  			if err != nil {
   142  				return nil, err
   143  			}
   144  		}
   145  
   146  	// support both number & string input
   147  	case abi.IntTy:
   148  		var ok bool
   149  		var err error
   150  
   151  		k := reflect.TypeOf(arg).Kind()
   152  		if k != reflect.String && k != reflect.Float64 {
   153  			return nil, ErrInvalidArg
   154  		}
   155  
   156  		var value int64
   157  		switch t.Size {
   158  		default:
   159  			if k == reflect.String {
   160  				arg, ok = new(big.Int).SetString(arg.(string), 10)
   161  				if !ok {
   162  					return nil, ErrInvalidArg
   163  				}
   164  			} else {
   165  				arg = big.NewInt(int64(arg.(float64)))
   166  			}
   167  		case 8:
   168  			if k == reflect.String {
   169  				value, err = strconv.ParseInt(arg.(string), 10, 8)
   170  				arg = int8(value)
   171  			} else {
   172  				arg = int8(arg.(float64))
   173  			}
   174  		case 16:
   175  			if k == reflect.String {
   176  				value, err = strconv.ParseInt(arg.(string), 10, 16)
   177  				arg = int16(value)
   178  			} else {
   179  				arg = int16(arg.(float64))
   180  			}
   181  		case 32:
   182  			if k == reflect.String {
   183  				value, err = strconv.ParseInt(arg.(string), 10, 32)
   184  				arg = int32(value)
   185  			} else {
   186  				arg = int32(arg.(float64))
   187  			}
   188  		case 64:
   189  			if k == reflect.String {
   190  				arg, err = strconv.ParseInt(arg.(string), 10, 64)
   191  			} else {
   192  				arg = int64(arg.(float64))
   193  			}
   194  		}
   195  
   196  		if err != nil {
   197  			return nil, err
   198  		}
   199  
   200  	// support both number & string input
   201  	case abi.UintTy:
   202  		var ok bool
   203  		var err error
   204  
   205  		k := reflect.TypeOf(arg).Kind()
   206  		if k != reflect.String && k != reflect.Float64 {
   207  			return nil, ErrInvalidArg
   208  		}
   209  
   210  		var value uint64
   211  		switch t.Size {
   212  		default:
   213  			if k == reflect.String {
   214  				arg, ok = new(big.Int).SetString(arg.(string), 10)
   215  				if !ok {
   216  					return nil, ErrInvalidArg
   217  				}
   218  			} else {
   219  				arg = big.NewInt(int64(arg.(float64)))
   220  			}
   221  
   222  			if arg.(*big.Int).Cmp(big.NewInt(0)) < 0 {
   223  				return nil, ErrInvalidArg
   224  			}
   225  		case 8:
   226  			if k == reflect.String {
   227  				value, err = strconv.ParseUint(arg.(string), 10, 8)
   228  				arg = uint8(value)
   229  			} else {
   230  				arg = uint8(arg.(float64))
   231  			}
   232  		case 16:
   233  			if k == reflect.String {
   234  				value, err = strconv.ParseUint(arg.(string), 10, 16)
   235  				arg = uint16(value)
   236  			} else {
   237  				arg = uint16(arg.(float64))
   238  			}
   239  		case 32:
   240  			if k == reflect.String {
   241  				value, err = strconv.ParseUint(arg.(string), 10, 32)
   242  				arg = uint32(value)
   243  			} else {
   244  				arg = uint32(arg.(float64))
   245  			}
   246  		case 64:
   247  			if k == reflect.String {
   248  				arg, err = strconv.ParseUint(arg.(string), 10, 64)
   249  			} else {
   250  				arg = uint64(arg.(float64))
   251  			}
   252  		}
   253  
   254  		if err != nil {
   255  			return nil, err
   256  		}
   257  
   258  	case abi.BytesTy:
   259  		if reflect.TypeOf(arg).Kind() != reflect.String {
   260  			return nil, ErrInvalidArg
   261  		}
   262  
   263  		bytecode, err := decodeBytecode(arg.(string))
   264  		if err != nil {
   265  			return nil, err
   266  		}
   267  
   268  		bytes := reflect.MakeSlice(t.GetType(), 0, len(bytecode))
   269  
   270  		for _, oneByte := range bytecode {
   271  			bytes = reflect.Append(bytes, reflect.ValueOf(oneByte))
   272  		}
   273  
   274  		arg = bytes.Interface()
   275  
   276  	case abi.FixedBytesTy, abi.FunctionTy:
   277  		if reflect.TypeOf(arg).Kind() != reflect.String {
   278  			return nil, ErrInvalidArg
   279  		}
   280  
   281  		bytecode, err := decodeBytecode(arg.(string))
   282  		if err != nil {
   283  			return nil, err
   284  		}
   285  
   286  		if t.Size != len(bytecode) {
   287  			return nil, ErrInvalidArg
   288  		}
   289  
   290  		bytesType := reflect.ArrayOf(t.Size, reflect.TypeOf(uint8(0)))
   291  		bytes := reflect.New(bytesType).Elem()
   292  
   293  		for i, oneByte := range bytecode {
   294  			bytes.Index(i).Set(reflect.ValueOf(oneByte))
   295  		}
   296  
   297  		arg = bytes.Interface()
   298  
   299  	}
   300  	return arg, nil
   301  }
   302  
   303  // parseOutputArgument parses output's argument as human-readable string
   304  func parseOutputArgument(v interface{}, t *abi.Type) (string, bool) {
   305  	str := fmt.Sprint(v)
   306  	ok := false
   307  
   308  	switch t.T {
   309  	case abi.StringTy, abi.BoolTy:
   310  		// case abi.StringTy & abi.BoolTy can be handled by fmt.Sprint()
   311  		ok = true
   312  
   313  	case abi.TupleTy:
   314  		if reflect.TypeOf(v).Kind() == reflect.Struct {
   315  			ok = true
   316  
   317  			tupleStr := make([]string, 0, len(t.TupleElems))
   318  			for i, elem := range t.TupleElems {
   319  				elemStr, elemOk := parseOutputArgument(reflect.ValueOf(v).Field(i).Interface(), elem)
   320  				tupleStr = append(tupleStr, t.TupleRawNames[i]+":"+elemStr)
   321  				ok = ok && elemOk
   322  			}
   323  
   324  			str = "{" + strings.Join(tupleStr, " ") + "}"
   325  		}
   326  
   327  	case abi.SliceTy, abi.ArrayTy:
   328  		if reflect.TypeOf(v).Kind() == reflect.Slice || reflect.TypeOf(v).Kind() == reflect.Array {
   329  			ok = true
   330  
   331  			value := reflect.ValueOf(v)
   332  			sliceStr := make([]string, 0, value.Len())
   333  			for i := 0; i < value.Len(); i++ {
   334  				elemStr, elemOk := parseOutputArgument(value.Index(i).Interface(), t.Elem)
   335  				sliceStr = append(sliceStr, elemStr)
   336  				ok = ok && elemOk
   337  			}
   338  
   339  			str = "[" + strings.Join(sliceStr, " ") + "]"
   340  		}
   341  
   342  	case abi.IntTy, abi.UintTy:
   343  		if reflect.TypeOf(v) == reflect.TypeOf(big.NewInt(0)) {
   344  			var bigInt *big.Int
   345  			bigInt, ok = v.(*big.Int)
   346  			if ok {
   347  				str = bigInt.String()
   348  			}
   349  		} else if 2 <= reflect.TypeOf(v).Kind() && reflect.TypeOf(v).Kind() <= 11 {
   350  			// other integer types (int8,uint16,...) can be handled by fmt.Sprint(v)
   351  			ok = true
   352  		}
   353  
   354  	case abi.AddressTy:
   355  		if reflect.TypeOf(v) == reflect.TypeOf(common.Address{}) {
   356  			var ethAddr common.Address
   357  			ethAddr, ok = v.(common.Address)
   358  			if ok {
   359  				ioAddress, err := address.FromBytes(ethAddr.Bytes())
   360  				if err == nil {
   361  					str = ioAddress.String()
   362  				}
   363  			}
   364  		}
   365  
   366  	case abi.BytesTy:
   367  		if reflect.TypeOf(v) == reflect.TypeOf([]byte{}) {
   368  			var bytes []byte
   369  			bytes, ok = v.([]byte)
   370  			if ok {
   371  				str = "0x" + hex.EncodeToString(bytes)
   372  			}
   373  		}
   374  
   375  	case abi.FixedBytesTy, abi.FunctionTy:
   376  		if reflect.TypeOf(v).Kind() == reflect.Array && reflect.TypeOf(v).Elem() == reflect.TypeOf(byte(0)) {
   377  			bytesValue := reflect.ValueOf(v)
   378  			byteSlice := reflect.MakeSlice(reflect.TypeOf([]byte{}), bytesValue.Len(), bytesValue.Len())
   379  			reflect.Copy(byteSlice, bytesValue)
   380  
   381  			str = "0x" + hex.EncodeToString(byteSlice.Bytes())
   382  			ok = true
   383  		}
   384  	}
   385  
   386  	return str, ok
   387  }