本文將繼續(xù)參數(shù)處理其他部分源碼的研讀。

本文主要涉及的源碼文件包括:
src/bitcond.cpp、src/util.h、src/util.cpp、src/init.h、src/init.cpp、src/chainparamsbase.h、src/chainparamsbase.cpp、src/chainparams.h、src/chainparams.cpp
一、比特幣網(wǎng)絡(luò)
比特幣網(wǎng)絡(luò)分為主網(wǎng)、測試網(wǎng)以及私有網(wǎng)三種網(wǎng)絡(luò),其中主網(wǎng)就是我們現(xiàn)在使用的正式運(yùn)行的可進(jìn)行實(shí)際交易的網(wǎng)絡(luò),在其上我們可以實(shí)現(xiàn)物品的交易與服務(wù);測試網(wǎng)顧名思義即為公共測試網(wǎng)絡(luò),因?yàn)槠鋵?shí)測試網(wǎng),所以,其上的信息是可以重設(shè)的;私有網(wǎng)的難度很低,很容易產(chǎn)生塊,所以開發(fā)者一般在私有網(wǎng)中開展應(yīng)用的開發(fā)與自測試。三個(gè)網(wǎng)絡(luò)的的英文名分別為:
主網(wǎng):Main network
測試網(wǎng):Testnet (v3)
私有網(wǎng):Regression test
二、選擇比特幣網(wǎng)絡(luò)
介紹完比特幣網(wǎng)絡(luò)的三種類型后,我們來看如下代碼:
//Check for -testnet or -regtest parameter (Params() calls are only valid afterthis clause)
try{
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception&e) {
fprintf(stderr,"Error: %s\n", e.what());
returnfalse;
}
首先我們來看代碼注釋,其注釋的含義為檢測-testnet或者-regtest參數(shù)。那么這兩個(gè)參數(shù)是什么意思呢?它們分別是我們前面介紹的測試網(wǎng)和私有網(wǎng)。
知道了后面代碼的具體功能后,我們就繼續(xù)對代碼進(jìn)行深入剖析。注釋后面的代碼通過try catch異常捕捉機(jī)制實(shí)現(xiàn)比特幣網(wǎng)絡(luò)設(shè)置工作。在try代碼塊中,SelectParams函數(shù)以ChainNameFromCommandLine()返回值作為參數(shù),SelectParams函數(shù)的聲明位于src/chainparams.h中,其參數(shù)為字符串類型。那ChainNameFromCommandLine()的返回值是什么呢?
(1)獲取網(wǎng)絡(luò)名稱
要知道ChainNameFromCommandLine()的返回值需進(jìn)入src/chainparamsbase.cpp一看究竟。其函數(shù)實(shí)現(xiàn)如下:
std::string ChainNameFromCommandLine()
{
boolfRegTest = GetBoolArg("-regtest", false);
boolfTestNet = GetBoolArg("-testnet", false);
if(fTestNet && fRegTest)
throwstd::runtime_error("Invalid combination of -regtest and -testnet.");
if(fRegTest)
returnCBaseChainParams::REGTEST;
if(fTestNet)
returnCBaseChainParams::TESTNET;
returnCBaseChainParams::MAIN;
}
ChainNameFromCommandLine()函數(shù)從其名稱可以看出,該函數(shù)將從命令行中獲取鏈路的名稱。其實(shí)現(xiàn)流程如圖所示。

1)該函數(shù)首先獲取"-regtest"與"-testnet"參數(shù)設(shè)置情況;
2)如果兩個(gè)參數(shù)都設(shè)置了,因?yàn)橐粋€(gè)比特幣程序不可能同時(shí)存在兩個(gè)網(wǎng)絡(luò),所以,程序?qū)惓M顺?,同時(shí)拋出異常錯(cuò)誤,由之前的try catch模塊處理,打印異常錯(cuò)誤提示信息;
3)如果只設(shè)置了回歸測試,則返回CBaseChainParams::REGTEST,REGTEST為靜態(tài)字符串常量,代表的是回歸測試,與其并行的另兩個(gè)網(wǎng)絡(luò)描述字符串也為靜態(tài)字符串常量,他們均在src/chainparamsbase.h中聲明,也同時(shí)在src/chainparamsbase.cpp中定義。其聲明與定義如下:
聲明:

