github.com/platonnetwork/platon-go@v0.7.6/eth/backend.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package eth implements the Ethereum protocol.
    18  package eth
    19  
    20  import (
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"sync"
    25  	"sync/atomic"
    26  
    27  	"github.com/PlatONnetwork/PlatON-Go/x/gov"
    28  
    29  	"github.com/PlatONnetwork/PlatON-Go/x/handler"
    30  
    31  	"github.com/PlatONnetwork/PlatON-Go/core/snapshotdb"
    32  
    33  	"github.com/PlatONnetwork/PlatON-Go/consensus/cbft/evidence"
    34  
    35  	"github.com/PlatONnetwork/PlatON-Go/accounts"
    36  	"github.com/PlatONnetwork/PlatON-Go/common"
    37  	"github.com/PlatONnetwork/PlatON-Go/consensus"
    38  	"github.com/PlatONnetwork/PlatON-Go/consensus/cbft"
    39  	ctypes "github.com/PlatONnetwork/PlatON-Go/consensus/cbft/types"
    40  	"github.com/PlatONnetwork/PlatON-Go/consensus/cbft/validator"
    41  	"github.com/PlatONnetwork/PlatON-Go/core"
    42  	"github.com/PlatONnetwork/PlatON-Go/core/bloombits"
    43  	"github.com/PlatONnetwork/PlatON-Go/core/rawdb"
    44  	"github.com/PlatONnetwork/PlatON-Go/core/types"
    45  	"github.com/PlatONnetwork/PlatON-Go/core/vm"
    46  	"github.com/PlatONnetwork/PlatON-Go/eth/downloader"
    47  	"github.com/PlatONnetwork/PlatON-Go/eth/filters"
    48  	"github.com/PlatONnetwork/PlatON-Go/eth/gasprice"
    49  	"github.com/PlatONnetwork/PlatON-Go/ethdb"
    50  	"github.com/PlatONnetwork/PlatON-Go/event"
    51  	"github.com/PlatONnetwork/PlatON-Go/internal/ethapi"
    52  	"github.com/PlatONnetwork/PlatON-Go/log"
    53  	"github.com/PlatONnetwork/PlatON-Go/miner"
    54  	"github.com/PlatONnetwork/PlatON-Go/node"
    55  	"github.com/PlatONnetwork/PlatON-Go/p2p"
    56  	"github.com/PlatONnetwork/PlatON-Go/p2p/discover"
    57  	"github.com/PlatONnetwork/PlatON-Go/params"
    58  	"github.com/PlatONnetwork/PlatON-Go/rpc"
    59  	xplugin "github.com/PlatONnetwork/PlatON-Go/x/plugin"
    60  	"github.com/PlatONnetwork/PlatON-Go/x/xcom"
    61  )
    62  
    63  type LesServer interface {
    64  	Start(srvr *p2p.Server)
    65  	Stop()
    66  	Protocols() []p2p.Protocol
    67  	SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
    68  }
    69  
    70  // Ethereum implements the Ethereum full node service.
    71  type Ethereum struct {
    72  	config      *Config
    73  	chainConfig *params.ChainConfig
    74  
    75  	// Channel for shutting down the service
    76  	shutdownChan chan bool // Channel for shutting down the Ethereum
    77  
    78  	// Handlers
    79  	txPool          *core.TxPool
    80  	blockchain      *core.BlockChain
    81  	protocolManager *ProtocolManager
    82  	lesServer       LesServer
    83  	// modify
    84  	//mpcPool *core.MPCPool
    85  	//vcPool  *core.VCPool
    86  
    87  	// DB interfaces
    88  	chainDb ethdb.Database // Block chain database
    89  
    90  	eventMux       *event.TypeMux
    91  	engine         consensus.Engine
    92  	accountManager *accounts.Manager
    93  
    94  	bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
    95  	bloomIndexer  *core.ChainIndexer             // Bloom indexer operating during block imports
    96  
    97  	APIBackend *EthAPIBackend
    98  
    99  	miner         *miner.Miner
   100  	gasPrice      *big.Int
   101  	networkID     uint64
   102  	netRPCService *ethapi.PublicNetAPI
   103  
   104  	lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
   105  }
   106  
   107  func (s *Ethereum) AddLesServer(ls LesServer) {
   108  	s.lesServer = ls
   109  	ls.SetBloomBitsIndexer(s.bloomIndexer)
   110  }
   111  
   112  // New creates a new Ethereum object (including the
   113  // initialisation of the common Ethereum object)
   114  func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
   115  	// Ensure configuration values are compatible and sane
   116  	if config.SyncMode == downloader.LightSync {
   117  		return nil, errors.New("can't run eth.PlatON in light sync mode, use les.LightPlatON")
   118  	}
   119  	if !config.SyncMode.IsValid() {
   120  		return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
   121  	}
   122  	if config.MinerGasPrice == nil || config.MinerGasPrice.Cmp(common.Big0) <= 0 {
   123  		log.Warn("Sanitizing invalid miner gas price", "provided", config.MinerGasPrice, "updated", DefaultConfig.MinerGasPrice)
   124  		config.MinerGasPrice = new(big.Int).Set(DefaultConfig.MinerGasPrice)
   125  	}
   126  	// Assemble the Ethereum object
   127  	chainDb, err := CreateDB(ctx, config, "chaindata")
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	snapshotdb.SetDBOptions(config.DatabaseCache, config.DatabaseHandles)
   132  
   133  	chainConfig, _, genesisErr := core.SetupGenesisBlock(chainDb, ctx.ResolvePath(snapshotdb.DBPath), config.Genesis)
   134  
   135  	if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
   136  		return nil, genesisErr
   137  	}
   138  
   139  	if chainConfig.Cbft.Period == 0 || chainConfig.Cbft.Amount == 0 {
   140  		chainConfig.Cbft.Period = config.CbftConfig.Period
   141  		chainConfig.Cbft.Amount = config.CbftConfig.Amount
   142  	}
   143  
   144  	log.Info("Initialised chain configuration", "config", chainConfig)
   145  
   146  	eth := &Ethereum{
   147  		config:         config,
   148  		chainDb:        chainDb,
   149  		chainConfig:    chainConfig,
   150  		eventMux:       ctx.EventMux,
   151  		accountManager: ctx.AccountManager,
   152  		engine:         CreateConsensusEngine(ctx, chainConfig, config.MinerNoverify, chainDb, &config.CbftConfig, ctx.EventMux),
   153  		shutdownChan:   make(chan bool),
   154  		networkID:      config.NetworkId,
   155  		gasPrice:       config.MinerGasPrice,
   156  		bloomRequests:  make(chan chan *bloombits.Retrieval),
   157  		bloomIndexer:   NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
   158  	}
   159  
   160  	log.Info("Initialising PlatON protocol", "versions", ProtocolVersions, "network", config.NetworkId)
   161  
   162  	if !config.SkipBcVersionCheck {
   163  		bcVersion := rawdb.ReadDatabaseVersion(chainDb)
   164  		if bcVersion != config.BlockChainVersion && bcVersion != 0 {
   165  			return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d).\n", bcVersion, config.BlockChainVersion)
   166  		}
   167  		rawdb.WriteDatabaseVersion(chainDb, config.BlockChainVersion)
   168  	}
   169  	var (
   170  		vmConfig = vm.Config{
   171  			ConsoleOutput: config.Debug,
   172  		}
   173  		cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout,
   174  			BodyCacheLimit: config.BodyCacheLimit, BlockCacheLimit: config.BlockCacheLimit,
   175  			MaxFutureBlocks: config.MaxFutureBlocks, BadBlockLimit: config.BadBlockLimit,
   176  			TriesInMemory: config.TriesInMemory, TrieDBCache: config.TrieDBCache,
   177  			DBGCInterval: config.DBGCInterval, DBGCTimeout: config.DBGCTimeout,
   178  			DBGCMpt: config.DBGCMpt, DBGCBlock: config.DBGCBlock,
   179  		}
   180  
   181  		minningConfig = &core.MiningConfig{MiningLogAtDepth: config.MiningLogAtDepth, TxChanSize: config.TxChanSize,
   182  			ChainHeadChanSize: config.ChainHeadChanSize, ChainSideChanSize: config.ChainSideChanSize,
   183  			ResultQueueSize: config.ResultQueueSize, ResubmitAdjustChanSize: config.ResubmitAdjustChanSize,
   184  			MinRecommitInterval: config.MinRecommitInterval, MaxRecommitInterval: config.MaxRecommitInterval,
   185  			IntervalAdjustRatio: config.IntervalAdjustRatio, IntervalAdjustBias: config.IntervalAdjustBias,
   186  			StaleThreshold: config.StaleThreshold, DefaultCommitRatio: config.DefaultCommitRatio,
   187  		}
   188  	)
   189  	cacheConfig.DBDisabledGC.Set(config.DBDisabledGC)
   190  
   191  	eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	snapshotdb.SetDBBlockChain(eth.blockchain)
   196  
   197  	blockChainCache := core.NewBlockChainCache(eth.blockchain)
   198  
   199  	// Rewind the chain in case of an incompatible config upgrade.
   200  	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
   201  		log.Warn("Rewinding chain to upgrade configuration", "err", compat)
   202  		return nil, compat
   203  		//eth.blockchain.SetHead(compat.RewindTo)
   204  		//rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
   205  	}
   206  	eth.bloomIndexer.Start(eth.blockchain)
   207  
   208  	if config.TxPool.Journal != "" {
   209  		config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
   210  	}
   211  	//eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)
   212  	eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, blockChainCache)
   213  
   214  	// mpcPool deal with mpc transactions
   215  	// modify By J
   216  	//if config.MPCPool.Journal != "" {
   217  	//	config.MPCPool.Journal = ctx.ResolvePath(config.MPCPool.Journal)
   218  	//} else {
   219  	//	config.MPCPool.Journal = ctx.ResolvePath(core.DefaultMPCPoolConfig.Journal)
   220  	//}
   221  	//if config.MPCPool.Rejournal == 0 {
   222  	//	config.MPCPool.Rejournal = core.DefaultMPCPoolConfig.Rejournal
   223  	//}
   224  	//if config.MPCPool.Lifetime == 0 {
   225  	//	config.MPCPool.Lifetime = core.DefaultMPCPoolConfig.Lifetime
   226  	//}
   227  	//eth.mpcPool = core.NewMPCPool(config.MPCPool, eth.chainConfig, eth.blockchain)
   228  	//eth.vcPool = core.NewVCPool(config.VCPool, eth.chainConfig, eth.blockchain)
   229  
   230  	// modify by platon remove consensusCache
   231  	//var consensusCache *cbft.Cache = cbft.NewCache(eth.blockchain)
   232  
   233  	currentBlock := eth.blockchain.CurrentBlock()
   234  	currentNumber := currentBlock.NumberU64()
   235  	currentHash := currentBlock.Hash()
   236  	gasCeil, err := gov.GovernMaxBlockGasLimit(currentNumber, currentHash)
   237  	if nil != err {
   238  		log.Error("Failed to query gasCeil from snapshotdb", "err", err)
   239  		return nil, err
   240  	}
   241  	if config.MinerGasFloor > uint64(gasCeil) {
   242  		log.Error("The gasFloor must be less than gasCeil", "gasFloor", config.MinerGasFloor, "gasCeil", gasCeil)
   243  		return nil, fmt.Errorf("The gasFloor must be less than gasCeil, got: %d, expect range (0, %d]", config.MinerGasFloor, gasCeil)
   244  	}
   245  
   246  	eth.miner = miner.New(eth, eth.chainConfig, minningConfig, eth.EventMux(), eth.engine, config.MinerRecommit,
   247  		config.MinerGasFloor /*config.MinerGasCeil,*/, eth.isLocalBlock, blockChainCache)
   248  
   249  	//extra data for each block will be set by worker.go
   250  	//eth.miner.SetExtra(makeExtraData(eth.blockchain, config.MinerExtraData))
   251  
   252  	reactor := core.NewBlockChainReactor(eth.EventMux())
   253  	node.GetCryptoHandler().SetPrivateKey(config.CbftConfig.NodePriKey)
   254  
   255  	if engine, ok := eth.engine.(consensus.Bft); ok {
   256  
   257  		var agency consensus.Agency
   258  		// validatorMode:
   259  		// - static (default)
   260  		// - inner (via inner contract)eth/handler.go
   261  		// - ppos
   262  
   263  		log.Debug("Validator mode", "mode", chainConfig.Cbft.ValidatorMode)
   264  		if chainConfig.Cbft.ValidatorMode == "" || chainConfig.Cbft.ValidatorMode == common.STATIC_VALIDATOR_MODE {
   265  			agency = validator.NewStaticAgency(chainConfig.Cbft.InitialNodes)
   266  			reactor.Start(common.STATIC_VALIDATOR_MODE)
   267  		} else if chainConfig.Cbft.ValidatorMode == common.INNER_VALIDATOR_MODE {
   268  			blocksPerNode := int(chainConfig.Cbft.Amount)
   269  			offset := blocksPerNode * 2
   270  			agency = validator.NewInnerAgency(chainConfig.Cbft.InitialNodes, eth.blockchain, blocksPerNode, offset)
   271  			reactor.Start(common.INNER_VALIDATOR_MODE)
   272  		} else if chainConfig.Cbft.ValidatorMode == common.PPOS_VALIDATOR_MODE {
   273  			reactor.Start(common.PPOS_VALIDATOR_MODE)
   274  			reactor.SetVRFhandler(handler.NewVrfHandler(eth.blockchain.Genesis().Nonce()))
   275  			reactor.SetPluginEventMux()
   276  			reactor.SetPrivateKey(ctx.NodePriKey())
   277  			handlePlugin(reactor)
   278  			agency = reactor
   279  
   280  			//register Govern parameter verifiers
   281  			gov.RegisterGovernParamVerifiers()
   282  		}
   283  
   284  		if err := recoverSnapshotDB(blockChainCache); err != nil {
   285  			log.Error("recover SnapshotDB fail", "error", err)
   286  			return nil, errors.New("Failed to recover SnapshotDB")
   287  		}
   288  
   289  		if err := engine.Start(eth.blockchain, blockChainCache, eth.txPool, agency); err != nil {
   290  			log.Error("Init cbft consensus engine fail", "error", err)
   291  			return nil, errors.New("Failed to init cbft consensus engine")
   292  		}
   293  	}
   294  
   295  	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	eth.APIBackend = &EthAPIBackend{eth, nil}
   300  	gpoParams := config.GPO
   301  	if gpoParams.Default == nil {
   302  		gpoParams.Default = config.MinerGasPrice
   303  	}
   304  	eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
   305  
   306  	return eth, nil
   307  }
   308  
   309  func recoverSnapshotDB(blockChainCache *core.BlockChainCache) error {
   310  	sdb := snapshotdb.Instance()
   311  	ch := sdb.GetCurrent().GetHighest(false).Num.Uint64()
   312  	blockChanHegiht := blockChainCache.CurrentHeader().Number.Uint64()
   313  	if ch < blockChanHegiht {
   314  		for i := ch + 1; i <= blockChanHegiht; i++ {
   315  			block, parentBlock := blockChainCache.GetBlockByNumber(i), blockChainCache.GetBlockByNumber(i-1)
   316  			log.Debug("snapshotdb recover block from blockchain", "num", block.Number(), "hash", block.Hash())
   317  			if err := blockChainCache.Execute(block, parentBlock); err != nil {
   318  				log.Error("snapshotdb recover block from blockchain  execute fail", "error", err)
   319  				return err
   320  			}
   321  			if err := sdb.Commit(block.Hash()); err != nil {
   322  				log.Error("snapshotdb recover block from blockchain  Commit fail", "error", err)
   323  				return err
   324  			}
   325  		}
   326  	}
   327  	return nil
   328  }
   329  
   330  // CreateDB creates the chain database.
   331  func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) {
   332  	db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles)
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  	if db, ok := db.(*ethdb.LDBDatabase); ok {
   337  		db.Meter("eth/db/chaindata/")
   338  	}
   339  	return db, nil
   340  }
   341  
   342  // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
   343  func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, noverify bool, db ethdb.Database,
   344  	cbftConfig *ctypes.OptionsConfig, eventMux *event.TypeMux) consensus.Engine {
   345  	// If proof-of-authority is requested, set it up
   346  	engine := cbft.New(chainConfig.Cbft, cbftConfig, eventMux, ctx)
   347  	if engine == nil {
   348  		panic("create consensus engine fail")
   349  	}
   350  	return engine
   351  }
   352  
   353  // APIs return the collection of RPC services the ethereum package offers.
   354  // NOTE, some of these services probably need to be moved to somewhere else.
   355  func (s *Ethereum) APIs() []rpc.API {
   356  	apis := ethapi.GetAPIs(s.APIBackend)
   357  
   358  	// Append any APIs exposed explicitly by the consensus engine
   359  	apis = append(apis, s.engine.APIs(s.BlockChain())...)
   360  
   361  	// Append all the local APIs and return
   362  	return append(apis, []rpc.API{
   363  		{
   364  			Namespace: "platon",
   365  			Version:   "1.0",
   366  			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
   367  			Public:    true,
   368  		}, {
   369  			Namespace: "miner",
   370  			Version:   "1.0",
   371  			Service:   NewPrivateMinerAPI(s),
   372  			Public:    false,
   373  		}, {
   374  			Namespace: "platon",
   375  			Version:   "1.0",
   376  			Service:   filters.NewPublicFilterAPI(s.APIBackend, false),
   377  			Public:    true,
   378  		}, {
   379  			Namespace: "admin",
   380  			Version:   "1.0",
   381  			Service:   NewPrivateAdminAPI(s),
   382  		}, {
   383  			Namespace: "debug",
   384  			Version:   "1.0",
   385  			Service:   NewPublicDebugAPI(s),
   386  			Public:    true,
   387  		}, {
   388  			Namespace: "debug",
   389  			Version:   "1.0",
   390  			Service:   NewPrivateDebugAPI(s.chainConfig, s),
   391  		}, {
   392  			Namespace: "net",
   393  			Version:   "1.0",
   394  			Service:   s.netRPCService,
   395  			Public:    true,
   396  		},
   397  	}...)
   398  }
   399  
   400  //func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
   401  //	s.blockchain.ResetWithGenesisBlock(gb)
   402  //}
   403  
   404  // isLocalBlock checks whether the specified block is mined
   405  // by local miner accounts.
   406  //
   407  // We regard two types of accounts as local miner account: etherbase
   408  // and accounts specified via `txpool.locals` flag.
   409  func (s *Ethereum) isLocalBlock(block *types.Block) bool {
   410  	author, err := s.engine.Author(block.Header())
   411  	if err != nil {
   412  		log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err)
   413  		return false
   414  	}
   415  	// Check whether the given address is etherbase.
   416  	s.lock.RLock()
   417  	etherbase := common.Address{}
   418  	s.lock.RUnlock()
   419  	if author == etherbase {
   420  		return true
   421  	}
   422  	// Check whether the given address is specified by `txpool.local`
   423  	// CLI flag.
   424  	for _, account := range s.config.TxPool.Locals {
   425  		if account == author {
   426  			return true
   427  		}
   428  	}
   429  	return false
   430  }
   431  
   432  // shouldPreserve checks whether we should preserve the given block
   433  // during the chain reorg depending on whether the author of block
   434  // is a local account.
   435  func (s *Ethereum) shouldPreserve(block *types.Block) bool {
   436  	// The reason we need to disable the self-reorg preserving for clique
   437  	// is it can be probable to introduce a deadlock.
   438  	//
   439  	// e.g. If there are 7 available signers
   440  	//
   441  	// r1   A
   442  	// r2     B
   443  	// r3       C
   444  	// r4         D
   445  	// r5   A      [X] F G
   446  	// r6    [X]
   447  	//
   448  	// In the round5, the inturn signer E is offline, so the worst case
   449  	// is A, F and G sign the block of round5 and reject the block of opponents
   450  	// and in the round6, the last available signer B is offline, the whole
   451  	// network is stuck.
   452  	return s.isLocalBlock(block)
   453  }
   454  
   455  //start mining
   456  func (s *Ethereum) StartMining() error {
   457  	// If the miner was not running, initialize it
   458  	if !s.IsMining() {
   459  		// Propagate the initial price point to the transaction pool
   460  		s.lock.RLock()
   461  		price := s.gasPrice
   462  		s.lock.RUnlock()
   463  		s.txPool.SetGasPrice(price)
   464  
   465  		// If mining is started, we can disable the transaction rejection mechanism
   466  		// introduced to speed sync times.
   467  		atomic.StoreUint32(&s.protocolManager.acceptTxs, 1)
   468  
   469  		go s.miner.Start()
   470  	}
   471  	return nil
   472  }
   473  
   474  // StopMining terminates the miner, both at the consensus engine level as well as
   475  // at the block creation level.
   476  func (s *Ethereum) StopMining() {
   477  	s.miner.Stop()
   478  }
   479  
   480  func (s *Ethereum) IsMining() bool      { return s.miner.Mining() }
   481  func (s *Ethereum) Miner() *miner.Miner { return s.miner }
   482  
   483  func (s *Ethereum) AccountManager() *accounts.Manager  { return s.accountManager }
   484  func (s *Ethereum) BlockChain() *core.BlockChain       { return s.blockchain }
   485  func (s *Ethereum) TxPool() *core.TxPool               { return s.txPool }
   486  func (s *Ethereum) EventMux() *event.TypeMux           { return s.eventMux }
   487  func (s *Ethereum) Engine() consensus.Engine           { return s.engine }
   488  func (s *Ethereum) ChainDb() ethdb.Database            { return s.chainDb }
   489  func (s *Ethereum) IsListening() bool                  { return true } // Always listening
   490  func (s *Ethereum) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }
   491  func (s *Ethereum) NetVersion() uint64                 { return s.networkID }
   492  func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
   493  
   494  // Protocols implements node.Service, returning all the currently configured
   495  // network protocols to start.
   496  func (s *Ethereum) Protocols() []p2p.Protocol {
   497  	protocols := make([]p2p.Protocol, 0)
   498  	protocols = append(protocols, s.protocolManager.SubProtocols...)
   499  	protocols = append(protocols, s.engine.Protocols()...)
   500  
   501  	if s.lesServer == nil {
   502  		return protocols
   503  	}
   504  	protocols = append(protocols, s.lesServer.Protocols()...)
   505  	return protocols
   506  }
   507  
   508  // Start implements node.Service, starting all internal goroutines needed by the
   509  // Ethereum protocol implementation.
   510  func (s *Ethereum) Start(srvr *p2p.Server) error {
   511  	// Start the bloom bits servicing goroutines
   512  	s.startBloomHandlers(params.BloomBitsBlocks)
   513  
   514  	// Start the RPC service
   515  	s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
   516  
   517  	// Figure out a max peers count based on the server limits
   518  	maxPeers := srvr.MaxPeers
   519  	if s.config.LightServ > 0 {
   520  		if s.config.LightPeers >= srvr.MaxPeers {
   521  			return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers)
   522  		}
   523  		maxPeers -= s.config.LightPeers
   524  	}
   525  	// Start the networking layer and the light server if requested
   526  	s.protocolManager.Start(maxPeers)
   527  
   528  	//log.Debug("node start", "srvr.Config.PrivateKey", srvr.Config.PrivateKey)
   529  	if cbftEngine, ok := s.engine.(consensus.Bft); ok {
   530  		if flag := cbftEngine.IsConsensusNode(); flag {
   531  			for _, n := range s.chainConfig.Cbft.InitialNodes {
   532  				// todo: Mock point.
   533  				if !node.FakeNetEnable {
   534  					srvr.AddConsensusPeer(discover.NewNode(n.Node.ID, n.Node.IP, n.Node.UDP, n.Node.TCP))
   535  				}
   536  			}
   537  		}
   538  		s.StartMining()
   539  	}
   540  	srvr.StartWatching(s.eventMux)
   541  
   542  	if s.lesServer != nil {
   543  		s.lesServer.Start(srvr)
   544  	}
   545  	return nil
   546  }
   547  
   548  // Stop implements node.Service, terminating all internal goroutines used by the
   549  // Ethereum protocol.
   550  func (s *Ethereum) Stop() error {
   551  	s.bloomIndexer.Close()
   552  	s.blockchain.Stop()
   553  	s.protocolManager.Stop()
   554  	s.engine.Close()
   555  	if s.lesServer != nil {
   556  		s.lesServer.Stop()
   557  	}
   558  	s.txPool.Stop()
   559  	s.miner.Stop()
   560  	s.eventMux.Stop()
   561  
   562  	core.GetReactorInstance().Close()
   563  	s.chainDb.Close()
   564  	close(s.shutdownChan)
   565  	return nil
   566  }
   567  
   568  // RegisterPlugin one by one
   569  func handlePlugin(reactor *core.BlockChainReactor) {
   570  	xplugin.RewardMgrInstance().SetCurrentNodeID(reactor.NodeId)
   571  
   572  	reactor.RegisterPlugin(xcom.SlashingRule, xplugin.SlashInstance())
   573  	xplugin.SlashInstance().SetDecodeEvidenceFun(evidence.NewEvidence)
   574  	reactor.RegisterPlugin(xcom.StakingRule, xplugin.StakingInstance())
   575  	reactor.RegisterPlugin(xcom.RestrictingRule, xplugin.RestrictingInstance())
   576  	reactor.RegisterPlugin(xcom.RewardRule, xplugin.RewardMgrInstance())
   577  	reactor.RegisterPlugin(xcom.GovernanceRule, xplugin.GovPluginInstance())
   578  
   579  	// set rule order
   580  	reactor.SetBeginRule([]int{xcom.StakingRule, xcom.SlashingRule, xcom.GovernanceRule})
   581  	reactor.SetEndRule([]int{xcom.RestrictingRule, xcom.RewardRule, xcom.GovernanceRule, xcom.StakingRule})
   582  
   583  }