六茧吊、初始化和啟動(dòng)模塊(5)

(十一)繼續(xù)看bitcoind.cpp中的142-146行

 if (!AppInitSanityChecks())
    {
      //InitError將被調(diào)用搓侄,并有詳細(xì)的錯(cuò)誤话速,最終將在控制臺(tái)結(jié)束
      exit(EXIT_FAILURE);
     }

這個(gè)部分最重要的是AppInitSanityChecks()函數(shù)泊交。對(duì)這個(gè)函數(shù)名的定義中我找出了幾個(gè)關(guān)鍵詞:“appinit”,“sanity”和“checks”筹麸,我猜測(cè)這個(gè)函數(shù)是關(guān)于初始化健全性檢查的。那么就來(lái)分析這個(gè)函數(shù)留晚。
AppInitSanityChecks()函數(shù)的聲明在init.h的第45行:

/**
*初始化健全性檢查:ecc初始化告嘲、健全性檢查橄唬、目錄鎖檢查。
*注意:這可以在daemonization之前完成隆判。如果此函數(shù)失敗侨嘀,請(qǐng)不要調(diào)用Shutdown()捂襟。 
*前提:參數(shù)解析和配置文件應(yīng)該已經(jīng)被讀過(guò)葬荷,AppInitParameterInteraction()函數(shù)應(yīng)該已經(jīng)被調(diào)用過(guò)宠漩。
*/
bool AppInitSanityChecks();

該函數(shù)的實(shí)現(xiàn)在init.cpp中1190-1209,其中的有效代碼只有8行:

bool AppInitSanityChecks()
{
    // *************第四步:健全性檢查

    // 初始化橢圓曲線密碼(ECC)
    std::string sha256_algo = SHA256AutoDetect();
    LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
    RandomInit();
    ECC_Start();
    globalVerifyHandle.reset(new ECCVerifyHandle());

    // 健全性檢查
    if (!InitSanityCheck())
        return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));

    // 如果可能照筑,探測(cè)數(shù)據(jù)目錄鎖以提供早期錯(cuò)誤消息凝危。
    // 我們不能將數(shù)據(jù)目錄鎖定在這里蛾默,因?yàn)閐eamon()尚未調(diào)用forking指令捉貌,
    // 并且fork指令將會(huì)對(duì)它產(chǎn)生一個(gè)奇怪的行為。
    return LockDataDirectory(true);
}

由此可以看出牧挣,這個(gè)函數(shù)完成的是初始化的第四步瀑构,在該函數(shù)中主要完成了三個(gè)內(nèi)容:

  1. 初始化橢圓曲線密碼(ECC)寺晌;
  2. 健全性檢查;
  3. 目錄鎖檢查耘婚。

下面對(duì)這三個(gè)內(nèi)容分別說(shuō)明:

1. 初始化橢圓曲線密碼(ECC)

對(duì)于橢圓曲線密碼的概念想必對(duì)比特幣的加密知識(shí)了解的都很清楚:比特幣使用橢圓曲線算法生成公鑰和私鑰沐祷,選擇的是secp256k1曲線攒岛。所以在此也再?gòu)?qiáng)調(diào)一點(diǎn):比特幣中的橢圓曲線算法只在生成公鑰和私鑰的時(shí)候才用到阵子,其他大部分的加密都是用SHA256算法挠进。橢圓曲線算法牽涉到一些密碼學(xué)知識(shí)和許多數(shù)學(xué)原理,感興趣的可以參考:

https://www.cnblogs.com/Kalafinaian/p/7392505.html

那么比特幣中應(yīng)用的是現(xiàn)有的SHA256算法和橢圓曲線加密算法暖璧,那么我們對(duì)這兩種算法在源碼中的定義和實(shí)現(xiàn)邏輯不詳細(xì)分析澎办,感興趣的可以在網(wǎng)絡(luò)上自行更深入的了解金砍,我們只是對(duì)應(yīng)用它們之后的效果進(jìn)行分析恕稠。
回到AppInitSanityChecks()函數(shù)的第一部分:

