github.com/MikyChow/arbitrum-go-ethereum@v0.0.0-20230306102812-078da49636de/arbitrum/apibackend.go (about)

     1  package arbitrum
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	ethereum "github.com/MikyChow/arbitrum-go-ethereum"
     8  	"math/big"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/MikyChow/arbitrum-go-ethereum/eth"
    14  	"github.com/MikyChow/arbitrum-go-ethereum/eth/tracers"
    15  	"github.com/MikyChow/arbitrum-go-ethereum/log"
    16  
    17  	"github.com/MikyChow/arbitrum-go-ethereum/accounts"
    18  	"github.com/MikyChow/arbitrum-go-ethereum/common"
    19  	"github.com/MikyChow/arbitrum-go-ethereum/consensus"
    20  	"github.com/MikyChow/arbitrum-go-ethereum/core"
    21  	"github.com/MikyChow/arbitrum-go-ethereum/core/bloombits"
    22  	"github.com/MikyChow/arbitrum-go-ethereum/core/rawdb"
    23  	"github.com/MikyChow/arbitrum-go-ethereum/core/state"
    24  	"github.com/MikyChow/arbitrum-go-ethereum/core/types"
    25  	"github.com/MikyChow/arbitrum-go-ethereum/core/vm"
    26  	"github.com/MikyChow/arbitrum-go-ethereum/eth/filters"
    27  	"github.com/MikyChow/arbitrum-go-ethereum/ethdb"
    28  	"github.com/MikyChow/arbitrum-go-ethereum/event"
    29  	"github.com/MikyChow/arbitrum-go-ethereum/internal/ethapi"
    30  	"github.com/MikyChow/arbitrum-go-ethereum/params"
    31  	"github.com/MikyChow/arbitrum-go-ethereum/rpc"
    32  )
    33  
    34  type APIBackend struct {
    35  	b *Backend
    36  
    37  	fallbackClient types.FallbackClient
    38  	sync           SyncProgressBackend
    39  }
    40  
    41  type timeoutFallbackClient struct {
    42  	impl    types.FallbackClient
    43  	timeout time.Duration
    44  }
    45  
    46  func (c *timeoutFallbackClient) CallContext(ctxIn context.Context, result interface{}, method string, args ...interface{}) error {
    47  	ctx, cancel := context.WithTimeout(ctxIn, c.timeout)
    48  	defer cancel()
    49  	return c.impl.CallContext(ctx, result, method, args...)
    50  }
    51  
    52  func CreateFallbackClient(fallbackClientUrl string, fallbackClientTimeout time.Duration) (types.FallbackClient, error) {
    53  	if fallbackClientUrl == "" {
    54  		return nil, nil
    55  	}
    56  	if strings.HasPrefix(fallbackClientUrl, "error:") {
    57  		fields := strings.Split(fallbackClientUrl, ":")[1:]
    58  		errNumber, convErr := strconv.ParseInt(fields[0], 0, 0)
    59  		if convErr == nil {
    60  			fields = fields[1:]
    61  		} else {
    62  			errNumber = -32000
    63  		}
    64  		types.SetFallbackError(strings.Join(fields, ":"), int(errNumber))
    65  		return nil, nil
    66  	}
    67  	var fallbackClient types.FallbackClient
    68  	var err error
    69  	fallbackClient, err = rpc.Dial(fallbackClientUrl)
    70  	if fallbackClient == nil || err != nil {
    71  		return nil, fmt.Errorf("failed creating fallback connection: %w", err)
    72  	}
    73  	if fallbackClientTimeout != 0 {
    74  		fallbackClient = &timeoutFallbackClient{
    75  			impl:    fallbackClient,
    76  			timeout: fallbackClientTimeout,
    77  		}
    78  	}
    79  	return fallbackClient, nil
    80  }
    81  
    82  type SyncProgressBackend interface {
    83  	SyncProgressMap() map[string]interface{}
    84  	SafeBlockNumber(ctx context.Context) (uint64, error)
    85  	FinalizedBlockNumber(ctx context.Context) (uint64, error)
    86  }
    87  
    88  func createRegisterAPIBackend(backend *Backend, sync SyncProgressBackend, filterConfig filters.Config, fallbackClientUrl string, fallbackClientTimeout time.Duration) (*filters.FilterSystem, error) {
    89  	fallbackClient, err := CreateFallbackClient(fallbackClientUrl, fallbackClientTimeout)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	backend.apiBackend = &APIBackend{
    94  		b:              backend,
    95  		fallbackClient: fallbackClient,
    96  		sync:           sync,
    97  	}
    98  	filterSystem := filters.NewFilterSystem(backend.apiBackend, filterConfig)
    99  	backend.stack.RegisterAPIs(backend.apiBackend.GetAPIs(filterSystem))
   100  	return filterSystem, nil
   101  }
   102  
   103  func (a *APIBackend) GetAPIs(filterSystem *filters.FilterSystem) []rpc.API {
   104  	apis := ethapi.GetAPIs(a)
   105  
   106  	apis = append(apis, rpc.API{
   107  		Namespace: "eth",
   108  		Version:   "1.0",
   109  		Service:   filters.NewFilterAPI(filterSystem, false),
   110  		Public:    true,
   111  	})
   112  
   113  	apis = append(apis, rpc.API{
   114  		Namespace: "net",
   115  		Version:   "1.0",
   116  		Service:   NewPublicNetAPI(a.ChainConfig().ChainID.Uint64()),
   117  		Public:    true,
   118  	})
   119  
   120  	apis = append(apis, rpc.API{
   121  		Namespace: "txpool",
   122  		Version:   "1.0",
   123  		Service:   NewPublicTxPoolAPI(),
   124  		Public:    true,
   125  	})
   126  
   127  	apis = append(apis, tracers.APIs(a)...)
   128  
   129  	return apis
   130  }
   131  
   132  func (a *APIBackend) blockChain() *core.BlockChain {
   133  	return a.b.arb.BlockChain()
   134  }
   135  
   136  func (a *APIBackend) GetArbitrumNode() interface{} {
   137  	return a.b.arb.ArbNode()
   138  }
   139  
   140  // General Ethereum API
   141  func (a *APIBackend) SyncProgressMap() map[string]interface{} {
   142  	return a.sync.SyncProgressMap()
   143  }
   144  
   145  func (a *APIBackend) SyncProgress() ethereum.SyncProgress {
   146  	progress := a.sync.SyncProgressMap()
   147  
   148  	if progress == nil || len(progress) == 0 {
   149  		return ethereum.SyncProgress{}
   150  	}
   151  	return ethereum.SyncProgress{
   152  		CurrentBlock: 0,
   153  		HighestBlock: 1,
   154  	}
   155  }
   156  
   157  func (a *APIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
   158  	return big.NewInt(0), nil // there's no tips in L2
   159  }
   160  
   161  func (a *APIBackend) FeeHistory(
   162  	ctx context.Context,
   163  	blocks int,
   164  	newestBlock rpc.BlockNumber,
   165  	rewardPercentiles []float64,
   166  ) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) {
   167  
   168  	if core.GetArbOSSpeedLimitPerSecond == nil {
   169  		return nil, nil, nil, nil, errors.New("ArbOS not installed")
   170  	}
   171  
   172  	nitroGenesis := rpc.BlockNumber(a.ChainConfig().ArbitrumChainParams.GenesisBlockNum)
   173  	newestBlock, latestBlock := a.blockChain().ClipToPostNitroGenesis(newestBlock)
   174  
   175  	maxFeeHistory := int(a.b.config.FeeHistoryMaxBlockCount)
   176  	if blocks > maxFeeHistory {
   177  		log.Warn("Sanitizing fee history length", "requested", blocks, "truncated", maxFeeHistory)
   178  		blocks = maxFeeHistory
   179  	}
   180  	if blocks < 1 {
   181  		// returning with no data and no error means there are no retrievable blocks
   182  		return common.Big0, nil, nil, nil, nil
   183  	}
   184  
   185  	// don't attempt to include blocks before genesis
   186  	if rpc.BlockNumber(blocks) > (newestBlock - nitroGenesis) {
   187  		blocks = int(newestBlock - nitroGenesis + 1)
   188  	}
   189  	oldestBlock := int(newestBlock) + 1 - blocks
   190  
   191  	// inform that tipping has no effect on inclusion
   192  	rewards := make([][]*big.Int, blocks)
   193  	zeros := make([]*big.Int, len(rewardPercentiles))
   194  	for i := range zeros {
   195  		zeros[i] = common.Big0
   196  	}
   197  	for i := range rewards {
   198  		rewards[i] = zeros
   199  	}
   200  	if len(rewardPercentiles) == 0 {
   201  		rewards = nil
   202  	}
   203  
   204  	// use the most recent average compute rate for all blocks
   205  	// note: while we could query this value for each block, it'd be prohibitively expensive
   206  	state, _, err := a.StateAndHeaderByNumber(ctx, rpc.BlockNumber(newestBlock))
   207  	if err != nil {
   208  		return common.Big0, nil, nil, nil, err
   209  	}
   210  	speedLimit, err := core.GetArbOSSpeedLimitPerSecond(state)
   211  	if err != nil {
   212  		return common.Big0, nil, nil, nil, err
   213  	}
   214  
   215  	gasUsed := make([]float64, blocks)
   216  	basefees := make([]*big.Int, blocks+1) // the RPC semantics are to predict the future value
   217  
   218  	// collect the basefees
   219  	baseFeeLookup := newestBlock + 1
   220  	if newestBlock == latestBlock {
   221  		baseFeeLookup = newestBlock
   222  	}
   223  	var prevTimestamp uint64
   224  	var timeSinceLastTimeChange uint64
   225  	var currentTimestampGasUsed uint64
   226  	if rpc.BlockNumber(oldestBlock) > nitroGenesis {
   227  		header, err := a.HeaderByNumber(ctx, rpc.BlockNumber(oldestBlock-1))
   228  		if err != nil {
   229  			return common.Big0, nil, nil, nil, err
   230  		}
   231  		prevTimestamp = header.Time
   232  	}
   233  	for block := oldestBlock; block <= int(baseFeeLookup); block++ {
   234  		header, err := a.HeaderByNumber(ctx, rpc.BlockNumber(block))
   235  		if err != nil {
   236  			return common.Big0, nil, nil, nil, err
   237  		}
   238  		basefees[block-oldestBlock] = header.BaseFee
   239  
   240  		if block > int(newestBlock) {
   241  			break
   242  		}
   243  
   244  		if header.Time > prevTimestamp {
   245  			timeSinceLastTimeChange = header.Time - prevTimestamp
   246  			currentTimestampGasUsed = 0
   247  		}
   248  
   249  		receipts := a.blockChain().GetReceiptsByHash(header.ReceiptHash)
   250  		for _, receipt := range receipts {
   251  			if receipt.GasUsed > receipt.GasUsedForL1 {
   252  				currentTimestampGasUsed += receipt.GasUsed - receipt.GasUsedForL1
   253  			}
   254  		}
   255  
   256  		prevTimestamp = header.Time
   257  
   258  		// In vanilla geth, this RPC returns the gasUsed ratio so a client can know how the basefee will change
   259  		// To emulate this, we translate the compute rate into something similar, centered at an analogous 0.5
   260  		var fullnessAnalogue float64
   261  		if timeSinceLastTimeChange > 0 {
   262  			fullnessAnalogue = float64(currentTimestampGasUsed) / float64(speedLimit) / float64(timeSinceLastTimeChange) / 2.0
   263  			if fullnessAnalogue > 1.0 {
   264  				fullnessAnalogue = 1.0
   265  			}
   266  		} else {
   267  			// We haven't looked far enough back to know the last timestamp change,
   268  			// so treat this block as full.
   269  			fullnessAnalogue = 1.0
   270  		}
   271  		gasUsed[block-oldestBlock] = fullnessAnalogue
   272  
   273  	}
   274  	if newestBlock == latestBlock {
   275  		basefees[blocks] = basefees[blocks-1] // guess the basefee won't change
   276  	}
   277  
   278  	return big.NewInt(int64(oldestBlock)), rewards, basefees, gasUsed, nil
   279  }
   280  
   281  func (a *APIBackend) ChainDb() ethdb.Database {
   282  	return a.b.chainDb
   283  }
   284  
   285  func (a *APIBackend) AccountManager() *accounts.Manager {
   286  	return a.b.stack.AccountManager()
   287  }
   288  
   289  func (a *APIBackend) ExtRPCEnabled() bool {
   290  	panic("not implemented") // TODO: Implement
   291  }
   292  
   293  func (a *APIBackend) RPCGasCap() uint64 {
   294  	return a.b.config.RPCGasCap
   295  }
   296  
   297  func (a *APIBackend) RPCTxFeeCap() float64 {
   298  	return a.b.config.RPCTxFeeCap
   299  }
   300  
   301  func (a *APIBackend) RPCEVMTimeout() time.Duration {
   302  	return a.b.config.RPCEVMTimeout
   303  }
   304  
   305  func (a *APIBackend) UnprotectedAllowed() bool {
   306  	return true // TODO: is that true?
   307  }
   308  
   309  // Blockchain API
   310  func (a *APIBackend) SetHead(number uint64) {
   311  	panic("not implemented") // TODO: Implement
   312  }
   313  
   314  func (a *APIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
   315  	return a.headerByNumberImpl(ctx, number)
   316  }
   317  
   318  func (a *APIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   319  	return a.blockChain().GetHeaderByHash(hash), nil
   320  }
   321  
   322  func (a *APIBackend) blockNumberToUint(ctx context.Context, number rpc.BlockNumber) (uint64, error) {
   323  	if number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber {
   324  		return a.blockChain().CurrentBlock().Number().Uint64(), nil
   325  	}
   326  	if number == rpc.SafeBlockNumber {
   327  		return a.sync.SafeBlockNumber(ctx)
   328  	}
   329  	if number == rpc.FinalizedBlockNumber {
   330  		return a.sync.FinalizedBlockNumber(ctx)
   331  	}
   332  	if number < 0 {
   333  		return 0, errors.New("block number not supported")
   334  	}
   335  	return uint64(number.Int64()), nil
   336  }
   337  
   338  func (a *APIBackend) headerByNumberImpl(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
   339  	if number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber {
   340  		return a.blockChain().CurrentBlock().Header(), nil
   341  	}
   342  	numUint, err := a.blockNumberToUint(ctx, number)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  	return a.blockChain().GetHeaderByNumber(numUint), nil
   347  }
   348  
   349  func (a *APIBackend) headerByNumberOrHashImpl(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
   350  	number, isnum := blockNrOrHash.Number()
   351  	if isnum {
   352  		return a.headerByNumberImpl(ctx, number)
   353  	}
   354  	hash, ishash := blockNrOrHash.Hash()
   355  	if ishash {
   356  		return a.blockChain().GetHeaderByHash(hash), nil
   357  	}
   358  	return nil, errors.New("invalid arguments; neither block nor hash specified")
   359  }
   360  
   361  func (a *APIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
   362  	return a.headerByNumberOrHashImpl(ctx, blockNrOrHash)
   363  }
   364  
   365  func (a *APIBackend) CurrentHeader() *types.Header {
   366  	return a.blockChain().CurrentHeader()
   367  }
   368  
   369  func (a *APIBackend) CurrentBlock() *types.Block {
   370  	return a.blockChain().CurrentBlock()
   371  }
   372  
   373  func (a *APIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   374  	if number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber {
   375  		return a.blockChain().CurrentBlock(), nil
   376  	}
   377  	numUint, err := a.blockNumberToUint(ctx, number)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  	return a.blockChain().GetBlockByNumber(numUint), nil
   382  }
   383  
   384  func (a *APIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   385  	return a.blockChain().GetBlockByHash(hash), nil
   386  }
   387  
   388  func (a *APIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
   389  	number, isnum := blockNrOrHash.Number()
   390  	if isnum {
   391  		return a.BlockByNumber(ctx, number)
   392  	}
   393  	hash, ishash := blockNrOrHash.Hash()
   394  	if ishash {
   395  		return a.BlockByHash(ctx, hash)
   396  	}
   397  	return nil, errors.New("invalid arguments; neither block nor hash specified")
   398  }
   399  
   400  func (a *APIBackend) stateAndHeaderFromHeader(header *types.Header, err error) (*state.StateDB, *types.Header, error) {
   401  	if err != nil {
   402  		return nil, header, err
   403  	}
   404  	if header == nil {
   405  		return nil, nil, errors.New("header not found")
   406  	}
   407  	if !a.blockChain().Config().IsArbitrumNitro(header.Number) {
   408  		return nil, header, types.ErrUseFallback
   409  	}
   410  	state, err := a.blockChain().StateAt(header.Root)
   411  	return state, header, err
   412  }
   413  
   414  func (a *APIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
   415  	return a.stateAndHeaderFromHeader(a.HeaderByNumber(ctx, number))
   416  }
   417  
   418  func (a *APIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
   419  	return a.stateAndHeaderFromHeader(a.HeaderByNumberOrHash(ctx, blockNrOrHash))
   420  }
   421  
   422  func (a *APIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
   423  	if !a.blockChain().Config().IsArbitrumNitro(block.Number()) {
   424  		return nil, types.ErrUseFallback
   425  	}
   426  	// DEV: This assumes that `StateAtBlock` only accesses the blockchain and chainDb fields
   427  	return eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtBlock(block, reexec, base, checkLive, preferDisk)
   428  }
   429  
   430  func (a *APIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) {
   431  	if !a.blockChain().Config().IsArbitrumNitro(block.Number()) {
   432  		return nil, vm.BlockContext{}, nil, types.ErrUseFallback
   433  	}
   434  	// DEV: This assumes that `StateAtTransaction` only accesses the blockchain and chainDb fields
   435  	return eth.NewArbEthereum(a.b.arb.BlockChain(), a.ChainDb()).StateAtTransaction(block, txIndex, reexec)
   436  }
   437  
   438  func (a *APIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
   439  	return a.blockChain().GetReceiptsByHash(hash), nil
   440  }
   441  
   442  func (a *APIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
   443  	if header := a.blockChain().GetHeaderByHash(hash); header != nil {
   444  		return a.blockChain().GetTd(hash, header.Number.Uint64())
   445  	}
   446  	return nil
   447  }
   448  
   449  func (a *APIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
   450  	vmError := func() error { return nil }
   451  	if vmConfig == nil {
   452  		vmConfig = a.blockChain().GetVMConfig()
   453  	}
   454  	txContext := core.NewEVMTxContext(msg)
   455  	context := core.NewEVMBlockContext(header, a.blockChain(), nil)
   456  	return vm.NewEVM(context, txContext, state, a.blockChain().Config(), *vmConfig), vmError, nil
   457  }
   458  
   459  func (a *APIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
   460  	return a.blockChain().SubscribeChainEvent(ch)
   461  }
   462  
   463  func (a *APIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
   464  	return a.blockChain().SubscribeChainHeadEvent(ch)
   465  }
   466  
   467  func (a *APIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
   468  	return a.blockChain().SubscribeChainSideEvent(ch)
   469  }
   470  
   471  // Transaction pool API
   472  func (a *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
   473  	return a.b.EnqueueL2Message(ctx, signedTx)
   474  }
   475  
   476  func (a *APIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
   477  	tx, blockHash, blockNumber, index := rawdb.ReadTransaction(a.b.chainDb, txHash)
   478  	return tx, blockHash, blockNumber, index, nil
   479  }
   480  
   481  func (a *APIBackend) GetPoolTransactions() (types.Transactions, error) {
   482  	// Arbitrum doesn't have a pool
   483  	return types.Transactions{}, nil
   484  }
   485  
   486  func (a *APIBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
   487  	// Arbitrum doesn't have a pool
   488  	return nil
   489  }
   490  
   491  func (a *APIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
   492  	stateDB, err := a.blockChain().State()
   493  	if err != nil {
   494  		return 0, err
   495  	}
   496  	return stateDB.GetNonce(addr), nil
   497  }
   498  
   499  func (a *APIBackend) Stats() (pending int, queued int) {
   500  	panic("not implemented") // TODO: Implement
   501  }
   502  
   503  func (a *APIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
   504  	panic("not implemented") // TODO: Implement
   505  }
   506  
   507  func (a *APIBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) {
   508  	panic("not implemented") // TODO: Implement
   509  }
   510  
   511  func (a *APIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
   512  	return a.b.SubscribeNewTxsEvent(ch)
   513  }
   514  
   515  // Filter API
   516  func (a *APIBackend) BloomStatus() (uint64, uint64) {
   517  	sections, _, _ := a.b.bloomIndexer.Sections()
   518  	return a.b.config.BloomBitsBlocks, sections
   519  }
   520  
   521  func (a *APIBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
   522  	return rawdb.ReadLogs(a.ChainDb(), hash, number, a.ChainConfig()), nil
   523  }
   524  
   525  func (a *APIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
   526  	for i := 0; i < bloomFilterThreads; i++ {
   527  		go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, a.b.bloomRequests)
   528  	}
   529  }
   530  
   531  func (a *APIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   532  	return a.blockChain().SubscribeLogsEvent(ch)
   533  }
   534  
   535  func (a *APIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
   536  	//Arbitrum doesn't really need pending logs. Logs are published as soon as we know them..
   537  	return a.SubscribeLogsEvent(ch)
   538  }
   539  
   540  func (a *APIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
   541  	return a.blockChain().SubscribeRemovedLogsEvent(ch)
   542  }
   543  
   544  func (a *APIBackend) ChainConfig() *params.ChainConfig {
   545  	return a.blockChain().Config()
   546  }
   547  
   548  func (a *APIBackend) Engine() consensus.Engine {
   549  	return a.blockChain().Engine()
   550  }
   551  
   552  func (b *APIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
   553  	return nil, nil
   554  }
   555  
   556  func (b *APIBackend) FallbackClient() types.FallbackClient {
   557  	return b.fallbackClient
   558  }