github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/node/node.go (about)

     1  package node
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net"
     7  	"net/http"
     8  	_ "net/http/pprof"
     9  	"path/filepath"
    10  
    11  	"github.com/prometheus/prometheus/util/flock"
    12  	log "github.com/sirupsen/logrus"
    13  	cmn "github.com/tendermint/tmlibs/common"
    14  	browser "github.com/toqueteos/webbrowser"
    15  
    16  	"github.com/bytom/bytom/accesstoken"
    17  	"github.com/bytom/bytom/account"
    18  	"github.com/bytom/bytom/api"
    19  	"github.com/bytom/bytom/asset"
    20  	"github.com/bytom/bytom/blockchain/pseudohsm"
    21  	"github.com/bytom/bytom/blockchain/txfeed"
    22  	cfg "github.com/bytom/bytom/config"
    23  	"github.com/bytom/bytom/consensus"
    24  	"github.com/bytom/bytom/database"
    25  	dbm "github.com/bytom/bytom/database/leveldb"
    26  	"github.com/bytom/bytom/env"
    27  	"github.com/bytom/bytom/event"
    28  	bytomLog "github.com/bytom/bytom/log"
    29  	"github.com/bytom/bytom/mining/cpuminer"
    30  	"github.com/bytom/bytom/mining/miningpool"
    31  	"github.com/bytom/bytom/mining/tensority"
    32  	"github.com/bytom/bytom/net/websocket"
    33  	"github.com/bytom/bytom/netsync"
    34  	"github.com/bytom/bytom/p2p"
    35  	"github.com/bytom/bytom/protocol"
    36  	w "github.com/bytom/bytom/wallet"
    37  )
    38  
    39  const (
    40  	webHost   = "http://127.0.0.1"
    41  	logModule = "node"
    42  )
    43  
    44  // Node represent bytom node
    45  type Node struct {
    46  	cmn.BaseService
    47  
    48  	config          *cfg.Config
    49  	eventDispatcher *event.Dispatcher
    50  	syncManager     *netsync.SyncManager
    51  
    52  	wallet          *w.Wallet
    53  	accessTokens    *accesstoken.CredentialStore
    54  	notificationMgr *websocket.WSNotificationManager
    55  	api             *api.API
    56  	chain           *protocol.Chain
    57  	txfeed          *txfeed.Tracker
    58  	cpuMiner        *cpuminer.CPUMiner
    59  	miningPool      *miningpool.MiningPool
    60  	miningEnable    bool
    61  }
    62  
    63  // NewNode create bytom node
    64  func NewNode(config *cfg.Config) *Node {
    65  	ctx := context.Background()
    66  	if err := lockDataDirectory(config); err != nil {
    67  		cmn.Exit("Error: " + err.Error())
    68  	}
    69  
    70  	if err := bytomLog.InitLogFile(config); err != nil {
    71  		log.WithField("err", err).Fatalln("InitLogFile failed")
    72  	}
    73  
    74  	initActiveNetParams(config)
    75  	initCommonConfig(config)
    76  
    77  	// Get store
    78  	if config.DBBackend != "memdb" && config.DBBackend != "leveldb" {
    79  		cmn.Exit(cmn.Fmt("Param db_backend [%v] is invalid, use leveldb or memdb", config.DBBackend))
    80  	}
    81  	coreDB := dbm.NewDB("core", config.DBBackend, config.DBDir())
    82  	store := database.NewStore(coreDB)
    83  
    84  	tokenDB := dbm.NewDB("accesstoken", config.DBBackend, config.DBDir())
    85  	accessTokens := accesstoken.NewStore(tokenDB)
    86  
    87  	dispatcher := event.NewDispatcher()
    88  	txPool := protocol.NewTxPool(store, dispatcher)
    89  	chain, err := protocol.NewChain(store, txPool)
    90  	if err != nil {
    91  		cmn.Exit(cmn.Fmt("Failed to create chain structure: %v", err))
    92  	}
    93  
    94  	var accounts *account.Manager
    95  	var assets *asset.Registry
    96  	var wallet *w.Wallet
    97  	var txFeed *txfeed.Tracker
    98  
    99  	txFeedDB := dbm.NewDB("txfeeds", config.DBBackend, config.DBDir())
   100  	txFeed = txfeed.NewTracker(txFeedDB, chain)
   101  
   102  	if err = txFeed.Prepare(ctx); err != nil {
   103  		log.WithFields(log.Fields{"module": logModule, "error": err}).Error("start txfeed")
   104  		return nil
   105  	}
   106  
   107  	hsm, err := pseudohsm.New(config.KeysDir())
   108  	if err != nil {
   109  		cmn.Exit(cmn.Fmt("initialize HSM failed: %v", err))
   110  	}
   111  
   112  	if !config.Wallet.Disable {
   113  		walletDB := dbm.NewDB("wallet", config.DBBackend, config.DBDir())
   114  		accounts = account.NewManager(walletDB, chain)
   115  		assets = asset.NewRegistry(walletDB, chain)
   116  		wallet, err = w.NewWallet(walletDB, accounts, assets, hsm, chain, dispatcher, config.Wallet.TxIndex)
   117  		if err != nil {
   118  			log.WithFields(log.Fields{"module": logModule, "error": err}).Error("init NewWallet")
   119  		}
   120  
   121  		// trigger rescan wallet
   122  		if config.Wallet.Rescan {
   123  			wallet.RescanBlocks()
   124  		}
   125  	}
   126  
   127  	syncManager, err := netsync.NewSyncManager(config, chain, txPool, dispatcher)
   128  	if err != nil {
   129  		cmn.Exit(cmn.Fmt("Failed to create sync manager: %v", err))
   130  	}
   131  
   132  	notificationMgr := websocket.NewWsNotificationManager(config.Websocket.MaxNumWebsockets, config.Websocket.MaxNumConcurrentReqs, chain, dispatcher)
   133  
   134  	// run the profile server
   135  	profileHost := config.ProfListenAddress
   136  	if profileHost != "" {
   137  		// Profiling bytomd programs.see (https://blog.golang.org/profiling-go-programs)
   138  		// go tool pprof http://profileHose/debug/pprof/heap
   139  		go func() {
   140  			if err = http.ListenAndServe(profileHost, nil); err != nil {
   141  				cmn.Exit(cmn.Fmt("Failed to register tcp profileHost: %v", err))
   142  			}
   143  		}()
   144  	}
   145  
   146  	node := &Node{
   147  		eventDispatcher: dispatcher,
   148  		config:          config,
   149  		syncManager:     syncManager,
   150  		accessTokens:    accessTokens,
   151  		wallet:          wallet,
   152  		chain:           chain,
   153  		txfeed:          txFeed,
   154  		miningEnable:    config.Mining,
   155  
   156  		notificationMgr: notificationMgr,
   157  	}
   158  
   159  	node.cpuMiner = cpuminer.NewCPUMiner(chain, accounts, txPool, dispatcher)
   160  	node.miningPool = miningpool.NewMiningPool(chain, accounts, txPool, dispatcher)
   161  
   162  	node.BaseService = *cmn.NewBaseService(nil, "Node", node)
   163  
   164  	if config.Simd.Enable {
   165  		tensority.UseSIMD = true
   166  	}
   167  
   168  	return node
   169  }
   170  
   171  // Lock data directory after daemonization
   172  func lockDataDirectory(config *cfg.Config) error {
   173  	_, _, err := flock.New(filepath.Join(config.RootDir, "LOCK"))
   174  	if err != nil {
   175  		return errors.New("datadir already used by another process")
   176  	}
   177  	return nil
   178  }
   179  
   180  func initActiveNetParams(config *cfg.Config) {
   181  	var exist bool
   182  	consensus.ActiveNetParams, exist = consensus.NetParams[config.ChainID]
   183  	if !exist {
   184  		cmn.Exit(cmn.Fmt("chain_id[%v] don't exist", config.ChainID))
   185  	}
   186  }
   187  
   188  func initCommonConfig(config *cfg.Config) {
   189  	cfg.CommonConfig = config
   190  }
   191  
   192  // Lanch web broser or not
   193  func launchWebBrowser(port string) {
   194  	webAddress := webHost + ":" + port
   195  	log.Info("Launching System Browser with :", webAddress)
   196  	if err := browser.Open(webAddress); err != nil {
   197  		log.Error(err.Error())
   198  		return
   199  	}
   200  }
   201  
   202  func (n *Node) initAndstartAPIServer() {
   203  	n.api = api.NewAPI(n.syncManager, n.wallet, n.txfeed, n.cpuMiner, n.miningPool, n.chain, n.config, n.accessTokens, n.eventDispatcher, n.notificationMgr)
   204  
   205  	listenAddr := env.String("LISTEN", n.config.ApiAddress)
   206  	env.Parse()
   207  	n.api.StartServer(*listenAddr)
   208  }
   209  
   210  func (n *Node) OnStart() error {
   211  	if n.miningEnable {
   212  		if _, err := n.wallet.AccountMgr.GetMiningAddress(); err != nil {
   213  			n.miningEnable = false
   214  			log.Error(err)
   215  		} else {
   216  			n.cpuMiner.Start()
   217  		}
   218  	}
   219  	if !n.config.VaultMode {
   220  		if err := n.syncManager.Start(); err != nil {
   221  			return err
   222  		}
   223  	}
   224  
   225  	n.initAndstartAPIServer()
   226  	if err := n.notificationMgr.Start(); err != nil {
   227  		return err
   228  	}
   229  
   230  	if !n.config.Web.Closed {
   231  		_, port, err := net.SplitHostPort(n.config.ApiAddress)
   232  		if err != nil {
   233  			log.Error("Invalid api address")
   234  			return err
   235  		}
   236  		launchWebBrowser(port)
   237  	}
   238  	return nil
   239  }
   240  
   241  func (n *Node) OnStop() {
   242  	n.notificationMgr.Shutdown()
   243  	n.notificationMgr.WaitForShutdown()
   244  	n.BaseService.OnStop()
   245  	if n.miningEnable {
   246  		n.cpuMiner.Stop()
   247  	}
   248  	if !n.config.VaultMode {
   249  		n.syncManager.Stop()
   250  	}
   251  	n.eventDispatcher.Stop()
   252  }
   253  
   254  func (n *Node) RunForever() {
   255  	// Sleep forever and then...
   256  	cmn.TrapSignal(func() {
   257  		n.Stop()
   258  	})
   259  }
   260  
   261  func (n *Node) NodeInfo() *p2p.NodeInfo {
   262  	return n.syncManager.NodeInfo()
   263  }
   264  
   265  func (n *Node) MiningPool() *miningpool.MiningPool {
   266  	return n.miningPool
   267  }