std::string sha256_algo = SHA256AutoDetect();
    LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
    RandomInit();
    ECC_Start();
    globalVerifyHandle.reset(new ECCVerifyHandle());

這個(gè)部分調(diào)用了5個(gè)函數(shù):
(1)SHA256AutoDetect():該函數(shù)是SHA256算法相關(guān)的函數(shù)鹅巍,函數(shù)聲明在sha256.h中32行料祠,函數(shù)實(shí)現(xiàn)在sha256.cpp的179-192行髓绽。由聲明可以知道該函數(shù)的功能是:

//自動(dòng)選擇最佳有效的SHA256實(shí)現(xiàn)顺呕。
//返回實(shí)現(xiàn)的名稱摆碉。

即這個(gè)函數(shù)選擇了最合適的實(shí)現(xiàn)SHA256的方式巷帝,并在日志中打印該消息楞泼。
(2)RandomInit():該函數(shù)聲明在random.h的第144行笤闯,實(shí)現(xiàn)在random.cpp中的464-467行颗味。由聲明知道該函數(shù)是:

初始化RNG

那么RNG是什么呢浦马?通過(guò)查找資料知道RNG(The Random Number Generator)是隨機(jī)數(shù)發(fā)生器,它是被嵌入到計(jì)算機(jī)硬件中的隨機(jī)數(shù)生成器谨娜,生成的是偽隨機(jī)數(shù)趴梢。對(duì)于普通用戶使用的筆記本和臺(tái)式機(jī)來(lái)說(shuō)是本身就含有的一部分币他,和有沒有比特幣客戶端無(wú)關(guān)蝴悉,這里可以理解成比特幣客戶端需要用到這個(gè)隨機(jī)數(shù)生成器辫封,給他在客戶端初始化了廉丽,方便軟件的使用正压。我們讀過(guò)《精通比特幣》這本書都知道:在生成私鑰的時(shí)候焦履,我們是需要有一個(gè)256位的隨機(jī)數(shù)的雏逾,而比特幣軟件使用操作系統(tǒng)底層的隨機(jī)數(shù)生成器來(lái)產(chǎn)生256位的熵(隨機(jī)性)栖博。那么就明白這個(gè)函數(shù)對(duì)私鑰生成的重要作用了仇让。
(3)ECC_Start():該函數(shù)的聲明在key.h的183行丧叽,實(shí)現(xiàn)在key.cpp中291-306行。由它的聲明知道該函數(shù)的功能:

初始化橢圓曲線支持假瞬。如果在調(diào)用了第一次之后不首先調(diào)用ECC_Stop笨触,就不能第二次調(diào)用這個(gè)函數(shù)雹舀。

由該函數(shù)的所在位置(key.cpp)可以知道該函數(shù)和私鑰與公鑰的操作有關(guān)说榆。而且它的聲明文件說(shuō)的很清楚签财,是初始化橢圓曲線支持唱蒸,該函數(shù)定義中也多次出現(xiàn)了secp256k1,說(shuō)明這個(gè)函數(shù)是開啟橢圓曲線算法功能庆捺。
(4)ECCVerifyHandle():該函數(shù)是ECCVerifyHandle類的一個(gè)方法滔以,聲明在pubkey.h中的241-248行你画,實(shí)現(xiàn)在pubkey.cpp中282-290行。由ECCVerifyHandle類的聲明:

此模塊的用戶必須持有ECCVerifyHandle拟逮。不過(guò)敦迄,它們的構(gòu)造函數(shù)和析構(gòu)函數(shù)不允許并行運(yùn)行颅崩。

說(shuō)明該函數(shù)是實(shí)例化ECC的核實(shí)處理蕊苗,這個(gè)函數(shù)在后面用來(lái)驗(yàn)證基于橢圓曲線創(chuàng)建的密鑰朽砰。
(5)globalVerifyHandle.reset():這個(gè)主要是reset()函數(shù)瞧柔,這個(gè)是重置函數(shù)造锅,主要清除上面的核實(shí)處理內(nèi)存廉邑。