定義:
const std::string CBaseChainParams::MAIN = "main"; //主網(wǎng)
const std::string CBaseChainParams::TESTNET = "test"; //測試網(wǎng)
const std::string CBaseChainParams::REGTEST = "regtest"; //私有網(wǎng)
4)如果只設(shè)置了測試網(wǎng)絡(luò),,則返回CBaseChainParams::TESTNET;
5)如果都沒有設(shè)置,則返回,則返回CBaseChainParams::MAIN。
(2)網(wǎng)絡(luò)基本參數(shù)設(shè)置
在獲得網(wǎng)絡(luò)名稱后,我們將其傳給SelectParams函數(shù),該函數(shù)的實(shí)現(xiàn)位于chainparams.cpp中,其函數(shù)實(shí)現(xiàn)如下:
void SelectParams(conststd::string& network)
{
SelectBaseParams(network);
pCurrentParams = &Params(network);
}
在該函數(shù)中首先調(diào)用SelectBaseParams函數(shù),該函數(shù)的實(shí)現(xiàn)位于chainparamsbase.cpp中,其函數(shù)實(shí)現(xiàn)內(nèi)容如下:
void SelectBaseParams(conststd::string& chain)
{
pCurrentBaseParams = &BaseParams(chain);
}
在該函數(shù)中,實(shí)現(xiàn)了對鏈參數(shù)對象pCurrentBaseParams的賦值,pCurrentBaseParams的類型為CBaseChainParams指針,其定義位于src/chainparams.cpp中,從定義可以看出pCurrentBaseParams為靜態(tài)全局變量。
static CBaseChainParams* pCurrentBaseParams = 0;
CBaseChainParams類為前面提到的3種區(qū)塊鏈基本參數(shù)的基類,3種區(qū)塊鏈基本參數(shù)設(shè)置類分別為:CBaseMainParams、CBaseTestNetParams、CBaseRegTestParams,其定義位于src/chainparamsbase.cpp中,具體定義代碼如下:
/**
*Main network主網(wǎng)
*/
class CBaseMainParams : publicCBaseChainParams
{
public:
CBaseMainParams()
{
nRPCPort = 8332;
}
};
static CBaseMainParams mainParams;
/**
*Testnet (v3)測試網(wǎng)
*/
class CBaseTestNetParams : publicCBaseChainParams
{
public:
CBaseTestNetParams()
{
nRPCPort = 18332;
strDataDir = "testnet3";
}
};
static CBaseTestNetParams testNetParams;
/*
*Regression test私有鏈
*/
class CBaseRegTestParams : publicCBaseChainParams
{
public:
CBaseRegTestParams()
{
nRPCPort = 18332;
strDataDir = "regtest";
}
};
static CBaseRegTestParams regTestParams;
從上述定義我們可以看到每個(gè)類的構(gòu)造函數(shù)中定義了主鏈、測試鏈以及私有鏈?zhǔn)褂玫亩丝谂c數(shù)據(jù)目錄,其端口分別為8332、18332以及18332。
在完成3種鏈的定義后,我們再來看BaseParams函數(shù)的實(shí)現(xiàn)就很容易明白其返回值的意義了:
CBaseChainParams& BaseParams(conststd::string& chain)
{
if (chain == CBaseChainParams::MAIN)
return mainParams;
else if (chain == CBaseChainParams::TESTNET)
return testNetParams;
else if (chain == CBaseChainParams::REGTEST)
return regTestParams;
else
throw std::runtime_error(strprintf("%s: Unknown chain %s.",__func__, chain));
}
BaseParams將返回對應(yīng)鏈的基本參數(shù)對象,并賦值給pCurrentBaseParams。
(3)主要參數(shù)設(shè)置
我們最后再來看SelectParams中的pCurrentParams = &Params(network);代碼。其實(shí)現(xiàn)與我們剛看到的BaseParams有點(diǎn)類似,只不過其少了Base單詞而已,我們可以這樣理解,在執(zhí)行完鏈的基本參數(shù)設(shè)置后,比特幣程序?qū)⒃O(shè)置相應(yīng)鏈的主要參數(shù)了。從Params函數(shù)實(shí)現(xiàn)我們可以看到,其實(shí)現(xiàn)與BaseParams是一樣的,都是根據(jù)鏈名稱獲取相應(yīng)的鏈參數(shù)對象,只不過此處的鏈路參數(shù)類中包含的參數(shù)信息更詳細(xì)些。主鏈、測試鏈以及私有鏈對應(yīng)的類分別為CMainParams、CTestNetParams、CRegTestParamsstatic,這3個(gè)類的定義位于src/chainparams.cpp中,它們均繼承了CChainParams類,通過CChainParams可知鏈參數(shù)類主要實(shí)現(xiàn)共識(shí)參數(shù)、CDNSSeedData種子數(shù)據(jù)、默認(rèn)端口、創(chuàng)世塊信息以及鏈交易數(shù)據(jù)等參數(shù)的設(shè)置。
這里要著重講解的是共識(shí)參數(shù)與創(chuàng)世塊信息參數(shù),它們分別為:
Consensus::Params consensus;
CBlock genesis;
因?yàn)槲覀冎饕褂弥骶W(wǎng),因此以主網(wǎng)中的參數(shù)內(nèi)容來說明我們經(jīng)常聽到的區(qū)塊獎(jiǎng)勵(lì)減半、出塊時(shí)間、創(chuàng)世塊獎(jiǎng)勵(lì)等參數(shù)是如何設(shè)置的。
區(qū)塊獎(jiǎng)勵(lì)減半間隔:consensus.nSubsidyHalvingInterval = 210000;
算力極限值:consensus.powLimit =uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
算力修改間隔:consensus.nPowTargetSpacing = 10 * 60;即10分鐘
創(chuàng)世塊genesis = CreateGenesisBlock(1231006505, 2083236893,0x1d00ffff, 1, 50 * COIN);第一個(gè)塊的獎(jiǎng)勵(lì)為50個(gè)比特幣
以上這些參數(shù)都是我們經(jīng)常聽到的名詞,如果我們想創(chuàng)建自己命名的數(shù)字貨幣,只需簡單修改這些參數(shù)即可,比如把區(qū)塊獎(jiǎng)勵(lì)減半間隔修改為420000或其他數(shù),創(chuàng)世塊中比特幣獎(jiǎng)勵(lì)的50該為100或其他數(shù)。所以要?jiǎng)?chuàng)建一個(gè)自己的數(shù)字貨幣并不難,關(guān)鍵在于看其是否有應(yīng)用價(jià)值。
程序在每個(gè)類的定義之后,程序也定義了對應(yīng)的靜態(tài)鏈參數(shù)對象。
static CMainParamsmainParams;
staticCTestNetParams testNetParams;
staticCRegTestParams regTestParams;
Params將根據(jù)用戶設(shè)置的鏈參數(shù)名稱,將對應(yīng)的鏈參數(shù)返回給pCurrentParams,從而完成鏈基本參數(shù)與主要參數(shù)的實(shí)現(xiàn)任務(wù)。
至此,程序根據(jù)用戶輸入的網(wǎng)絡(luò)類型參數(shù)完成了比特幣運(yùn)行網(wǎng)絡(luò)的設(shè)置。在這段代碼中,我知道了私有網(wǎng)絡(luò),以前聽得最多的是主網(wǎng)和測試網(wǎng),而私有網(wǎng)或私有鏈基本很少聽到,在這段代碼中我知道了私有鏈?zhǔn)情_發(fā)團(tuán)隊(duì)在開發(fā)時(shí)使用的網(wǎng)絡(luò),因?yàn)槠渫诘V難度很低,很容易進(jìn)行程序的調(diào)試與功能試驗(yàn)。進(jìn)而讓我明白了一些區(qū)塊鏈項(xiàng)目為什么會(huì)說在XX時(shí)刻要進(jìn)入測試網(wǎng)階段,然后再是最終的主網(wǎng)運(yùn)行階段。因此區(qū)塊鏈開發(fā)過程應(yīng)該是這樣的:

以上就是本文的源碼研讀過程,通過源碼的研讀確實(shí)讓我更好地理解區(qū)塊鏈網(wǎng)絡(luò)的運(yùn)轉(zhuǎn)過程,也讓我清晰地明白市場上每個(gè)區(qū)塊鏈的具體進(jìn)程,這樣可以讓我更好地判斷每個(gè)區(qū)塊鏈產(chǎn)品的價(jià)值,對我投資區(qū)塊鏈資產(chǎn)也有很大的幫助。
我是區(qū)塊鏈研習(xí)社的菜菜子,我將繼續(xù)深入研究比特幣源碼,源碼研讀系列也將繼續(xù)更新,敬請期待!
作者:區(qū)塊鏈研習(xí)社比特幣源碼研讀班 菜菜子
以下是廣告:
我們區(qū)塊鏈研習(xí)社已創(chuàng)建“區(qū)塊鏈研習(xí)社幣圈交流”小密圈”,在小密圈中,我們將帶領(lǐng)大家一起學(xué)習(xí)區(qū)塊鏈的原理與投資,還將提供區(qū)塊鏈基本原理解答、交易所注冊與交易操作、ICO交易與操作、投資分析、風(fēng)險(xiǎn)分析等內(nèi)容。
目前入圈價(jià)格初始定價(jià)50元,50人調(diào)整一次價(jià)格,每次調(diào)整幅度為50元!
