github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/ethapi_backend.go (about)

     1  package gossip
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/big"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/pkg/errors"
    13  	"github.com/unicornultrafoundation/go-helios/hash"
    14  	"github.com/unicornultrafoundation/go-helios/native/idx"
    15  
    16  	"github.com/unicornultrafoundation/go-u2u/accounts"
    17  	"github.com/unicornultrafoundation/go-u2u/common"
    18  	"github.com/unicornultrafoundation/go-u2u/core/state"
    19  	"github.com/unicornultrafoundation/go-u2u/core/types"
    20  	"github.com/unicornultrafoundation/go-u2u/core/vm"
    21  	"github.com/unicornultrafoundation/go-u2u/ethapi"
    22  	"github.com/unicornultrafoundation/go-u2u/ethdb"
    23  	notify "github.com/unicornultrafoundation/go-u2u/event"
    24  	"github.com/unicornultrafoundation/go-u2u/evmcore"
    25  	"github.com/unicornultrafoundation/go-u2u/evmcore/txtracer"
    26  	"github.com/unicornultrafoundation/go-u2u/gossip/evmstore"
    27  	"github.com/unicornultrafoundation/go-u2u/native"
    28  	"github.com/unicornultrafoundation/go-u2u/native/iblockproc"
    29  	"github.com/unicornultrafoundation/go-u2u/params"
    30  	"github.com/unicornultrafoundation/go-u2u/rpc"
    31  	"github.com/unicornultrafoundation/go-u2u/topicsdb"
    32  	"github.com/unicornultrafoundation/go-u2u/tracing"
    33  	"github.com/unicornultrafoundation/go-u2u/u2u"
    34  )
    35  
    36  // EthAPIBackend implements ethapi.Backend.
    37  type EthAPIBackend struct {
    38  	extRPCEnabled       bool
    39  	svc                 *Service
    40  	state               *EvmStateReader
    41  	signer              types.Signer
    42  	allowUnprotectedTxs bool
    43  }
    44  
    45  // SetExtRPCEnabled updates extRPCEnabled
    46  func (b *EthAPIBackend) SetExtRPCEnabled(v bool) {
    47  	b.extRPCEnabled = v
    48  }
    49  
    50  // ChainConfig returns the active chain configuration.
    51  func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
    52  	return b.svc.store.GetEvmChainConfig()
    53  }
    54  
    55  func (b *EthAPIBackend) CurrentBlock() *evmcore.EvmBlock {
    56  	return b.state.CurrentBlock()
    57  }
    58  
    59  func (b *EthAPIBackend) ResolveRpcBlockNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (idx.Block, error) {
    60  	latest := b.svc.store.GetLatestBlockIndex()
    61  	if number, ok := blockNrOrHash.Number(); ok && (number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber) {
    62  		return latest, nil
    63  	} else if number, ok := blockNrOrHash.Number(); ok {
    64  		if idx.Block(number) > latest {
    65  			return 0, errors.New("block not found")
    66  		}
    67  		return idx.Block(number), nil
    68  	} else if h, ok := blockNrOrHash.Hash(); ok {
    69  		index := b.svc.store.GetBlockIndex(hash.Event(h))
    70  		if index == nil {
    71  			return 0, errors.New("block not found")
    72  		}
    73  		return *index, nil
    74  	}
    75  	return 0, errors.New("unknown header selector")
    76  }
    77  
    78  // HeaderByNumber returns evm block header by its number, or nil if not exists.
    79  func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*evmcore.EvmHeader, error) {
    80  	blk, err := b.BlockByNumber(ctx, number)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	if blk == nil {
    85  		return nil, nil
    86  	}
    87  	return blk.Header(), err
    88  }
    89  
    90  // HeaderByHash returns evm block header by its (atropos) hash, or nil if not exists.
    91  func (b *EthAPIBackend) HeaderByHash(ctx context.Context, h common.Hash) (*evmcore.EvmHeader, error) {
    92  	index := b.svc.store.GetBlockIndex(hash.Event(h))
    93  	if index == nil {
    94  		return nil, nil
    95  	}
    96  	return b.HeaderByNumber(ctx, rpc.BlockNumber(*index))
    97  }
    98  
    99  // TxTraceByHash returns transaction trace from store db by the hash.
   100  func (b *EthAPIBackend) TxTraceByHash(ctx context.Context, h common.Hash) (*[]txtracer.ActionTrace, error) {
   101  	if b.state.store.txtracer == nil {
   102  		return nil, errors.New("Transaction trace key-value store db is not initialized")
   103  	}
   104  	txBytes := b.state.store.txtracer.GetTx(h)
   105  	traces := make([]txtracer.ActionTrace, 0)
   106  	json.Unmarshal(txBytes, &traces)
   107  	if len(traces) == 0 {
   108  		return nil, fmt.Errorf("No trace for tx hash: %s", h.String())
   109  	}
   110  	return &traces, nil
   111  }
   112  
   113  // TxTraceSave saves transaction trace into store db
   114  func (b *EthAPIBackend) TxTraceSave(ctx context.Context, h common.Hash, traces []byte) error {
   115  	if b.state.store.txtracer != nil {
   116  		return b.state.store.txtracer.SetTxTrace(h, traces)
   117  	}
   118  	return errors.New("Transaction trace key-value store db is not initialized")
   119  }
   120  
   121  // BlockByNumber returns evm block by its number, or nil if not exists.
   122  func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*evmcore.EvmBlock, error) {
   123  	if number == rpc.PendingBlockNumber {
   124  		number = rpc.LatestBlockNumber
   125  	}
   126  	// Otherwise, resolve and return the block
   127  	var blk *evmcore.EvmBlock
   128  	if number == rpc.LatestBlockNumber {
   129  		blk = b.state.CurrentBlock()
   130  	} else {
   131  		n := uint64(number.Int64())
   132  		blk = b.state.GetBlock(common.Hash{}, n)
   133  	}
   134  
   135  	return blk, nil
   136  }
   137  
   138  // StateAndHeaderByNumberOrHash returns evm state and block header by block number or block hash, err if not exists.
   139  func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *evmcore.EvmHeader, error) {
   140  	var header *evmcore.EvmHeader
   141  	if number, ok := blockNrOrHash.Number(); ok && (number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber) {
   142  		header = &b.state.CurrentBlock().EvmHeader
   143  	} else if number, ok := blockNrOrHash.Number(); ok {
   144  		header = b.state.GetHeader(common.Hash{}, uint64(number))
   145  	} else if h, ok := blockNrOrHash.Hash(); ok {
   146  		index := b.svc.store.GetBlockIndex(hash.Event(h))
   147  		if index == nil {
   148  			return nil, nil, errors.New("header not found")
   149  		}
   150  		header = b.state.GetHeader(common.Hash{}, uint64(*index))
   151  	} else {
   152  		return nil, nil, errors.New("unknown header selector")
   153  	}
   154  	if header == nil {
   155  		return nil, nil, errors.New("header not found")
   156  	}
   157  	stateDb, err := b.svc.store.evm.StateDB(hash.Hash(header.Root))
   158  	if err != nil {
   159  		return nil, nil, err
   160  	}
   161  	return stateDb, header, nil
   162  }
   163  
   164  // decodeShortEventID decodes ShortID
   165  // example of a ShortID: "5:26:a2395846", where 5 is epoch, 26 is lamport, a2395846 are first bytes of the hash
   166  // s is a string splitted by ":" separator
   167  func decodeShortEventID(s []string) (idx.Epoch, idx.Lamport, []byte, error) {
   168  	if len(s) != 3 {
   169  		return 0, 0, nil, errors.New("incorrect format of short event ID (need Epoch:Lamport:Hash")
   170  	}
   171  	epoch, err := strconv.ParseUint(s[0], 10, 32)
   172  	if err != nil {
   173  		return 0, 0, nil, errors.Wrap(err, "short hash parsing error (lamport)")
   174  	}
   175  	lamport, err := strconv.ParseUint(s[1], 10, 32)
   176  	if err != nil {
   177  		return 0, 0, nil, errors.Wrap(err, "short hash parsing error (lamport)")
   178  	}
   179  	return idx.Epoch(epoch), idx.Lamport(lamport), common.FromHex(s[2]), nil
   180  }
   181  
   182  // GetFullEventID "converts" ShortID to full event's hash, by searching in events DB.
   183  func (b *EthAPIBackend) GetFullEventID(shortEventID string) (hash.Event, error) {
   184  	s := strings.Split(shortEventID, ":")
   185  	if len(s) == 1 {
   186  		// it's a full hash
   187  		return hash.HexToEventHash(shortEventID), nil
   188  	}
   189  	// short hash
   190  	epoch, lamport, prefix, err := decodeShortEventID(s)
   191  	if err != nil {
   192  		return hash.Event{}, err
   193  	}
   194  
   195  	options := b.svc.store.FindEventHashes(epoch, lamport, prefix)
   196  	if len(options) == 0 {
   197  		return hash.Event{}, errors.New("event not found by short ID")
   198  	}
   199  	if len(options) > 1 {
   200  		return hash.Event{}, errors.New("there're multiple events with the same short ID, please use full ID")
   201  	}
   202  	return options[0], nil
   203  }
   204  
   205  // GetEventPayload returns Hashgraph event by hash or short ID.
   206  func (b *EthAPIBackend) GetEventPayload(ctx context.Context, shortEventID string) (*native.EventPayload, error) {
   207  	id, err := b.GetFullEventID(shortEventID)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	return b.svc.store.GetEventPayload(id), nil
   212  }
   213  
   214  // GetEvent returns the Hashgraph event header by hash or short ID.
   215  func (b *EthAPIBackend) GetEvent(ctx context.Context, shortEventID string) (*native.Event, error) {
   216  	id, err := b.GetFullEventID(shortEventID)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	return b.svc.store.GetEvent(id), nil
   221  }
   222  
   223  // GetHeads returns IDs of all the epoch events with no descendants.
   224  // * When epoch is -2 the heads for latest epoch are returned.
   225  // * When epoch is -1 the heads for latest sealed epoch are returned.
   226  func (b *EthAPIBackend) GetHeads(ctx context.Context, epoch rpc.BlockNumber) (heads hash.Events, err error) {
   227  	current := b.svc.store.GetEpoch()
   228  
   229  	requested, err := b.epochWithDefault(ctx, epoch)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	if requested == current {
   235  		heads = b.svc.store.GetHeadsSlice(requested)
   236  	} else {
   237  		err = errors.New("heads for previous epochs are not available")
   238  		return
   239  	}
   240  
   241  	if heads == nil {
   242  		heads = hash.Events{}
   243  	}
   244  
   245  	return
   246  }
   247  
   248  func (b *EthAPIBackend) epochWithDefault(ctx context.Context, epoch rpc.BlockNumber) (requested idx.Epoch, err error) {
   249  	current := b.svc.store.GetEpoch()
   250  
   251  	switch {
   252  	case epoch == rpc.PendingBlockNumber:
   253  		requested = current
   254  	case epoch == rpc.LatestBlockNumber:
   255  		requested = current - 1
   256  	case epoch >= 0 && idx.Epoch(epoch) <= current:
   257  		requested = idx.Epoch(epoch)
   258  	default:
   259  		err = errors.New("epoch is not in range")
   260  		return
   261  	}
   262  	return requested, nil
   263  }
   264  
   265  // ForEachEpochEvent iterates all the events which are observed by head, and accepted by a filter.
   266  // filter CANNOT called twice for the same event.
   267  func (b *EthAPIBackend) ForEachEpochEvent(ctx context.Context, epoch rpc.BlockNumber, onEvent func(event *native.EventPayload) bool) error {
   268  	requested, err := b.epochWithDefault(ctx, epoch)
   269  	if err != nil {
   270  		return err
   271  	}
   272  
   273  	b.svc.store.ForEachEpochEvent(requested, onEvent)
   274  	return nil
   275  }
   276  
   277  func (b *EthAPIBackend) BlockByHash(ctx context.Context, h common.Hash) (*evmcore.EvmBlock, error) {
   278  	index := b.svc.store.GetBlockIndex(hash.Event(h))
   279  	if index == nil {
   280  		return nil, nil
   281  	}
   282  
   283  	if rpc.BlockNumber(*index) == rpc.PendingBlockNumber {
   284  		return nil, errors.New("pending block request isn't allowed")
   285  	}
   286  	// Otherwise resolve and return the block
   287  	var blk *evmcore.EvmBlock
   288  	if rpc.BlockNumber(*index) == rpc.LatestBlockNumber {
   289  		blk = b.state.CurrentBlock()
   290  	} else {
   291  		n := uint64(*index)
   292  		blk = b.state.GetBlock(common.Hash{}, n)
   293  	}
   294  
   295  	return blk, nil
   296  }
   297  
   298  // GetReceiptsByNumber returns receipts by block number.
   299  func (b *EthAPIBackend) GetReceiptsByNumber(ctx context.Context, number rpc.BlockNumber) (types.Receipts, error) {
   300  	if !b.svc.config.TxIndex {
   301  		return nil, errors.New("transactions index is disabled (enable TxIndex and re-process the DAGs)")
   302  	}
   303  
   304  	if number == rpc.PendingBlockNumber {
   305  		number = rpc.LatestBlockNumber
   306  	}
   307  	if number == rpc.LatestBlockNumber {
   308  		header := b.state.CurrentHeader()
   309  		number = rpc.BlockNumber(header.Number.Uint64())
   310  	}
   311  
   312  	block := b.state.GetBlock(common.Hash{}, uint64(number))
   313  	receipts := b.svc.store.evm.GetReceipts(idx.Block(number), b.signer, block.Hash, block.Transactions)
   314  	return receipts, nil
   315  }
   316  
   317  // GetReceipts retrieves the receipts for all transactions in a given block.
   318  func (b *EthAPIBackend) GetReceipts(ctx context.Context, block common.Hash) (types.Receipts, error) {
   319  	number := b.svc.store.GetBlockIndex(hash.Event(block))
   320  	if number == nil {
   321  		return nil, nil
   322  	}
   323  
   324  	return b.GetReceiptsByNumber(ctx, rpc.BlockNumber(*number))
   325  }
   326  
   327  func (b *EthAPIBackend) GetLogs(ctx context.Context, block common.Hash) ([][]*types.Log, error) {
   328  	receipts, err := b.GetReceipts(ctx, block)
   329  	if receipts == nil || err != nil {
   330  		return nil, err
   331  	}
   332  	logs := make([][]*types.Log, receipts.Len())
   333  	for i, receipt := range receipts {
   334  		logs[i] = receipt.Logs
   335  	}
   336  	return logs, nil
   337  }
   338  
   339  func (b *EthAPIBackend) GetTd(_ common.Hash) *big.Int {
   340  	return big.NewInt(0)
   341  }
   342  
   343  func (b *EthAPIBackend) GetEVM(ctx context.Context, msg evmcore.Message, state *state.StateDB, header *evmcore.EvmHeader, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
   344  	vmError := func() error { return nil }
   345  
   346  	if vmConfig == nil {
   347  		vmConfig = &u2u.DefaultVMConfig
   348  	}
   349  	txContext := evmcore.NewEVMTxContext(msg)
   350  	context := evmcore.NewEVMBlockContext(header, b.state, nil)
   351  	config := b.ChainConfig()
   352  	return vm.NewEVM(context, txContext, state, config, *vmConfig), vmError, nil
   353  }
   354  
   355  func (b *EthAPIBackend) GetBlockContext(header *evmcore.EvmHeader) vm.BlockContext {
   356  	return evmcore.NewEVMBlockContext(header, b.state, nil)
   357  }
   358  
   359  func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
   360  	err := b.svc.txpool.AddLocal(signedTx)
   361  	if err == nil {
   362  		// NOTE: only sent txs tracing, see TxPool.addTxs() for all
   363  		tracing.StartTx(signedTx.Hash(), "EthAPIBackend.SendTx()")
   364  	}
   365  	return err
   366  }
   367  
   368  func (b *EthAPIBackend) SubscribeLogsNotify(ch chan<- []*types.Log) notify.Subscription {
   369  	return b.svc.feed.SubscribeNewLogs(ch)
   370  }
   371  
   372  func (b *EthAPIBackend) SubscribeNewBlockNotify(ch chan<- evmcore.ChainHeadNotify) notify.Subscription {
   373  	return b.svc.feed.SubscribeNewBlock(ch)
   374  }
   375  
   376  func (b *EthAPIBackend) SubscribeNewTxsNotify(ch chan<- evmcore.NewTxsNotify) notify.Subscription {
   377  	return b.svc.txpool.SubscribeNewTxsNotify(ch)
   378  }
   379  
   380  func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
   381  	pending, err := b.svc.txpool.Pending(false)
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  	var txs types.Transactions
   386  	for _, batch := range pending {
   387  		txs = append(txs, batch...)
   388  	}
   389  	return txs, nil
   390  }
   391  
   392  func (b *EthAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
   393  	return b.svc.txpool.Get(hash)
   394  }
   395  
   396  func (b *EthAPIBackend) GetTxPosition(txHash common.Hash) *evmstore.TxPosition {
   397  	return b.svc.store.evm.GetTxPosition(txHash)
   398  }
   399  
   400  func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, uint64, uint64, error) {
   401  	if !b.svc.config.TxIndex {
   402  		return nil, 0, 0, errors.New("transactions index is disabled (enable TxIndex and re-process the DAG)")
   403  	}
   404  
   405  	position := b.svc.store.evm.GetTxPosition(txHash)
   406  	if position == nil {
   407  		return nil, 0, 0, nil
   408  	}
   409  
   410  	var tx *types.Transaction
   411  	if position.Event.IsZero() {
   412  		tx = b.svc.store.evm.GetTx(txHash)
   413  	} else {
   414  		event := b.svc.store.GetEventPayload(position.Event)
   415  		if position.EventOffset > uint32(event.Txs().Len()) {
   416  			return nil, 0, 0, fmt.Errorf("transactions index is corrupted (offset is larger than number of txs in event), event=%s, txid=%s, block=%d, offset=%d, txs_num=%d",
   417  				position.Event.String(),
   418  				txHash.String(),
   419  				position.Block,
   420  				position.EventOffset,
   421  				event.Txs().Len())
   422  		}
   423  		tx = event.Txs()[position.EventOffset]
   424  	}
   425  
   426  	return tx, uint64(position.Block), uint64(position.BlockOffset), nil
   427  }
   428  
   429  func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
   430  	return b.svc.txpool.Nonce(addr), nil
   431  }
   432  
   433  func (b *EthAPIBackend) Stats() (pending int, queued int) {
   434  	return b.svc.txpool.Stats()
   435  }
   436  
   437  func (b *EthAPIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
   438  	return b.svc.txpool.Content()
   439  }
   440  
   441  // Progress returns current synchronization status of this node
   442  func (b *EthAPIBackend) Progress() ethapi.PeerProgress {
   443  	p2pProgress := b.svc.handler.myProgress()
   444  	highestP2pProgress := b.svc.handler.highestPeerProgress()
   445  	lastBlock := b.svc.store.GetBlock(p2pProgress.LastBlockIdx)
   446  
   447  	return ethapi.PeerProgress{
   448  		CurrentEpoch:     p2pProgress.Epoch,
   449  		CurrentBlock:     p2pProgress.LastBlockIdx,
   450  		CurrentBlockHash: p2pProgress.LastBlockAtropos,
   451  		CurrentBlockTime: lastBlock.Time,
   452  		HighestBlock:     highestP2pProgress.LastBlockIdx,
   453  		HighestEpoch:     highestP2pProgress.Epoch,
   454  	}
   455  }
   456  
   457  func (b *EthAPIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) {
   458  	return b.svc.txpool.ContentFrom(addr)
   459  }
   460  
   461  func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context, certainty uint64) *big.Int {
   462  	return b.svc.gpo.SuggestTip(certainty)
   463  }
   464  
   465  func (b *EthAPIBackend) EffectiveMinGasPrice(ctx context.Context) *big.Int {
   466  	return b.svc.gpo.EffectiveMinGasPrice()
   467  }
   468  
   469  func (b *EthAPIBackend) ChainDb() ethdb.Database {
   470  	return b.svc.store.evm.EvmDb
   471  }
   472  
   473  func (b *EthAPIBackend) AccountManager() *accounts.Manager {
   474  	return b.svc.AccountManager()
   475  }
   476  
   477  func (b *EthAPIBackend) ExtRPCEnabled() bool {
   478  	return b.extRPCEnabled
   479  }
   480  
   481  func (b *EthAPIBackend) UnprotectedAllowed() bool {
   482  	return b.allowUnprotectedTxs
   483  }
   484  
   485  func (b *EthAPIBackend) RPCGasCap() uint64 {
   486  	return b.svc.config.RPCGasCap
   487  }
   488  
   489  func (b *EthAPIBackend) RPCTimeout() time.Duration {
   490  	return b.svc.config.RPCTimeout
   491  }
   492  
   493  func (b *EthAPIBackend) RPCTxFeeCap() float64 {
   494  	return b.svc.config.RPCTxFeeCap
   495  }
   496  
   497  func (b *EthAPIBackend) EvmLogIndex() topicsdb.Index {
   498  	return b.svc.store.evm.EvmLogs
   499  }
   500  
   501  // CurrentEpoch returns current epoch number.
   502  func (b *EthAPIBackend) CurrentEpoch(ctx context.Context) idx.Epoch {
   503  	return b.svc.store.GetEpoch()
   504  }
   505  
   506  func (b *EthAPIBackend) MinGasPrice() *big.Int {
   507  	return b.state.MinGasPrice()
   508  }
   509  func (b *EthAPIBackend) MaxGasLimit() uint64 {
   510  	return b.state.MaxGasLimit()
   511  }
   512  
   513  func (b *EthAPIBackend) GetUptime(ctx context.Context, vid idx.ValidatorID) (*big.Int, error) {
   514  	// Note: loads bs and es atomically to avoid a race condition
   515  	bs, es := b.svc.store.GetBlockEpochState()
   516  	if !es.Validators.Exists(vid) {
   517  		return nil, nil
   518  	}
   519  	return new(big.Int).SetUint64(uint64(bs.GetValidatorState(vid, es.Validators).Uptime)), nil
   520  }
   521  
   522  func (b *EthAPIBackend) GetOriginatedFee(ctx context.Context, vid idx.ValidatorID) (*big.Int, error) {
   523  	// Note: loads bs and es atomically to avoid a race condition
   524  	bs, es := b.svc.store.GetBlockEpochState()
   525  	if !es.Validators.Exists(vid) {
   526  		return nil, nil
   527  	}
   528  	return bs.GetValidatorState(vid, es.Validators).Originated, nil
   529  }
   530  
   531  func (b *EthAPIBackend) GetDowntime(ctx context.Context, vid idx.ValidatorID) (idx.Block, native.Timestamp, error) {
   532  	// Note: loads bs and es atomically to avoid a race condition
   533  	bs, es := b.svc.store.GetBlockEpochState()
   534  	if !es.Validators.Exists(vid) {
   535  		return 0, 0, nil
   536  	}
   537  	vs := bs.GetValidatorState(vid, es.Validators)
   538  	missedBlocks := idx.Block(0)
   539  	if bs.LastBlock.Idx > vs.LastBlock {
   540  		missedBlocks = bs.LastBlock.Idx - vs.LastBlock
   541  	}
   542  	missedTime := native.Timestamp(0)
   543  	if bs.LastBlock.Time > vs.LastOnlineTime {
   544  		missedTime = bs.LastBlock.Time - vs.LastOnlineTime
   545  	}
   546  	if missedBlocks < es.Rules.Economy.BlockMissedSlack {
   547  		return 0, 0, nil
   548  	}
   549  	return missedBlocks, missedTime, nil
   550  }
   551  
   552  func (b *EthAPIBackend) GetEpochBlockState(ctx context.Context, epoch rpc.BlockNumber) (*iblockproc.BlockState, *iblockproc.EpochState, error) {
   553  	if epoch == rpc.PendingBlockNumber {
   554  		bs, es := b.svc.store.GetBlockState(), b.svc.store.GetEpochState()
   555  		return &bs, &es, nil
   556  	}
   557  	if epoch == rpc.LatestBlockNumber {
   558  		epoch = rpc.BlockNumber(b.svc.store.GetEpoch())
   559  	}
   560  	bs, es := b.svc.store.GetHistoryBlockEpochState(idx.Epoch(epoch))
   561  	return bs, es, nil
   562  }
   563  
   564  func (b *EthAPIBackend) CalcBlockExtApi() bool {
   565  	return b.svc.config.RPCBlockExt
   566  }
   567  
   568  func (b *EthAPIBackend) SealedEpochTiming(ctx context.Context) (start native.Timestamp, end native.Timestamp) {
   569  	es := b.svc.store.GetEpochState()
   570  	return es.PrevEpochStart, es.EpochStart
   571  }
   572  
   573  func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *evmcore.EvmBlock, reexec uint64, base *state.StateDB, checkLive bool) (*state.StateDB, error) {
   574  	return b.svc.stateAtBlock(block, reexec, base, checkLive)
   575  }
   576  
   577  func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *evmcore.EvmBlock, txIndex int, reexec uint64) (evmcore.Message, vm.BlockContext, *state.StateDB, error) {
   578  	return b.svc.stateAtTransaction(block, txIndex, reexec)
   579  }