總之蛛蒙,這個(gè)部分是對(duì)橢圓曲線密碼(ECC)的初始化牵祟。選擇SHA256準(zhǔn)備诺苹、隨機(jī)數(shù)生成器準(zhǔn)備雹拄、橢圓曲線功能開啟办桨、驗(yàn)證橢圓曲線開啟和重置內(nèi)存呢撞,都是為ECC的正常運(yùn)行提供的條件殊霞。

2. 健全性檢查

這個(gè)部分只有兩行代碼:

    if (!InitSanityCheck())
        return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));

主要是判斷InitSanityCheck()函數(shù)绷蹲。
該函數(shù)實(shí)現(xiàn)位于init.cpp的707-723行:

/** 健全性檢查
 *  確保比特幣在一個(gè)可用的環(huán)境中運(yùn)行顾孽,并提供所有必要的庫(kù)支持若厚。
*/
bool InitSanityCheck(void)
{
    if(!ECC_InitSanityCheck()) {
        InitError("Elliptic curve cryptography sanity check failure. Aborting.");
        return false;
    }

    if (!glibc_sanity_test() || !glibcxx_sanity_test())
        return false;

    if (!Random_SanityCheck()) {
        InitError("OS cryptographic RNG sanity check failure. Aborting.");
        return false;
    }

    return true;
}

該部分又有三個(gè)判斷函數(shù)测秸,ECC_InitSanityCheck()為橢圓曲線加密結(jié)果的完整性驗(yàn)證霎冯,glibc_sanity_test()glibcxx_sanity_test()驗(yàn)證當(dāng)前運(yùn)行環(huán)境是否支持C/C++運(yùn)行環(huán)境沈撞,Random_SanityCheck()驗(yàn)證系統(tǒng)的隨機(jī)數(shù)生成器是否可用缠俺。
(1)ECC_InitSanityCheck():橢圓曲線加密結(jié)果驗(yàn)證晋修。
這個(gè)函數(shù)聲明在key.h中189行:

/** 驗(yàn)證橢圓曲線算法的計(jì)算功能是否實(shí)時(shí)有效 */
bool ECC_InitSanityCheck(void);

它的實(shí)現(xiàn)在key.cpp中的284-289行:

bool ECC_InitSanityCheck() {
    CKey key;
    key.MakeNewKey(true);
    CPubKey pubkey = key.GetPubKey();
    return key.VerifyPubKey(pubkey);
}

現(xiàn)在我們對(duì)這段代碼進(jìn)行分析:
CKey
這個(gè)類在key.h中第35行定義墓卦,對(duì)這個(gè)類解釋為:一個(gè)封裝的私鑰。則可以知道key為私鑰對(duì)象睁本,它是一個(gè)無(wú)符號(hào)字符串類型的數(shù)組呢堰,在CKey的構(gòu)造函數(shù)中對(duì)該參數(shù)進(jìn)行了初始化枉疼,定義其字節(jié)大小為32字節(jié)骂维,并且是必須為32字節(jié)。
這個(gè)類中還有兩個(gè)變量:fValidfCompressed
fValid:參數(shù)用于表示私鑰是否有效褪测,該參數(shù)是在私鑰值發(fā)生變化時(shí)進(jìn)行相應(yīng)修改侮措,即私鑰值有效時(shí)分扎,其為true笆包,反之則為false。
fCompressed:參數(shù)代表的是公鑰是否為壓縮公鑰汛兜,true為壓縮公鑰粥谬,false為非壓縮公鑰漏策。
MakeNewKey()函數(shù):
該函數(shù)在key.h中98行聲明:

    //使用加密PRNG(偽隨機(jī)數(shù))來(lái)生成私鑰

    void MakeNewKey(bool fCompressed);

該函數(shù)的實(shí)現(xiàn)在key.cpp的126-132行:

void CKey::MakeNewKey(bool fCompressedIn) {
    do {
        GetStrongRandBytes(keydata.data(), keydata.size());
    } while (!Check(keydata.data()));
    fValid = true;
    fCompressed = fCompressedIn;
}

