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 }