四、初始化和啟動模塊(3)

(四)我們接著看bitcoind.cpp文件代碼的99-110行

這幾行主要作用是:判斷數(shù)據(jù)目錄是否存在并讀取配置文件參數(shù)指定的配置文件。代碼的內(nèi)容是:

需要分析4個部分內(nèi)容:

  • GetDataDir(false)函數(shù);
  • BITCOIN_CONF_FILENAME 宏定義;
  • GetArg()函數(shù);
  • ReadConfigFile()函數(shù)。
    (1)GetDataDir(false)函數(shù)
    這個函數(shù)在util.t中的第172行聲明:
    在util.cpp的第555行實現(xiàn):
    其中注釋文字內(nèi)容為:

這可以通過LogPrintf()來調(diào)用,因此我們緩存了值,這樣我們就不必在之后執(zhí)行內(nèi)存分配了.

更詳細(xì)的講解可以參考下面的鏈接:

http://m.itdecent.cn/p/bd1903a31b4b

(2)BITCOIN_CONF_FILENAME 宏定義
該定義在util.cpp中的第90行:


(3)GetArg()函數(shù)
此處的函數(shù)使用的代碼為:
gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)
其中 gArgsArgsManager類定義的變量,GetArg()聲明在util.h中第221行,屬于ArgsManager類中的方法:
std::string GetArg(const std::string& strArg, const std::string& strDefault);
它的實現(xiàn)在util.cpp中436-442行:

std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault)
{
    LOCK(cs_args);
    if (mapArgs.count(strArg))
        return mapArgs[strArg];
    return strDefault;
}

它在這里實現(xiàn)的功能為:

判斷是否有參數(shù)"-conf",如果有,則使用前面ParseParmeters()函數(shù)使用后保存的參數(shù)值作為配置文件;如果沒有,則使用默認(rèn)的“bitcoin.conf”。

(4)ReadConfigFile()函數(shù)
這個函數(shù)在util.h的第203行聲明,在util.cpp的第601實現(xiàn),其中它的實現(xiàn)代碼如下圖所示:

這個函數(shù)主要是先讀取配置文件的參數(shù)和參數(shù)值,并存儲這些信息;最后用ClearDatadirCache()函數(shù)將數(shù)據(jù)文件路徑參數(shù)設(shè)置成空目錄。其中ClearDatadirCache()函數(shù)在util.cpp的第584行實現(xiàn):

總之,對于這部分實現(xiàn)的功能邏輯如下所示:

  1. 判斷函數(shù)GetDataDir()得到的路徑是否為規(guī)范的目錄名稱。如果不是,打印指定目錄不存在的錯誤信息,并返回false值,程序退出;如果是,則繼續(xù)下面的程序。
  2. 使用ReadConfigFile()函數(shù)來讀取配置文件中的參數(shù)名與參數(shù)值,并把得到的參數(shù)信息存入mapArgs和_mapMultiArgs中。

(五)繼續(xù)看bitcoind.cpp中代碼的112-117行

對此段代碼的注釋為:

檢查- testnet- regtest參數(shù) (Params()調(diào)用僅在此子句之后有效)

其中- testnet指代比特幣的測試網(wǎng)絡(luò)Testnet,而- regtest指代比特幣的私有網(wǎng)絡(luò)Regression test。那么可以知道這個部分是選擇比特幣網(wǎng)絡(luò)的。
其中主要的是兩個函數(shù):

  • ChainNameFromCommandLine()函數(shù);
  • SelectParams()函數(shù)。
    其中SelectParams()是以ChainNameFromCommandLine()函數(shù)的返回值當(dāng)作參數(shù)的。下面對這兩個函數(shù)具體分析:
    (1)ChainNameFromCommandLine()函數(shù)
    這個函數(shù)的聲明在chainparamsbase.h中的第60行:
    對它的注釋內(nèi)容為:

