github.com/klaytn/klaytn@v1.12.1/node/cn/api_backend.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of go-ethereum.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from eth/api_backend.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package cn
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  	"math/big"
    27  	"time"
    28  
    29  	"github.com/klaytn/klaytn"
    30  	"github.com/klaytn/klaytn/accounts"
    31  	"github.com/klaytn/klaytn/blockchain"
    32  	"github.com/klaytn/klaytn/blockchain/bloombits"
    33  	"github.com/klaytn/klaytn/blockchain/state"
    34  	"github.com/klaytn/klaytn/blockchain/types"
    35  	"github.com/klaytn/klaytn/blockchain/vm"
    36  	"github.com/klaytn/klaytn/common"
    37  	"github.com/klaytn/klaytn/consensus"
    38  	"github.com/klaytn/klaytn/event"
    39  	"github.com/klaytn/klaytn/governance"
    40  	"github.com/klaytn/klaytn/networks/rpc"
    41  	"github.com/klaytn/klaytn/node/cn/gasprice"
    42  	"github.com/klaytn/klaytn/params"
    43  	"github.com/klaytn/klaytn/reward"
    44  	"github.com/klaytn/klaytn/storage/database"
    45  	"github.com/klaytn/klaytn/work"
    46  )
    47  
    48  // CNAPIBackend implements api.Backend for full nodes
    49  type CNAPIBackend struct {
    50  	cn  *CN
    51  	gpo *gasprice.Oracle
    52  }
    53  
    54  // GetTxLookupInfoAndReceipt retrieves a tx and lookup info and receipt for a given transaction hash.
    55  func (b *CNAPIBackend) GetTxLookupInfoAndReceipt(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, *types.Receipt) {
    56  	return b.cn.blockchain.GetTxLookupInfoAndReceipt(txHash)
    57  }
    58  
    59  // GetTxAndLookupInfoInCache retrieves a tx and lookup info for a given transaction hash in cache.
    60  func (b *CNAPIBackend) GetTxAndLookupInfoInCache(txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
    61  	return b.cn.blockchain.GetTxAndLookupInfoInCache(txHash)
    62  }
    63  
    64  // GetBlockReceiptsInCache retrieves receipts for a given block hash in cache.
    65  func (b *CNAPIBackend) GetBlockReceiptsInCache(blockHash common.Hash) types.Receipts {
    66  	return b.cn.blockchain.GetBlockReceiptsInCache(blockHash)
    67  }
    68  
    69  // GetTxLookupInfoAndReceiptInCache retrieves a tx and lookup info and receipt for a given transaction hash in cache.
    70  func (b *CNAPIBackend) GetTxLookupInfoAndReceiptInCache(txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, *types.Receipt) {
    71  	return b.cn.blockchain.GetTxLookupInfoAndReceiptInCache(txHash)
    72  }
    73  
    74  func (b *CNAPIBackend) ChainConfig() *params.ChainConfig {
    75  	return b.cn.chainConfig
    76  }
    77  
    78  func (b *CNAPIBackend) CurrentBlock() *types.Block {
    79  	return b.cn.blockchain.CurrentBlock()
    80  }
    81  
    82  func doSetHead(bc work.BlockChain, cn consensus.Engine, gov governance.Engine, targetBlkNum uint64) error {
    83  	if err := bc.SetHead(targetBlkNum); err != nil {
    84  		return err
    85  	}
    86  	// Initialize snapshot cache, staking info cache, and governance cache
    87  	cn.InitSnapshot()
    88  	if reward.GetStakingManager() != nil {
    89  		reward.PurgeStakingInfoCache()
    90  	}
    91  	gov.InitGovCache()
    92  	gov.InitLastGovStateBlkNum()
    93  	return nil
    94  }
    95  
    96  func (b *CNAPIBackend) SetHead(number uint64) error {
    97  	b.cn.protocolManager.Downloader().Cancel()
    98  	b.cn.protocolManager.SetSyncStop(true)
    99  	defer b.cn.protocolManager.SetSyncStop(false)
   100  	return doSetHead(b.cn.blockchain, b.cn.engine, b.cn.governance, number)
   101  }
   102  
   103  func (b *CNAPIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
   104  	// Pending block is only known by the miner
   105  	if blockNr == rpc.PendingBlockNumber {
   106  		block := b.cn.miner.PendingBlock()
   107  		if block == nil {
   108  			return nil, fmt.Errorf("pending block is not prepared yet")
   109  		}
   110  		return block.Header(), nil
   111  	}
   112  	// Otherwise resolve and return the block
   113  	if blockNr == rpc.LatestBlockNumber {
   114  		return b.cn.blockchain.CurrentBlock().Header(), nil
   115  	}
   116  	header := b.cn.blockchain.GetHeaderByNumber(uint64(blockNr))
   117  	if header == nil {
   118  		return nil, fmt.Errorf("the header does not exist (block number: %d)", blockNr)
   119  	}
   120  	return header, nil
   121  }
   122  
   123  func (b *CNAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
   124  	if blockNr, ok := blockNrOrHash.Number(); ok {
   125  		return b.HeaderByNumber(ctx, blockNr)
   126  	}
   127  	if hash, ok := blockNrOrHash.Hash(); ok {
   128  		header, err := b.HeaderByHash(ctx, hash)
   129  		if err != nil {
   130  			return nil, err
   131  		}
   132  		return header, nil
   133  	}
   134  	return nil, fmt.Errorf("invalid arguments; neither block nor hash specified")
   135  }
   136  
   137  func (b *CNAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   138  	if header := b.cn.blockchain.GetHeaderByHash(hash); header != nil {
   139  		return header, nil
   140  	}
   141  	return nil, fmt.Errorf("the header does not exist (hash: %d)", hash)
   142  }
   143  
   144  func (b *CNAPIBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
   145  	// Pending block is only known by the miner
   146  	if blockNr == rpc.PendingBlockNumber {
   147  		block := b.cn.miner.PendingBlock()
   148  		if block == nil {
   149  			return nil, fmt.Errorf("pending block is not prepared yet")
   150  		}
   151  		return block, nil
   152  	}
   153  	// Otherwise resolve and return the block
   154  	if blockNr == rpc.LatestBlockNumber {
   155  		return b.cn.blockchain.CurrentBlock(), nil
   156  	}
   157  	block := b.cn.blockchain.GetBlockByNumber(uint64(blockNr))
   158  	if block == nil {
   159  		return nil, fmt.Errorf("the block does not exist (block number: %d)", blockNr)
   160  	}
   161  	return block, nil
   162  }
   163  
   164  func (b *CNAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
   165  	if blockNr, ok := blockNrOrHash.Number(); ok {
   166  		return b.BlockByNumber(ctx, blockNr)
   167  	}
   168  	if hash, ok := blockNrOrHash.Hash(); ok {
   169  		block, err := b.BlockByHash(ctx, hash)
   170  		if err != nil {
   171  			return nil, err
   172  		}
   173  		return block, nil
   174  	}
   175  	return nil, fmt.Errorf("invalid arguments; neither block nor hash specified")
   176  }
   177  
   178  func (b *CNAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
   179  	// Pending state is only known by the miner
   180  	if blockNr == rpc.PendingBlockNumber {
   181  		block, state := b.cn.miner.Pending()
   182  		if block == nil || state == nil {
   183  			return nil, nil, fmt.Errorf("pending block is not prepared yet")
   184  		}
   185  		return state, block.Header(), nil
   186  	}
   187  	// Otherwise resolve the block number and return its state
   188  	header, err := b.HeaderByNumber(ctx, blockNr)
   189  	if header == nil || err != nil {
   190  		return nil, nil, err
   191  	}
   192  	stateDb, err := b.cn.BlockChain().StateAt(header.Root)
   193  	return stateDb, header, err
   194  }
   195  
   196  func (b *CNAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
   197  	if blockNr, ok := blockNrOrHash.Number(); ok {
   198  		return b.StateAndHeaderByNumber(ctx, blockNr)
   199  	}
   200  	if hash, ok := blockNrOrHash.Hash(); ok {
   201  		header := b.cn.blockchain.GetHeaderByHash(hash)
   202  		if header == nil {
   203  			return nil, nil, fmt.Errorf("header for hash not found")
   204  		}
   205  		stateDb, err := b.cn.BlockChain().StateAt(header.Root)
   206  		return stateDb, header, err
   207  	}
   208  	return nil, nil, fmt.Errorf("invalid arguments; neither block nor hash specified")
   209  }
   210  
   211  func (b *CNAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   212  	block := b.cn.blockchain.GetBlockByHash(hash)
   213  	if block == nil {
   214  		return nil, fmt.Errorf("the block does not exist (block hash: %s)", hash.String())
   215  	}
   216  	return block, nil
   217  }
   218  
   219  // GetTxAndLookupInfo retrieves a tx and lookup info for a given transaction hash.
   220  func (b *CNAPIBackend) GetTxAndLookupInfo(hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
   221  	return b.cn.blockchain.GetTxAndLookupInfo(hash)
   222  }
   223  
   224  // GetBlockReceipts retrieves the receipts for all transactions with given block hash.
   225  func (b *CNAPIBackend) GetBlockReceipts(ctx context.Context, hash common.Hash) types.Receipts {
   226  	return b.cn.blockchain.GetReceiptsByBlockHash(hash)
   227  }
   228  
   229  func (b *CNAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
   230  	return b.cn.blockchain.GetLogsByHash(hash), nil
   231  }
   232  
   233  func (b *CNAPIBackend) GetTd(blockHash common.Hash) *big.Int {
   234  	return b.cn.blockchain.GetTdByHash(blockHash)
   235  }
   236  
   237  func (b *CNAPIBackend) GetEVM(ctx context.Context, msg blockchain.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
   238  	vmError := func() error { return nil }
   239  
   240  	txContext := blockchain.NewEVMTxContext(msg, header)
   241  	blockContext := blockchain.NewEVMBlockContext(header, b.cn.BlockChain(), nil)
   242  
   243  	return vm.NewEVM(blockContext, txContext, state, b.cn.chainConfig, &vmCfg), vmError, nil
   244  }
   245  
   246  func (b *CNAPIBackend) SubscribeRemovedLogsEvent(ch chan<- blockchain.RemovedLogsEvent) event.Subscription {
   247  	return b.cn.BlockChain().SubscribeRemovedLogsEvent(ch)
   248  }
   249  
   250  func (b *CNAPIBackend) SubscribeChainEvent(ch chan<- blockchain.ChainEvent) event.Subscription {
   251  	return b.cn.BlockChain().SubscribeChainEvent(ch)
   252  }
   253  
   254  func (b *CNAPIBackend) SubscribeChainHeadEvent(ch chan<- blockchain.ChainHeadEvent) event.Subscription {
   255  	return b.cn.BlockChain().SubscribeChainHeadEvent(ch)
   256  }
   257  
   258  func (b *CNAPIBackend) SubscribeChainSideEvent(ch chan<- blockchain.ChainSideEvent) event.Subscription {
   259  	return b.cn.BlockChain().SubscribeChainSideEvent(ch)
   260  }
   261  
   262  func (b *CNAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   263  	return b.cn.BlockChain().SubscribeLogsEvent(ch)
   264  }
   265  
   266  func (b *CNAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
   267  	return b.cn.txPool.AddLocal(signedTx)
   268  }
   269  
   270  func (b *CNAPIBackend) GetPoolTransactions() (types.Transactions, error) {
   271  	pending, err := b.cn.txPool.Pending()
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  	var txs types.Transactions
   276  	for _, batch := range pending {
   277  		txs = append(txs, batch...)
   278  	}
   279  	return txs, nil
   280  }
   281  
   282  func (b *CNAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
   283  	return b.cn.txPool.Get(hash)
   284  }
   285  
   286  func (b *CNAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) uint64 {
   287  	return b.cn.txPool.GetPendingNonce(addr)
   288  }
   289  
   290  func (b *CNAPIBackend) Stats() (pending int, queued int) {
   291  	return b.cn.txPool.Stats()
   292  }
   293  
   294  func (b *CNAPIBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
   295  	return b.cn.TxPool().Content()
   296  }
   297  
   298  func (b *CNAPIBackend) SubscribeNewTxsEvent(ch chan<- blockchain.NewTxsEvent) event.Subscription {
   299  	return b.cn.TxPool().SubscribeNewTxsEvent(ch)
   300  }
   301  
   302  func (b *CNAPIBackend) Progress() klaytn.SyncProgress {
   303  	return b.cn.Progress()
   304  }
   305  
   306  func (b *CNAPIBackend) ProtocolVersion() int {
   307  	return b.cn.ProtocolVersion()
   308  }
   309  
   310  // SuggestPrice returns the baseFee * 2 if the current block is magma hard forked.
   311  // Other cases, it returns the unitPrice.
   312  func (b *CNAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
   313  	return b.gpo.SuggestPrice(ctx)
   314  }
   315  
   316  // SuggestTipCap returns the baseFee if the current block is magma hard forked.
   317  // Other cases, it returns the unitPrice.
   318  func (b *CNAPIBackend) SuggestTipCap(ctx context.Context) (*big.Int, error) {
   319  	return b.gpo.SuggestTipCap(ctx)
   320  }
   321  
   322  func (b *CNAPIBackend) UpperBoundGasPrice(ctx context.Context) *big.Int {
   323  	bignum := b.CurrentBlock().Number()
   324  	pset, err := b.cn.governance.EffectiveParams(bignum.Uint64() + 1)
   325  	if err != nil {
   326  		return nil
   327  	}
   328  	if b.cn.chainConfig.IsMagmaForkEnabled(bignum) {
   329  		return new(big.Int).SetUint64(pset.UpperBoundBaseFee())
   330  	} else {
   331  		return new(big.Int).SetUint64(pset.UnitPrice())
   332  	}
   333  }
   334  
   335  func (b *CNAPIBackend) LowerBoundGasPrice(ctx context.Context) *big.Int {
   336  	bignum := b.CurrentBlock().Number()
   337  	pset, err := b.cn.governance.EffectiveParams(bignum.Uint64() + 1)
   338  	if err != nil {
   339  		return nil
   340  	}
   341  	if b.cn.chainConfig.IsMagmaForkEnabled(bignum) {
   342  		return new(big.Int).SetUint64(pset.LowerBoundBaseFee())
   343  	} else {
   344  		return new(big.Int).SetUint64(pset.UnitPrice())
   345  	}
   346  }
   347  
   348  func (b *CNAPIBackend) ChainDB() database.DBManager {
   349  	return b.cn.ChainDB()
   350  }
   351  
   352  func (b *CNAPIBackend) EventMux() *event.TypeMux {
   353  	return b.cn.EventMux()
   354  }
   355  
   356  func (b *CNAPIBackend) AccountManager() accounts.AccountManager {
   357  	return b.cn.AccountManager()
   358  }
   359  
   360  func (b *CNAPIBackend) BloomStatus() (uint64, uint64) {
   361  	sections, _, _ := b.cn.bloomIndexer.Sections()
   362  	return params.BloomBitsBlocks, sections
   363  }
   364  
   365  func (b *CNAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
   366  	for i := 0; i < bloomFilterThreads; i++ {
   367  		go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.cn.bloomRequests)
   368  	}
   369  }
   370  
   371  func (b *CNAPIBackend) IsParallelDBWrite() bool {
   372  	return b.cn.BlockChain().IsParallelDBWrite()
   373  }
   374  
   375  func (b *CNAPIBackend) IsSenderTxHashIndexingEnabled() bool {
   376  	return b.cn.BlockChain().IsSenderTxHashIndexingEnabled()
   377  }
   378  
   379  func (b *CNAPIBackend) RPCGasCap() *big.Int {
   380  	return b.cn.config.RPCGasCap
   381  }
   382  
   383  func (b *CNAPIBackend) RPCEVMTimeout() time.Duration {
   384  	return b.cn.config.RPCEVMTimeout
   385  }
   386  
   387  func (b *CNAPIBackend) RPCTxFeeCap() float64 {
   388  	return b.cn.config.RPCTxFeeCap
   389  }
   390  
   391  func (b *CNAPIBackend) Engine() consensus.Engine {
   392  	return b.cn.engine
   393  }
   394  
   395  func (b *CNAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) {
   396  	return b.cn.stateAtBlock(block, reexec, base, checkLive, preferDisk)
   397  }
   398  
   399  func (b *CNAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (blockchain.Message, vm.BlockContext, vm.TxContext, *state.StateDB, error) {
   400  	return b.cn.stateAtTransaction(block, txIndex, reexec)
   401  }
   402  
   403  func (b *CNAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) {
   404  	return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles)
   405  }