github.com/iotexproject/iotex-core@v1.14.1-rc1/api/web3server.go (about) 1 package api 2 3 import ( 4 "context" 5 "encoding/hex" 6 "encoding/json" 7 "fmt" 8 "io" 9 "math/big" 10 "strconv" 11 "time" 12 13 "github.com/ethereum/go-ethereum/common" 14 "github.com/ethereum/go-ethereum/core/types" 15 "github.com/ethereum/go-ethereum/eth/tracers" 16 "github.com/ethereum/go-ethereum/eth/tracers/logger" 17 "github.com/iotexproject/go-pkgs/crypto" 18 "github.com/iotexproject/go-pkgs/hash" 19 "github.com/iotexproject/go-pkgs/util" 20 "github.com/iotexproject/iotex-address/address" 21 "github.com/iotexproject/iotex-proto/golang/iotextypes" 22 "github.com/pkg/errors" 23 "github.com/prometheus/client_golang/prometheus" 24 "github.com/tidwall/gjson" 25 "go.uber.org/zap" 26 "google.golang.org/grpc/codes" 27 "google.golang.org/grpc/status" 28 29 "github.com/iotexproject/iotex-core/action" 30 rewardingabi "github.com/iotexproject/iotex-core/action/protocol/rewarding/ethabi" 31 stakingabi "github.com/iotexproject/iotex-core/action/protocol/staking/ethabi" 32 apitypes "github.com/iotexproject/iotex-core/api/types" 33 "github.com/iotexproject/iotex-core/pkg/log" 34 "github.com/iotexproject/iotex-core/pkg/tracer" 35 "github.com/iotexproject/iotex-core/pkg/util/addrutil" 36 ) 37 38 const ( 39 _metamaskBalanceContractAddr = "io1k8uw2hrlvnfq8s2qpwwc24ws2ru54heenx8chr" 40 // _defaultBatchRequestLimit is the default maximum number of items in a batch. 41 _defaultBatchRequestLimit = 100 // Maximum number of items in a batch. 42 ) 43 44 type ( 45 // Web3Handler handle JRPC request 46 Web3Handler interface { 47 HandlePOSTReq(context.Context, io.Reader, apitypes.Web3ResponseWriter) error 48 } 49 50 web3Handler struct { 51 coreService CoreService 52 cache apiCache 53 batchRequestLimit int 54 } 55 ) 56 57 type ( 58 filterObject struct { 59 LogHeight uint64 `json:"logHeight"` 60 FilterType string `json:"filterType"` 61 FromBlock string `json:"fromBlock,omitempty"` 62 ToBlock string `json:"toBlock,omitempty"` 63 Address []string `json:"address,omitempty"` 64 Topics [][]string `json:"topics,omitempty"` 65 } 66 ) 67 68 var ( 69 _web3ServerMtc = prometheus.NewCounterVec(prometheus.CounterOpts{ 70 Name: "iotex_web3_api_metrics", 71 Help: "web3 api metrics.", 72 }, []string{"method"}) 73 74 errUnkownType = errors.New("wrong type of params") 75 errNullPointer = errors.New("null pointer") 76 errInvalidFormat = errors.New("invalid format of request") 77 errNotImplemented = errors.New("method not implemented") 78 errInvalidFilterID = errors.New("filter not found") 79 errInvalidEvmChainID = errors.New("invalid EVM chain ID") 80 errInvalidBlock = errors.New("invalid block") 81 errUnsupportedAction = errors.New("the type of action is not supported") 82 errMsgBatchTooLarge = errors.New("batch too large") 83 84 _pendingBlockNumber = "pending" 85 _latestBlockNumber = "latest" 86 _earliestBlockNumber = "earliest" 87 ) 88 89 func init() { 90 prometheus.MustRegister(_web3ServerMtc) 91 } 92 93 // NewWeb3Handler creates a handle to process web3 requests 94 func NewWeb3Handler(core CoreService, cacheURL string, batchRequestLimit int) Web3Handler { 95 return &web3Handler{ 96 coreService: core, 97 cache: newAPICache(15*time.Minute, cacheURL), 98 batchRequestLimit: batchRequestLimit, 99 } 100 } 101 102 // HandlePOSTReq handles web3 request 103 func (svr *web3Handler) HandlePOSTReq(ctx context.Context, reader io.Reader, writer apitypes.Web3ResponseWriter) error { 104 ctx, span := tracer.NewSpan(ctx, "svr.HandlePOSTReq") 105 defer span.End() 106 web3Reqs, err := parseWeb3Reqs(reader) 107 if err != nil { 108 err := errors.Wrap(err, "failed to parse web3 requests.") 109 span.RecordError(err) 110 _, err = writer.Write(&web3Response{err: err}) 111 return err 112 } 113 if !web3Reqs.IsArray() { 114 return svr.handleWeb3Req(ctx, &web3Reqs, writer) 115 } 116 web3ReqArr := web3Reqs.Array() 117 if len(web3ReqArr) > int(svr.batchRequestLimit) { 118 err := errors.Wrapf( 119 errMsgBatchTooLarge, 120 "batch size %d exceeds the limit %d", 121 len(web3ReqArr), 122 svr.batchRequestLimit, 123 ) 124 span.RecordError(err) 125 _, err = writer.Write(&web3Response{err: err}) 126 return err 127 } 128 batchWriter := apitypes.NewBatchWriter(writer) 129 for i := range web3ReqArr { 130 if err := svr.handleWeb3Req(ctx, &web3ReqArr[i], batchWriter); err != nil { 131 return err 132 } 133 } 134 return batchWriter.Flush() 135 } 136 137 func (svr *web3Handler) handleWeb3Req(ctx context.Context, web3Req *gjson.Result, writer apitypes.Web3ResponseWriter) error { 138 var ( 139 res interface{} 140 err, err1 error 141 method = web3Req.Get("method").Value() 142 size int 143 ) 144 defer func(start time.Time) { svr.coreService.Track(ctx, start, method.(string), int64(size), err == nil) }(time.Now()) 145 146 log.T(ctx).Debug("handleWeb3Req", zap.String("method", method.(string)), zap.String("requestParams", fmt.Sprintf("%+v", web3Req))) 147 _web3ServerMtc.WithLabelValues(method.(string)).Inc() 148 _web3ServerMtc.WithLabelValues("requests_total").Inc() 149 switch method { 150 case "eth_accounts": 151 res, err = svr.ethAccounts() 152 case "eth_gasPrice": 153 res, err = svr.gasPrice() 154 case "eth_getBlockByHash": 155 res, err = svr.getBlockByHash(web3Req) 156 case "eth_chainId": 157 res, err = svr.getChainID() 158 case "eth_blockNumber": 159 res, err = svr.getBlockNumber() 160 case "eth_getBalance": 161 res, err = svr.getBalance(web3Req) 162 case "eth_getTransactionCount": 163 res, err = svr.getTransactionCount(web3Req) 164 case "eth_call": 165 res, err = svr.call(web3Req) 166 case "eth_getCode": 167 res, err = svr.getCode(web3Req) 168 case "eth_protocolVersion": 169 res, err = svr.getProtocolVersion() 170 case "web3_clientVersion": 171 res, err = svr.getNodeInfo() 172 case "net_version": 173 res, err = svr.getNetworkID() 174 case "net_peerCount": 175 res, err = svr.getPeerCount() 176 case "net_listening": 177 res, err = svr.isListening() 178 case "eth_syncing": 179 res, err = svr.isSyncing() 180 case "eth_mining": 181 res, err = svr.isMining() 182 case "eth_hashrate": 183 res, err = svr.getHashrate() 184 case "eth_getLogs": 185 var filter *filterObject 186 filter, err = parseLogRequest(web3Req.Get("params")) 187 if err == nil { 188 res, err = svr.getLogs(filter) 189 } 190 case "eth_getBlockTransactionCountByHash": 191 res, err = svr.getBlockTransactionCountByHash(web3Req) 192 case "eth_getBlockByNumber": 193 res, err = svr.getBlockByNumber(web3Req) 194 case "eth_estimateGas": 195 res, err = svr.estimateGas(web3Req) 196 case "eth_sendRawTransaction": 197 res, err = svr.sendRawTransaction(web3Req) 198 case "eth_getTransactionByHash": 199 res, err = svr.getTransactionByHash(web3Req) 200 case "eth_getTransactionByBlockNumberAndIndex": 201 res, err = svr.getTransactionByBlockNumberAndIndex(web3Req) 202 case "eth_getTransactionByBlockHashAndIndex": 203 res, err = svr.getTransactionByBlockHashAndIndex(web3Req) 204 case "eth_getBlockTransactionCountByNumber": 205 res, err = svr.getBlockTransactionCountByNumber(web3Req) 206 case "eth_getTransactionReceipt": 207 res, err = svr.getTransactionReceipt(web3Req) 208 case "eth_getStorageAt": 209 res, err = svr.getStorageAt(web3Req) 210 case "eth_getFilterLogs": 211 res, err = svr.getFilterLogs(web3Req) 212 case "eth_getFilterChanges": 213 res, err = svr.getFilterChanges(web3Req) 214 case "eth_uninstallFilter": 215 res, err = svr.uninstallFilter(web3Req) 216 case "eth_newFilter": 217 var filter *filterObject 218 filter, err = parseLogRequest(web3Req.Get("params")) 219 if err == nil { 220 res, err = svr.newFilter(filter) 221 } 222 case "eth_newBlockFilter": 223 res, err = svr.newBlockFilter() 224 case "eth_subscribe": 225 res, err = svr.subscribe(web3Req, writer) 226 case "eth_unsubscribe": 227 res, err = svr.unsubscribe(web3Req) 228 case "debug_traceTransaction": 229 res, err = svr.traceTransaction(ctx, web3Req) 230 case "debug_traceCall": 231 res, err = svr.traceCall(ctx, web3Req) 232 case "eth_coinbase", "eth_getUncleCountByBlockHash", "eth_getUncleCountByBlockNumber", 233 "eth_sign", "eth_signTransaction", "eth_sendTransaction", "eth_getUncleByBlockHashAndIndex", 234 "eth_getUncleByBlockNumberAndIndex", "eth_pendingTransactions": 235 res, err = svr.unimplemented() 236 default: 237 res, err = nil, errors.Wrapf(errors.New("web3 method not found"), "method: %s\n", web3Req.Get("method")) 238 } 239 if err != nil { 240 log.Logger("api").Debug("web3server", 241 zap.String("requestParams", fmt.Sprintf("%+v", web3Req)), 242 zap.Error(err)) 243 } else { 244 log.Logger("api").Debug("web3Debug", zap.String("response", fmt.Sprintf("%+v", res))) 245 } 246 var id any 247 reqID := web3Req.Get("id") 248 switch reqID.Type { 249 case gjson.String: 250 id = reqID.String() 251 case gjson.Number: 252 id = reqID.Int() 253 default: 254 id = 0 255 res, err = nil, errors.New("invalid id type") 256 } 257 size, err1 = writer.Write(&web3Response{ 258 id: id, 259 result: res, 260 err: err, 261 }) 262 return err1 263 } 264 265 func parseWeb3Reqs(reader io.Reader) (gjson.Result, error) { 266 data, err := io.ReadAll(reader) 267 if err != nil { 268 return gjson.Result{}, err 269 } 270 if !gjson.Valid(string(data)) { 271 return gjson.Result{}, errors.New("request json format is not valid") 272 } 273 ret := gjson.Parse(string(data)) 274 // check rquired field 275 for _, req := range ret.Array() { 276 id := req.Get("id") 277 method := req.Get("method") 278 if !id.Exists() || !method.Exists() { 279 return gjson.Result{}, errors.New("request field is incomplete") 280 } 281 } 282 return ret, nil 283 } 284 285 func (svr *web3Handler) ethAccounts() (interface{}, error) { 286 return []string{}, nil 287 } 288 289 func (svr *web3Handler) gasPrice() (interface{}, error) { 290 ret, err := svr.coreService.SuggestGasPrice() 291 if err != nil { 292 return nil, err 293 } 294 return uint64ToHex(ret), nil 295 } 296 297 func (svr *web3Handler) getChainID() (interface{}, error) { 298 return uint64ToHex(uint64(svr.coreService.EVMNetworkID())), nil 299 } 300 301 func (svr *web3Handler) getBlockNumber() (interface{}, error) { 302 return uint64ToHex(svr.coreService.TipHeight()), nil 303 } 304 305 func (svr *web3Handler) getBlockByNumber(in *gjson.Result) (interface{}, error) { 306 blkNum, isDetailed := in.Get("params.0"), in.Get("params.1") 307 if !blkNum.Exists() || !isDetailed.Exists() { 308 return nil, errInvalidFormat 309 } 310 num, err := svr.parseBlockNumber(blkNum.String()) 311 if err != nil { 312 return nil, err 313 } 314 315 blk, err := svr.coreService.BlockByHeight(num) 316 if err != nil { 317 if errors.Cause(err) == ErrNotFound { 318 return nil, nil 319 } 320 return nil, err 321 } 322 return svr.getBlockWithTransactions(blk.Block, blk.Receipts, isDetailed.Bool()) 323 } 324 325 func (svr *web3Handler) getBalance(in *gjson.Result) (interface{}, error) { 326 addr := in.Get("params.0") 327 if !addr.Exists() { 328 return nil, errInvalidFormat 329 } 330 ioAddr, err := ethAddrToIoAddr(addr.String()) 331 if err != nil { 332 return nil, err 333 } 334 accountMeta, _, err := svr.coreService.Account(ioAddr) 335 if err != nil { 336 return nil, err 337 } 338 return intStrToHex(accountMeta.Balance) 339 } 340 341 // getTransactionCount returns the nonce for the given address 342 func (svr *web3Handler) getTransactionCount(in *gjson.Result) (interface{}, error) { 343 addr := in.Get("params.0") 344 if !addr.Exists() { 345 return nil, errInvalidFormat 346 } 347 ioAddr, err := ethAddrToIoAddr(addr.String()) 348 if err != nil { 349 return nil, err 350 } 351 // TODO (liuhaai): returns the nonce in given block height after archive mode is supported 352 // blkNum, err := getStringFromArray(in, 1) 353 pendingNonce, err := svr.coreService.PendingNonce(ioAddr) 354 if err != nil { 355 return nil, err 356 } 357 return uint64ToHex(pendingNonce), nil 358 } 359 360 func (svr *web3Handler) call(in *gjson.Result) (interface{}, error) { 361 callerAddr, to, gasLimit, gasPrice, value, data, err := parseCallObject(in) 362 if err != nil { 363 return nil, err 364 } 365 if to == _metamaskBalanceContractAddr { 366 return nil, nil 367 } 368 if to == address.StakingProtocolAddr { 369 sctx, err := stakingabi.BuildReadStateRequest(data) 370 if err != nil { 371 return nil, err 372 } 373 states, err := svr.coreService.ReadState("staking", "", sctx.Parameters().MethodName, sctx.Parameters().Arguments) 374 if err != nil { 375 return nil, err 376 } 377 ret, err := sctx.EncodeToEth(states) 378 if err != nil { 379 return nil, err 380 } 381 return "0x" + ret, nil 382 } 383 if to == address.RewardingProtocol { 384 sctx, err := rewardingabi.BuildReadStateRequest(data) 385 if err != nil { 386 return nil, err 387 } 388 states, err := svr.coreService.ReadState("rewarding", "", sctx.Parameters().MethodName, sctx.Parameters().Arguments) 389 if err != nil { 390 return nil, err 391 } 392 ret, err := sctx.EncodeToEth(states) 393 if err != nil { 394 return nil, err 395 } 396 return "0x" + ret, nil 397 } 398 exec, _ := action.NewExecution(to, 0, value, gasLimit, gasPrice, data) 399 ret, receipt, err := svr.coreService.ReadContract(context.Background(), callerAddr, exec) 400 if err != nil { 401 return nil, err 402 } 403 if receipt != nil && len(receipt.GetExecutionRevertMsg()) > 0 { 404 return "0x" + ret, status.Error(codes.InvalidArgument, "execution reverted: "+receipt.GetExecutionRevertMsg()) 405 } 406 return "0x" + ret, nil 407 } 408 409 func (svr *web3Handler) estimateGas(in *gjson.Result) (interface{}, error) { 410 from, to, gasLimit, gasPrice, value, data, err := parseCallObject(in) 411 if err != nil { 412 return nil, err 413 } 414 415 var ( 416 tx *types.Transaction 417 toAddr *common.Address 418 ) 419 if len(to) != 0 { 420 addr, err := addrutil.IoAddrToEvmAddr(to) 421 if err != nil { 422 return nil, err 423 } 424 toAddr = &addr 425 } 426 tx = types.NewTx(&types.LegacyTx{ 427 Nonce: 0, 428 GasPrice: gasPrice, 429 Gas: gasLimit, 430 To: toAddr, 431 Value: value, 432 Data: data, 433 }) 434 elp, err := svr.ethTxToEnvelope(tx) 435 if err != nil { 436 return nil, err 437 } 438 439 var estimatedGas uint64 440 if exec, ok := elp.Action().(*action.Execution); ok { 441 estimatedGas, err = svr.coreService.EstimateExecutionGasConsumption(context.Background(), exec, from) 442 } else { 443 estimatedGas, err = svr.coreService.EstimateGasForNonExecution(elp.Action()) 444 } 445 if err != nil { 446 return nil, err 447 } 448 if estimatedGas < 21000 { 449 estimatedGas = 21000 450 } 451 return uint64ToHex(estimatedGas), nil 452 } 453 454 func (svr *web3Handler) sendRawTransaction(in *gjson.Result) (interface{}, error) { 455 dataStr := in.Get("params.0") 456 if !dataStr.Exists() { 457 return nil, errInvalidFormat 458 } 459 // parse raw data string from json request 460 var ( 461 cs = svr.coreService 462 tx *types.Transaction 463 encoding iotextypes.Encoding 464 sig []byte 465 pubkey crypto.PublicKey 466 err error 467 ) 468 if g := cs.Genesis(); g.IsSumatra(cs.TipHeight()) { 469 tx, err = action.DecodeEtherTx(dataStr.String()) 470 if err != nil { 471 return nil, err 472 } 473 if tx.Protected() && tx.ChainId().Uint64() != uint64(cs.EVMNetworkID()) { 474 return nil, errors.Wrapf(errInvalidEvmChainID, "expect chainID = %d, got %d", cs.EVMNetworkID(), tx.ChainId().Uint64()) 475 } 476 encoding, sig, pubkey, err = action.ExtractTypeSigPubkey(tx) 477 if err != nil { 478 return nil, err 479 } 480 } else { 481 tx, sig, pubkey, err = action.DecodeRawTx(dataStr.String(), cs.EVMNetworkID()) 482 if err != nil { 483 return nil, err 484 } 485 // before Sumatra height, all tx are EIP-155 format 486 encoding = iotextypes.Encoding_ETHEREUM_EIP155 487 } 488 elp, err := svr.ethTxToEnvelope(tx) 489 if err != nil { 490 return nil, err 491 } 492 req := &iotextypes.Action{ 493 Core: elp.Proto(), 494 SenderPubKey: pubkey.Bytes(), 495 Signature: sig, 496 Encoding: encoding, 497 } 498 actionHash, err := cs.SendAction(context.Background(), req) 499 if err != nil { 500 return nil, err 501 } 502 return "0x" + actionHash, nil 503 } 504 505 func (svr *web3Handler) getCode(in *gjson.Result) (interface{}, error) { 506 addr := in.Get("params.0") 507 if !addr.Exists() { 508 return nil, errInvalidFormat 509 } 510 ioAddr, err := ethAddrToIoAddr(addr.String()) 511 if err != nil { 512 return nil, err 513 } 514 accountMeta, _, err := svr.coreService.Account(ioAddr) 515 if err != nil { 516 return nil, err 517 } 518 return "0x" + hex.EncodeToString(accountMeta.ContractByteCode), nil 519 } 520 521 func (svr *web3Handler) getNodeInfo() (interface{}, error) { 522 packageVersion, _, _, goVersion, _ := svr.coreService.ServerMeta() 523 return packageVersion + "/" + goVersion, nil 524 } 525 526 func (svr *web3Handler) getNetworkID() (interface{}, error) { 527 return strconv.Itoa(int(svr.coreService.EVMNetworkID())), nil 528 } 529 530 func (svr *web3Handler) getPeerCount() (interface{}, error) { 531 return "0x64", nil 532 } 533 534 func (svr *web3Handler) isListening() (interface{}, error) { 535 return true, nil 536 } 537 538 func (svr *web3Handler) getProtocolVersion() (interface{}, error) { 539 return "64", nil 540 } 541 542 func (svr *web3Handler) isSyncing() (interface{}, error) { 543 start, curr, highest := svr.coreService.SyncingProgress() 544 if curr >= highest { 545 return false, nil 546 } 547 return &getSyncingResult{ 548 StartingBlock: uint64ToHex(start), 549 CurrentBlock: uint64ToHex(curr), 550 HighestBlock: uint64ToHex(highest), 551 }, nil 552 } 553 554 func (svr *web3Handler) isMining() (interface{}, error) { 555 return false, nil 556 } 557 558 func (svr *web3Handler) getHashrate() (interface{}, error) { 559 return "0x500000", nil 560 } 561 562 func (svr *web3Handler) getBlockTransactionCountByHash(in *gjson.Result) (interface{}, error) { 563 txHash := in.Get("params.0") 564 if !txHash.Exists() { 565 return nil, errInvalidFormat 566 } 567 blk, err := svr.coreService.BlockByHash(util.Remove0xPrefix(txHash.String())) 568 if err != nil { 569 return nil, errors.Wrap(err, "the block is not found") 570 } 571 return uint64ToHex(uint64(len(blk.Block.Actions))), nil 572 } 573 574 func (svr *web3Handler) getBlockByHash(in *gjson.Result) (interface{}, error) { 575 blkHash, isDetailed := in.Get("params.0"), in.Get("params.1") 576 if !blkHash.Exists() || !isDetailed.Exists() { 577 return nil, errInvalidFormat 578 } 579 blk, err := svr.coreService.BlockByHash(util.Remove0xPrefix(blkHash.String())) 580 if err != nil { 581 if errors.Cause(err) == ErrNotFound { 582 return nil, nil 583 } 584 return nil, err 585 } 586 return svr.getBlockWithTransactions(blk.Block, blk.Receipts, isDetailed.Bool()) 587 } 588 589 func (svr *web3Handler) getTransactionByHash(in *gjson.Result) (interface{}, error) { 590 txHash := in.Get("params.0") 591 if !txHash.Exists() { 592 return nil, errInvalidFormat 593 } 594 actHash, err := hash.HexStringToHash256(util.Remove0xPrefix(txHash.String())) 595 if err != nil { 596 return nil, err 597 } 598 599 selp, blk, _, err := svr.coreService.ActionByActionHash(actHash) 600 if err == nil { 601 receipt, err := svr.coreService.ReceiptByActionHash(actHash) 602 if err == nil { 603 return svr.assembleConfirmedTransaction(blk.HashBlock(), selp, receipt) 604 } 605 if errors.Cause(err) == ErrNotFound { 606 return nil, nil 607 } 608 return nil, err 609 } 610 if errors.Cause(err) == ErrNotFound { 611 selp, err = svr.coreService.PendingActionByActionHash(actHash) 612 if err == nil { 613 return svr.assemblePendingTransaction(selp) 614 } 615 if errors.Cause(err) == ErrNotFound { 616 return nil, nil 617 } 618 return nil, err 619 } 620 return nil, err 621 } 622 623 func (svr *web3Handler) getLogs(filter *filterObject) (interface{}, error) { 624 from, to, err := svr.parseBlockRange(filter.FromBlock, filter.ToBlock) 625 if err != nil { 626 return nil, err 627 } 628 return svr.getLogsWithFilter(from, to, filter.Address, filter.Topics) 629 } 630 631 func (svr *web3Handler) getTransactionReceipt(in *gjson.Result) (interface{}, error) { 632 // parse action hash from request 633 actHashStr := in.Get("params.0") 634 if !actHashStr.Exists() { 635 return nil, errInvalidFormat 636 } 637 actHash, err := hash.HexStringToHash256(util.Remove0xPrefix(actHashStr.String())) 638 if err != nil { 639 return nil, errors.Wrapf(errUnkownType, "actHash: %s", actHashStr.String()) 640 } 641 642 // acquire action receipt by action hash 643 selp, blk, _, err := svr.coreService.ActionByActionHash(actHash) 644 if err != nil { 645 if errors.Cause(err) == ErrNotFound { 646 return nil, nil 647 } 648 return nil, err 649 } 650 receipt, err := svr.coreService.ReceiptByActionHash(actHash) 651 if err != nil { 652 if errors.Cause(err) == ErrNotFound { 653 return nil, nil 654 } 655 return nil, err 656 } 657 to, contractAddr, err := getRecipientAndContractAddrFromAction(selp, receipt) 658 if err != nil { 659 return nil, err 660 } 661 662 // acquire logsBloom from blockMeta 663 var logsBloomStr string 664 if logsBloom := blk.LogsBloomfilter(); logsBloom != nil { 665 logsBloomStr = hex.EncodeToString(logsBloom.Bytes()) 666 } 667 668 return &getReceiptResult{ 669 blockHash: blk.HashBlock(), 670 from: selp.SenderAddress(), 671 to: to, 672 contractAddress: contractAddr, 673 logsBloom: logsBloomStr, 674 receipt: receipt, 675 }, nil 676 677 } 678 679 func (svr *web3Handler) getBlockTransactionCountByNumber(in *gjson.Result) (interface{}, error) { 680 blkNum := in.Get("params.0") 681 if !blkNum.Exists() { 682 return nil, errInvalidFormat 683 } 684 num, err := svr.parseBlockNumber(blkNum.String()) 685 if err != nil { 686 return nil, err 687 } 688 blk, err := svr.coreService.BlockByHeight(num) 689 if err != nil { 690 if errors.Cause(err) == ErrNotFound { 691 return nil, nil 692 } 693 return nil, err 694 } 695 return uint64ToHex(uint64(len(blk.Block.Actions))), nil 696 } 697 698 func (svr *web3Handler) getTransactionByBlockHashAndIndex(in *gjson.Result) (interface{}, error) { 699 blkHashStr, idxStr := in.Get("params.0"), in.Get("params.1") 700 if !blkHashStr.Exists() || !idxStr.Exists() { 701 return nil, errInvalidFormat 702 } 703 idx, err := hexStringToNumber(idxStr.String()) 704 if err != nil { 705 return nil, err 706 } 707 blkHashHex := util.Remove0xPrefix(blkHashStr.String()) 708 blk, err := svr.coreService.BlockByHash(blkHashHex) 709 if errors.Cause(err) == ErrNotFound || idx >= uint64(len(blk.Receipts)) || len(blk.Receipts) == 0 { 710 return nil, nil 711 } 712 if err != nil { 713 return nil, err 714 } 715 blkHash, err := hash.HexStringToHash256(blkHashHex) 716 if err != nil { 717 return nil, err 718 } 719 return svr.assembleConfirmedTransaction(blkHash, blk.Block.Actions[idx], blk.Receipts[idx]) 720 } 721 722 func (svr *web3Handler) getTransactionByBlockNumberAndIndex(in *gjson.Result) (interface{}, error) { 723 blkNum, idxStr := in.Get("params.0"), in.Get("params.1") 724 if !blkNum.Exists() || !idxStr.Exists() { 725 return nil, errInvalidFormat 726 } 727 num, err := svr.parseBlockNumber(blkNum.String()) 728 if err != nil { 729 return nil, err 730 } 731 idx, err := hexStringToNumber(idxStr.String()) 732 if err != nil { 733 return nil, err 734 } 735 blk, err := svr.coreService.BlockByHeight(num) 736 if errors.Cause(err) == ErrNotFound || idx >= uint64(len(blk.Receipts)) || len(blk.Receipts) == 0 { 737 return nil, nil 738 } 739 if err != nil { 740 return nil, err 741 } 742 return svr.assembleConfirmedTransaction(blk.Block.HashBlock(), blk.Block.Actions[idx], blk.Receipts[idx]) 743 } 744 745 func (svr *web3Handler) getStorageAt(in *gjson.Result) (interface{}, error) { 746 ethAddr, storagePos := in.Get("params.0"), in.Get("params.1") 747 if !ethAddr.Exists() || !storagePos.Exists() { 748 return nil, errInvalidFormat 749 } 750 contractAddr, err := address.FromHex(ethAddr.String()) 751 if err != nil { 752 return nil, err 753 } 754 pos, err := hexToBytes(storagePos.String()) 755 if err != nil { 756 return nil, err 757 } 758 val, err := svr.coreService.ReadContractStorage(context.Background(), contractAddr, pos) 759 if err != nil { 760 return nil, err 761 } 762 return "0x" + hex.EncodeToString(val), nil 763 } 764 765 func (svr *web3Handler) newFilter(filter *filterObject) (interface{}, error) { 766 //check the validity of filter before caching 767 if filter == nil { 768 return nil, errNullPointer 769 } 770 if _, err := svr.parseBlockNumber(filter.FromBlock); err != nil { 771 return nil, errors.Wrapf(errUnkownType, "from: %s", filter.FromBlock) 772 } 773 if _, err := svr.parseBlockNumber(filter.ToBlock); err != nil { 774 return nil, errors.Wrapf(errUnkownType, "to: %s", filter.ToBlock) 775 } 776 for _, ethAddr := range filter.Address { 777 if _, err := ethAddrToIoAddr(ethAddr); err != nil { 778 return nil, err 779 } 780 } 781 for _, tp := range filter.Topics { 782 for _, str := range tp { 783 if _, err := hexToBytes(str); err != nil { 784 return nil, err 785 } 786 } 787 } 788 789 // cache filter and return hash value of the filter as filter id 790 filter.FilterType = "log" 791 objInByte, _ := json.Marshal(*filter) 792 keyHash := hash.Hash256b(objInByte) 793 filterID := hex.EncodeToString(keyHash[:]) 794 err := svr.cache.Set(filterID, objInByte) 795 if err != nil { 796 return nil, err 797 } 798 return "0x" + filterID, nil 799 } 800 801 func (svr *web3Handler) newBlockFilter() (interface{}, error) { 802 filterObj := filterObject{ 803 FilterType: "block", 804 LogHeight: svr.coreService.TipHeight(), 805 } 806 objInByte, _ := json.Marshal(filterObj) 807 keyHash := hash.Hash256b(objInByte) 808 filterID := hex.EncodeToString(keyHash[:]) 809 err := svr.cache.Set(filterID, objInByte) 810 if err != nil { 811 return nil, err 812 } 813 return "0x" + filterID, nil 814 } 815 816 func (svr *web3Handler) uninstallFilter(in *gjson.Result) (interface{}, error) { 817 id := in.Get("params.0") 818 if !id.Exists() { 819 return nil, errInvalidFormat 820 } 821 return svr.cache.Del(util.Remove0xPrefix(id.String())), nil 822 } 823 824 func (svr *web3Handler) getFilterChanges(in *gjson.Result) (interface{}, error) { 825 id := in.Get("params.0") 826 if !id.Exists() { 827 return nil, errInvalidFormat 828 } 829 filterID := util.Remove0xPrefix(id.String()) 830 filterObj, err := loadFilterFromCache(svr.cache, filterID) 831 if err != nil { 832 return nil, err 833 } 834 var ( 835 ret interface{} 836 newLogHeight uint64 837 tipHeight = svr.coreService.TipHeight() 838 ) 839 switch filterObj.FilterType { 840 case "log": 841 if filterObj.LogHeight > tipHeight { 842 return []*getLogsResult{}, nil 843 } 844 from, to, hasNewLogs, err := svr.getLogQueryRange(filterObj.FromBlock, filterObj.ToBlock, filterObj.LogHeight) 845 if err != nil { 846 return nil, err 847 } 848 if !hasNewLogs { 849 return []*getLogsResult{}, nil 850 } 851 logs, err := svr.getLogsWithFilter(from, to, filterObj.Address, filterObj.Topics) 852 if err != nil { 853 return nil, err 854 } 855 ret, newLogHeight = logs, tipHeight+1 856 case "block": 857 if filterObj.LogHeight > tipHeight { 858 return []string{}, nil 859 } 860 queryCount := tipHeight - filterObj.LogHeight + 1 861 blkStores, err := svr.coreService.BlockByHeightRange(filterObj.LogHeight, queryCount) 862 if err != nil { 863 return nil, err 864 } 865 hashArr := make([]string, 0) 866 for _, blkStore := range blkStores { 867 blkHash := blkStore.Block.HashBlock() 868 hashArr = append(hashArr, "0x"+hex.EncodeToString(blkHash[:])) 869 } 870 ret, newLogHeight = hashArr, filterObj.LogHeight+queryCount 871 default: 872 return nil, errors.Wrapf(errUnkownType, "filterType: %s", filterObj.FilterType) 873 } 874 875 // update the logHeight of filter cache 876 filterObj.LogHeight = newLogHeight 877 objInByte, _ := json.Marshal(filterObj) 878 if err = svr.cache.Set(filterID, objInByte); err != nil { 879 return nil, err 880 } 881 return ret, nil 882 } 883 884 func (svr *web3Handler) getFilterLogs(in *gjson.Result) (interface{}, error) { 885 id := in.Get("params.0") 886 if !id.Exists() { 887 return nil, errInvalidFormat 888 } 889 filterID := util.Remove0xPrefix(id.String()) 890 filterObj, err := loadFilterFromCache(svr.cache, filterID) 891 if err != nil { 892 return nil, err 893 } 894 if filterObj.FilterType != "log" { 895 return nil, errInvalidFilterID 896 } 897 from, to, err := svr.parseBlockRange(filterObj.FromBlock, filterObj.ToBlock) 898 if err != nil { 899 return nil, err 900 } 901 return svr.getLogsWithFilter(from, to, filterObj.Address, filterObj.Topics) 902 } 903 904 func (svr *web3Handler) subscribe(in *gjson.Result, writer apitypes.Web3ResponseWriter) (interface{}, error) { 905 subscription := in.Get("params.0") 906 if !subscription.Exists() { 907 return nil, errInvalidFormat 908 } 909 switch subscription.String() { 910 case "newHeads": 911 return svr.streamBlocks(writer) 912 case "logs": 913 filter, err := parseLogRequest(in.Get("params.1")) 914 if err != nil { 915 return nil, err 916 } 917 return svr.streamLogs(filter, writer) 918 default: 919 return nil, errInvalidFormat 920 } 921 } 922 923 func (svr *web3Handler) streamBlocks(writer apitypes.Web3ResponseWriter) (interface{}, error) { 924 chainListener := svr.coreService.ChainListener() 925 streamID, err := chainListener.AddResponder(NewWeb3BlockListener(writer.Write)) 926 if err != nil { 927 return nil, err 928 } 929 return streamID, nil 930 } 931 932 func (svr *web3Handler) streamLogs(filterObj *filterObject, writer apitypes.Web3ResponseWriter) (interface{}, error) { 933 filter, err := newLogFilterFrom(filterObj.Address, filterObj.Topics) 934 if err != nil { 935 return nil, err 936 } 937 chainListener := svr.coreService.ChainListener() 938 streamID, err := chainListener.AddResponder(NewWeb3LogListener(filter, writer.Write)) 939 if err != nil { 940 return nil, err 941 } 942 return streamID, nil 943 } 944 945 func (svr *web3Handler) unsubscribe(in *gjson.Result) (interface{}, error) { 946 id := in.Get("params.0") 947 if !id.Exists() { 948 return nil, errInvalidFormat 949 } 950 chainListener := svr.coreService.ChainListener() 951 return chainListener.RemoveResponder(id.String()) 952 } 953 954 func (svr *web3Handler) traceTransaction(ctx context.Context, in *gjson.Result) (interface{}, error) { 955 actHash, options := in.Get("params.0"), in.Get("params.1") 956 if !actHash.Exists() { 957 return nil, errInvalidFormat 958 } 959 var ( 960 enableMemory, disableStack, disableStorage, enableReturnData bool 961 ) 962 if options.Exists() { 963 enableMemory = options.Get("enableMemory").Bool() 964 disableStack = options.Get("disableStack").Bool() 965 disableStorage = options.Get("disableStorage").Bool() 966 enableReturnData = options.Get("enableReturnData").Bool() 967 } 968 cfg := &tracers.TraceConfig{ 969 Config: &logger.Config{ 970 EnableMemory: enableMemory, 971 DisableStack: disableStack, 972 DisableStorage: disableStorage, 973 EnableReturnData: enableReturnData, 974 }, 975 } 976 if tracer := options.Get("tracer"); tracer.Exists() { 977 cfg.Tracer = new(string) 978 *cfg.Tracer = tracer.String() 979 if tracerConfig := options.Get("tracerConfig"); tracerConfig.Exists() { 980 cfg.TracerConfig = json.RawMessage(tracerConfig.Raw) 981 } 982 } 983 retval, receipt, tracer, err := svr.coreService.TraceTransaction(ctx, actHash.String(), cfg) 984 if err != nil { 985 return nil, err 986 } 987 switch tracer := tracer.(type) { 988 case *logger.StructLogger: 989 return &debugTraceTransactionResult{ 990 Failed: receipt.Status != uint64(iotextypes.ReceiptStatus_Success), 991 Revert: receipt.ExecutionRevertMsg(), 992 ReturnValue: byteToHex(retval), 993 StructLogs: fromLoggerStructLogs(tracer.StructLogs()), 994 Gas: receipt.GasConsumed, 995 }, nil 996 case tracers.Tracer: 997 return tracer.GetResult() 998 default: 999 return nil, fmt.Errorf("unknown tracer type: %T", tracer) 1000 } 1001 } 1002 1003 func (svr *web3Handler) traceCall(ctx context.Context, in *gjson.Result) (interface{}, error) { 1004 var ( 1005 err error 1006 contractAddr string 1007 callData []byte 1008 gasLimit uint64 1009 value *big.Int 1010 callerAddr address.Address 1011 ) 1012 blkNumOrHashObj, options := in.Get("params.1"), in.Get("params.2") 1013 callerAddr, contractAddr, gasLimit, _, value, callData, err = parseCallObject(in) 1014 if err != nil { 1015 return nil, err 1016 } 1017 var blkNumOrHash any 1018 if blkNumOrHashObj.Exists() { 1019 blkNumOrHash = blkNumOrHashObj.Get("blockHash").String() 1020 if blkNumOrHash == "" { 1021 blkNumOrHash = blkNumOrHashObj.Get("blockNumber").Uint() 1022 } 1023 } 1024 1025 var ( 1026 enableMemory, disableStack, disableStorage, enableReturnData bool 1027 tracerJs, tracerTimeout *string 1028 ) 1029 if options.Exists() { 1030 enableMemory = options.Get("enableMemory").Bool() 1031 disableStack = options.Get("disableStack").Bool() 1032 disableStorage = options.Get("disableStorage").Bool() 1033 enableReturnData = options.Get("enableReturnData").Bool() 1034 trace := options.Get("tracer") 1035 if trace.Exists() { 1036 tracerJs = new(string) 1037 *tracerJs = trace.String() 1038 } 1039 traceTimeout := options.Get("timeout") 1040 if traceTimeout.Exists() { 1041 tracerTimeout = new(string) 1042 *tracerTimeout = traceTimeout.String() 1043 } 1044 } 1045 cfg := &tracers.TraceConfig{ 1046 Tracer: tracerJs, 1047 Timeout: tracerTimeout, 1048 Config: &logger.Config{ 1049 EnableMemory: enableMemory, 1050 DisableStack: disableStack, 1051 DisableStorage: disableStorage, 1052 EnableReturnData: enableReturnData, 1053 }, 1054 } 1055 1056 retval, receipt, tracer, err := svr.coreService.TraceCall(ctx, callerAddr, blkNumOrHash, contractAddr, 0, value, gasLimit, callData, cfg) 1057 if err != nil { 1058 return nil, err 1059 } 1060 switch tracer := tracer.(type) { 1061 case *logger.StructLogger: 1062 return &debugTraceTransactionResult{ 1063 Failed: receipt.Status != uint64(iotextypes.ReceiptStatus_Success), 1064 Revert: receipt.ExecutionRevertMsg(), 1065 ReturnValue: byteToHex(retval), 1066 StructLogs: fromLoggerStructLogs(tracer.StructLogs()), 1067 Gas: receipt.GasConsumed, 1068 }, nil 1069 case tracers.Tracer: 1070 return tracer.GetResult() 1071 default: 1072 return nil, fmt.Errorf("unknown tracer type: %T", tracer) 1073 } 1074 } 1075 1076 func (svr *web3Handler) unimplemented() (interface{}, error) { 1077 return nil, errNotImplemented 1078 }