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 }