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  }