可以看出掺喻,在MakeNewKey()函數(shù)中是通過(guò)GetStrongRandBytes()函數(shù)循環(huán)獲取私鑰感耙,直到獲取的私鑰滿足Check()函數(shù)驗(yàn)證條件時(shí)才停止即硼。
其實(shí)MakeNewKey()函數(shù)的作用可以這樣理解:我們?cè)谇懊嬷懒怂借€是機(jī)器內(nèi)部的隨機(jī)數(shù)生成器生成的只酥,但是也不是任意生成的隨機(jī)數(shù)就能滿足成為私鑰的條件,還是要規(guī)定能成為私鑰的條件的性锭,MakeNewKey()函數(shù)就是找到符合要求的私鑰的草冈。其中GetStrongRandBytes()函數(shù)是生成一個(gè)未驗(yàn)證的私鑰的怎棱,而這個(gè)過(guò)程也不簡(jiǎn)單:

a. 首先會(huì)通過(guò)Open SSL的RNG獲取隨機(jī)數(shù)拳恋;
b. 然后通過(guò)操作系統(tǒng)的RNG獲取隨機(jī)數(shù)谬运;
c. 再然后獲得私鑰的哈希值梆暖;
d. 最后清除隨機(jī)數(shù)的內(nèi)存轰驳。

Check()函數(shù)就是檢查該隨機(jī)數(shù)是否滿足要求的级解。其實(shí)在Check()函數(shù)的有個(gè)函數(shù)secp256k1_ec_seckey_verify()就是通過(guò)調(diào)用libsecp256k1庫(kù)實(shí)現(xiàn)隨機(jī)數(shù)的驗(yàn)證的:如果返回值如果為1勤哗,密鑰有效芒划;如果為0則無(wú)效豁延。傳入的兩個(gè)參數(shù)ctx與seckey均不能為NULL,都需要有值腊状。
獲得私鑰并檢查符合作為私鑰的條件后诱咏,將私鑰有效性標(biāo)志fValid設(shè)置為true,同時(shí)將傳入的fCompressedIn值賦值給fCompressed缴挖,用于標(biāo)識(shí)是否使用壓縮公鑰袋狞。
CPubKey類:
CKey類相似,這個(gè)就是公鑰類映屋,pubkey就是公鑰對(duì)象。chHeader值為2或3棚点,為壓縮公鑰早处,長(zhǎng)度為33;chHeader值為4或6或7瘫析,為非壓縮公鑰砌梆,長(zhǎng)度為65;都不是時(shí)其長(zhǎng)度為空贬循,也可說(shuō)明該公鑰值無(wú)效咸包。
key.GetPubKey()函數(shù):
那么由私鑰怎么怎么到公鑰呢?其實(shí)就是用這個(gè)函數(shù)來(lái)實(shí)現(xiàn)杖虾。這個(gè)函數(shù)在key.cpp的147-158行烂瘫,其實(shí)包括很多加密相關(guān)函數(shù)的調(diào)用,主要調(diào)用了secp256k1_ec_pubkey_create()函數(shù)創(chuàng)建公鑰值奇适,然后調(diào)用secp256k1_ec_pubkey_serialize()函數(shù)實(shí)現(xiàn)壓縮或非壓縮公鑰序列值的計(jì)算坟比。

注意
我們都知道橢圓曲線這種非對(duì)稱加密方式,使比特幣中的私鑰得到公鑰是很簡(jiǎn)單的嚷往,但是要想從公鑰反推出私鑰基本是不可能的葛账,在這里就是用這兩個(gè)橢圓曲線算法函數(shù)來(lái)實(shí)現(xiàn)這個(gè)特點(diǎn)。

VerifyPubKey()函數(shù):
這個(gè)是驗(yàn)證公鑰的函數(shù)间影,這個(gè)函數(shù)在key.h的134行聲明注竿,在key.cpp中的175-187行實(shí)現(xiàn)茄茁。由它的聲明中的注釋可以知道魂贬,這個(gè)函數(shù)是用來(lái)徹底檢查私鑰和公鑰的匹配,這個(gè)過(guò)程是用另一個(gè)完全不同的機(jī)制來(lái)完成的裙顽。我們知道橢圓曲線加密方式的不可逆性付燥,我們得到公鑰的機(jī)制就用了這個(gè)加密算法,那么驗(yàn)證時(shí)就不能再根據(jù)這個(gè)公鑰反推出私鑰和私鑰比較來(lái)驗(yàn)證愈犹,那么在比特幣中是用什么機(jī)制來(lái)驗(yàn)證的呢键科?其實(shí)可以把它的驗(yàn)證機(jī)制看作是模擬交易的簽名檢驗(yàn)機(jī)制:

