github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/arbitrum/apibackend.go (about)

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