比特幣源碼研讀之二

上一篇文章我們大致分析了一下比特幣源碼src文件夾的目錄結(jié)構(gòu)以及數(shù)據(jù)目錄結(jié)構(gòu),接下來(lái)我們將進(jìn)入源碼的分析。本篇涉及的文件包括:

bitcoind.cpp、noui.cpp、ui_interface.hui_interface.h、util.cpp、init.cpp、chainparamsbase.cpp、chainparams.cpp

下圖整理了本篇文章中涉及的一些主要方法調(diào)用,以及相互的調(diào)用關(guān)系。

在編譯完源碼后,我們可以通過(guò)src/bitcoind命令啟動(dòng)比特幣守護(hù)進(jìn)程。根據(jù)該名稱,我們很容易可以在src目錄下找到一個(gè)名為bitcoind.cpp的文件。打開該文件,其main函數(shù)的內(nèi)容如下:

int main(int argc, char* argv[])

{

SetupEnvironment();

// Connect bitcoind signal handlers

noui_connect();

return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);

}

SetupEnvironment()

該方法中處理了32位虛擬地址分配以及l(fā)ocale相關(guān)的問題,具體可參考http://www.lxweimin.com/p/4fc762796f83 。

noui_connect()

方法定義如下:

void noui_connect()

{

// Connect bitcoind signal handlers

uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);

uiInterface.ThreadSafeQuestion.connect(noui_ThreadSafeQuestion);

uiInterface.InitMessage.connect(noui_InitMessage);

}

ThreadSafeMessageBox、ThreadSafeQuestion、InitMessage是在uiInterface定義的三個(gè)信號(hào)量boost::signal:signal2,其定義如下:

/** Show message box. */?

boost::signals2::signal <bool (const std::string& message, const std::string& caption, unsigned int style), boost::signals2::last_value<bool>>ThreadSafeMessageBox;

/** If possible, ask the user a question. If not, falls back to ThreadSafeMessageBox(noninteractive_message, caption, style) and returns false. */? ??

boost::signals2::signal<bool (const std::string& message, const std::string& noninteractive_message, const std::string& caption, unsigned int style), boost::signals2::last_value<bool>> ThreadSafeQuestion;

/** Progress message during initialization. */

boost::signals2::signal<void (const std::string &message)> InitMessage;

<>中定義了其插槽需要滿足的接口以及返回值需求,以ThreadSafeMessageBox為例,其對(duì)插槽的要求是函數(shù)返回值為bool且形參分別是std::string&、std::string&、std::string&和unsigned int.據(jù)上分析,我們看下為ThreadSafeMessageBox綁定的插槽noui_ThreadSafeMessageBox的定義(noui.cpp中), 其符合信號(hào)ThreadSafeMessageBox的定義。

static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style);

AppInit

首先方法處理了用戶提供的運(yùn)行參數(shù)gArgs.ParseParameters(argc, argv)。gArgs為定義在util.cpp中的一個(gè)全局ArgsManager變量,我們來(lái)看下其提供的ParseParameters方法,相關(guān)代碼解釋如下。

void ArgsManager::ParseParameters(int argc, const char* const argv[])

{? ??

LOCK(cs_args);//cs_args是一個(gè)boost::recursive_mutex變量,即只有獲取了該鎖,才能往下操作? ??

mapArgs.clear();//類型為std::map <std::string, std::string>,存儲(chǔ)鍵值一一對(duì)應(yīng)的參數(shù)鍵值對(duì)? ?

mapMultiArgs.clear();//類型為std::map<std::string, std::vector<std::string>>,可存儲(chǔ)多值

for (int i = 1; i < argc; i++)

{

std::string str(argv[i]);

std::string strValue;

size_t is_index = str.find('=');//找到參數(shù)鍵值對(duì)的分割位置“=”

if (is_index != std::string::npos)

{

strValue = str.substr(is_index+1);//“=”號(hào)前面的為value

str = str.substr(0, is_index); //“=”號(hào)后面的為key

}

#ifdef WIN32//如果是WIN32系統(tǒng)且參數(shù)以“/”開頭,則將“/”替換為“-”

boost::to_lower(str);

if (boost::algorithm::starts_with(str, "/"))

str = "-" + str.substr(1);

#endif

if (str[0] != '-')//如果不是以“-”開頭,則退出循環(huán)

break;

// Interpret --foo as -foo.--foo當(dāng)作-foo處理

// If both --foo and -foo are set, the last takes effect.

if (str.length() > 1 && str[1] == '-')

str = str.substr(1);

InterpretNegativeSetting(str, strValue);//將-noX替換為-X=0

mapArgs[str] = strValue;

mapMultiArgs[str].push_back(strValue);

}

}

我們回到AppInit方法中,在解析完用戶提供的運(yùn)行參數(shù)后,如果參數(shù)中包含了以下幾項(xiàng),將向用戶提供相應(yīng)的信息提示,程序終止。其中HelpMessage定義在init.cpp中,提供了各種參數(shù)的解釋幫助信息。

if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") ||? gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version")){

…………

if (gArgs.IsArgSet("-version")){

strUsage += FormatParagraph(LicenseInfo());

}else{

strUsage += "\n" + HelpMessage(HMM_BITCOIND);

}

fprintf(stdout, "%s", strUsage.c_str());

return true;

}

接下來(lái),程序?qū)z查用戶是否提供了datadir參數(shù),如果沒有,將根據(jù)不同的系統(tǒng)為其設(shè)定默認(rèn)值。

if (!fs::is_directory(GetDataDir(false))){

fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());

return false;

}