a. 通過(guò)OpenSSL的GetRandBytes()函數(shù)實(shí)現(xiàn)隨機(jī)數(shù)的生成闻丑;
b. 根據(jù)"Bitcoin key verification\n"字符串與剛生成的隨機(jī)數(shù)共同作用計(jì)算隨機(jī)哈希值;
c. 在Sign函數(shù)通過(guò)該隨機(jī)哈希值基于ECDSA算法實(shí)現(xiàn)簽名值的計(jì)算勋颖;
d. 利用該簽名信息驗(yàn)證獲取的公鑰的有效性嗦嗡,驗(yàn)證函數(shù)位于CPubKey的Verify()函數(shù)中。

(2)glibc_sanity_test()glibcxx_sanity_test():C與C++運(yùn)行環(huán)境驗(yàn)證饭玲。
這兩個(gè)函數(shù)主要是為了驗(yàn)證運(yùn)行環(huán)境中的C/C++運(yùn)行庫(kù)的有效性侥祭,即比特幣核心軟件能否在當(dāng)前環(huán)境中正常運(yùn)行,其所需的運(yùn)行庫(kù)是否能夠支撐比特幣核心的正常運(yùn)行茄厘。
(3)Random_SanityCheck()函數(shù):驗(yàn)證系統(tǒng)的隨機(jī)數(shù)生成器矮冬。
該函數(shù)的聲明在random.h的第141行:

/**檢查操作系統(tǒng)的隨機(jī)性是否可用,
 * 并返回所請(qǐng)求的字節(jié)數(shù)次哈。
 */
bool Random_SanityCheck();

該函數(shù)的實(shí)現(xiàn)在random.cpp的411-453行胎署,由實(shí)現(xiàn)函數(shù)代碼中的注釋我們可以知道:

這并不能度量隨機(jī)性的質(zhì)量,但它確實(shí)測(cè)試了OSRandom()在給定最大嘗試次數(shù)的情況下覆蓋了輸出的所有32個(gè)字節(jié)窑滞。

琼牧??哀卫?障陶??聊训?抱究??带斑?鼓寺??勋磕?妈候??挂滓?苦银??赶站?幔虏??贝椿?想括??烙博?
對(duì)于這部分的源碼我有了點(diǎn)困惑
首先我知道了RNG是隨機(jī)數(shù)生成器瑟蜈,猜測(cè)這個(gè)函數(shù)是檢測(cè)生成的隨機(jī)數(shù)是否可用的烟逊。那么如果是這樣的話為什么不把它放在生成私鑰之前,即ECC_InitSanityCheck()函數(shù)的前面铺根?像源碼中那樣把該驗(yàn)證放在公鑰都已經(jīng)生成了之后宪躯,那么如果檢測(cè)到的結(jié)果不符合條件,那么按理說(shuō)私鑰和公鑰都有問題位迂,那樣私鑰和公鑰生成和檢測(cè)的工作算是白做了眷唉,何不把它放在私鑰和公鑰生成之前呢?
然后我就懷疑我對(duì)這個(gè)函數(shù)的理解不對(duì)囤官,但注釋中對(duì)它的解釋不夠全面冬阳,代碼有些又看不太明白,就先把這個(gè)問題留著党饮,等詢問大牛和在網(wǎng)上查找相關(guān)問題后再補(bǔ)上肝陪!
?刑顺?氯窍??蹲堂?狼讨??柒竞?朽基?霎俩????具垫?起宽?擒滑?库车??垫蛆?虑乖?仅叫?帜篇??诫咱?

3. 目錄鎖檢查

