Derek解讀Bytom源碼-啟動與停止

來源:互聯網
上載者:User

作者:Derek

簡介

Github地址:https://github.com/Bytom/bytom

Gitee地址:https://gitee.com/BytomBlockc...

本章介紹bytom代碼啟動、節點初始化、及停止的過程

作者使用MacOS作業系統,其他平台也大同小異
Golang Version: 1.8

預備工作

編譯安裝

詳細步驟見官方 bytom install

設定debug日誌輸出

開啟debug輸出檔案、函數、行號等詳細資料

export BYTOM_DEBUG=debug

初始化並啟動bytomd

初始化

./bytomd init --chain_id testnet

bytomd目前支援兩種網路,這裡我們使用測試網
mainnet:主網
testnet:測試網

啟動bytomd

./bytomd node --mining --prof_laddr=":8011"

--prof_laddr=":8080" // 開啟pprof輸出效能指標
訪問:http://127.0.0.1:8080/debug/pprof/

bytomd init初始化

入口函數
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()}

init函數會在main執行之前做初始化操作,可以看到init中bytomd載入BYTOM_DEBUG變數來設定debug日誌輸出

command cli傳參初始化
bytomd的cli解析使用cobra庫

cmd/bytomd/commands

  • cmd/bytomd/commands/root.go

初始化--root傳參。bytomd儲存配置、keystore、資料的root目錄。在MacOS下,預設路徑是~/Library/Bytom/

  • cmd/bytomd/commands/init.go

初始化--chain_id傳參。選擇網路類型,在啟動bytomd時我們選擇了testnet也就是測試網路

  • cmd/bytomd/commands/version.go

初始化version傳參

  • cmd/bytomd/commands/run_node.go

初始化node節點運行時所需要的傳參

初始化預設配置
使用者傳參只有一部分參數,那節點所需的其他參數需要從預設配置中載入。
cmd/bytomd/commands/root.go

var (    config = cfg.DefaultConfig())

在root.go中有一個config全域變數載入了node所需的所有預設參數

// Default configurable parameters.func DefaultConfig() *Config {    return &Config{        BaseConfig: DefaultBaseConfig(),  // node基礎相關配置        P2P:        DefaultP2PConfig(),   // p2p網路相關配置        Wallet:     DefaultWalletConfig(),   // 錢包相關配置        Auth:       DefaultRPCAuthConfig(),  // 驗證相關配置        Web:        DefaultWebConfig(),   // web相關配置    }}

後面的文章會一一介紹每個配置的作用

bytomd 守護進程啟動與退出

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}

runNode函數有三步操作:
node.NewNode:初始化node運行環境
n.Start:啟動node
n.RunForever:監聽退出訊號,收到ctrl+c操作則退出node。在linux中守進程一般監聽SIGTERM訊號(ctrl+c)作為退出守護進程的訊號

初始化node運行環境

在bytomd中有五個db資料庫儲存在--root參數下的data目錄

  • accesstoken.db // 儲存token相關資訊(錢包存取控制許可權)
  • trusthistory.db // 儲存p2p網路同步相關資訊
  • txdb.db // 儲存體交易相關資訊
  • txfeeds.db //
  • wallet.db // 儲存錢包相關資訊

node/node.go

func NewNode(config *cfg.Config) *Node {    ctx := context.Background()    initActiveNetParams(config)    // Get store 初始化txdb資料庫    txDB := dbm.NewDB("txdb", config.DBBackend, config.DBDir())    store := leveldb.NewStore(txDB)  // 初始化accesstoken資料庫    tokenDB := dbm.NewDB("accesstoken", config.DBBackend, config.DBDir())    accessTokens := accesstoken.NewStore(tokenDB)  // 初始化event事件調度器,也叫任務調度器。一個任務可以被多次調用    // Make event switch    eventSwitch := types.NewEventSwitch()    _, err := eventSwitch.Start()    if err != nil {        cmn.Exit(cmn.Fmt("Failed to start switch: %v", err))    }  // 初始化交易池    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  // 初始化txfeeds資料庫    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    }  // 初始化keystore    hsm, err := pseudohsm.New(config.KeysDir())    if err != nil {        cmn.Exit(cmn.Fmt("initialize HSM failed: %v", err))    }  // 初始化錢包,預設wallet是開啟狀態    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)  // 初始化網路節點同步管理    syncManager, _ := netsync.NewSyncManager(config, chain, txPool, newBlockCh)  // 初始化pprof,pprof用於輸出效能指標,需要制定--prof_laddr參數來開啟,在文章開頭我們已經開啟該功能    // run the profile server    profileHost := config.ProfListenAddress    if profileHost != "" {        // Profiling bytomd programs.see (https://blog.golang.org/profiling-go-programs)        // go tool pprof http://profileHose/debug/pprof/heap        go func() {            http.ListenAndServe(profileHost, nil)        }()    }  // 初始化節點,填充節點所需的所有參數環境    node := &Node{        config:       config,        syncManager:  syncManager,        evsw:         eventSwitch,        accessTokens: accessTokens,        wallet:       wallet,        chain:        chain,        txfeed:       txFeed,        miningEnable: config.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}

目前bytomd只支援cpu挖礦,所以在代碼中只有cpuminer的初始化資訊

啟動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() 啟動node進程如下:

  • 啟動挖礦功能
  • 啟動p2p網路同步
  • 啟動http協議的apiserver服務
  • 開啟瀏覽器訪問bytond的交易頁面

停止node

bytomd在啟動時執行了n.RunForever()函數,該函數是由tendermint架構啟動了監聽訊號的功能:
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函數監聽了SIGTERM訊號,bytomd才能成為不退出的守護進程。只有當觸發了ctrl+c或kill bytomd_pid才能終止bytomd進程退出。退出時bytomd執行如下操作
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.}

bytomd會將挖礦功能停止,p2p網路停止等操作。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.