GetDataDir()方法位于util.cpp中,方法將通過(guò)gArgs.IsArgSet("-datadir")檢查用戶是否提供datadir參數(shù),若沒有則將調(diào)用util.cpp中的GetDefaultDataDir()獲取默認(rèn)值,根據(jù)不同的操作系統(tǒng)數(shù)據(jù)目錄的具體默認(rèn)位置如下:

// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin

// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin

// Mac: ~/Library/Application Support/Bitcoin

// Unix: ~/.bitcoin

緊接著程序?qū)⒆x取相關(guān)的參數(shù)配置文件,BITCOIN_CONF_FILENAME為定義在util.cpp中的一個(gè)常量,其值為bitcoin.conf,表示默認(rèn)的配置文件名。ReadConfigFile方法將會(huì)讀取用戶提供的配置文件路徑或默認(rèn)讀取$datadir/bitcoin.conf文件,并將配置存儲(chǔ)在mapArgs和mapMultiArgs中。代碼如下:

gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));

比特幣源碼中設(shè)置了三個(gè)不同的網(wǎng)絡(luò),分別是main、testnet和regtest。可以在啟動(dòng)bitcoind或bitcoin-qt時(shí),加入?yún)?shù)-testnet或-regtest來(lái)選擇不同的網(wǎng)絡(luò),默認(rèn)為main。函數(shù)ChainNameFromCommandLine將返回一個(gè)CBaseChainParams類型,表示選擇的網(wǎng)絡(luò)類型。SelectParams函數(shù)將根據(jù)網(wǎng)絡(luò)類型創(chuàng)建兩個(gè)全局變量globalChainBaseParams和globalChainParams.?

SelectParams(ChainNameFromCommandLine());

void SelectParams(const std::string& network){

// globalChainBaseParams = CreateBaseChainParams(chain);

SelectBaseParams(network);

globalChainParams = CreateChainParams(network);

}

globalChainBaseParams中存儲(chǔ)了nRPCPort端口號(hào)以及數(shù)據(jù)存儲(chǔ)目錄strDataDir。如主網(wǎng)絡(luò)的該配置中,nRPCPort的默認(rèn)值為8333,testnet的strDataDir為“testnet3”。方法CreateChainParams將根據(jù)網(wǎng)絡(luò)類型創(chuàng)建不同的網(wǎng)絡(luò)參數(shù)存儲(chǔ)對(duì)象。這些對(duì)象分別存儲(chǔ)了每個(gè)網(wǎng)絡(luò)各自擁有的特定參數(shù),可以說(shuō),整個(gè)比特幣網(wǎng)絡(luò)就是通過(guò)這些參數(shù)來(lái)確定兩個(gè)節(jié)點(diǎn)是否位于同一網(wǎng)絡(luò)的依據(jù)。后續(xù)我們也將分析位于chainparams.cpp中的類CMainParams、CTestNetParams以及CRegTestParams,分析各個(gè)網(wǎng)絡(luò)參數(shù)的含義。(順便提一下,基于比特幣的山寨幣制作,主要就是修改這些網(wǎng)絡(luò)參數(shù))

std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain){? ??

if (chain == CBaseChainParams::MAIN)? ? ? ??

? ? ?return std::unique_ptr(new CMainParams());? ??

else if (chain == CBaseChainParams::TESTNET)? ? ? ??

? ? ?return std::unique_ptr(new CTestNetParams());? ?

else if (chain == CBaseChainParams::REGTEST)? ? ? ??

? ? ?return std::unique_ptr(new CRegTestParams());

throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));

}

本篇主要分析了bitcoind守護(hù)進(jìn)程啟動(dòng)時(shí),程序如何對(duì)用戶提供的參數(shù)進(jìn)行解析,程序?qū)⒏鶕?jù)不同的參數(shù)配置,作出與之對(duì)應(yīng)的操作選擇。

因本人水平有限,如有問題,歡迎大家批評(píng)指出,非常感謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評(píng)論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,324評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,417評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,783評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,960評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,522評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,267評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,471評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,698評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,204評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,436評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容

  • 前一篇文章中已經(jīng)完成了main函數(shù)運(yùn)行過(guò)程的梳理,并且也繪制了其運(yùn)行流程圖,為了更清晰地記錄每個(gè)過(guò)程的詳細(xì)執(zhí)行內(nèi)容...
    菜菜子_forest閱讀 5,676評(píng)論 8 14
  • 注:純粹是自己的記錄,沒有任何參考價(jià)值 面對(duì)著不知所云的比特幣源碼,我嘗試著采用逐字閱讀的笨辦法來(lái)解讀。同時(shí)也參考...
    時(shí)汝佳閱讀 259評(píng)論 0 1
  • 區(qū)塊鏈研習(xí)社比特幣源碼研讀班今天研讀第二,第三流程,SetupEnvironment和noui_connect函數(shù)...
    劍有偏鋒閱讀 350評(píng)論 0 0
  • 上一節(jié)提到了一個(gè)問題:比特幣默認(rèn)的日志輸出文件是哪個(gè)? 不知道大家找到了沒,現(xiàn)在答案公布如下: 如果有看過(guò)我的第一...
    Jacky_2c9f閱讀 622評(píng)論 0 0
  • 我媽大嗓門,性格行動(dòng)大大咧咧,行動(dòng)風(fēng)風(fēng)火火,但是,卻是個(gè)玻璃心,受不了我對(duì)她的任何刺激和打擊還有語(yǔ)氣,否則就會(huì)難過(guò)...
    又又雙兒閱讀 183評(píng)論 2 1