這個(gè)是AppInitSanityChecks()函數(shù)的最后一步笙隙,通過(guò)調(diào)用LockDataDirectory()函數(shù)來(lái)完成,其中LockDataDirectory()函數(shù)實(shí)現(xiàn)位于init.cpp的1167-1188行坎缭。該函數(shù)主要是確保只有一個(gè)比特幣進(jìn)程正在使用數(shù)據(jù)目錄竟痰,因?yàn)橐C數(shù)據(jù)目錄在同一臺(tái)機(jī)器中僅被一個(gè)比特幣核心核心程序所使用,否則如果多個(gè)比特幣核心程序同時(shí)使用同一數(shù)據(jù)目錄掏呼,將會(huì)造成該程序數(shù)據(jù)內(nèi)容產(chǎn)生不一致的情況坏快。
在LockDataDirectory中,首先獲取數(shù)據(jù)目錄值憎夷,然后打開數(shù)據(jù)目錄下的.lock文件莽鸿,判斷其是否存在。該文件在ubuntu中的$HOME/.bitcoin/文件夾下是存在的岭接,其內(nèi)容為空富拗。.lock文件的作用是:該文件將通過(guò)lock.try_lock()被鎖定,但是如果已被其它先啟動(dòng)的比特幣程序鎖定了的話鸣戴,本次鎖定將失效啃沪,同時(shí)提示錯(cuò)誤信息,并返回false窄锅,整個(gè)程序?qū)⑼顺觥?/p>

********************************************
第四步總結(jié):
這一步在函數(shù)AppInitSanityChecks()中實(shí)現(xiàn)创千,主要分為三個(gè)部分:首先是初始化橢圓曲線密碼(ECC),為一系列的準(zhǔn)備工作——選擇SHA256準(zhǔn)備入偷、隨機(jī)數(shù)生成器準(zhǔn)備追驴、橢圓曲線功能開啟、驗(yàn)證橢圓曲線開啟和重置內(nèi)存疏之,都是為了下一步做準(zhǔn)備工作殿雪;然后是InitSanityCheck()函數(shù)進(jìn)行的健全性檢查——包括橢圓曲線加密結(jié)果的完整性驗(yàn)證、驗(yàn)證當(dāng)前運(yùn)行環(huán)境是否支持C/C++運(yùn)行環(huán)境和驗(yàn)證系統(tǒng)的隨機(jī)數(shù)生成器是否可用锋爪,是此步驟的核心丙曙;最后是AppInitSanityChecks()函數(shù)控制的目錄鎖檢查——確保只有一個(gè)比特幣進(jìn)程正在使用數(shù)據(jù)目錄,也是確保只有一個(gè)bitcoind運(yùn)行其骄。
********************************************


(十二)繼續(xù)看bitcoind.cpp中的147-161行

if (gArgs.GetBoolArg("-daemon", false))
        {
#if HAVE_DECL_DAEMON
            fprintf(stdout, "Bitcoin server starting\n");

            // 后臺(tái)運(yùn)行
            if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
                fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
                return false;
            }
#else
            fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
            return false;
#endif // HAVE_DECL_DAEMON
        }

大概可以知道這一部分主要是-deamon參數(shù)的解析亏镰,該參數(shù)應(yīng)用于比特幣核心的bitcond.exe控制臺(tái)程序,該程序?yàn)楸忍貛藕诵牡暮笈_(tái)服務(wù)程序拯爽。
這段代碼的實(shí)現(xiàn)流程是:

①首先if條件語(yǔ)句判斷是否在啟動(dòng)時(shí)設(shè)置了守護(hù)進(jìn)程 -daemon參數(shù)索抓,如果設(shè)置了則該參數(shù)使用設(shè)置的代碼,并且繼續(xù)下面的代碼;否則返回false逼肯。
②用條件編譯判斷是否包含HAVE_DECL_DAEMON宏定義耸黑,包含則繼續(xù)下面的代碼;不包含則將在控制臺(tái)中輸出當(dāng)前系統(tǒng)不支持守護(hù)進(jìn)程的錯(cuò)誤提示汉矿。

