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