Derek
Brief introduction
GitHub Address: Github.com/bytom/bytom
Gitee Address: Gitee.com/bytomblockchain/bytom
This chapter describes the process of Bytom code Initiation, node initialization, and stopping
The author uses the MacOS operating system, and the other platforms are similar
Golang version:1.8
Preparatory work compiling the installation
For detailed steps See official Bytom Install
Set Debug Log Output
Open debug output file, function, line number and other details
export BYTOM_DEBUG=debug
Initialize and start BYTOMD
Initialization
./bytomd init --chain_id testnet
BYTOMD currently supports two types of networks, where we use the test network
Mainnet: Main network
Testnet: Test Network
Start BYTOMD
./bytomd node --mining --prof_laddr=":8011"
--prof_laddr= ": 8080"//Turn on PPROF output performance indicator
Visit: http://127.0.0.1:8080/debug/pprof/
BYTOMD Init initialization
Entry function
* * CMD/BYTOMD/MAIN.GO * *
func init() { log.SetFormatter(&log.TextFormatter{FullTimestamp: true, DisableColors: true}) // If environment variable BYTOM_DEBUG is not empty, // then add the hook to logrus and set the log level to DEBUG if os.Getenv("BYTOM_DEBUG") != "" { log.AddHook(ContextHook{}) log.SetLevel(log.DebugLevel) }}func main() { cmd := cli.PrepareBaseCmd(commands.RootCmd, "TM", os.ExpandEnv(config.DefaultDataDir())) cmd.Execute()}
The INIT function will initialize before main executes, and you can see the BYTOMD load bytom_debug variable in init to set the debug log output
Command CLI parameter initialization
BYTOMD CLI parsing using the Cobra Library
* * Cmd/bytomd/commands * *
- Cmd/bytomd/commands/root.go
Initializes the--root pass parameter. BYTOMD storage configuration, KeyStore, the root directory of the data. Under MacOS, the default path is ~/library/bytom/
- Cmd/bytomd/commands/init.go
Initializes the--chain_id pass parameter. Select the network type, when we start BYTOMD we select Testnet, which is the test network
- Cmd/bytomd/commands/version.go
Initializing version parameters
- Cmd/bytomd/commands/run_node.go
Initialize the parameters required to run node nodes
Initialize default configuration
The user passes only a subset of parameters, and the other parameters required by the node need to be loaded from the default configuration.
* * CMD/BYTOMD/COMMANDS/ROOT.GO * *
var ( config = cfg.DefaultConfig())
In Root.go, there is a config global variable that loads all the default parameters required by node
// Default configurable parameters.func DefaultConfig() *Config { return &Config{ BaseConfig: DefaultBaseConfig(), // node基础相关配置 P2P: DefaultP2PConfig(), // p2p网络相关配置 Wallet: DefaultWalletConfig(), // 钱包相关配置 Auth: DefaultRPCAuthConfig(), // 验证相关配置 Web: DefaultWebConfig(), // web相关配置 }}
Each of the following articles will describe the role of each configuration
BYTOMD Daemon Start and exit
* * CMD/BYTOMD/COMMANDS/RUN_NODE.GO * *
func runNode(cmd *cobra.Command, args []string) error { // Create & start node n := node.NewNode(config) if _, err := n.Start(); err != nil { return fmt.Errorf("Failed to start node: %v", err) } else { log.WithField("nodeInfo", n.SyncManager().Switch().NodeInfo()).Info("Started node") } // Trap signal, run forever. n.RunForever() return nil}
The Runnode function has three steps:
Node. NewNode: Initializing node Runtime environment
N.start: Start node
N.runforever: Listen for exit signal, receive CTRL + C operation to exit node. Keep the process in Linux listen to the sigterm signal (CTRL + C) as a signal to exit the daemon
Initializing the Node runtime environment
In BYTOMD, there are five DB databases stored in the data directory under the--root parameter
- Accesstoken.db//Store Token-related information (Wallet access control rights)
- TRUSTHISTORY.DB//Storage-to-peer network synchronization related information
- TXDB.DB//Store Transaction related information
- Txfeeds.db//
- WALLET.DB//Storage wallet related information
* * Node/node.go * *
Func NewNode (config *cfg. Config) *node {ctx: = context. Background () initactivenetparams (config)//Get Store initializes the TXDB database txdb: = dbm. Newdb ("txdb", config. Dbbackend, CONFIG. Dbdir ()) Store: = Leveldb. Newstore (TXDB)//Initialize Accesstoken database tokendb: = dbm. Newdb ("Accesstoken", config. Dbbackend, CONFIG. Dbdir ()) Accesstokens: = Accesstoken. Newstore (TOKENDB)//Initialize event Scheduler, also known as Task Scheduler. A task can be called multiple times//make event switch Eventswitch: = types. Neweventswitch () _, Err: = Eventswitch.start () if err! = Nil {cmn. Exit (CMN. FMT ("Failed to start switch:%v", err)}//Initialize the trading pool Txpool: = protocol. Newtxpool () chain, err: = protocol. Newchain (store, txpool) if err! = Nil {cmn. Exit (CMN. FMT ("Failed to create chain structure:%v", err)} var accounts *account. Manager = nil var assets *asset. Registry = nil var wallet *w.wallet = nil var txfeed *txfeed. Tracker = nil//Initialize Txfeeds database txfeeddb: = dbm. Newdb ("txfeeds", config. Dbbackend, config. Dbdir ()) Txfeed = Txfeed. Newtracker (TXFEEDDB, chain) If Err = Txfeed.prepare (CTX); Err! = Nil {log. Withfield ("error", err). Error ("Start Txfeed") return nil}//Initialize KeyStore HSM, err: = Pseudohsm. New (config. Keysdir ()) if err! = Nil {cmn. Exit (CMN. FMT ("Initialize HSM failed:%v", err)}//Initialize wallet, default wallet is on if!config. wallet.disable {walletdb: = dbm. NEWDB ("wallet", config. Dbbackend, CONFIG. Dbdir ()) accounts = account. Newmanager (WALLETDB, chain) assets = asset. Newregistry (WALLETDB, chain) wallet, err = W.newwallet (walletdb, accounts, assets, HSM, chain) if err! = Nil {log. Withfield ("error", err). Error ("Init Newwallet")}//Clean up expired UTXO reservations periodically. Go accounts. Expirereservations (CTX, Expirereservationsperiod)} Newblockch: = Make (chan *bc. Hash, Maxnewblockchsize)//Initialize Network node synchronization management SyncManager, _: = Netsync. Newsyncmanager (config, chain, txpool, NEWBLOCKCH)//Initialize PPROF,PPROF for output performance indicators, need to set--PROF_LADDR parameters to open, at the beginning of the article we have opened the function//run the profile server Profilehost : = config. proflistenaddress if Profilehost! = "" {//Profiling BYTOMD Programs.see (blog.golang.org/profiling-go-programs )//GO tool pprof Http://profileHose/debug/pprof/heap go func () {http. Listenandserve (Profilehost, Nil)} ()}//Initialize node, populate all parameters required for node: = &node{Config:config , Syncmanager:syncmanager, Evsw:eventswitch, Accesstokens:accesstokens, wallet: Wallet, Chain:chain, Txfeed:txfeed, Miningenable:config. Mining,}//Initialize mining Node.cpuminer = Cpuminer. Newcpuminer (chain, accounts, Txpool, newblockch) Node.miningpool = Miningpool. Newminingpool (chain, accounts, Txpool, newblockch) node. Baseservice = *cmn. Newbaseservice (Nil, "node", node) return node}
Currently BYTOMD only supports CPU mining, so only cpuminer initialization information in the code
Start node
* * NODE/NODE.GO * *
// Lanch web broser or notfunc lanchWebBroser() { log.Info("Launching System Browser with :", webAddress) if err := browser.Open(webAddress); err != nil { log.Error(err.Error()) return }}func (n *Node) initAndstartApiServer() { n.api = api.NewAPI(n.syncManager, n.wallet, n.txfeed, n.cpuMiner, n.miningPool, n.chain, n.config, n.accessTokens) listenAddr := env.String("LISTEN", n.config.ApiAddress) env.Parse() n.api.StartServer(*listenAddr)}func (n *Node) OnStart() error { if n.miningEnable { n.cpuMiner.Start() } n.syncManager.Start() n.initAndstartApiServer() if !n.config.Web.Closed { lanchWebBroser() } return nil}
OnStart () starts the node process as follows:
- Start Mining function
- Start Peer-Network synchronization
- Apiserver service to start the HTTP protocol
- Open a browser to access Bytond's trading page
Stop node
The BYTOMD executes n at boot time. The Runforever () function, which is the function of the Tendermint framework to initiate a listening signal:
* * VENDOR/GITHUB.COM/TENDERMINT/TMLIBS/COMMON/OS.GO * *
func TrapSignal(cb func()) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { for sig := range c { fmt.Printf("captured %v, exiting...\n", sig) if cb != nil { cb() } os.Exit(1) } }() select {}}
trapsignal function listens to the sigterm signal, BYTOMD can become a daemon that does not quit. The BYTOMD process exits only if CTRL + C or kill bytomd_pid is triggered. When exiting BYTOMD do the following:
* * NODE/NODE.GO * *
func (n *Node) OnStop() { n.BaseService.OnStop() if n.miningEnable { n.cpuMiner.Stop() } n.syncManager.Stop() log.Info("Stopping Node") // TODO: gracefully disconnect from peers.}
The BYTOMD will stop the mining function, and the peer network stops.