github.com/klaytn/klaytn@v1.10.2/node/cn/backend.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2014 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/backend.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package cn
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"math/big"
    27  	"os/exec"
    28  	"runtime"
    29  	"sync"
    30  	"time"
    31  
    32  	"github.com/klaytn/klaytn"
    33  	"github.com/klaytn/klaytn/accounts"
    34  	"github.com/klaytn/klaytn/api"
    35  	"github.com/klaytn/klaytn/blockchain"
    36  	"github.com/klaytn/klaytn/blockchain/bloombits"
    37  	"github.com/klaytn/klaytn/blockchain/state"
    38  	"github.com/klaytn/klaytn/blockchain/types"
    39  	"github.com/klaytn/klaytn/common"
    40  	"github.com/klaytn/klaytn/common/hexutil"
    41  	"github.com/klaytn/klaytn/consensus"
    42  	"github.com/klaytn/klaytn/consensus/istanbul"
    43  	istanbulBackend "github.com/klaytn/klaytn/consensus/istanbul/backend"
    44  	"github.com/klaytn/klaytn/crypto"
    45  	"github.com/klaytn/klaytn/datasync/downloader"
    46  	"github.com/klaytn/klaytn/event"
    47  	"github.com/klaytn/klaytn/governance"
    48  	"github.com/klaytn/klaytn/networks/p2p"
    49  	"github.com/klaytn/klaytn/networks/rpc"
    50  	"github.com/klaytn/klaytn/node"
    51  	"github.com/klaytn/klaytn/node/cn/filters"
    52  	"github.com/klaytn/klaytn/node/cn/gasprice"
    53  	"github.com/klaytn/klaytn/node/cn/tracers"
    54  	"github.com/klaytn/klaytn/params"
    55  	"github.com/klaytn/klaytn/reward"
    56  	"github.com/klaytn/klaytn/rlp"
    57  	"github.com/klaytn/klaytn/storage/database"
    58  	"github.com/klaytn/klaytn/work"
    59  )
    60  
    61  var errCNLightSync = errors.New("can't run cn.CN in light sync mode")
    62  
    63  //go:generate mockgen -destination=node/cn/mocks/lesserver_mock.go -package=mocks github.com/klaytn/klaytn/node/cn LesServer
    64  type LesServer interface {
    65  	Start(srvr p2p.Server)
    66  	Stop()
    67  	Protocols() []p2p.Protocol
    68  	SetBloomBitsIndexer(bbIndexer *blockchain.ChainIndexer)
    69  }
    70  
    71  // Miner is an interface of work.Miner used by ServiceChain.
    72  //
    73  //go:generate mockgen -destination=node/cn/mocks/miner_mock.go -package=mocks github.com/klaytn/klaytn/node/cn Miner
    74  type Miner interface {
    75  	Start()
    76  	Stop()
    77  	Register(agent work.Agent)
    78  	Mining() bool
    79  	HashRate() (tot int64)
    80  	SetExtra(extra []byte) error
    81  	Pending() (*types.Block, *state.StateDB)
    82  	PendingBlock() *types.Block
    83  }
    84  
    85  // BackendProtocolManager is an interface of cn.ProtocolManager used from cn.CN and cn.ServiceChain.
    86  //
    87  //go:generate mockgen -destination=node/cn/protocolmanager_mock_test.go github.com/klaytn/klaytn/node/cn BackendProtocolManager
    88  type BackendProtocolManager interface {
    89  	Downloader() ProtocolManagerDownloader
    90  	SetWsEndPoint(wsep string)
    91  	GetSubProtocols() []p2p.Protocol
    92  	ProtocolVersion() int
    93  	ReBroadcastTxs(transactions types.Transactions)
    94  	SetAcceptTxs()
    95  	SetRewardbase(addr common.Address)
    96  	SetRewardbaseWallet(wallet accounts.Wallet)
    97  	NodeType() common.ConnType
    98  	Start(maxPeers int)
    99  	Stop()
   100  	SetSyncStop(flag bool)
   101  }
   102  
   103  // CN implements the Klaytn consensus node service.
   104  type CN struct {
   105  	config      *Config
   106  	chainConfig *params.ChainConfig
   107  
   108  	// Handlers
   109  	txPool          work.TxPool
   110  	blockchain      work.BlockChain
   111  	protocolManager BackendProtocolManager
   112  	lesServer       LesServer
   113  
   114  	// DB interfaces
   115  	chainDB database.DBManager // Block chain database
   116  
   117  	eventMux       *event.TypeMux
   118  	engine         consensus.Engine
   119  	accountManager accounts.AccountManager
   120  
   121  	bloomRequests     chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
   122  	bloomIndexer      *blockchain.ChainIndexer       // Bloom indexer operating during block imports
   123  	closeBloomHandler chan struct{}
   124  
   125  	APIBackend *CNAPIBackend
   126  
   127  	miner    Miner
   128  	gasPrice *big.Int
   129  
   130  	rewardbase common.Address
   131  
   132  	networkId     uint64
   133  	netRPCService *api.PublicNetAPI
   134  
   135  	lock sync.RWMutex // Protects the variadic fields (e.g. gas price)
   136  
   137  	components []interface{}
   138  
   139  	governance governance.Engine
   140  }
   141  
   142  func (s *CN) AddLesServer(ls LesServer) {
   143  	s.lesServer = ls
   144  	ls.SetBloomBitsIndexer(s.bloomIndexer)
   145  }
   146  
   147  // senderTxHashIndexer subscribes chainEvent and stores senderTxHash to txHash mapping information.
   148  func senderTxHashIndexer(db database.DBManager, chainEvent <-chan blockchain.ChainEvent, subscription event.Subscription) {
   149  	defer subscription.Unsubscribe()
   150  
   151  	for {
   152  		select {
   153  		case event := <-chainEvent:
   154  			var err error
   155  			batch := db.NewSenderTxHashToTxHashBatch()
   156  			for _, tx := range event.Block.Transactions() {
   157  				senderTxHash, ok := tx.SenderTxHash()
   158  
   159  				// senderTxHash and txHash are the same if tx is not a fee-delegated tx.
   160  				// Do not store mapping between senderTxHash and txHash in this case.
   161  				if !ok {
   162  					continue
   163  				}
   164  
   165  				txHash := tx.Hash()
   166  
   167  				if err = db.PutSenderTxHashToTxHashToBatch(batch, senderTxHash, txHash); err != nil {
   168  					logger.Error("Failed to store senderTxHash to txHash mapping to database",
   169  						"blockNum", event.Block.Number(), "senderTxHash", senderTxHash, "txHash", txHash, "err", err)
   170  					break
   171  				}
   172  			}
   173  
   174  			if err == nil {
   175  				batch.Write()
   176  			}
   177  
   178  		case <-subscription.Err():
   179  			return
   180  		}
   181  	}
   182  }
   183  
   184  func checkSyncMode(config *Config) error {
   185  	if !config.SyncMode.IsValid() {
   186  		return fmt.Errorf("invalid sync mode %d", config.SyncMode)
   187  	}
   188  	if config.SyncMode == downloader.LightSync {
   189  		return errCNLightSync
   190  	}
   191  	return nil
   192  }
   193  
   194  func setEngineType(chainConfig *params.ChainConfig) {
   195  	if chainConfig.Clique != nil {
   196  		types.EngineType = types.Engine_Clique
   197  	}
   198  	if chainConfig.Istanbul != nil {
   199  		types.EngineType = types.Engine_IBFT
   200  	}
   201  }
   202  
   203  // New creates a new CN object (including the
   204  // initialisation of the common CN object)
   205  func New(ctx *node.ServiceContext, config *Config) (*CN, error) {
   206  	if err := checkSyncMode(config); err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	chainDB := CreateDB(ctx, config, "chaindata")
   211  
   212  	chainConfig, genesisHash, genesisErr := blockchain.SetupGenesisBlock(chainDB, config.Genesis, config.NetworkId, config.IsPrivate, false)
   213  	if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
   214  		return nil, genesisErr
   215  	}
   216  
   217  	setEngineType(chainConfig)
   218  
   219  	// load governance state
   220  	chainConfig.SetDefaults()
   221  	// latest values will be applied to chainConfig after NewMixedEngine call
   222  	governance := governance.NewMixedEngine(chainConfig, chainDB)
   223  	logger.Info("Initialised chain configuration", "config", chainConfig)
   224  
   225  	config.GasPrice = new(big.Int).SetUint64(chainConfig.UnitPrice)
   226  
   227  	cn := &CN{
   228  		config:            config,
   229  		chainDB:           chainDB,
   230  		chainConfig:       chainConfig,
   231  		eventMux:          ctx.EventMux,
   232  		accountManager:    ctx.AccountManager,
   233  		engine:            CreateConsensusEngine(ctx, config, chainConfig, chainDB, governance, ctx.NodeType()),
   234  		networkId:         config.NetworkId,
   235  		gasPrice:          config.GasPrice,
   236  		rewardbase:        config.Rewardbase,
   237  		bloomRequests:     make(chan chan *bloombits.Retrieval),
   238  		bloomIndexer:      NewBloomIndexer(chainDB, params.BloomBitsBlocks),
   239  		closeBloomHandler: make(chan struct{}),
   240  		governance:        governance,
   241  	}
   242  
   243  	// istanbul BFT. Derive and set node's address using nodekey
   244  	if cn.chainConfig.Istanbul != nil {
   245  		governance.SetNodeAddress(crypto.PubkeyToAddress(ctx.NodeKey().PublicKey))
   246  	}
   247  
   248  	logger.Info("Initialising Klaytn protocol", "versions", cn.engine.Protocol().Versions, "network", config.NetworkId)
   249  
   250  	if !config.SkipBcVersionCheck {
   251  		if err := blockchain.CheckBlockChainVersion(chainDB); err != nil {
   252  			return nil, err
   253  		}
   254  	}
   255  	var (
   256  		vmConfig    = config.getVMConfig()
   257  		cacheConfig = &blockchain.CacheConfig{
   258  			ArchiveMode: config.NoPruning, CacheSize: config.TrieCacheSize,
   259  			BlockInterval: config.TrieBlockInterval, TriesInMemory: config.TriesInMemory,
   260  			TrieNodeCacheConfig: &config.TrieNodeCacheConfig, SenderTxHashIndexing: config.SenderTxHashIndexing, SnapshotCacheSize: config.SnapshotCacheSize, SnapshotAsyncGen: config.SnapshotAsyncGen,
   261  		}
   262  	)
   263  
   264  	bc, err := blockchain.NewBlockChain(chainDB, cacheConfig, cn.chainConfig, cn.engine, vmConfig)
   265  	if err != nil {
   266  		return nil, err
   267  	}
   268  	bc.SetCanonicalBlock(config.StartBlockNumber)
   269  
   270  	cn.blockchain = bc
   271  	governance.SetBlockchain(cn.blockchain)
   272  	if err := governance.UpdateParams(cn.blockchain.CurrentBlock().NumberU64()); err != nil {
   273  		return nil, err
   274  	}
   275  	blockchain.InitDeriveShaWithGov(cn.chainConfig, governance)
   276  
   277  	// Synchronize proposerpolicy & useGiniCoeff
   278  	pset, err := governance.EffectiveParams(bc.CurrentBlock().NumberU64() + 1)
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  	if cn.blockchain.Config().Istanbul != nil {
   283  		cn.blockchain.Config().Istanbul.ProposerPolicy = pset.Policy()
   284  	}
   285  	if cn.blockchain.Config().Governance.Reward != nil {
   286  		cn.blockchain.Config().Governance.Reward.UseGiniCoeff = pset.UseGiniCoeff()
   287  	}
   288  
   289  	if config.SenderTxHashIndexing {
   290  		ch := make(chan blockchain.ChainEvent, 255)
   291  		chainEventSubscription := cn.blockchain.SubscribeChainEvent(ch)
   292  		go senderTxHashIndexer(chainDB, ch, chainEventSubscription)
   293  	}
   294  
   295  	// Rewind the chain in case of an incompatible config upgrade.
   296  	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
   297  		logger.Error("Rewinding chain to upgrade configuration", "err", compat)
   298  		cn.blockchain.SetHead(compat.RewindTo)
   299  		chainDB.WriteChainConfig(genesisHash, cn.chainConfig)
   300  	}
   301  	cn.bloomIndexer.Start(cn.blockchain)
   302  
   303  	if config.TxPool.Journal != "" {
   304  		config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
   305  	}
   306  	// TODO-Klaytn-ServiceChain: add account creation prevention in the txPool if TxTypeAccountCreation is supported.
   307  	config.TxPool.NoAccountCreation = config.NoAccountCreation
   308  	cn.txPool = blockchain.NewTxPool(config.TxPool, cn.chainConfig, bc)
   309  	governance.SetTxPool(cn.txPool)
   310  
   311  	// Permit the downloader to use the trie cache allowance during fast sync
   312  	cacheLimit := cacheConfig.TrieNodeCacheConfig.LocalCacheSizeMiB
   313  	if cn.protocolManager, err = NewProtocolManager(cn.chainConfig, config.SyncMode, config.NetworkId, cn.eventMux, cn.txPool, cn.engine, cn.blockchain, chainDB, cacheLimit, ctx.NodeType(), config); err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	if err := cn.setAcceptTxs(); err != nil {
   318  		logger.Error("Failed to decode IstanbulExtra", "err", err)
   319  	}
   320  
   321  	cn.protocolManager.SetWsEndPoint(config.WsEndpoint)
   322  
   323  	if err := cn.setRewardWallet(); err != nil {
   324  		logger.Error("Error happened while setting the reward wallet", "err", err)
   325  	}
   326  
   327  	if pset.Policy() == uint64(istanbul.WeightedRandom) {
   328  		// NewStakingManager is called with proper non-nil parameters
   329  		reward.NewStakingManager(cn.blockchain, governance, cn.chainDB)
   330  	}
   331  
   332  	// set worker
   333  	if config.WorkerDisable {
   334  		cn.miner = work.NewFakeWorker()
   335  		// Istanbul backend can be accessed by APIs to call its methods even though the core of the
   336  		// consensus engine doesn't run.
   337  		istBackend, ok := cn.engine.(consensus.Istanbul)
   338  		if ok {
   339  			istBackend.SetChain(cn.blockchain)
   340  		}
   341  	} else {
   342  		// TODO-Klaytn improve to handle drop transaction on network traffic in PN and EN
   343  		cn.miner = work.New(cn, cn.chainConfig, cn.EventMux(), cn.engine, ctx.NodeType(), crypto.PubkeyToAddress(ctx.NodeKey().PublicKey), cn.config.TxResendUseLegacy)
   344  	}
   345  
   346  	// istanbul BFT
   347  	cn.miner.SetExtra(makeExtraData(config.ExtraData))
   348  
   349  	cn.APIBackend = &CNAPIBackend{cn, nil}
   350  
   351  	gpoParams := config.GPO
   352  
   353  	// NOTE-Klaytn Now we use latest unitPrice
   354  	//         So let's override gpoParams.Default with config.GasPrice
   355  	gpoParams.Default = config.GasPrice
   356  
   357  	cn.APIBackend.gpo = gasprice.NewOracle(cn.APIBackend, gpoParams, cn.txPool)
   358  	//@TODO Klaytn add core component
   359  	cn.addComponent(cn.blockchain)
   360  	cn.addComponent(cn.txPool)
   361  	cn.addComponent(cn.APIs())
   362  	cn.addComponent(cn.ChainDB())
   363  	cn.addComponent(cn.engine)
   364  
   365  	if config.AutoRestartFlag {
   366  		daemonPath := config.DaemonPathFlag
   367  		restartInterval := config.RestartTimeOutFlag
   368  		if restartInterval <= time.Second {
   369  			logger.Crit("Invalid auto-restart timeout", "timeout", restartInterval)
   370  		}
   371  
   372  		// Restarts the node with the same configuration if blockNumber is not changed for a specific time.
   373  		restartTimer := time.AfterFunc(restartInterval, func() {
   374  			logger.Warn("Restart node", "command", daemonPath+" restart")
   375  			cmd := exec.Command(daemonPath, "restart")
   376  			cmd.Run()
   377  		})
   378  		logger.Info("Initialize auto-restart feature", "timeout", restartInterval, "daemonPath", daemonPath)
   379  
   380  		go func() {
   381  			blockChecker := time.NewTicker(time.Second)
   382  			prevBlockNum := cn.blockchain.CurrentBlock().NumberU64()
   383  
   384  			for range blockChecker.C {
   385  				currentBlockNum := cn.blockchain.CurrentBlock().NumberU64()
   386  
   387  				if prevBlockNum != currentBlockNum {
   388  					prevBlockNum = currentBlockNum
   389  					restartTimer.Reset(restartInterval)
   390  				}
   391  			}
   392  		}()
   393  	}
   394  
   395  	// Only for KES nodes
   396  	if config.TrieNodeCacheConfig.RedisSubscribeBlockEnable {
   397  		go cn.blockchain.BlockSubscriptionLoop(cn.txPool.(*blockchain.TxPool))
   398  	}
   399  
   400  	return cn, nil
   401  }
   402  
   403  // setAcceptTxs sets AcceptTxs flag in 1CN case to receive tx propagation.
   404  func (s *CN) setAcceptTxs() error {
   405  	if s.chainConfig.Istanbul != nil {
   406  		istanbulExtra, err := types.ExtractIstanbulExtra(s.blockchain.Genesis().Header())
   407  		if err != nil {
   408  			return err
   409  		} else {
   410  			if len(istanbulExtra.Validators) == 1 {
   411  				s.protocolManager.SetAcceptTxs()
   412  			}
   413  		}
   414  	}
   415  	return nil
   416  }
   417  
   418  // setRewardWallet sets reward base and reward base wallet if the node is CN.
   419  func (s *CN) setRewardWallet() error {
   420  	if s.protocolManager.NodeType() == common.CONSENSUSNODE {
   421  		wallet, err := s.RewardbaseWallet()
   422  		if err != nil {
   423  			return err
   424  		} else {
   425  			s.protocolManager.SetRewardbaseWallet(wallet)
   426  		}
   427  		s.protocolManager.SetRewardbase(s.rewardbase)
   428  	}
   429  	return nil
   430  }
   431  
   432  // add component which may be used in another service component
   433  func (s *CN) addComponent(component interface{}) {
   434  	s.components = append(s.components, component)
   435  }
   436  
   437  func (s *CN) Components() []interface{} {
   438  	return s.components
   439  }
   440  
   441  func (s *CN) SetComponents(component []interface{}) {
   442  	// do nothing
   443  }
   444  
   445  // istanbul BFT
   446  func makeExtraData(extra []byte) []byte {
   447  	if len(extra) == 0 {
   448  		// create default extradata
   449  		extra, _ = rlp.EncodeToBytes([]interface{}{
   450  			uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch),
   451  			"klay",
   452  			runtime.Version(),
   453  			runtime.GOOS,
   454  		})
   455  	}
   456  	if uint64(len(extra)) > params.GetMaximumExtraDataSize() {
   457  		logger.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.GetMaximumExtraDataSize())
   458  		extra = nil
   459  	}
   460  	return extra
   461  }
   462  
   463  // CreateDB creates the chain database.
   464  func CreateDB(ctx *node.ServiceContext, config *Config, name string) database.DBManager {
   465  	dbc := &database.DBConfig{
   466  		Dir: name, DBType: config.DBType, ParallelDBWrite: config.ParallelDBWrite, SingleDB: config.SingleDB, NumStateTrieShards: config.NumStateTrieShards,
   467  		LevelDBCacheSize: config.LevelDBCacheSize, OpenFilesLimit: database.GetOpenFilesLimit(), LevelDBCompression: config.LevelDBCompression,
   468  		LevelDBBufferPool: config.LevelDBBufferPool, EnableDBPerfMetrics: config.EnableDBPerfMetrics, DynamoDBConfig: &config.DynamoDBConfig,
   469  	}
   470  	return ctx.OpenDatabase(dbc)
   471  }
   472  
   473  // CreateConsensusEngine creates the required type of consensus engine instance for a Klaytn service
   474  func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig *params.ChainConfig, db database.DBManager, gov governance.Engine, nodetype common.ConnType) consensus.Engine {
   475  	// Only istanbul  BFT is allowed in the main net. PoA is supported by service chain
   476  	if chainConfig.Governance == nil {
   477  		chainConfig.Governance = params.GetDefaultGovernanceConfig()
   478  	}
   479  	return istanbulBackend.New(config.Rewardbase, &config.Istanbul, ctx.NodeKey(), db, gov, nodetype)
   480  }
   481  
   482  // APIs returns the collection of RPC services the ethereum package offers.
   483  // NOTE, some of these services probably need to be moved to somewhere else.
   484  func (s *CN) APIs() []rpc.API {
   485  	apis, ethAPI := api.GetAPIs(s.APIBackend, s.config.DisableUnsafeDebug)
   486  
   487  	// Append any APIs exposed explicitly by the consensus engine
   488  	apis = append(apis, s.engine.APIs(s.BlockChain())...)
   489  
   490  	publicFilterAPI := filters.NewPublicFilterAPI(s.APIBackend, false)
   491  	governanceKlayAPI := governance.NewGovernanceKlayAPI(s.governance, s.blockchain)
   492  	publicGovernanceAPI := governance.NewGovernanceAPI(s.governance)
   493  	publicDownloaderAPI := downloader.NewPublicDownloaderAPI(s.protocolManager.Downloader(), s.eventMux)
   494  	privateDownloaderAPI := downloader.NewPrivateDownloaderAPI(s.protocolManager.Downloader())
   495  
   496  	ethAPI.SetPublicFilterAPI(publicFilterAPI)
   497  	ethAPI.SetGovernanceKlayAPI(governanceKlayAPI)
   498  	ethAPI.SetPublicGovernanceAPI(publicGovernanceAPI)
   499  
   500  	var tracerAPI *tracers.API
   501  	if s.config.DisableUnsafeDebug {
   502  		tracerAPI = tracers.NewAPIUnsafeDisabled(s.APIBackend)
   503  	} else {
   504  		tracerAPI = tracers.NewAPI(s.APIBackend)
   505  		apis = append(apis, []rpc.API{
   506  			{
   507  				Namespace: "debug",
   508  				Version:   "1.0",
   509  				Service:   NewPrivateDebugAPI(s.chainConfig, s),
   510  				Public:    false,
   511  			},
   512  		}...)
   513  	}
   514  
   515  	// Append all the local APIs and return
   516  	return append(apis, []rpc.API{
   517  		{
   518  			Namespace: "klay",
   519  			Version:   "1.0",
   520  			Service:   NewPublicKlayAPI(s),
   521  			Public:    true,
   522  		}, {
   523  			Namespace: "klay",
   524  			Version:   "1.0",
   525  			Service:   publicDownloaderAPI,
   526  			Public:    true,
   527  		}, {
   528  			Namespace: "klay",
   529  			Version:   "1.0",
   530  			Service:   publicFilterAPI,
   531  			Public:    true,
   532  		}, {
   533  			Namespace: "eth",
   534  			Version:   "1.0",
   535  			Service:   publicDownloaderAPI,
   536  			Public:    true,
   537  		}, {
   538  			Namespace: "admin",
   539  			Version:   "1.0",
   540  			Service:   privateDownloaderAPI,
   541  		}, {
   542  			Namespace: "admin",
   543  			Version:   "1.0",
   544  			Service:   NewPrivateAdminAPI(s),
   545  		}, {
   546  			Namespace: "debug",
   547  			Version:   "1.0",
   548  			Service:   NewPublicDebugAPI(s),
   549  			Public:    false,
   550  		}, {
   551  			Namespace: "debug",
   552  			Version:   "1.0",
   553  			Service:   tracerAPI,
   554  			Public:    false,
   555  		}, {
   556  			Namespace: "net",
   557  			Version:   "1.0",
   558  			Service:   s.netRPCService,
   559  			Public:    true,
   560  		}, {
   561  			Namespace: "governance",
   562  			Version:   "1.0",
   563  			Service:   governance.NewGovernanceAPI(s.governance),
   564  			Public:    true,
   565  		}, {
   566  			Namespace: "klay",
   567  			Version:   "1.0",
   568  			Service:   governanceKlayAPI,
   569  			Public:    true,
   570  		}, {
   571  			Namespace: "eth",
   572  			Version:   "1.0",
   573  			Service:   ethAPI,
   574  			Public:    true,
   575  		},
   576  	}...)
   577  }
   578  
   579  func (s *CN) ResetWithGenesisBlock(gb *types.Block) {
   580  	s.blockchain.ResetWithGenesisBlock(gb)
   581  }
   582  
   583  func (s *CN) Rewardbase() (eb common.Address, err error) {
   584  	s.lock.RLock()
   585  	rewardbase := s.rewardbase
   586  	s.lock.RUnlock()
   587  
   588  	if rewardbase != (common.Address{}) {
   589  		return rewardbase, nil
   590  	}
   591  	if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
   592  		if accounts := wallets[0].Accounts(); len(accounts) > 0 {
   593  			rewardbase := accounts[0].Address
   594  
   595  			s.lock.Lock()
   596  			s.rewardbase = rewardbase
   597  			s.lock.Unlock()
   598  
   599  			logger.Info("Rewardbase automatically configured", "address", rewardbase)
   600  			return rewardbase, nil
   601  		}
   602  	}
   603  
   604  	return common.Address{}, fmt.Errorf("rewardbase must be explicitly specified")
   605  }
   606  
   607  func (s *CN) RewardbaseWallet() (accounts.Wallet, error) {
   608  	rewardBase, err := s.Rewardbase()
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  
   613  	account := accounts.Account{Address: rewardBase}
   614  	wallet, err := s.AccountManager().Find(account)
   615  	if err != nil {
   616  		logger.Error("find err", "err", err)
   617  		return nil, err
   618  	}
   619  	return wallet, nil
   620  }
   621  
   622  func (s *CN) SetRewardbase(rewardbase common.Address) {
   623  	s.lock.Lock()
   624  	s.rewardbase = rewardbase
   625  	s.lock.Unlock()
   626  	wallet, err := s.RewardbaseWallet()
   627  	if err != nil {
   628  		logger.Error("find err", "err", err)
   629  	}
   630  	s.protocolManager.SetRewardbase(rewardbase)
   631  	s.protocolManager.SetRewardbaseWallet(wallet)
   632  }
   633  
   634  func (s *CN) StartMining(local bool) error {
   635  	if local {
   636  		// If local (CPU) mining is started, we can disable the transaction rejection
   637  		// mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous
   638  		// so none will ever hit this path, whereas marking sync done on CPU mining
   639  		// will ensure that private networks work in single miner mode too.
   640  		s.protocolManager.SetAcceptTxs()
   641  	}
   642  	go s.miner.Start()
   643  	return nil
   644  }
   645  
   646  func (s *CN) StopMining()    { s.miner.Stop() }
   647  func (s *CN) IsMining() bool { return s.miner.Mining() }
   648  func (s *CN) Miner() Miner   { return s.miner }
   649  
   650  func (s *CN) AccountManager() accounts.AccountManager { return s.accountManager }
   651  func (s *CN) BlockChain() work.BlockChain             { return s.blockchain }
   652  func (s *CN) TxPool() work.TxPool                     { return s.txPool }
   653  func (s *CN) EventMux() *event.TypeMux                { return s.eventMux }
   654  func (s *CN) Engine() consensus.Engine                { return s.engine }
   655  func (s *CN) ChainDB() database.DBManager             { return s.chainDB }
   656  func (s *CN) IsListening() bool                       { return true } // Always listening
   657  func (s *CN) ProtocolVersion() int                    { return s.protocolManager.ProtocolVersion() }
   658  func (s *CN) NetVersion() uint64                      { return s.networkId }
   659  func (s *CN) Progress() klaytn.SyncProgress           { return s.protocolManager.Downloader().Progress() }
   660  func (s *CN) Governance() governance.Engine           { return s.governance }
   661  
   662  func (s *CN) ReBroadcastTxs(transactions types.Transactions) {
   663  	s.protocolManager.ReBroadcastTxs(transactions)
   664  }
   665  
   666  // Protocols implements node.Service, returning all the currently configured
   667  // network protocols to start.
   668  func (s *CN) Protocols() []p2p.Protocol {
   669  	if s.lesServer == nil {
   670  		return s.protocolManager.GetSubProtocols()
   671  	}
   672  	return append(s.protocolManager.GetSubProtocols(), s.lesServer.Protocols()...)
   673  }
   674  
   675  // Start implements node.Service, starting all internal goroutines needed by the
   676  // Klaytn protocol implementation.
   677  func (s *CN) Start(srvr p2p.Server) error {
   678  	// Start the bloom bits servicing goroutines
   679  	s.startBloomHandlers()
   680  
   681  	// Start the RPC service
   682  	s.netRPCService = api.NewPublicNetAPI(srvr, s.NetVersion())
   683  
   684  	// Figure out a max peers count based on the server limits
   685  	maxPeers := srvr.MaxPeers()
   686  	// Start the networking layer and the light server if requested
   687  	s.protocolManager.Start(maxPeers)
   688  	if s.lesServer != nil {
   689  		s.lesServer.Start(srvr)
   690  	}
   691  
   692  	reward.StakingManagerSubscribe()
   693  
   694  	return nil
   695  }
   696  
   697  // Stop implements node.Service, terminating all internal goroutines used by the
   698  // Klaytn protocol.
   699  func (s *CN) Stop() error {
   700  	// Stop all the peer-related stuff first.
   701  	s.protocolManager.Stop()
   702  	if s.lesServer != nil {
   703  		s.lesServer.Stop()
   704  	}
   705  
   706  	// Then stop everything else.
   707  	s.bloomIndexer.Close()
   708  	close(s.closeBloomHandler)
   709  	s.txPool.Stop()
   710  	s.miner.Stop()
   711  	reward.StakingManagerUnsubscribe()
   712  	s.blockchain.Stop()
   713  	s.chainDB.Close()
   714  	s.eventMux.Stop()
   715  
   716  	return nil
   717  }