尋找- regtest,- testnet并返回適當(dāng)?shù)腂IP70鏈名。
如果給定無效組合,則返回CBaseChainParams::MAX_NETWORK_TYPES;默認(rèn)情況下返回CBaseChainParams::MAIN

它的實現(xiàn)在chainparamsbase.cpp中的第90行,具體代碼如圖所示:

對于它的具體實現(xiàn)過程可以參考下面鏈接:

http://m.itdecent.cn/p/6fcfc5969733

總之:這是一個獲取網(wǎng)絡(luò)名稱的函數(shù)。對于具體的實現(xiàn)邏輯如下:

檢測是否含有- regtest- testnet參數(shù),如果只含有- regtest參數(shù),則獲取網(wǎng)絡(luò)名稱為"regtest",即私有網(wǎng)絡(luò);如果只含有- testnet參數(shù),則獲取的網(wǎng)絡(luò)名稱為"test",即測試網(wǎng)絡(luò);當(dāng)兩個參數(shù)同時含有,則會報錯;當(dāng)兩個參數(shù)都沒有則獲取的網(wǎng)絡(luò)名稱為"main",即主網(wǎng)絡(luò)。

(2)SelectParams()函數(shù)
這個函數(shù)的聲明在chainparams.h中的第116行:

對這個函數(shù)的注釋為:

根據(jù)params()返回的值設(shè)置成指定的BIP70的鏈名稱的參數(shù)。
當(dāng)鏈不被支持時,拋出錯誤信息std::runtime_error

它的實現(xiàn)在chainparams.cpp中的第353行:

這個函數(shù)調(diào)用了兩個函數(shù):

  • SelectBaseParams()函數(shù);
  • CreateChainParams()函數(shù)。
    SelectBaseParams()函數(shù)的聲明在chainparamsbase.h的第54行注釋上對它的解釋是:

根據(jù)params()返回的值設(shè)置成指定網(wǎng)絡(luò)的參數(shù)。

函數(shù)的實現(xiàn)在chainparamsbase.cpp中的第85行:

可以知道它調(diào)用了CreateBaseChainParams()函數(shù),這個和下面說要說的CreateChainParams()函數(shù)名稱相似,其實這兩個函數(shù)的功能也相似,都是對不同默認(rèn)網(wǎng)絡(luò)的參數(shù)設(shè)置,只是CreateChainParams()函數(shù)設(shè)置的更具體,而CreateBaseChainParams()函數(shù)只是基本設(shè)置。
CreateBaseChainParams()函數(shù)在chainparamsbase.h中的第39行聲明,在chainparamsbase.cpp的第73行實現(xiàn):
可以知道根據(jù)不同的鏈名稱選擇對應(yīng)的CBaseMainParams()CBaseTestNetParams()CBaseRegTestParams() ,而則三個函數(shù)是分別對私有網(wǎng)絡(luò)、測試網(wǎng)絡(luò)和主網(wǎng)絡(luò)的RPC端口參數(shù)和數(shù)據(jù)目錄。在chainparamsbase.cpp的30-63行:
從這些數(shù)據(jù)可以知道比特幣主網(wǎng)絡(luò)的RPC端口為8332,測試網(wǎng)絡(luò)的RPC端口為18332,私有網(wǎng)絡(luò)的RPC端口為18332,以及他們各自的目錄名 。
CreateChainParams()函數(shù)
這個函數(shù)的聲明在chainparams.h中的第104行,其中注釋對它解釋為:

創(chuàng)建并返回一個std::unique_ptr <cchainparams>的選擇鏈。
返回所選鏈的CChainParams *指針。
如果這個鏈沒有被支持則拋出一個錯誤信息:std::runtime_error

這個就是根據(jù)上面得到的網(wǎng)絡(luò)名稱設(shè)置成對應(yīng)的網(wǎng)絡(luò)參數(shù),并把參數(shù)賦值給globalChainParams。
它的實現(xiàn)在chainparams.cpp的第342行:

CreateBaseChainParams()函數(shù)類似,它在實現(xiàn)的時候同時也實例化了對應(yīng)網(wǎng)絡(luò)類型的參數(shù)設(shè)置函數(shù):CMainParams() 、CTestNetParams()CRegTestParams()。對于這三個函數(shù)在chainparams.cpp的73-333行的大量代碼中有詳細(xì)的代碼實現(xiàn),這里基本上包含了不同網(wǎng)絡(luò)的網(wǎng)絡(luò)名稱、挖礦難度、區(qū)塊信息等等幾乎所有需要的參數(shù)。

所以,如果想要創(chuàng)建自己需要的數(shù)字貨幣,只需要單獨修改這里面的參數(shù)就行了,比如修改難度,獎勵金額等。這個部分是開發(fā)時經(jīng)常要修改的地方。

總結(jié):
SelectParams()函數(shù)實現(xiàn)的功能就是把ChainNameFromCommandLine()函數(shù)獲取得到的網(wǎng)絡(luò)名稱設(shè)置成對應(yīng)的基本的網(wǎng)絡(luò)基本參數(shù)。


(六)繼續(xù)看bitcoind.cpp中代碼的120-125行

這段代碼的注釋為:

當(dāng)命令行中有不準(zhǔn)確的無參數(shù)符號時出現(xiàn)錯誤提示。

這部分有個判斷函數(shù)IsSwitchChar(),它的作用是判斷是否有'-'或'/',含有的將會是正確的。它的實現(xiàn)在util.h中的第186行:

那么如果符號不正確,則在終端輸出:
Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.
而且程序會因為異常而退出。


(七)繼續(xù)看bitcoind.cpp中代碼的第128行

這部分的代碼就只有一行,注釋對它的說明為:

對于bitcoind來說-server默認(rèn)是開啟的,但對于GUI(圖形界面)-server默認(rèn)則是關(guān)閉的,所以在此添加代碼。

這里面有個主要的函數(shù):SoftSetBoolArg(),這個函數(shù)的聲明在util.h的第257行:

它的注釋主要的意思是:

如果它還沒有值,就設(shè)置一個布爾參數(shù)

它的實現(xiàn)在util.cpp中的第469行:

這個函數(shù)中調(diào)用了一個函數(shù)SoftSetArg(),這個函數(shù)在util.h中聲明,主要是:

如果它還沒有值,就設(shè)置一個參數(shù)

它的實現(xiàn)在util.cpp中的第460行:


這個函數(shù)就有很多熟悉面孔,它也是ArgsManager(即參數(shù)管理類)的一個方法;也有個互斥鎖:LOCK(cs_args);;也有mapArgs.count(strArg)函數(shù),這個是關(guān)于mapArgs參數(shù)的驗證。還有個我們不是很熟悉的函數(shù):ForceSetArg(),這個函數(shù)在當(dāng)前文件中的第477行實現(xiàn):
主要還是對mapArgsmapMultiArgs這兩個參數(shù)的操作。

總的來看:
gArgs.SoftSetBoolArg("-server", true);函數(shù)的實現(xiàn)邏輯是:

解析mapArgs參數(shù),判斷其中是否有-server這個參數(shù),如果存在就無需設(shè)置了;如果沒有這個參數(shù),就根據(jù)SoftSetBoolArg()傳入的fValue值進行設(shè)置。


(八)繼續(xù)看bitcoind.cpp中代碼的130-131行

這個部分只有兩行,分別有兩個函數(shù),其中對它的注釋為:

提前設(shè)置這部分,使參數(shù)交互內(nèi)容進入控制臺中。

InitLogging()函數(shù)
這個函數(shù)的聲明在init.h的第25行:

對它的注釋為:

初始化日志基礎(chǔ)設(shè)施

它的實現(xiàn)在init.cpp的821行:


可以了解這是一個初始化日志的函數(shù),而且通過查詢也知道這個函數(shù)作用的是把數(shù)據(jù)存儲在debug.log文件中,這個文件在ubuntu系統(tǒng)是在$HOME/.bitcoin/文件夾中,接下來對它初始化實現(xiàn)的6個設(shè)置內(nèi)容較詳細(xì)說明:
a.函數(shù)的第一行代碼主要是檢測參數(shù)命令中是否含有-printtoconsole命令,如果有則讓日志信息發(fā)送跟蹤/調(diào)試信息到控制臺中,但默認(rèn)是false,即默認(rèn)只是記錄在日志文件debug.log中,而不是在控制臺中顯示;
///////////////////////////////////////////////////////////////////
補充一點:
DEFAULT_LOGTIMESTAMPS DEFAULT_LOGTIMEMICROS
DEFAULT_LOGIPS這三個靜態(tài)常量在util.h中有定義:
///////////////////////////////////////////////////////////////////
b.函數(shù)的第二行代碼主要是檢測參數(shù)命令中是否含有-logtimestamps,該參數(shù)的含義是在日志中打印時間戳,由上面的補充內(nèi)容知道默認(rèn)是在日志文件中打印時間戳的;
c.函數(shù)的第三行代碼主要是檢測參數(shù)命令中是否含有-logtimemicros,該參數(shù)的含義是打印日志單位精確到微妙(μs),由上面的補充內(nèi)容知道默認(rèn)是false,即默認(rèn)初始化日志文件精確到秒(s);
d. 函數(shù)的第四行代碼主要是檢測參數(shù)命令中是否含有-logips,該參數(shù)的含義是打印IP地址,由上面的補充內(nèi)容知道默認(rèn)是false,即默認(rèn)在日志文件中是不打印IP地址的;
e.函數(shù)第五行是在日志文件中空19行;
f.函數(shù)最后一行是打印“Bitcoin version”,并緊跟上比特幣客戶端的版本信息。

由上面可以知道,這個函數(shù)只是一個基本的初始化日志文件函數(shù)。而接下來的InitParameterInteraction函數(shù)是日志文件中存儲參數(shù)交互信息。

如下圖為初始化日志的基本格式:

InitParameterInteraction()函數(shù)
開始還是解析這個函數(shù)代碼:
這個函數(shù)的聲明在init.h第27行:

對它的注釋為:

參數(shù)交互:根據(jù)不同的規(guī)則改變當(dāng)前參數(shù)。

它的實現(xiàn)在init.cpp中的744-814行,它主要包括了8個規(guī)則:

下面簡單的對這8部分解釋:
a.綁定并監(jiān)聽地址
注釋為:當(dāng)顯示指定了綁定地址后,即使指定了-connect和-proxy參數(shù)信息,程序?qū)邮軄碜酝獠康倪B接,并監(jiān)聽該地址。
通過參數(shù)-bind-whitebind這兩個參數(shù)設(shè)置,并通過SoftSetBoolArg()函數(shù)實現(xiàn)了-listen參數(shù)的設(shè)置,把它設(shè)置成true,代表要監(jiān)聽設(shè)置的外部連接IP地址。
b.連接可信的節(jié)點
首先判斷參數(shù)命令中是否含有-connect參數(shù),如果有將-dnsseed(使用DNS查找節(jié)點)和-listen(即接受來自外部的連接,并對其進行監(jiān)聽)設(shè)置為true。并進行日志打印。
注意:此處代碼的有效執(zhí)行是在為設(shè)置-bind-whitebind參數(shù)的情況下進行的。
c.代理模式
設(shè)置代理參數(shù)的目的是為了保護隱私,則此處將-listen、-upnp以及-discover均設(shè)置為false,也就是說比特幣后臺進程只使用代理提供的監(jiān)聽地址與端口,并且不去查找默認(rèn)的監(jiān)聽地址。這里的upnp代表的意思是使用全局即插即用(UPNP)映射監(jiān)聽端口,默認(rèn)不使用。
注意:此處代碼的有效執(zhí)行也是在為設(shè)置-bind-whitebind參數(shù)的情況下進行的。
d.監(jiān)聽設(shè)置處理
當(dāng)不監(jiān)聽時,不要映射端口或嘗試檢索公共IP。就是如果監(jiān)聽參數(shù)設(shè)置為false,則upnp(端口)、discover(自動發(fā)現(xiàn)默認(rèn)地址)以及l(fā)istenonion(匿名地址監(jiān)聽)均設(shè)置為false。
/////////////////////////////////////////////////////////////////////
補充:這里的listenonion(匿名地址監(jiān)聽)實際上設(shè)計一個通信機制的一個概念:第二代洋蔥路由(onion routing),對它的理解可以借鑒網(wǎng)絡(luò)的解釋:

Tor(The Onion Router)是第二代洋蔥路由(onion routing)的一種實現(xiàn),用戶通過Tor可以在因特網(wǎng)上進行匿名交流。Tor專門防范流量過濾、嗅探分析,讓用戶免受其害。最初該項目由美國海軍研究實驗室贊助。2004年后期,Tor成為電子前哨基金會的一個項目。2005年后期,EFF不再贊助Tor項目,但他們繼續(xù)維持Tor的官方網(wǎng)站。

而在bitcoind源碼src文件夾下的torcontrol.h和torcontrol.cpp實現(xiàn)了Tor的控制。
/////////////////////////////////////////////////////////////////////
e.外部IP參數(shù)處理
如果顯示指定了公共IP地址,那么bitcoind就不需要查找其他監(jiān)聽地址了。
f.區(qū)塊模式參數(shù)設(shè)置
DEFAULT_BLOCKSONLY在net.h中定義,默認(rèn)值為false。表示在blocksonly模式(區(qū)塊模式)下禁用whitelistrelay。即在區(qū)塊模式下白名單列表失效。
g.強制白名單節(jié)點連接參數(shù)處理
強制白名單節(jié)點連接參數(shù)處理意味著比特幣網(wǎng)絡(luò)中的信息將優(yōu)先在白名單節(jié)點間傳遞。
g.區(qū)塊大小設(shè)置
這個區(qū)塊大小是設(shè)置默認(rèn)的礦工產(chǎn)生區(qū)塊的大小。

總結(jié):

InitParameterInteraction()函數(shù)主要是根據(jù)參數(shù)命令,改變當(dāng)前的參數(shù),并把相應(yīng)的信息打印到日志文件中。其中還涉及到一些網(wǎng)絡(luò)中IP地址的監(jiān)聽設(shè)置方法、白名單的禁用和啟用情況等。其實就是日志文件中初始化日志后(即版本信息打印后)的大量的日志內(nèi)容,如圖:

而這兩個函數(shù)基本決定了日志文件debug.log中的所有預(yù)輸出日志的打印內(nèi)容,但是我們知道日志不僅包括初始化準(zhǔn)備的預(yù)輸出日志,還包括啟動程序時和啟動之后的一系列操作的日志,那么日志文件中的啟動后的輸出日志內(nèi)容是什么呢?我們將在后面的AppInitMain()函數(shù)中進一步講解程序初始化啟動時的調(diào)試日志內(nèi)容。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Ⅲ:AppInit()函數(shù)解讀 這個函數(shù)定義在bitcoind.cpp中的63行,這是個重要的函數(shù),我們來一行行解...
    風(fēng)來霧去閱讀 1,006評論 0 2
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,347評論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評論 19 139
  • 2017年的元旦,在百無聊賴中發(fā)了一條朋友圈:回顧這一年,雞毛沒剩。 配了張被禿嚕毛的雞。 很少被關(guān)注的我...
    找削的蘋果閱讀 318評論 0 0
  • 今天在做后臺項目的時候,發(fā)現(xiàn)了一個單位 vh,媽呀,這是個什么鬼,沒有接觸過,雖然說還是個菜鳥但是一般的單位還是知...
    AlisaMfz閱讀 1,518評論 0 0

友情鏈接更多精彩內(nèi)容