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