github.com/iotexproject/iotex-core@v1.14.1-rc1/api/coreservice.go (about)

     1  // Copyright (c) 2022 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 api
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"math"
    14  	"math/big"
    15  	"strconv"
    16  	"time"
    17  
    18  	"github.com/ethereum/go-ethereum/core/vm"
    19  	"github.com/ethereum/go-ethereum/eth/tracers"
    20  
    21  	// Force-load the tracer engines to trigger registration
    22  	_ "github.com/ethereum/go-ethereum/eth/tracers/js"
    23  	_ "github.com/ethereum/go-ethereum/eth/tracers/native"
    24  
    25  	"github.com/ethereum/go-ethereum/eth/tracers/logger"
    26  	"github.com/pkg/errors"
    27  	"go.uber.org/zap"
    28  	"golang.org/x/sync/errgroup"
    29  	"google.golang.org/genproto/googleapis/rpc/errdetails"
    30  	"google.golang.org/grpc/codes"
    31  	"google.golang.org/grpc/status"
    32  	"google.golang.org/protobuf/proto"
    33  	"google.golang.org/protobuf/types/known/durationpb"
    34  	"google.golang.org/protobuf/types/known/timestamppb"
    35  
    36  	"github.com/iotexproject/go-pkgs/hash"
    37  	"github.com/iotexproject/go-pkgs/util"
    38  	"github.com/iotexproject/iotex-address/address"
    39  	"github.com/iotexproject/iotex-election/committee"
    40  	"github.com/iotexproject/iotex-proto/golang/iotexapi"
    41  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    42  
    43  	"github.com/iotexproject/iotex-core/action"
    44  	"github.com/iotexproject/iotex-core/action/protocol"
    45  	accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
    46  	"github.com/iotexproject/iotex-core/action/protocol/execution/evm"
    47  	"github.com/iotexproject/iotex-core/action/protocol/poll"
    48  	"github.com/iotexproject/iotex-core/action/protocol/rewarding"
    49  	"github.com/iotexproject/iotex-core/action/protocol/rolldpos"
    50  	"github.com/iotexproject/iotex-core/actpool"
    51  	logfilter "github.com/iotexproject/iotex-core/api/logfilter"
    52  	apitypes "github.com/iotexproject/iotex-core/api/types"
    53  	"github.com/iotexproject/iotex-core/blockchain"
    54  	"github.com/iotexproject/iotex-core/blockchain/block"
    55  	"github.com/iotexproject/iotex-core/blockchain/blockdao"
    56  	"github.com/iotexproject/iotex-core/blockchain/filedao"
    57  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    58  	"github.com/iotexproject/iotex-core/blockindex"
    59  	"github.com/iotexproject/iotex-core/blocksync"
    60  	"github.com/iotexproject/iotex-core/db"
    61  	"github.com/iotexproject/iotex-core/gasstation"
    62  	"github.com/iotexproject/iotex-core/pkg/log"
    63  	batch "github.com/iotexproject/iotex-core/pkg/messagebatcher"
    64  	"github.com/iotexproject/iotex-core/pkg/tracer"
    65  	"github.com/iotexproject/iotex-core/pkg/version"
    66  	"github.com/iotexproject/iotex-core/server/itx/nodestats"
    67  	"github.com/iotexproject/iotex-core/state"
    68  	"github.com/iotexproject/iotex-core/state/factory"
    69  )
    70  
    71  const _workerNumbers int = 5
    72  const (
    73  	// defaultTraceTimeout is the amount of time a single transaction can execute
    74  	// by default before being forcefully aborted.
    75  	defaultTraceTimeout = 5 * time.Second
    76  )
    77  
    78  type (
    79  	// CoreService provides api interface for user to interact with blockchain data
    80  	CoreService interface {
    81  		// Account returns the metadata of an account
    82  		Account(addr address.Address) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error)
    83  		// ChainMeta returns blockchain metadata
    84  		ChainMeta() (*iotextypes.ChainMeta, string, error)
    85  		// ServerMeta gets the server metadata
    86  		ServerMeta() (packageVersion string, packageCommitID string, gitStatus string, goVersion string, buildTime string)
    87  		// SendAction is the API to send an action to blockchain.
    88  		SendAction(ctx context.Context, in *iotextypes.Action) (string, error)
    89  		// ReadContract reads the state in a contract address specified by the slot
    90  		ReadContract(ctx context.Context, callerAddr address.Address, sc *action.Execution) (string, *iotextypes.Receipt, error)
    91  		// ReadState reads state on blockchain
    92  		ReadState(protocolID string, height string, methodName []byte, arguments [][]byte) (*iotexapi.ReadStateResponse, error)
    93  		// SuggestGasPrice suggests gas price
    94  		SuggestGasPrice() (uint64, error)
    95  		// EstimateGasForAction estimates gas for action
    96  		EstimateGasForAction(ctx context.Context, in *iotextypes.Action) (uint64, error)
    97  		// EpochMeta gets epoch metadata
    98  		EpochMeta(epochNum uint64) (*iotextypes.EpochData, uint64, []*iotexapi.BlockProducerInfo, error)
    99  		// RawBlocks gets raw block data
   100  		RawBlocks(startHeight uint64, count uint64, withReceipts bool, withTransactionLogs bool) ([]*iotexapi.BlockInfo, error)
   101  		// ElectionBuckets returns the native election buckets.
   102  		ElectionBuckets(epochNum uint64) ([]*iotextypes.ElectionBucket, error)
   103  		// ReceiptByActionHash returns receipt by action hash
   104  		ReceiptByActionHash(h hash.Hash256) (*action.Receipt, error)
   105  		// TransactionLogByActionHash returns transaction log by action hash
   106  		TransactionLogByActionHash(actHash string) (*iotextypes.TransactionLog, error)
   107  		// TransactionLogByBlockHeight returns transaction log by block height
   108  		TransactionLogByBlockHeight(blockHeight uint64) (*iotextypes.BlockIdentifier, *iotextypes.TransactionLogs, error)
   109  
   110  		// Start starts the API server
   111  		Start(ctx context.Context) error
   112  		// Stop stops the API server
   113  		Stop(ctx context.Context) error
   114  		// Actions returns actions within the range
   115  		Actions(start uint64, count uint64) ([]*iotexapi.ActionInfo, error)
   116  		// TODO: unify the three get action by hash methods: Action, ActionByActionHash, PendingActionByActionHash
   117  		// Action returns action by action hash
   118  		Action(actionHash string, checkPending bool) (*iotexapi.ActionInfo, error)
   119  		// ActionsByAddress returns all actions associated with an address
   120  		ActionsByAddress(addr address.Address, start uint64, count uint64) ([]*iotexapi.ActionInfo, error)
   121  		// ActionByActionHash returns action by action hash
   122  		ActionByActionHash(h hash.Hash256) (*action.SealedEnvelope, *block.Block, uint32, error)
   123  		// PendingActionByActionHash returns action by action hash
   124  		PendingActionByActionHash(h hash.Hash256) (*action.SealedEnvelope, error)
   125  		// ActPoolActions returns the all Transaction Identifiers in the actpool
   126  		ActionsInActPool(actHashes []string) ([]*action.SealedEnvelope, error)
   127  		// BlockByHeightRange returns blocks within the height range
   128  		BlockByHeightRange(uint64, uint64) ([]*apitypes.BlockWithReceipts, error)
   129  		// BlockByHeight returns the block and its receipt from block height
   130  		BlockByHeight(uint64) (*apitypes.BlockWithReceipts, error)
   131  		// BlockByHash returns the block and its receipt
   132  		BlockByHash(string) (*apitypes.BlockWithReceipts, error)
   133  		// UnconfirmedActionsByAddress returns all unconfirmed actions in actpool associated with an address
   134  		UnconfirmedActionsByAddress(address string, start uint64, count uint64) ([]*iotexapi.ActionInfo, error)
   135  		// EstimateGasForNonExecution  estimates action gas except execution
   136  		EstimateGasForNonExecution(action.Action) (uint64, error)
   137  		// EstimateExecutionGasConsumption estimate gas consumption for execution action
   138  		EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address) (uint64, error)
   139  		// LogsInBlockByHash filter logs in the block by hash
   140  		LogsInBlockByHash(filter *logfilter.LogFilter, blockHash hash.Hash256) ([]*action.Log, error)
   141  		// LogsInRange filter logs among [start, end] blocks
   142  		LogsInRange(filter *logfilter.LogFilter, start, end, paginationSize uint64) ([]*action.Log, []hash.Hash256, error)
   143  		// Genesis returns the genesis of the chain
   144  		Genesis() genesis.Genesis
   145  		// EVMNetworkID returns the network id of evm
   146  		EVMNetworkID() uint32
   147  		// ChainID returns the chain id of evm
   148  		ChainID() uint32
   149  		// ReadContractStorage reads contract's storage
   150  		ReadContractStorage(ctx context.Context, addr address.Address, key []byte) ([]byte, error)
   151  		// ChainListener returns the instance of Listener
   152  		ChainListener() apitypes.Listener
   153  		// SimulateExecution simulates execution
   154  		SimulateExecution(context.Context, address.Address, *action.Execution) ([]byte, *action.Receipt, error)
   155  		// SyncingProgress returns the syncing status of node
   156  		SyncingProgress() (uint64, uint64, uint64)
   157  		// TipHeight returns the tip of the chain
   158  		TipHeight() uint64
   159  		// PendingNonce returns the pending nonce of an account
   160  		PendingNonce(address.Address) (uint64, error)
   161  		// ReceiveBlock broadcasts the block to api subscribers
   162  		ReceiveBlock(blk *block.Block) error
   163  		// BlockHashByBlockHeight returns block hash by block height
   164  		BlockHashByBlockHeight(blkHeight uint64) (hash.Hash256, error)
   165  		// TraceTransaction returns the trace result of a transaction
   166  		TraceTransaction(ctx context.Context, actHash string, config *tracers.TraceConfig) ([]byte, *action.Receipt, any, error)
   167  		// TraceCall returns the trace result of a call
   168  		TraceCall(ctx context.Context,
   169  			callerAddr address.Address,
   170  			blkNumOrHash any,
   171  			contractAddress string,
   172  			nonce uint64,
   173  			amount *big.Int,
   174  			gasLimit uint64,
   175  			data []byte,
   176  			config *tracers.TraceConfig) ([]byte, *action.Receipt, any, error)
   177  
   178  		// Track tracks the api call
   179  		Track(ctx context.Context, start time.Time, method string, size int64, success bool)
   180  	}
   181  
   182  	// coreService implements the CoreService interface
   183  	coreService struct {
   184  		bc                blockchain.Blockchain
   185  		bs                blocksync.BlockSync
   186  		sf                factory.Factory
   187  		dao               blockdao.BlockDAO
   188  		indexer           blockindex.Indexer
   189  		bfIndexer         blockindex.BloomFilterIndexer
   190  		ap                actpool.ActPool
   191  		gs                *gasstation.GasStation
   192  		broadcastHandler  BroadcastOutbound
   193  		cfg               Config
   194  		registry          *protocol.Registry
   195  		chainListener     apitypes.Listener
   196  		electionCommittee committee.Committee
   197  		readCache         *ReadCache
   198  		messageBatcher    *batch.Manager
   199  		apiStats          *nodestats.APILocalStats
   200  		sgdIndexer        blockindex.SGDRegistry
   201  		getBlockTime      evm.GetBlockTime
   202  	}
   203  
   204  	// jobDesc provides a struct to get and store logs in core.LogsInRange
   205  	jobDesc struct {
   206  		idx    int
   207  		blkNum uint64
   208  	}
   209  )
   210  
   211  // Option is the option to override the api config
   212  type Option func(cfg *coreService)
   213  
   214  // BroadcastOutbound sends a broadcast message to the whole network
   215  type BroadcastOutbound func(ctx context.Context, chainID uint32, msg proto.Message) error
   216  
   217  // WithBroadcastOutbound is the option to broadcast msg outbound
   218  func WithBroadcastOutbound(broadcastHandler BroadcastOutbound) Option {
   219  	return func(svr *coreService) {
   220  		svr.broadcastHandler = broadcastHandler
   221  	}
   222  }
   223  
   224  // WithNativeElection is the option to return native election data through API.
   225  func WithNativeElection(committee committee.Committee) Option {
   226  	return func(svr *coreService) {
   227  		svr.electionCommittee = committee
   228  	}
   229  }
   230  
   231  // WithAPIStats is the option to return RPC stats through API.
   232  func WithAPIStats(stats *nodestats.APILocalStats) Option {
   233  	return func(svr *coreService) {
   234  		svr.apiStats = stats
   235  	}
   236  }
   237  
   238  // WithSGDIndexer is the option to return SGD Indexer through API.
   239  func WithSGDIndexer(sgdIndexer blockindex.SGDRegistry) Option {
   240  	return func(svr *coreService) {
   241  		svr.sgdIndexer = sgdIndexer
   242  	}
   243  }
   244  
   245  type intrinsicGasCalculator interface {
   246  	IntrinsicGas() (uint64, error)
   247  }
   248  
   249  var (
   250  	// ErrNotFound indicates the record isn't found
   251  	ErrNotFound = errors.New("not found")
   252  )
   253  
   254  // newcoreService creates a api server that contains major blockchain components
   255  func newCoreService(
   256  	cfg Config,
   257  	chain blockchain.Blockchain,
   258  	bs blocksync.BlockSync,
   259  	sf factory.Factory,
   260  	dao blockdao.BlockDAO,
   261  	indexer blockindex.Indexer,
   262  	bfIndexer blockindex.BloomFilterIndexer,
   263  	actPool actpool.ActPool,
   264  	registry *protocol.Registry,
   265  	getBlockTime evm.GetBlockTime,
   266  	opts ...Option,
   267  ) (CoreService, error) {
   268  	if cfg == (Config{}) {
   269  		log.L().Warn("API server is not configured.")
   270  		cfg = DefaultConfig
   271  	}
   272  
   273  	if cfg.RangeQueryLimit < uint64(cfg.TpsWindow) {
   274  		return nil, errors.New("range query upper limit cannot be less than tps window")
   275  	}
   276  
   277  	core := coreService{
   278  		bc:            chain,
   279  		bs:            bs,
   280  		sf:            sf,
   281  		dao:           dao,
   282  		indexer:       indexer,
   283  		bfIndexer:     bfIndexer,
   284  		ap:            actPool,
   285  		cfg:           cfg,
   286  		registry:      registry,
   287  		chainListener: NewChainListener(500),
   288  		gs:            gasstation.NewGasStation(chain, dao, cfg.GasStation),
   289  		readCache:     NewReadCache(),
   290  		getBlockTime:  getBlockTime,
   291  	}
   292  
   293  	for _, opt := range opts {
   294  		opt(&core)
   295  	}
   296  
   297  	if core.broadcastHandler != nil {
   298  		core.messageBatcher = batch.NewManager(func(msg *batch.Message) error {
   299  			return core.broadcastHandler(context.Background(), core.bc.ChainID(), msg.Data)
   300  		})
   301  	}
   302  
   303  	return &core, nil
   304  }
   305  
   306  // Account returns the metadata of an account
   307  func (core *coreService) Account(addr address.Address) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error) {
   308  	ctx, span := tracer.NewSpan(context.Background(), "coreService.Account")
   309  	defer span.End()
   310  	addrStr := addr.String()
   311  	if addrStr == address.RewardingPoolAddr || addrStr == address.StakingBucketPoolAddr {
   312  		return core.getProtocolAccount(ctx, addrStr)
   313  	}
   314  	span.AddEvent("accountutil.AccountStateWithHeight")
   315  	ctx = genesis.WithGenesisContext(ctx, core.bc.Genesis())
   316  	state, tipHeight, err := accountutil.AccountStateWithHeight(ctx, core.sf, addr)
   317  	if err != nil {
   318  		return nil, nil, status.Error(codes.NotFound, err.Error())
   319  	}
   320  	span.AddEvent("ap.GetPendingNonce")
   321  	pendingNonce, err := core.ap.GetPendingNonce(addrStr)
   322  	if err != nil {
   323  		return nil, nil, status.Error(codes.Internal, err.Error())
   324  	}
   325  	if core.indexer == nil {
   326  		return nil, nil, status.Error(codes.NotFound, blockindex.ErrActionIndexNA.Error())
   327  	}
   328  	span.AddEvent("indexer.GetActionCount")
   329  	numActions, err := core.indexer.GetActionCountByAddress(hash.BytesToHash160(addr.Bytes()))
   330  	if err != nil {
   331  		return nil, nil, status.Error(codes.NotFound, err.Error())
   332  	}
   333  	// TODO: deprecate nonce field in account meta
   334  	accountMeta := &iotextypes.AccountMeta{
   335  		Address:      addrStr,
   336  		Balance:      state.Balance.String(),
   337  		PendingNonce: pendingNonce,
   338  		NumActions:   numActions,
   339  		IsContract:   state.IsContract(),
   340  	}
   341  	if state.IsContract() {
   342  		var code protocol.SerializableBytes
   343  		_, err = core.sf.State(&code, protocol.NamespaceOption(evm.CodeKVNameSpace), protocol.KeyOption(state.CodeHash))
   344  		if err != nil {
   345  			return nil, nil, status.Error(codes.NotFound, err.Error())
   346  		}
   347  		accountMeta.ContractByteCode = code
   348  	}
   349  	span.AddEvent("bc.BlockHeaderByHeight")
   350  	header, err := core.bc.BlockHeaderByHeight(tipHeight)
   351  	if err != nil {
   352  		return nil, nil, status.Error(codes.NotFound, err.Error())
   353  	}
   354  	hash := header.HashBlock()
   355  	span.AddEvent("coreService.Account.End")
   356  	return accountMeta, &iotextypes.BlockIdentifier{
   357  		Hash:   hex.EncodeToString(hash[:]),
   358  		Height: tipHeight,
   359  	}, nil
   360  }
   361  
   362  // ChainMeta returns blockchain metadata
   363  func (core *coreService) ChainMeta() (*iotextypes.ChainMeta, string, error) {
   364  	tipHeight := core.bc.TipHeight()
   365  	if tipHeight == 0 {
   366  		return &iotextypes.ChainMeta{
   367  			Epoch:   &iotextypes.EpochData{},
   368  			ChainID: core.bc.ChainID(),
   369  		}, "", nil
   370  	}
   371  	syncStatus := ""
   372  	if core.bs != nil {
   373  		_, _, _, syncStatus = core.bs.SyncStatus()
   374  	}
   375  	chainMeta := &iotextypes.ChainMeta{
   376  		Height:  tipHeight,
   377  		ChainID: core.bc.ChainID(),
   378  	}
   379  	if core.indexer == nil {
   380  		return chainMeta, syncStatus, nil
   381  	}
   382  	totalActions, err := core.indexer.GetTotalActions()
   383  	if err != nil {
   384  		return nil, "", status.Error(codes.Internal, err.Error())
   385  	}
   386  	blockLimit := int64(core.cfg.TpsWindow)
   387  	if blockLimit <= 0 {
   388  		return nil, "", status.Errorf(codes.Internal, "block limit is %d", blockLimit)
   389  	}
   390  
   391  	// avoid genesis block
   392  	if int64(tipHeight) < blockLimit {
   393  		blockLimit = int64(tipHeight)
   394  	}
   395  	blkStores, err := core.BlockByHeightRange(tipHeight-uint64(blockLimit)+1, uint64(blockLimit))
   396  	if err != nil {
   397  		return nil, "", status.Error(codes.NotFound, err.Error())
   398  	}
   399  	if len(blkStores) == 0 {
   400  		return nil, "", status.Error(codes.NotFound, "get 0 blocks! not able to calculate aps")
   401  	}
   402  
   403  	var numActions uint64
   404  	for _, blkStore := range blkStores {
   405  		numActions += uint64(len(blkStore.Block.Actions))
   406  	}
   407  
   408  	t1 := blkStores[0].Block.Timestamp()
   409  	t2 := blkStores[len(blkStores)-1].Block.Timestamp()
   410  	// duration of time difference in milli-seconds
   411  	// TODO: use config.Genesis.BlockInterval after PR1289 merges
   412  	timeDiff := (t2.Sub(t1) + 10*time.Second) / time.Millisecond
   413  	tps := float32(numActions*1000) / float32(timeDiff)
   414  
   415  	chainMeta.NumActions = int64(totalActions)
   416  	chainMeta.Tps = int64(math.Ceil(float64(tps)))
   417  	chainMeta.TpsFloat = tps
   418  
   419  	rp := rolldpos.FindProtocol(core.registry)
   420  	if rp != nil {
   421  		epochNum := rp.GetEpochNum(tipHeight)
   422  		epochHeight := rp.GetEpochHeight(epochNum)
   423  		gravityChainStartHeight, err := core.getGravityChainStartHeight(epochHeight)
   424  		if err != nil {
   425  			return nil, "", status.Error(codes.NotFound, err.Error())
   426  		}
   427  		chainMeta.Epoch = &iotextypes.EpochData{
   428  			Num:                     epochNum,
   429  			Height:                  epochHeight,
   430  			GravityChainStartHeight: gravityChainStartHeight,
   431  		}
   432  	}
   433  	return chainMeta, syncStatus, nil
   434  }
   435  
   436  // ServerMeta gets the server metadata
   437  func (core *coreService) ServerMeta() (packageVersion string, packageCommitID string, gitStatus string, goVersion string, buildTime string) {
   438  	packageVersion = version.PackageVersion
   439  	packageCommitID = version.PackageCommitID
   440  	gitStatus = version.GitStatus
   441  	goVersion = version.GoVersion
   442  	buildTime = version.BuildTime
   443  	return
   444  }
   445  
   446  // SendAction is the API to send an action to blockchain.
   447  func (core *coreService) SendAction(ctx context.Context, in *iotextypes.Action) (string, error) {
   448  	log.Logger("api").Debug("receive send action request")
   449  	selp, err := (&action.Deserializer{}).SetEvmNetworkID(core.EVMNetworkID()).ActionToSealedEnvelope(in)
   450  	if err != nil {
   451  		return "", status.Error(codes.InvalidArgument, err.Error())
   452  	}
   453  
   454  	// reject action if chainID is not matched at KamchatkaHeight
   455  	if err := core.validateChainID(in.GetCore().GetChainID()); err != nil {
   456  		return "", err
   457  	}
   458  	// reject action if a replay tx is not whitelisted
   459  	var (
   460  		g        = core.Genesis()
   461  		deployer = selp.SenderAddress()
   462  	)
   463  	if selp.Encoding() == uint32(iotextypes.Encoding_ETHEREUM_UNPROTECTED) && !g.IsDeployerWhitelisted(deployer) {
   464  		return "", status.Errorf(codes.InvalidArgument, "replay deployer %v not whitelisted", deployer.Hex())
   465  	}
   466  
   467  	// Add to local actpool
   468  	ctx = protocol.WithRegistry(ctx, core.registry)
   469  	hash, err := selp.Hash()
   470  	if err != nil {
   471  		return "", err
   472  	}
   473  	l := log.Logger("api").With(zap.String("actionHash", hex.EncodeToString(hash[:])))
   474  	if err = core.ap.Add(ctx, selp); err != nil {
   475  		txBytes, serErr := proto.Marshal(in)
   476  		if serErr != nil {
   477  			l.Error("Data corruption", zap.Error(serErr))
   478  		} else {
   479  			l.With(zap.String("txBytes", hex.EncodeToString(txBytes))).Debug("Failed to accept action", zap.Error(err))
   480  		}
   481  		st := status.New(codes.Internal, err.Error())
   482  		br := &errdetails.BadRequest{
   483  			FieldViolations: []*errdetails.BadRequest_FieldViolation{
   484  				{
   485  					Field:       "Action rejected",
   486  					Description: action.LoadErrorDescription(err),
   487  				},
   488  			},
   489  		}
   490  		st, err := st.WithDetails(br)
   491  		if err != nil {
   492  			log.Logger("api").Panic("Unexpected error attaching metadata", zap.Error(err))
   493  		}
   494  		return "", st.Err()
   495  	}
   496  	// If there is no error putting into local actpool, broadcast it to the network
   497  	if core.messageBatcher != nil {
   498  		err = core.messageBatcher.Put(&batch.Message{
   499  			ChainID: core.bc.ChainID(),
   500  			Target:  nil,
   501  			Data:    in,
   502  		})
   503  	} else {
   504  		err = core.broadcastHandler(ctx, core.bc.ChainID(), in)
   505  	}
   506  	if err != nil {
   507  		l.Warn("Failed to broadcast SendAction request.", zap.Error(err))
   508  	}
   509  	return hex.EncodeToString(hash[:]), nil
   510  }
   511  
   512  func (core *coreService) PendingNonce(addr address.Address) (uint64, error) {
   513  	return core.ap.GetPendingNonce(addr.String())
   514  }
   515  
   516  func (core *coreService) validateChainID(chainID uint32) error {
   517  	ge := core.bc.Genesis()
   518  	if ge.IsQuebec(core.bc.TipHeight()) && chainID != core.bc.ChainID() {
   519  		return status.Errorf(codes.InvalidArgument, "ChainID does not match, expecting %d, got %d", core.bc.ChainID(), chainID)
   520  	}
   521  	if ge.IsMidway(core.bc.TipHeight()) && chainID != core.bc.ChainID() && chainID != 0 {
   522  		return status.Errorf(codes.InvalidArgument, "ChainID does not match, expecting %d, got %d", core.bc.ChainID(), chainID)
   523  	}
   524  	return nil
   525  }
   526  
   527  // ReadContract reads the state in a contract address specified by the slot
   528  func (core *coreService) ReadContract(ctx context.Context, callerAddr address.Address, sc *action.Execution) (string, *iotextypes.Receipt, error) {
   529  	log.Logger("api").Debug("receive read smart contract request")
   530  	key := hash.Hash160b(append([]byte(sc.Contract()), sc.Data()...))
   531  	// TODO: either moving readcache into the upper layer or change the storage format
   532  	if d, ok := core.readCache.Get(key); ok {
   533  		res := iotexapi.ReadContractResponse{}
   534  		if err := proto.Unmarshal(d, &res); err == nil {
   535  			return res.Data, res.Receipt, nil
   536  		}
   537  	}
   538  	ctx = genesis.WithGenesisContext(ctx, core.bc.Genesis())
   539  	state, err := accountutil.AccountState(ctx, core.sf, callerAddr)
   540  	if err != nil {
   541  		return "", nil, status.Error(codes.InvalidArgument, err.Error())
   542  	}
   543  	if ctx, err = core.bc.Context(ctx); err != nil {
   544  		return "", nil, err
   545  	}
   546  	ctx = protocol.WithFeatureCtx(protocol.WithBlockCtx(ctx, protocol.BlockCtx{
   547  		BlockHeight: core.bc.TipHeight(),
   548  	}))
   549  	var pendingNonce uint64
   550  	if protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion {
   551  		pendingNonce = state.PendingNonceConsideringFreshAccount()
   552  	} else {
   553  		pendingNonce = state.PendingNonce()
   554  	}
   555  	sc.SetNonce(pendingNonce)
   556  	var (
   557  		g             = core.bc.Genesis()
   558  		blockGasLimit = g.BlockGasLimitByHeight(core.bc.TipHeight())
   559  	)
   560  	if sc.GasLimit() == 0 || blockGasLimit < sc.GasLimit() {
   561  		sc.SetGasLimit(blockGasLimit)
   562  	}
   563  	sc.SetGasPrice(big.NewInt(0)) // ReadContract() is read-only, use 0 to prevent insufficient gas
   564  
   565  	retval, receipt, err := core.simulateExecution(ctx, callerAddr, sc, core.dao.GetBlockHash, core.getBlockTime)
   566  	if err != nil {
   567  		return "", nil, status.Error(codes.Internal, err.Error())
   568  	}
   569  	// ReadContract() is read-only, if no error returned, we consider it a success
   570  	receipt.Status = uint64(iotextypes.ReceiptStatus_Success)
   571  	res := iotexapi.ReadContractResponse{
   572  		Data:    hex.EncodeToString(retval),
   573  		Receipt: receipt.ConvertToReceiptPb(),
   574  	}
   575  	if d, err := proto.Marshal(&res); err == nil {
   576  		core.readCache.Put(key, d)
   577  	}
   578  	return res.Data, res.Receipt, nil
   579  }
   580  
   581  // ReadState reads state on blockchain
   582  func (core *coreService) ReadState(protocolID string, height string, methodName []byte, arguments [][]byte) (*iotexapi.ReadStateResponse, error) {
   583  	p, ok := core.registry.Find(protocolID)
   584  	if !ok {
   585  		return nil, status.Errorf(codes.Internal, "protocol %s isn't registered", protocolID)
   586  	}
   587  	data, readStateHeight, err := core.readState(context.Background(), p, height, methodName, arguments...)
   588  	if err != nil {
   589  		return nil, status.Error(codes.NotFound, err.Error())
   590  	}
   591  	blkHash, err := core.dao.GetBlockHash(readStateHeight)
   592  	if err != nil {
   593  		if errors.Cause(err) == db.ErrNotExist {
   594  			return nil, status.Error(codes.NotFound, err.Error())
   595  		}
   596  		return nil, status.Error(codes.Internal, err.Error())
   597  	}
   598  	return &iotexapi.ReadStateResponse{
   599  		Data: data,
   600  		BlockIdentifier: &iotextypes.BlockIdentifier{
   601  			Height: readStateHeight,
   602  			Hash:   hex.EncodeToString(blkHash[:]),
   603  		},
   604  	}, nil
   605  }
   606  
   607  // SuggestGasPrice suggests gas price
   608  func (core *coreService) SuggestGasPrice() (uint64, error) {
   609  	return core.gs.SuggestGasPrice()
   610  }
   611  
   612  // EstimateGasForAction estimates gas for action
   613  func (core *coreService) EstimateGasForAction(ctx context.Context, in *iotextypes.Action) (uint64, error) {
   614  	selp, err := (&action.Deserializer{}).SetEvmNetworkID(core.EVMNetworkID()).ActionToSealedEnvelope(in)
   615  	if err != nil {
   616  		return 0, status.Error(codes.Internal, err.Error())
   617  	}
   618  	sc, ok := selp.Action().(*action.Execution)
   619  	if !ok {
   620  		gas, err := selp.IntrinsicGas()
   621  		if err != nil {
   622  			return 0, status.Error(codes.Internal, err.Error())
   623  		}
   624  		return gas, nil
   625  	}
   626  	callerAddr := selp.SenderAddress()
   627  	if callerAddr == nil {
   628  		return 0, status.Error(codes.Internal, "failed to get address")
   629  	}
   630  	_, receipt, err := core.SimulateExecution(ctx, callerAddr, sc)
   631  	if err != nil {
   632  		return 0, status.Error(codes.Internal, err.Error())
   633  	}
   634  	return receipt.GasConsumed, nil
   635  }
   636  
   637  // EpochMeta gets epoch metadata
   638  func (core *coreService) EpochMeta(epochNum uint64) (*iotextypes.EpochData, uint64, []*iotexapi.BlockProducerInfo, error) {
   639  	rp := rolldpos.FindProtocol(core.registry)
   640  	if rp == nil {
   641  		return nil, 0, nil, nil
   642  	}
   643  	if epochNum < 1 {
   644  		return nil, 0, nil, status.Error(codes.InvalidArgument, "epoch number cannot be less than one")
   645  	}
   646  	epochHeight := rp.GetEpochHeight(epochNum)
   647  	gravityChainStartHeight, err := core.getGravityChainStartHeight(epochHeight)
   648  	if err != nil {
   649  		return nil, 0, nil, status.Error(codes.NotFound, err.Error())
   650  	}
   651  	epochData := &iotextypes.EpochData{
   652  		Num:                     epochNum,
   653  		Height:                  epochHeight,
   654  		GravityChainStartHeight: gravityChainStartHeight,
   655  	}
   656  
   657  	pp := poll.FindProtocol(core.registry)
   658  	if pp == nil {
   659  		return nil, 0, nil, status.Error(codes.Internal, "poll protocol is not registered")
   660  	}
   661  
   662  	methodName := []byte("ActiveBlockProducersByEpoch")
   663  	arguments := [][]byte{[]byte(strconv.FormatUint(epochNum, 10))}
   664  	height := strconv.FormatUint(epochHeight, 10)
   665  	data, _, err := core.readState(context.Background(), pp, height, methodName, arguments...)
   666  	if err != nil {
   667  		return nil, 0, nil, status.Error(codes.NotFound, err.Error())
   668  	}
   669  
   670  	var activeConsensusBlockProducers state.CandidateList
   671  	if err := activeConsensusBlockProducers.Deserialize(data); err != nil {
   672  		return nil, 0, nil, status.Error(codes.Internal, err.Error())
   673  	}
   674  
   675  	numBlks, produce, err := core.getProductivityByEpoch(rp, epochNum, core.bc.TipHeight(), activeConsensusBlockProducers)
   676  	if err != nil {
   677  		return nil, 0, nil, status.Error(codes.NotFound, err.Error())
   678  	}
   679  
   680  	methodName = []byte("BlockProducersByEpoch")
   681  	data, _, err = core.readState(context.Background(), pp, height, methodName, arguments...)
   682  	if err != nil {
   683  		return nil, 0, nil, status.Error(codes.NotFound, err.Error())
   684  	}
   685  
   686  	var BlockProducers state.CandidateList
   687  	if err := BlockProducers.Deserialize(data); err != nil {
   688  		return nil, 0, nil, status.Error(codes.Internal, err.Error())
   689  	}
   690  
   691  	var blockProducersInfo []*iotexapi.BlockProducerInfo
   692  	for _, bp := range BlockProducers {
   693  		var active bool
   694  		var blockProduction uint64
   695  		if production, ok := produce[bp.Address]; ok {
   696  			active = true
   697  			blockProduction = production
   698  		}
   699  		blockProducersInfo = append(blockProducersInfo, &iotexapi.BlockProducerInfo{
   700  			Address:    bp.Address,
   701  			Votes:      bp.Votes.String(),
   702  			Active:     active,
   703  			Production: blockProduction,
   704  		})
   705  	}
   706  	return epochData, numBlks, blockProducersInfo, nil
   707  }
   708  
   709  // RawBlocks gets raw block data
   710  func (core *coreService) RawBlocks(startHeight uint64, count uint64, withReceipts bool, withTransactionLogs bool) ([]*iotexapi.BlockInfo, error) {
   711  	if count == 0 || count > core.cfg.RangeQueryLimit {
   712  		return nil, status.Error(codes.InvalidArgument, "range exceeds the limit")
   713  	}
   714  
   715  	tipHeight := core.bc.TipHeight()
   716  	if startHeight > tipHeight {
   717  		return nil, status.Error(codes.InvalidArgument, "start height should not exceed tip height")
   718  	}
   719  	endHeight := startHeight + count - 1
   720  	if endHeight > tipHeight {
   721  		endHeight = tipHeight
   722  	}
   723  	var res []*iotexapi.BlockInfo
   724  	for height := startHeight; height <= endHeight; height++ {
   725  		blk, err := core.dao.GetBlockByHeight(height)
   726  		if err != nil {
   727  			return nil, status.Error(codes.NotFound, err.Error())
   728  		}
   729  		var receiptsPb []*iotextypes.Receipt
   730  		if withReceipts && height > 0 {
   731  			receipts, err := core.dao.GetReceipts(height)
   732  			if err != nil {
   733  				return nil, status.Error(codes.NotFound, err.Error())
   734  			}
   735  			for _, receipt := range receipts {
   736  				receiptsPb = append(receiptsPb, receipt.ConvertToReceiptPb())
   737  			}
   738  		}
   739  		var transactionLogs *iotextypes.TransactionLogs
   740  		if withTransactionLogs {
   741  			if transactionLogs, err = core.dao.TransactionLogs(height); err != nil {
   742  				return nil, status.Error(codes.NotFound, err.Error())
   743  			}
   744  		}
   745  		res = append(res, &iotexapi.BlockInfo{
   746  			Block:           blk.ConvertToBlockPb(),
   747  			Receipts:        receiptsPb,
   748  			TransactionLogs: transactionLogs,
   749  		})
   750  	}
   751  	return res, nil
   752  }
   753  
   754  // ChainListener returns the instance of Listener
   755  func (core *coreService) ChainListener() apitypes.Listener {
   756  	return core.chainListener
   757  }
   758  
   759  // ElectionBuckets returns the native election buckets.
   760  func (core *coreService) ElectionBuckets(epochNum uint64) ([]*iotextypes.ElectionBucket, error) {
   761  	if core.electionCommittee == nil {
   762  		return nil, status.Error(codes.Unavailable, "Native election no supported")
   763  	}
   764  	buckets, err := core.electionCommittee.NativeBucketsByEpoch(epochNum)
   765  	if err != nil {
   766  		return nil, status.Error(codes.Internal, err.Error())
   767  	}
   768  	re := make([]*iotextypes.ElectionBucket, len(buckets))
   769  	for i, b := range buckets {
   770  		startTime := timestamppb.New(b.StartTime())
   771  		re[i] = &iotextypes.ElectionBucket{
   772  			Voter:     b.Voter(),
   773  			Candidate: b.Candidate(),
   774  			Amount:    b.Amount().Bytes(),
   775  			StartTime: startTime,
   776  			Duration:  durationpb.New(b.Duration()),
   777  			Decay:     b.Decay(),
   778  		}
   779  	}
   780  	return re, nil
   781  }
   782  
   783  // ReceiptByActionHash returns receipt by action hash
   784  func (core *coreService) ReceiptByActionHash(h hash.Hash256) (*action.Receipt, error) {
   785  	if core.indexer == nil {
   786  		return nil, status.Error(codes.NotFound, blockindex.ErrActionIndexNA.Error())
   787  	}
   788  
   789  	actIndex, err := core.indexer.GetActionIndex(h[:])
   790  	if err != nil {
   791  		return nil, errors.Wrap(ErrNotFound, err.Error())
   792  	}
   793  
   794  	receipts, err := core.dao.GetReceipts(actIndex.BlockHeight())
   795  	if err != nil {
   796  		return nil, err
   797  	}
   798  	if receipt := filterReceipts(receipts, h); receipt != nil {
   799  		return receipt, nil
   800  	}
   801  	return nil, errors.Wrapf(ErrNotFound, "failed to find receipt for action %x", h)
   802  }
   803  
   804  // TransactionLogByActionHash returns transaction log by action hash
   805  func (core *coreService) TransactionLogByActionHash(actHash string) (*iotextypes.TransactionLog, error) {
   806  	if core.indexer == nil {
   807  		return nil, status.Error(codes.Unimplemented, blockindex.ErrActionIndexNA.Error())
   808  	}
   809  	if !core.dao.ContainsTransactionLog() {
   810  		return nil, status.Error(codes.Unimplemented, filedao.ErrNotSupported.Error())
   811  	}
   812  
   813  	h, err := hex.DecodeString(actHash)
   814  	if err != nil {
   815  		return nil, status.Error(codes.InvalidArgument, err.Error())
   816  	}
   817  
   818  	actIndex, err := core.indexer.GetActionIndex(h)
   819  	if err != nil {
   820  		if errors.Cause(err) == db.ErrNotExist {
   821  			return nil, status.Error(codes.NotFound, err.Error())
   822  		}
   823  		return nil, status.Error(codes.Internal, err.Error())
   824  	}
   825  
   826  	sysLog, err := core.dao.TransactionLogs(actIndex.BlockHeight())
   827  	if err != nil {
   828  		if errors.Cause(err) == db.ErrNotExist {
   829  			return nil, status.Error(codes.NotFound, err.Error())
   830  		}
   831  		return nil, status.Error(codes.Internal, err.Error())
   832  	}
   833  
   834  	for _, log := range sysLog.Logs {
   835  		if bytes.Equal(h, log.ActionHash) {
   836  			return log, nil
   837  		}
   838  	}
   839  	return nil, status.Errorf(codes.NotFound, "transaction log not found for action %s", actHash)
   840  }
   841  
   842  // TransactionLogByBlockHeight returns transaction log by block height
   843  func (core *coreService) TransactionLogByBlockHeight(blockHeight uint64) (*iotextypes.BlockIdentifier, *iotextypes.TransactionLogs, error) {
   844  	if !core.dao.ContainsTransactionLog() {
   845  		return nil, nil, status.Error(codes.Unimplemented, filedao.ErrNotSupported.Error())
   846  	}
   847  
   848  	tip, err := core.dao.Height()
   849  	if err != nil {
   850  		return nil, nil, status.Error(codes.Internal, err.Error())
   851  	}
   852  	if blockHeight < 1 || blockHeight > tip {
   853  		return nil, nil, status.Errorf(codes.InvalidArgument, "invalid block height = %d", blockHeight)
   854  	}
   855  
   856  	h, err := core.dao.GetBlockHash(blockHeight)
   857  	if err != nil {
   858  		if errors.Cause(err) == db.ErrNotExist {
   859  			return nil, nil, status.Error(codes.NotFound, err.Error())
   860  		}
   861  		return nil, nil, status.Error(codes.Internal, err.Error())
   862  	}
   863  
   864  	blockIdentifier := &iotextypes.BlockIdentifier{
   865  		Hash:   hex.EncodeToString(h[:]),
   866  		Height: blockHeight,
   867  	}
   868  	sysLog, err := core.dao.TransactionLogs(blockHeight)
   869  	if err != nil {
   870  		if errors.Cause(err) == db.ErrNotExist {
   871  			// should return empty, no transaction happened in block
   872  			return blockIdentifier, nil, nil
   873  		}
   874  		return nil, nil, status.Error(codes.Internal, err.Error())
   875  	}
   876  	return blockIdentifier, sysLog, nil
   877  }
   878  
   879  func (core *coreService) TipHeight() uint64 {
   880  	return core.bc.TipHeight()
   881  }
   882  
   883  // Start starts the API server
   884  func (core *coreService) Start(_ context.Context) error {
   885  	if err := core.chainListener.Start(); err != nil {
   886  		return errors.Wrap(err, "failed to start blockchain listener")
   887  	}
   888  	if core.messageBatcher != nil {
   889  		if err := core.messageBatcher.Start(); err != nil {
   890  			return errors.Wrap(err, "failed to start message batcher")
   891  		}
   892  	}
   893  	return nil
   894  }
   895  
   896  // Stop stops the API server
   897  func (core *coreService) Stop(_ context.Context) error {
   898  	if core.messageBatcher != nil {
   899  		if err := core.messageBatcher.Stop(); err != nil {
   900  			return errors.Wrap(err, "failed to stop message batcher")
   901  		}
   902  	}
   903  	return core.chainListener.Stop()
   904  }
   905  
   906  func (core *coreService) readState(ctx context.Context, p protocol.Protocol, height string, methodName []byte, arguments ...[]byte) ([]byte, uint64, error) {
   907  	key := ReadKey{
   908  		Name:   p.Name(),
   909  		Height: height,
   910  		Method: methodName,
   911  		Args:   arguments,
   912  	}
   913  	if d, ok := core.readCache.Get(key.Hash()); ok {
   914  		var h uint64
   915  		if height != "" {
   916  			h, _ = strconv.ParseUint(height, 0, 64)
   917  		}
   918  		return d, h, nil
   919  	}
   920  
   921  	// TODO: need to complete the context
   922  	tipHeight := core.bc.TipHeight()
   923  	ctx = protocol.WithBlockCtx(ctx, protocol.BlockCtx{
   924  		BlockHeight: tipHeight,
   925  	})
   926  	ctx = genesis.WithGenesisContext(
   927  		protocol.WithRegistry(ctx, core.registry),
   928  		core.bc.Genesis(),
   929  	)
   930  	ctx = protocol.WithFeatureCtx(protocol.WithFeatureWithHeightCtx(ctx))
   931  
   932  	rp := rolldpos.FindProtocol(core.registry)
   933  	if rp == nil {
   934  		return nil, uint64(0), errors.New("rolldpos is not registered")
   935  	}
   936  
   937  	tipEpochNum := rp.GetEpochNum(tipHeight)
   938  	if height != "" {
   939  		inputHeight, err := strconv.ParseUint(height, 0, 64)
   940  		if err != nil {
   941  			return nil, uint64(0), err
   942  		}
   943  		inputEpochNum := rp.GetEpochNum(inputHeight)
   944  		if inputEpochNum < tipEpochNum {
   945  			// old data, wrap to history state reader
   946  			d, h, err := p.ReadState(ctx, factory.NewHistoryStateReader(core.sf, rp.GetEpochHeight(inputEpochNum)), methodName, arguments...)
   947  			if err == nil {
   948  				core.readCache.Put(key.Hash(), d)
   949  			}
   950  			return d, h, err
   951  		}
   952  	}
   953  
   954  	// TODO: need to distinguish user error and system error
   955  	d, h, err := p.ReadState(ctx, core.sf, methodName, arguments...)
   956  	if err == nil {
   957  		core.readCache.Put(key.Hash(), d)
   958  	}
   959  	return d, h, err
   960  }
   961  
   962  func (core *coreService) getActionsFromIndex(totalActions, start, count uint64) ([]*iotexapi.ActionInfo, error) {
   963  	hashes, err := core.indexer.GetActionHashFromIndex(start, count)
   964  	if err != nil {
   965  		return nil, status.Error(codes.Unavailable, err.Error())
   966  	}
   967  	var actionInfo []*iotexapi.ActionInfo
   968  	for i := range hashes {
   969  		act, err := core.getAction(hash.BytesToHash256(hashes[i]), false)
   970  		if err != nil {
   971  			return nil, status.Error(codes.Unavailable, err.Error())
   972  		}
   973  		actionInfo = append(actionInfo, act)
   974  	}
   975  	return actionInfo, nil
   976  }
   977  
   978  // Actions returns actions within the range
   979  func (core *coreService) Actions(start uint64, count uint64) ([]*iotexapi.ActionInfo, error) {
   980  	if err := core.checkActionIndex(); err != nil {
   981  		return nil, err
   982  	}
   983  	if count == 0 {
   984  		return nil, status.Error(codes.InvalidArgument, "count must be greater than zero")
   985  	}
   986  	if count > core.cfg.RangeQueryLimit {
   987  		return nil, status.Error(codes.InvalidArgument, "range exceeds the limit")
   988  	}
   989  
   990  	totalActions, err := core.indexer.GetTotalActions()
   991  	if err != nil {
   992  		return nil, status.Error(codes.Internal, err.Error())
   993  	}
   994  	if start >= totalActions {
   995  		return nil, status.Error(codes.InvalidArgument, "start exceeds the total actions in the block")
   996  	}
   997  	if totalActions == uint64(0) || count == 0 {
   998  		return []*iotexapi.ActionInfo{}, nil
   999  	}
  1000  	if start+count > totalActions {
  1001  		count = totalActions - start
  1002  	}
  1003  	if core.indexer != nil {
  1004  		return core.getActionsFromIndex(totalActions, start, count)
  1005  	}
  1006  	// Finding actions in reverse order saves time for querying most recent actions
  1007  	reverseStart := totalActions - (start + count)
  1008  	if totalActions < start+count {
  1009  		reverseStart = uint64(0)
  1010  		count = totalActions - start
  1011  	}
  1012  
  1013  	var res []*iotexapi.ActionInfo
  1014  	var actsList [][]*iotexapi.ActionInfo
  1015  	var hit bool
  1016  	for height := core.bc.TipHeight(); height >= 1 && count > 0; height-- {
  1017  		blk, err := core.dao.GetBlockByHeight(height)
  1018  		if err != nil {
  1019  			return nil, status.Error(codes.NotFound, err.Error())
  1020  		}
  1021  		if !hit && reverseStart >= uint64(len(blk.Actions)) {
  1022  			reverseStart -= uint64(len(blk.Actions))
  1023  			continue
  1024  		}
  1025  		// now reverseStart < len(blk.Actions), we are going to fetch actions from this block
  1026  		hit = true
  1027  		acts := core.reverseActionsInBlock(blk, reverseStart, count)
  1028  		actsList = append(actsList, acts)
  1029  		count -= uint64(len(acts))
  1030  		reverseStart = 0
  1031  	}
  1032  	for i := len(actsList) - 1; i >= 0; i-- {
  1033  		res = append(res, actsList[i]...)
  1034  	}
  1035  	return res, nil
  1036  }
  1037  
  1038  // Action returns action by action hash
  1039  func (core *coreService) Action(actionHash string, checkPending bool) (*iotexapi.ActionInfo, error) {
  1040  	if err := core.checkActionIndex(); err != nil {
  1041  		return nil, err
  1042  	}
  1043  	actHash, err := hash.HexStringToHash256(actionHash)
  1044  	if err != nil {
  1045  		return nil, status.Error(codes.InvalidArgument, err.Error())
  1046  	}
  1047  	act, err := core.getAction(actHash, checkPending)
  1048  	if err != nil {
  1049  		return nil, status.Error(codes.Unavailable, err.Error())
  1050  	}
  1051  	return act, nil
  1052  }
  1053  
  1054  // ActionsByAddress returns all actions associated with an address
  1055  func (core *coreService) ActionsByAddress(addr address.Address, start uint64, count uint64) ([]*iotexapi.ActionInfo, error) {
  1056  	if err := core.checkActionIndex(); err != nil {
  1057  		return nil, err
  1058  	}
  1059  	if count == 0 {
  1060  		return nil, status.Error(codes.InvalidArgument, "count must be greater than zero")
  1061  	}
  1062  	if count > core.cfg.RangeQueryLimit {
  1063  		return nil, status.Error(codes.InvalidArgument, "range exceeds the limit")
  1064  	}
  1065  
  1066  	actions, err := core.indexer.GetActionsByAddress(hash.BytesToHash160(addr.Bytes()), start, count)
  1067  	if err != nil {
  1068  		if errors.Cause(err) == db.ErrBucketNotExist || errors.Cause(err) == db.ErrNotExist {
  1069  			// no actions associated with address, return nil
  1070  			return nil, nil
  1071  		}
  1072  		return nil, status.Error(codes.NotFound, err.Error())
  1073  	}
  1074  
  1075  	var res []*iotexapi.ActionInfo
  1076  	for i := range actions {
  1077  		act, err := core.getAction(hash.BytesToHash256(actions[i]), false)
  1078  		if err != nil {
  1079  			continue
  1080  		}
  1081  		res = append(res, act)
  1082  	}
  1083  	return res, nil
  1084  }
  1085  
  1086  // BlockHashByBlockHeight returns block hash by block height
  1087  func (core *coreService) BlockHashByBlockHeight(blkHeight uint64) (hash.Hash256, error) {
  1088  	return core.dao.GetBlockHash(blkHeight)
  1089  }
  1090  
  1091  // ActionByActionHash returns action by action hash
  1092  func (core *coreService) ActionByActionHash(h hash.Hash256) (*action.SealedEnvelope, *block.Block, uint32, error) {
  1093  	if err := core.checkActionIndex(); err != nil {
  1094  		return nil, nil, 0, status.Error(codes.NotFound, blockindex.ErrActionIndexNA.Error())
  1095  	}
  1096  
  1097  	actIndex, err := core.indexer.GetActionIndex(h[:])
  1098  	if err != nil {
  1099  		return nil, nil, 0, errors.Wrap(ErrNotFound, err.Error())
  1100  	}
  1101  	blk, err := core.dao.GetBlockByHeight(actIndex.BlockHeight())
  1102  	if err != nil {
  1103  		return nil, nil, 0, errors.Wrap(ErrNotFound, err.Error())
  1104  	}
  1105  	selp, index, err := blk.ActionByHash(h)
  1106  	if err != nil {
  1107  		return nil, nil, 0, errors.Wrap(ErrNotFound, err.Error())
  1108  	}
  1109  	return selp, blk, index, nil
  1110  }
  1111  
  1112  // ActionByActionHash returns action by action hash
  1113  func (core *coreService) PendingActionByActionHash(h hash.Hash256) (*action.SealedEnvelope, error) {
  1114  	selp, err := core.ap.GetActionByHash(h)
  1115  	if err != nil {
  1116  		return nil, errors.Wrap(ErrNotFound, err.Error())
  1117  	}
  1118  	return selp, nil
  1119  }
  1120  
  1121  // UnconfirmedActionsByAddress returns all unconfirmed actions in actpool associated with an address
  1122  func (core *coreService) UnconfirmedActionsByAddress(address string, start uint64, count uint64) ([]*iotexapi.ActionInfo, error) {
  1123  	if count == 0 {
  1124  		return nil, status.Error(codes.InvalidArgument, "count must be greater than zero")
  1125  	}
  1126  	if count > core.cfg.RangeQueryLimit {
  1127  		return nil, status.Error(codes.InvalidArgument, "range exceeds the limit")
  1128  	}
  1129  
  1130  	selps := core.ap.GetUnconfirmedActs(address)
  1131  	if len(selps) == 0 {
  1132  		return []*iotexapi.ActionInfo{}, nil
  1133  	}
  1134  	if start >= uint64(len(selps)) {
  1135  		return nil, status.Error(codes.InvalidArgument, "start exceeds the limit")
  1136  	}
  1137  
  1138  	var res []*iotexapi.ActionInfo
  1139  	for i := start; i < uint64(len(selps)) && i < start+count; i++ {
  1140  		if act, err := core.pendingAction(selps[i]); err == nil {
  1141  			res = append(res, act)
  1142  		}
  1143  	}
  1144  	return res, nil
  1145  }
  1146  
  1147  // BlockByHash returns the block and its receipt from block hash
  1148  func (core *coreService) BlockByHash(blkHash string) (*apitypes.BlockWithReceipts, error) {
  1149  	if err := core.checkActionIndex(); err != nil {
  1150  		return nil, err
  1151  	}
  1152  	hash, err := hash.HexStringToHash256(blkHash)
  1153  	if err != nil {
  1154  		return nil, err
  1155  	}
  1156  	blk, err := core.dao.GetBlock(hash)
  1157  	if err != nil {
  1158  		return nil, errors.Wrap(ErrNotFound, err.Error())
  1159  	}
  1160  	receipts, err := core.dao.GetReceipts(blk.Height())
  1161  	if err != nil {
  1162  		return nil, errors.Wrap(ErrNotFound, err.Error())
  1163  	}
  1164  	return &apitypes.BlockWithReceipts{
  1165  		Block:    blk,
  1166  		Receipts: receipts,
  1167  	}, nil
  1168  }
  1169  
  1170  // BlockByHeightRange returns blocks within the height range
  1171  func (core *coreService) BlockByHeightRange(start uint64, count uint64) ([]*apitypes.BlockWithReceipts, error) {
  1172  	if count == 0 {
  1173  		return nil, errors.Wrap(errInvalidFormat, "count must be greater than zero")
  1174  	}
  1175  	if count > core.cfg.RangeQueryLimit {
  1176  		return nil, errors.Wrap(errInvalidFormat, "range exceeds the limit")
  1177  	}
  1178  
  1179  	var (
  1180  		tipHeight = core.bc.TipHeight()
  1181  		res       = make([]*apitypes.BlockWithReceipts, 0)
  1182  	)
  1183  	if start > tipHeight {
  1184  		return nil, errors.Wrap(errInvalidFormat, "start height should not exceed tip height")
  1185  	}
  1186  	for height := start; height <= tipHeight && count > 0; height++ {
  1187  		blkStore, err := core.getBlockByHeight(height)
  1188  		if err != nil {
  1189  			return nil, err
  1190  		}
  1191  		res = append(res, blkStore)
  1192  		count--
  1193  	}
  1194  	return res, nil
  1195  }
  1196  
  1197  // BlockByHeight returns the block and its receipt from block height
  1198  func (core *coreService) BlockByHeight(height uint64) (*apitypes.BlockWithReceipts, error) {
  1199  	return core.getBlockByHeight(height)
  1200  }
  1201  
  1202  func (core *coreService) getBlockByHeight(height uint64) (*apitypes.BlockWithReceipts, error) {
  1203  	if height > core.bc.TipHeight() {
  1204  		return nil, ErrNotFound
  1205  	}
  1206  	blk, err := core.dao.GetBlockByHeight(height)
  1207  	if err != nil {
  1208  		return nil, errors.Wrap(ErrNotFound, err.Error())
  1209  	}
  1210  	receipts := []*action.Receipt{}
  1211  	if blk.Height() > 0 {
  1212  		var err error
  1213  		receipts, err = core.dao.GetReceipts(height)
  1214  		if err != nil {
  1215  			return nil, errors.Wrap(ErrNotFound, err.Error())
  1216  		}
  1217  	}
  1218  	return &apitypes.BlockWithReceipts{
  1219  		Block:    blk,
  1220  		Receipts: receipts,
  1221  	}, nil
  1222  }
  1223  
  1224  func (core *coreService) getGravityChainStartHeight(epochHeight uint64) (uint64, error) {
  1225  	gravityChainStartHeight := epochHeight
  1226  	if pp := poll.FindProtocol(core.registry); pp != nil {
  1227  		methodName := []byte("GetGravityChainStartHeight")
  1228  		arguments := [][]byte{[]byte(strconv.FormatUint(epochHeight, 10))}
  1229  		data, _, err := core.readState(context.Background(), pp, "", methodName, arguments...)
  1230  		if err != nil {
  1231  			return 0, err
  1232  		}
  1233  		if len(data) == 0 {
  1234  			return 0, nil
  1235  		}
  1236  		if gravityChainStartHeight, err = strconv.ParseUint(string(data), 10, 64); err != nil {
  1237  			return 0, err
  1238  		}
  1239  	}
  1240  	return gravityChainStartHeight, nil
  1241  }
  1242  
  1243  func (core *coreService) committedAction(selp *action.SealedEnvelope, blkHash hash.Hash256, blkHeight uint64) (*iotexapi.ActionInfo, error) {
  1244  	actHash, err := selp.Hash()
  1245  	if err != nil {
  1246  		return nil, err
  1247  	}
  1248  	header, err := core.dao.Header(blkHash)
  1249  	if err != nil {
  1250  		return nil, err
  1251  	}
  1252  	sender := selp.SenderAddress()
  1253  	receipts, err := core.dao.GetReceipts(blkHeight)
  1254  	if err != nil {
  1255  		return nil, err
  1256  	}
  1257  	receipt := filterReceipts(receipts, actHash)
  1258  	if receipt == nil {
  1259  		return nil, errors.Wrapf(ErrNotFound, "failed to find receipt for action %x", actHash)
  1260  	}
  1261  
  1262  	gas := new(big.Int)
  1263  	gas = gas.Mul(selp.GasPrice(), big.NewInt(int64(receipt.GasConsumed)))
  1264  	return &iotexapi.ActionInfo{
  1265  		Action:    selp.Proto(),
  1266  		ActHash:   hex.EncodeToString(actHash[:]),
  1267  		BlkHash:   hex.EncodeToString(blkHash[:]),
  1268  		BlkHeight: header.Height(),
  1269  		Sender:    sender.String(),
  1270  		GasFee:    gas.String(),
  1271  		Timestamp: header.BlockHeaderCoreProto().Timestamp,
  1272  	}, nil
  1273  }
  1274  
  1275  func (core *coreService) pendingAction(selp *action.SealedEnvelope) (*iotexapi.ActionInfo, error) {
  1276  	actHash, err := selp.Hash()
  1277  	if err != nil {
  1278  		return nil, err
  1279  	}
  1280  	sender := selp.SenderAddress()
  1281  	return &iotexapi.ActionInfo{
  1282  		Action:    selp.Proto(),
  1283  		ActHash:   hex.EncodeToString(actHash[:]),
  1284  		BlkHash:   hex.EncodeToString(hash.ZeroHash256[:]),
  1285  		BlkHeight: 0,
  1286  		Sender:    sender.String(),
  1287  		Timestamp: nil,
  1288  		Index:     0,
  1289  	}, nil
  1290  }
  1291  
  1292  func (core *coreService) getAction(actHash hash.Hash256, checkPending bool) (*iotexapi.ActionInfo, error) {
  1293  	selp, blk, actIndex, err := core.ActionByActionHash(actHash)
  1294  	if err == nil {
  1295  		act, err := core.committedAction(selp, blk.HashBlock(), blk.Height())
  1296  		if err != nil {
  1297  			return nil, err
  1298  		}
  1299  		act.Index = actIndex
  1300  		return act, nil
  1301  	}
  1302  	// Try to fetch pending action from actpool
  1303  	if checkPending {
  1304  		selp, err = core.ap.GetActionByHash(actHash)
  1305  	}
  1306  	if err != nil {
  1307  		return nil, err
  1308  	}
  1309  	return core.pendingAction(selp)
  1310  }
  1311  
  1312  func (core *coreService) reverseActionsInBlock(blk *block.Block, reverseStart, count uint64) []*iotexapi.ActionInfo {
  1313  	h := blk.HashBlock()
  1314  	blkHash := hex.EncodeToString(h[:])
  1315  	blkHeight := blk.Height()
  1316  
  1317  	size := uint64(len(blk.Actions))
  1318  	if reverseStart > size || count == 0 {
  1319  		return nil
  1320  	}
  1321  	// TODO (saito): fix overflow
  1322  	start := size - (reverseStart + count)
  1323  	if start < 0 {
  1324  		start = 0
  1325  	}
  1326  	end := size - 1 - reverseStart
  1327  	res := make([]*iotexapi.ActionInfo, 0, start-end+1)
  1328  	receipts, err := core.dao.GetReceipts(blkHeight)
  1329  	if err != nil {
  1330  		log.Logger("api").Debug("Skipping action due to failing to get receipt", zap.Error(err))
  1331  		return nil
  1332  	}
  1333  	receiptMap := make(map[hash.Hash256]*action.Receipt, len(receipts))
  1334  	for _, receipt := range receipts {
  1335  		receiptMap[receipt.ActionHash] = receipt
  1336  	}
  1337  	for idx := start; idx <= end; idx++ {
  1338  		selp := blk.Actions[idx]
  1339  		actHash, err := selp.Hash()
  1340  		if err != nil {
  1341  			log.Logger("api").Debug("Skipping action due to hash error", zap.Error(err))
  1342  			continue
  1343  		}
  1344  		receipt, ok := receiptMap[actHash]
  1345  		if !ok {
  1346  			log.Logger("api").With(zap.String("actionHash", hex.EncodeToString(actHash[:]))).Debug("Skipping action due to failing to get receipt")
  1347  			continue
  1348  		}
  1349  		gas := new(big.Int).Mul(selp.GasPrice(), big.NewInt(int64(receipt.GasConsumed)))
  1350  		sender := selp.SenderAddress()
  1351  		res = append(res, &iotexapi.ActionInfo{
  1352  			Action:    selp.Proto(),
  1353  			ActHash:   hex.EncodeToString(actHash[:]),
  1354  			BlkHash:   blkHash,
  1355  			Timestamp: blk.Header.BlockHeaderCoreProto().Timestamp,
  1356  			BlkHeight: blkHeight,
  1357  			Sender:    sender.String(),
  1358  			GasFee:    gas.String(),
  1359  			Index:     uint32(idx),
  1360  		})
  1361  	}
  1362  	return res
  1363  }
  1364  
  1365  func (core *coreService) LogsInBlockByHash(filter *logfilter.LogFilter, blockHash hash.Hash256) ([]*action.Log, error) {
  1366  	blkHeight, err := core.dao.GetBlockHeight(blockHash)
  1367  	if err != nil {
  1368  		return nil, status.Error(codes.InvalidArgument, "invalid block hash")
  1369  	}
  1370  	return core.logsInBlock(filter, blkHeight)
  1371  }
  1372  
  1373  func (core *coreService) logsInBlock(filter *logfilter.LogFilter, blockNumber uint64) ([]*action.Log, error) {
  1374  	logBloomFilter, err := core.bfIndexer.BlockFilterByHeight(blockNumber)
  1375  	if err != nil {
  1376  		return nil, err
  1377  	}
  1378  
  1379  	if !filter.ExistInBloomFilterv2(logBloomFilter) {
  1380  		return []*action.Log{}, nil
  1381  	}
  1382  
  1383  	receipts, err := core.dao.GetReceipts(blockNumber)
  1384  	if err != nil {
  1385  		return nil, err
  1386  	}
  1387  
  1388  	return filter.MatchLogs(receipts), nil
  1389  }
  1390  
  1391  // LogsInRange filter logs among [start, end] blocks
  1392  func (core *coreService) LogsInRange(filter *logfilter.LogFilter, start, end, paginationSize uint64) ([]*action.Log, []hash.Hash256, error) {
  1393  	start, end, err := core.correctQueryRange(start, end)
  1394  	if err != nil {
  1395  		return nil, nil, err
  1396  	}
  1397  	if paginationSize == 0 {
  1398  		paginationSize = 1000
  1399  	}
  1400  	if paginationSize > 5000 {
  1401  		paginationSize = 5000
  1402  	}
  1403  	// getLogs via range Blooom filter [start, end]
  1404  	blockNumbers, err := core.bfIndexer.FilterBlocksInRange(filter, start, end, paginationSize)
  1405  	if err != nil {
  1406  		return nil, nil, err
  1407  	}
  1408  	var (
  1409  		logs      = []*action.Log{}
  1410  		hashes    = []hash.Hash256{}
  1411  		logsInBlk = make([][]*action.Log, len(blockNumbers))
  1412  		HashInBlk = make([]hash.Hash256, len(blockNumbers))
  1413  		jobs      = make(chan jobDesc, len(blockNumbers))
  1414  		eg, ctx   = errgroup.WithContext(context.Background())
  1415  	)
  1416  	if len(blockNumbers) == 0 {
  1417  		return logs, hashes, nil
  1418  	}
  1419  
  1420  	for i, v := range blockNumbers {
  1421  		jobs <- jobDesc{i, v}
  1422  	}
  1423  	close(jobs)
  1424  	for w := 0; w < _workerNumbers; w++ {
  1425  		eg.Go(func() error {
  1426  			for {
  1427  				select {
  1428  				case <-ctx.Done():
  1429  					return ctx.Err()
  1430  				default:
  1431  					job, ok := <-jobs
  1432  					if !ok {
  1433  						return nil
  1434  					}
  1435  					logsInBlock, err := core.logsInBlock(filter, job.blkNum)
  1436  					if err != nil {
  1437  						return err
  1438  					}
  1439  					blkHash, err := core.dao.GetBlockHash(job.blkNum)
  1440  					if err != nil {
  1441  						return err
  1442  					}
  1443  					logsInBlk[job.idx] = logsInBlock
  1444  					HashInBlk[job.idx] = blkHash
  1445  				}
  1446  			}
  1447  		})
  1448  	}
  1449  	if err := eg.Wait(); err != nil {
  1450  		return nil, nil, err
  1451  	}
  1452  
  1453  	for i := 0; i < len(blockNumbers); i++ {
  1454  		for j := range logsInBlk[i] {
  1455  			logs = append(logs, logsInBlk[i][j])
  1456  			hashes = append(hashes, HashInBlk[i])
  1457  			if len(logs) >= int(paginationSize) {
  1458  				return logs, hashes, nil
  1459  			}
  1460  		}
  1461  	}
  1462  
  1463  	return logs, hashes, nil
  1464  }
  1465  
  1466  func (core *coreService) correctQueryRange(start, end uint64) (uint64, uint64, error) {
  1467  	if start == 0 {
  1468  		start = core.bc.TipHeight()
  1469  	}
  1470  	if end == 0 {
  1471  		end = core.bc.TipHeight()
  1472  	}
  1473  	if start > end {
  1474  		return 0, 0, errors.New("invalid start or end height")
  1475  	}
  1476  	if start > core.bc.TipHeight() {
  1477  		return 0, 0, errors.New("start block > tip height")
  1478  	}
  1479  	if end > core.bc.TipHeight() {
  1480  		end = core.bc.TipHeight()
  1481  	}
  1482  	return start, end, nil
  1483  }
  1484  
  1485  // EstimateGasForNonExecution estimates action gas except execution
  1486  func (core *coreService) EstimateGasForNonExecution(actType action.Action) (uint64, error) {
  1487  	act, ok := actType.(intrinsicGasCalculator)
  1488  	if !ok {
  1489  		return 0, errors.Errorf("invalid action type not supported")
  1490  	}
  1491  	return act.IntrinsicGas()
  1492  }
  1493  
  1494  // EstimateExecutionGasConsumption estimate gas consumption for execution action
  1495  func (core *coreService) EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address) (uint64, error) {
  1496  	ctx = genesis.WithGenesisContext(ctx, core.bc.Genesis())
  1497  	state, err := accountutil.AccountState(ctx, core.sf, callerAddr)
  1498  	if err != nil {
  1499  		return 0, status.Error(codes.InvalidArgument, err.Error())
  1500  	}
  1501  	ctx = protocol.WithFeatureCtx(protocol.WithBlockCtx(ctx, protocol.BlockCtx{
  1502  		BlockHeight: core.bc.TipHeight(),
  1503  	}))
  1504  	var pendingNonce uint64
  1505  	if protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion {
  1506  		pendingNonce = state.PendingNonceConsideringFreshAccount()
  1507  	} else {
  1508  		pendingNonce = state.PendingNonce()
  1509  	}
  1510  	sc.SetNonce(pendingNonce)
  1511  	//gasprice should be 0, otherwise it may cause the API to return an error, such as insufficient balance.
  1512  	sc.SetGasPrice(big.NewInt(0))
  1513  	var (
  1514  		g             = core.bc.Genesis()
  1515  		blockGasLimit = g.BlockGasLimitByHeight(core.bc.TipHeight())
  1516  	)
  1517  	sc.SetGasLimit(blockGasLimit)
  1518  	enough, receipt, err := core.isGasLimitEnough(ctx, callerAddr, sc)
  1519  	if err != nil {
  1520  		return 0, status.Error(codes.Internal, err.Error())
  1521  	}
  1522  	if !enough {
  1523  		if receipt.ExecutionRevertMsg() != "" {
  1524  			return 0, status.Errorf(codes.Internal, fmt.Sprintf("execution simulation is reverted due to the reason: %s", receipt.ExecutionRevertMsg()))
  1525  		}
  1526  		return 0, status.Error(codes.Internal, fmt.Sprintf("execution simulation failed: status = %d", receipt.Status))
  1527  	}
  1528  	estimatedGas := receipt.GasConsumed
  1529  	sc.SetGasLimit(estimatedGas)
  1530  	enough, _, err = core.isGasLimitEnough(ctx, callerAddr, sc)
  1531  	if err != nil && err != action.ErrInsufficientFunds {
  1532  		return 0, status.Error(codes.Internal, err.Error())
  1533  	}
  1534  	if !enough {
  1535  		low, high := estimatedGas, blockGasLimit
  1536  		estimatedGas = high
  1537  		for low <= high {
  1538  			mid := (low + high) / 2
  1539  			sc.SetGasLimit(mid)
  1540  			enough, _, err = core.isGasLimitEnough(ctx, callerAddr, sc)
  1541  			if err != nil && err != action.ErrInsufficientFunds {
  1542  				return 0, status.Error(codes.Internal, err.Error())
  1543  			}
  1544  			if enough {
  1545  				estimatedGas = mid
  1546  				high = mid - 1
  1547  			} else {
  1548  				low = mid + 1
  1549  			}
  1550  		}
  1551  	}
  1552  
  1553  	return estimatedGas, nil
  1554  }
  1555  
  1556  func (core *coreService) isGasLimitEnough(
  1557  	ctx context.Context,
  1558  	caller address.Address,
  1559  	sc *action.Execution,
  1560  ) (bool, *action.Receipt, error) {
  1561  	ctx, span := tracer.NewSpan(ctx, "Server.isGasLimitEnough")
  1562  	defer span.End()
  1563  	ctx, err := core.bc.Context(ctx)
  1564  	if err != nil {
  1565  		return false, nil, err
  1566  	}
  1567  
  1568  	_, receipt, err := core.simulateExecution(ctx, caller, sc, core.dao.GetBlockHash, core.getBlockTime)
  1569  	if err != nil {
  1570  		return false, nil, err
  1571  	}
  1572  	return receipt.Status == uint64(iotextypes.ReceiptStatus_Success), receipt, nil
  1573  }
  1574  
  1575  func (core *coreService) getProductivityByEpoch(
  1576  	rp *rolldpos.Protocol,
  1577  	epochNum uint64,
  1578  	tipHeight uint64,
  1579  	abps state.CandidateList,
  1580  ) (uint64, map[string]uint64, error) {
  1581  	num, produce, err := rp.ProductivityByEpoch(epochNum, tipHeight, func(start uint64, end uint64) (map[string]uint64, error) {
  1582  		return blockchain.Productivity(core.bc, start, end)
  1583  	})
  1584  	if err != nil {
  1585  		return 0, nil, status.Error(codes.NotFound, err.Error())
  1586  	}
  1587  	// check if there is any active block producer who didn't prodcue any block
  1588  	for _, abp := range abps {
  1589  		if _, ok := produce[abp.Address]; !ok {
  1590  			produce[abp.Address] = 0
  1591  		}
  1592  	}
  1593  	return num, produce, nil
  1594  }
  1595  
  1596  func (core *coreService) checkActionIndex() error {
  1597  	if core.indexer == nil {
  1598  		return errors.New("no action index")
  1599  	}
  1600  	return nil
  1601  }
  1602  
  1603  func (core *coreService) getProtocolAccount(ctx context.Context, addr string) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error) {
  1604  	span := tracer.SpanFromContext(ctx)
  1605  	defer span.End()
  1606  	var (
  1607  		balance string
  1608  		out     *iotexapi.ReadStateResponse
  1609  		err     error
  1610  	)
  1611  	switch addr {
  1612  	case address.RewardingPoolAddr:
  1613  		if out, err = core.ReadState("rewarding", "", []byte("TotalBalance"), nil); err != nil {
  1614  			return nil, nil, err
  1615  		}
  1616  		val, ok := new(big.Int).SetString(string(out.GetData()), 10)
  1617  		if !ok {
  1618  			return nil, nil, errors.New("balance convert error")
  1619  		}
  1620  		balance = val.String()
  1621  	case address.StakingBucketPoolAddr:
  1622  		methodName, err := proto.Marshal(&iotexapi.ReadStakingDataMethod{
  1623  			Method: iotexapi.ReadStakingDataMethod_TOTAL_STAKING_AMOUNT,
  1624  		})
  1625  		if err != nil {
  1626  			return nil, nil, err
  1627  		}
  1628  		arg, err := proto.Marshal(&iotexapi.ReadStakingDataRequest{
  1629  			Request: &iotexapi.ReadStakingDataRequest_TotalStakingAmount_{
  1630  				TotalStakingAmount: &iotexapi.ReadStakingDataRequest_TotalStakingAmount{},
  1631  			},
  1632  		})
  1633  		if err != nil {
  1634  			return nil, nil, err
  1635  		}
  1636  		if out, err = core.ReadState("staking", "", methodName, [][]byte{arg}); err != nil {
  1637  			return nil, nil, err
  1638  		}
  1639  		acc := iotextypes.AccountMeta{}
  1640  		if err := proto.Unmarshal(out.GetData(), &acc); err != nil {
  1641  			return nil, nil, errors.Wrap(err, "failed to unmarshal account meta")
  1642  		}
  1643  		balance = acc.GetBalance()
  1644  	default:
  1645  		return nil, nil, errors.Errorf("invalid address %s", addr)
  1646  	}
  1647  	return &iotextypes.AccountMeta{
  1648  		Address: addr,
  1649  		Balance: balance,
  1650  	}, out.GetBlockIdentifier(), nil
  1651  }
  1652  
  1653  // ActionsInActPool returns the all Transaction Identifiers in the actpool
  1654  func (core *coreService) ActionsInActPool(actHashes []string) ([]*action.SealedEnvelope, error) {
  1655  	var ret []*action.SealedEnvelope
  1656  	if len(actHashes) == 0 {
  1657  		for _, sealeds := range core.ap.PendingActionMap() {
  1658  			ret = append(ret, sealeds...)
  1659  		}
  1660  		return ret, nil
  1661  	}
  1662  
  1663  	for _, hashStr := range actHashes {
  1664  		hs, err := hash.HexStringToHash256(hashStr)
  1665  		if err != nil {
  1666  			return nil, err
  1667  		}
  1668  		sealed, err := core.ap.GetActionByHash(hs)
  1669  		if err != nil {
  1670  			return nil, err
  1671  		}
  1672  		ret = append(ret, sealed)
  1673  	}
  1674  	return ret, nil
  1675  }
  1676  
  1677  // Genesis returns the genesis of the chain
  1678  func (core *coreService) Genesis() genesis.Genesis {
  1679  	return core.bc.Genesis()
  1680  }
  1681  
  1682  // EVMNetworkID returns the network id of evm
  1683  func (core *coreService) EVMNetworkID() uint32 {
  1684  	return core.bc.EvmNetworkID()
  1685  }
  1686  
  1687  // ChainID returns the chain id of evm
  1688  func (core *coreService) ChainID() uint32 {
  1689  	return core.bc.ChainID()
  1690  }
  1691  
  1692  // ReadContractStorage reads contract's storage
  1693  func (core *coreService) ReadContractStorage(ctx context.Context, addr address.Address, key []byte) ([]byte, error) {
  1694  	ctx, err := core.bc.Context(ctx)
  1695  	if err != nil {
  1696  		return nil, status.Error(codes.Internal, err.Error())
  1697  	}
  1698  	return core.sf.ReadContractStorage(ctx, addr, key)
  1699  }
  1700  
  1701  func (core *coreService) ReceiveBlock(blk *block.Block) error {
  1702  	core.readCache.Clear()
  1703  	return core.chainListener.ReceiveBlock(blk)
  1704  }
  1705  
  1706  func (core *coreService) SimulateExecution(ctx context.Context, addr address.Address, exec *action.Execution) ([]byte, *action.Receipt, error) {
  1707  	ctx = genesis.WithGenesisContext(ctx, core.bc.Genesis())
  1708  	state, err := accountutil.AccountState(ctx, core.sf, addr)
  1709  	if err != nil {
  1710  		return nil, nil, err
  1711  	}
  1712  	ctx, err = core.bc.Context(ctx)
  1713  	if err != nil {
  1714  		return nil, nil, err
  1715  	}
  1716  	// TODO (liuhaai): Use original nonce and gas limit properly
  1717  	ctx = protocol.WithFeatureCtx(protocol.WithBlockCtx(ctx, protocol.BlockCtx{
  1718  		BlockHeight: core.bc.TipHeight(),
  1719  	}))
  1720  	var pendingNonce uint64
  1721  	if protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion {
  1722  		pendingNonce = state.PendingNonceConsideringFreshAccount()
  1723  	} else {
  1724  		pendingNonce = state.PendingNonce()
  1725  	}
  1726  	exec.SetNonce(pendingNonce)
  1727  	var (
  1728  		g             = core.bc.Genesis()
  1729  		blockGasLimit = g.BlockGasLimitByHeight(core.bc.TipHeight())
  1730  	)
  1731  	exec.SetGasLimit(blockGasLimit)
  1732  	return core.simulateExecution(ctx, addr, exec, core.dao.GetBlockHash, core.getBlockTime)
  1733  }
  1734  
  1735  // SyncingProgress returns the syncing status of node
  1736  func (core *coreService) SyncingProgress() (uint64, uint64, uint64) {
  1737  	startingHeight, currentHeight, targetHeight, _ := core.bs.SyncStatus()
  1738  	return startingHeight, currentHeight, targetHeight
  1739  }
  1740  
  1741  // TraceTransaction returns the trace result of transaction
  1742  func (core *coreService) TraceTransaction(ctx context.Context, actHash string, config *tracers.TraceConfig) ([]byte, *action.Receipt, any, error) {
  1743  	actInfo, err := core.Action(util.Remove0xPrefix(actHash), false)
  1744  	if err != nil {
  1745  		return nil, nil, nil, err
  1746  	}
  1747  	act, err := (&action.Deserializer{}).SetEvmNetworkID(core.EVMNetworkID()).ActionToSealedEnvelope(actInfo.Action)
  1748  	if err != nil {
  1749  		return nil, nil, nil, err
  1750  	}
  1751  	sc, ok := act.Action().(*action.Execution)
  1752  	if !ok {
  1753  		return nil, nil, nil, errors.New("the type of action is not supported")
  1754  	}
  1755  	addr, _ := address.FromString(address.ZeroAddress)
  1756  	retval, receipt, tracer, err := core.traceTx(ctx, new(tracers.Context), config, func(ctx context.Context) ([]byte, *action.Receipt, error) {
  1757  
  1758  		return core.simulateExecution(ctx, addr, sc, core.dao.GetBlockHash, core.getBlockTime)
  1759  	})
  1760  	return retval, receipt, tracer, err
  1761  }
  1762  
  1763  // TraceCall returns the trace result of call
  1764  func (core *coreService) TraceCall(ctx context.Context,
  1765  	callerAddr address.Address,
  1766  	blkNumOrHash any,
  1767  	contractAddress string,
  1768  	nonce uint64,
  1769  	amount *big.Int,
  1770  	gasLimit uint64,
  1771  	data []byte,
  1772  	config *tracers.TraceConfig) ([]byte, *action.Receipt, any, error) {
  1773  	var (
  1774  		g             = core.bc.Genesis()
  1775  		blockGasLimit = g.BlockGasLimitByHeight(core.bc.TipHeight())
  1776  	)
  1777  	if gasLimit == 0 {
  1778  		gasLimit = blockGasLimit
  1779  	}
  1780  	ctx, err := core.bc.Context(ctx)
  1781  	if err != nil {
  1782  		return nil, nil, nil, err
  1783  	}
  1784  	if nonce == 0 {
  1785  		state, err := accountutil.AccountState(ctx, core.sf, callerAddr)
  1786  		if err != nil {
  1787  			return nil, nil, nil, err
  1788  		}
  1789  		ctx = protocol.WithFeatureCtx(protocol.WithBlockCtx(ctx, protocol.BlockCtx{
  1790  			BlockHeight: core.bc.TipHeight(),
  1791  		}))
  1792  		var pendingNonce uint64
  1793  		if protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion {
  1794  			pendingNonce = state.PendingNonceConsideringFreshAccount()
  1795  		} else {
  1796  			pendingNonce = state.PendingNonce()
  1797  		}
  1798  		nonce = pendingNonce
  1799  	}
  1800  	exec, err := action.NewExecution(
  1801  		contractAddress,
  1802  		nonce,
  1803  		amount,
  1804  		gasLimit,
  1805  		big.NewInt(0),
  1806  		data,
  1807  	)
  1808  	if err != nil {
  1809  		return nil, nil, nil, err
  1810  	}
  1811  	retval, receipt, tracer, err := core.traceTx(ctx, new(tracers.Context), config, func(ctx context.Context) ([]byte, *action.Receipt, error) {
  1812  		return core.simulateExecution(ctx, callerAddr, exec, core.dao.GetBlockHash, core.getBlockTime)
  1813  	})
  1814  	return retval, receipt, tracer, err
  1815  }
  1816  
  1817  // Track tracks the api call
  1818  func (core *coreService) Track(ctx context.Context, start time.Time, method string, size int64, success bool) {
  1819  	if core.apiStats == nil {
  1820  		return
  1821  	}
  1822  	elapsed := time.Since(start)
  1823  	core.apiStats.ReportCall(nodestats.APIReport{
  1824  		Method:       method,
  1825  		HandlingTime: elapsed,
  1826  		Success:      success,
  1827  	}, size)
  1828  }
  1829  
  1830  func (core *coreService) traceTx(ctx context.Context, txctx *tracers.Context, config *tracers.TraceConfig, simulateFn func(ctx context.Context) ([]byte, *action.Receipt, error)) ([]byte, *action.Receipt, any, error) {
  1831  	var (
  1832  		tracer vm.EVMLogger
  1833  		err    error
  1834  	)
  1835  	switch {
  1836  	case config == nil:
  1837  		tracer = logger.NewStructLogger(nil)
  1838  	case config.Tracer != nil:
  1839  		// Define a meaningful timeout of a single transaction trace
  1840  		timeout := defaultTraceTimeout
  1841  		if config.Timeout != nil {
  1842  			if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
  1843  				return nil, nil, nil, err
  1844  			}
  1845  		}
  1846  		t, err := tracers.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
  1847  		if err != nil {
  1848  			return nil, nil, nil, err
  1849  		}
  1850  		deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
  1851  		defer cancel()
  1852  		go func() {
  1853  			<-deadlineCtx.Done()
  1854  			if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
  1855  				t.Stop(errors.New("execution timeout"))
  1856  			}
  1857  		}()
  1858  		tracer = t
  1859  
  1860  	default:
  1861  		tracer = logger.NewStructLogger(config.Config)
  1862  	}
  1863  	ctx = protocol.WithVMConfigCtx(ctx, vm.Config{
  1864  		Debug:     true,
  1865  		Tracer:    tracer,
  1866  		NoBaseFee: true,
  1867  	})
  1868  	ctx = protocol.WithBlockCtx(ctx, protocol.BlockCtx{})
  1869  	ctx = genesis.WithGenesisContext(ctx, core.bc.Genesis())
  1870  	ctx = protocol.WithBlockchainCtx(protocol.WithFeatureCtx(ctx), protocol.BlockchainCtx{})
  1871  	retval, receipt, err := simulateFn(ctx)
  1872  	return retval, receipt, tracer, err
  1873  }
  1874  
  1875  func (core *coreService) simulateExecution(ctx context.Context, addr address.Address, exec *action.Execution, getBlockHash evm.GetBlockHash, getBlockTime evm.GetBlockTime) ([]byte, *action.Receipt, error) {
  1876  	ctx = evm.WithHelperCtx(ctx, evm.HelperContext{
  1877  		GetBlockHash:   getBlockHash,
  1878  		GetBlockTime:   getBlockTime,
  1879  		DepositGasFunc: rewarding.DepositGasWithSGD,
  1880  		Sgd:            core.sgdIndexer,
  1881  	})
  1882  	return core.sf.SimulateExecution(ctx, addr, exec)
  1883  }
  1884  
  1885  func filterReceipts(receipts []*action.Receipt, actHash hash.Hash256) *action.Receipt {
  1886  	for _, r := range receipts {
  1887  		if r.ActionHash == actHash {
  1888  			return r
  1889  		}
  1890  	}
  1891  	return nil
  1892  }