HAVE_DECL_DAEMON宏定義在未經(jīng)編譯的源碼中是不包含的崎坊,需經(jīng)過(guò)./configure配置后才會(huì)出現(xiàn)备禀,該定義位于config/bitcoin-config.h的106行洲拇,默認(rèn)為1,表示定義了daemon曲尸;如果為0則為不定義daemon赋续。

③如果包含HAVE_DECL_DAEMON宏定義,且該值為1另患,則在控制臺(tái)中輸出"Bitcoin server starting"信息纽乱,表明比特幣后臺(tái)守護(hù)進(jìn)程在運(yùn)行。
④然后再判斷daemon(1, 0)函數(shù)的返回值昆箕,如果返回值為非零鸦列,則輸出errorno對(duì)應(yīng)的錯(cuò)誤提示,并返回false鹏倘,程序退出薯嗤;如果daemon()函數(shù)返回為0時(shí)則正常運(yùn)行。

daemon()函數(shù)是成功時(shí)返回0纤泵,否則返回-1并設(shè)置errno骆姐。daemon()函數(shù)的用法可以參考:http://www.cppblog.com/cjz/archive/2011/12/29/163123.html

daemon(1, 0)可知:當(dāng)前設(shè)置的參數(shù)為1和0,根據(jù)其注釋我們可以得知捏题,該守護(hù)進(jìn)程將當(dāng)前目錄設(shè)為根目錄玻褪,即程序中的相對(duì)目錄是從該目錄開始的,第二個(gè)參數(shù)設(shè)置為0則表示不輸出任何信息公荧。

********************************************

-deamon參數(shù)設(shè)置總結(jié):

該參數(shù)應(yīng)用于比特幣核心的bitcond.exe控制臺(tái)程序带射,該程序?yàn)楸忍貛藕诵牡暮笈_(tái)服務(wù)程序。一般在啟動(dòng)時(shí)會(huì)設(shè)置此參數(shù)循狰,表示啟動(dòng)bitcoin的后臺(tái)守護(hù)進(jìn)程窟社,但是如果判斷沒有在啟動(dòng)時(shí)設(shè)置此參數(shù)會(huì)報(bào)錯(cuò),提示當(dāng)前系統(tǒng)不支持守護(hù)進(jìn)程的錯(cuò)誤消息晤揣。并且就算是啟動(dòng)了該參數(shù)桥爽,如果設(shè)置的參數(shù)不對(duì),也會(huì)報(bào)錯(cuò)昧识∧扑模總之就是檢測(cè)在程序啟動(dòng)時(shí)是否有-deamon參數(shù)并是否是正確設(shè)置的值,保證程序正常啟動(dòng)后臺(tái)服務(wù)。
********************************************


(十三)繼續(xù)看bitcoind.cpp中的163-167行

 // 在守護(hù)進(jìn)程后鎖定數(shù)據(jù)目錄缀去。
        if (!AppInitLockDataDirectory())
        {
            // 如果鎖定數(shù)據(jù)目錄失敗侣灶,立即退出
            exit(EXIT_FAILURE);
        }

對(duì)于這部分我們可以在注釋中了解它主要是完成鎖定數(shù)據(jù)目錄的。這部分主要調(diào)用了AppInitLockDataDirectory()函數(shù)缕碎,該函數(shù)的聲明在init.h的51行:

/**
 * 鎖定比特幣核心數(shù)據(jù)目錄褥影。
 * 注意: 這只能在守護(hù)進(jìn)程之后完成。 如果此功能失敗咏雌,請(qǐng)勿調(diào)用Shutdown()凡怎。
 * 前提: 應(yīng)該解析參數(shù)并讀取配置文件,應(yīng)該調(diào)用過(guò)AppInitSanityChecks赊抖。
 */
bool AppInitLockDataDirectory();

從該注釋中我們知道這個(gè)步驟只能在守護(hù)進(jìn)程完成之后统倒,而且要是調(diào)用過(guò)AppInitSanityChecks()函數(shù)之后。AppInitSanityChecks()函數(shù)我們前面已經(jīng)學(xué)習(xí)過(guò)了氛雪,這個(gè)是目標(biāo)鎖檢查函數(shù)房匆,其中它主要是調(diào)用LockDataDirectory() 函數(shù)來(lái)完成的。我們?cè)倏纯此膶?shí)現(xiàn)文件报亩,在init.cpp中的1211-1221行:

bool AppInitLockDataDirectory()
{
    // 在守護(hù)進(jìn)程之后浴鸿,再次獲取數(shù)據(jù)目錄鎖定并保持它直到退出;
    // 這為競(jìng)爭(zhēng)條件創(chuàng)造了一個(gè)小小的窗口弦追,但是這個(gè)條件是無(wú)害的:它最多會(huì)讓我們退出而不打印消息給控制臺(tái)岳链。
    if (!LockDataDirectory(false)) {
        // 在LockDataDirectory內(nèi)部打印詳細(xì)的錯(cuò)誤
        return false;
    }
    return true;
}

不出所料,該函數(shù)的實(shí)現(xiàn)真的調(diào)用了LockDataDirectory() 函數(shù)骗卜,該函數(shù)實(shí)現(xiàn)位于init.cpp的1167-1188行宠页,它是目錄鎖檢查的主要實(shí)現(xiàn)函數(shù),主要是確保只有一個(gè)bitcoind運(yùn)行寇仓。這里是再次獲取數(shù)據(jù)目錄鎖定并一直保持它目錄鎖鎖定狀態(tài)举户,直到程序的退出。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遍烦,一起剝皮案震驚了整個(gè)濱河市俭嘁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌服猪,老刑警劉巖供填,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異罢猪,居然都是意外死亡近她,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門膳帕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粘捎,“玉大人,你說(shuō)我怎么就攤上這事≡苣ィ” “怎么了泳桦?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)娩缰。 經(jīng)常有香客問我灸撰,道長(zhǎng),這世上最難降的妖魔是什么拼坎? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任浮毯,我火速辦了婚禮,結(jié)果婚禮上演痒,老公的妹妹穿的比我還像新娘亲轨。我一直安慰自己趋惨,他們只是感情好鸟顺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著器虾,像睡著了一般讯嫂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兆沙,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天欧芽,我揣著相機(jī)與錄音,去河邊找鬼葛圃。 笑死千扔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的库正。 我是一名探鬼主播曲楚,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼褥符!你這毒婦竟也來(lái)了龙誊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤喷楣,失蹤者是張志新(化名)和其女友劉穎趟大,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铣焊,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逊朽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了曲伊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叽讳。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绽榛,到底是詐尸還是另有隱情湿酸,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布灭美,位于F島的核電站推溃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏届腐。R本人自食惡果不足惜铁坎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望犁苏。 院中可真熱鬧硬萍,春花似錦、人聲如沸围详。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)助赞。三九已至买羞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雹食,已是汗流浹背畜普。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留群叶,地道東北人吃挑。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像街立,于是被迫代替她去往敵國(guó)和親舶衬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • 一几晤、快速術(shù)語(yǔ)檢索 比特幣地址:(例如:1DSrfJdB2AnWaFNgSbv3MZC2m74996JafV)由一串...
    不如假如閱讀 15,981評(píng)論 4 87
  • 在比特幣中,經(jīng)常出現(xiàn)三個(gè)詞:私鑰憾朴,公鑰和地址狸捕。他們是什么意思呢?他們之間又有什么樣的關(guān)系呢众雷?搞清楚他們之間的關(guān)系和...
    姜家志閱讀 44,968評(píng)論 3 48
  • 前些日子買了一些花草灸拍,我將它輕輕放在陽(yáng)光下的窗臺(tái)做祝。新發(fā)的綠色讓我欣喜,但枯萎的漸漸枯萎鸡岗。綠色的歸宿是枯萎混槐,那枯萎的...
    199x20xx閱讀 270評(píng)論 0 0
  • npm config list查看可配置項(xiàng),npm設(shè)置代理 proxynpm config set proxy="...
    LongfeiSong閱讀 937評(píng)論 0 0
  • 這深秋的雪啊 是透明的 夾雜著些許淚 落到地上 身上 這深秋的天哪 冷的瘆人 像穿堂的風(fēng) 掠過(guò)...
    一顆半糖閱讀 346評(píng)論 9 8