欧美成人午夜免费全部完,亚洲午夜福利精品久久,а√最新版在线天堂,另类亚洲综合区图片小说区,亚洲欧美日韩精品色xxx

扣丁學(xué)堂區(qū)塊鏈培訓(xùn)之如何接入比特幣網(wǎng)絡(luò)及原理分析

2018-09-18 13:57:33 1174瀏覽

今天扣丁學(xué)堂區(qū)塊鏈培訓(xùn)給大家介紹一下關(guān)于從零開(kāi)始學(xué)習(xí)區(qū)塊鏈技術(shù)之如何接入比特幣網(wǎng)絡(luò)以及其原理分析的詳細(xì)介紹,下面我們一起來(lái)看一下吧。



1、如何接入比特幣網(wǎng)絡(luò)?

其實(shí)接入比特幣網(wǎng)絡(luò)是非常簡(jiǎn)單的,我說(shuō)了你一定不信,啟動(dòng)比特幣客戶端即可:

在命令行終端輸入啟動(dòng)命令:./src/bitcoind-testnet

輸入之后會(huì)有一個(gè)和網(wǎng)絡(luò)同步數(shù)據(jù)的過(guò)程,你會(huì)看到:

?這個(gè)過(guò)程需要一點(diǎn)時(shí)間,同步數(shù)據(jù)完成后,即接入了比特幣網(wǎng)絡(luò)。

2、啟動(dòng)流程鳥(niǎo)瞰

雖然說(shuō)一句命令即搞定,但是,這個(gè)背后代碼運(yùn)行的邏輯可就不簡(jiǎn)單咯~

來(lái),我給大家分析一下

當(dāng)在命令行終端輸入啟動(dòng)命令:./src/bitcoind-testnet后,操作系統(tǒng)就會(huì)找到這個(gè)文件中的main函數(shù),開(kāi)始比特幣客戶端的啟動(dòng)。

對(duì)于所有的c++代碼,整個(gè)程序都是從main函數(shù)開(kāi)始執(zhí)行的,bitcoind的main函數(shù)位于src/bitcoind.cpp,代碼拉到最后就找到了我們的main函數(shù)。

main函數(shù)本身沒(méi)有太多東西,主要是調(diào)用3個(gè)函數(shù)來(lái)執(zhí)行,它們的主要作用是設(shè)置環(huán)境變量、設(shè)置信號(hào)處理和啟動(dòng)系統(tǒng)。

具體代碼如下:

int main(int argc, char* argv[])
{
    SetupEnvironment();
    // Connect bitcoind signal handlers
    noui_connect();

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

這段代碼簡(jiǎn)單說(shuō)明如下:

SetupEnvironment函數(shù),主要用來(lái)設(shè)置系統(tǒng)的環(huán)境變量,包括:malloc分配內(nèi)存的行為、Locale、文件路徑的本地化設(shè)置等。

noui_connect函數(shù),設(shè)置連接到bitcoind的信號(hào)的處理。

AppInit函數(shù),進(jìn)行系統(tǒng)啟動(dòng)。

下面我們重點(diǎn)講下AppInit函數(shù)的執(zhí)行

調(diào)用SetupServerArgs函數(shù),設(shè)置系統(tǒng)可接受的所有命令行參數(shù)。然后開(kāi)始解析命令行傳遞的各種參數(shù)。系統(tǒng)執(zhí)行的重要一步就是設(shè)置可以接收的參數(shù)并解析用戶啟動(dòng)時(shí)傳遞的各種參數(shù),SetupServerArgs函數(shù)就是完成這個(gè)目的。下面來(lái)看這個(gè)函數(shù)的執(zhí)行流程。

首先,調(diào)用CreateBaseChainParams函數(shù),生成默認(rèn)的基本參數(shù),包括:使用的數(shù)據(jù)目錄和監(jiān)聽(tīng)的端口。根據(jù)不同的網(wǎng)絡(luò)類型,主網(wǎng)絡(luò)使用8332端口和指定目錄下的當(dāng)前目錄,測(cè)試網(wǎng)絡(luò)使用18332端口和指定目錄下的testnet3子目錄,回歸測(cè)試網(wǎng)絡(luò)使用18443端口和指定目錄下的regtest子目錄。

然后,調(diào)用CreateChainParams函數(shù),生成默認(rèn)的區(qū)塊鏈參數(shù)。這個(gè)方法也會(huì)區(qū)分不同的網(wǎng)絡(luò)。如果是主網(wǎng)絡(luò),則生成CMainParams對(duì)象進(jìn)行初始化。在構(gòu)造函數(shù)中,進(jìn)行如下的設(shè)置:

設(shè)置網(wǎng)絡(luò)ID為main;

設(shè)置共識(shí)參數(shù)(Consensus::Params)的各個(gè)值:

每隔多少個(gè)塊(nSubsidyHalvingInterval)后續(xù)比特幣的獎(jiǎng)勵(lì)會(huì)減半,值為210000。根據(jù)創(chuàng)世區(qū)塊獎(jiǎng)勵(lì)的數(shù)量(50),根據(jù)等比數(shù)列求和公式:

50?(1/(1?0.5))?210000"role="presentation">50?(1/(1?0.5))?21000050?(1/(1?0.5))?210000

,可計(jì)算貨幣總量為2100W個(gè)比特幣。

BIP34激活高度(BIP34Height)為227931。

BIP34激活哈希(BIP34Hash)為0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8。

BIP65激活高度(BIP65Height)為388381。

BIP66激活高度(BIP66Height)為363725。

工作量限制(powLimit)為一個(gè)大整數(shù)。

難度改變的周期(nPowTargetTimespan)為2周。

平均出塊時(shí)間(nPowTargetSpacing)為10分鐘。

改變共識(shí)需要的區(qū)塊數(shù)(nRuleChangeActivationThreshold)為1916,即2016的95%。

礦工確認(rèn)窗口(nMinerConfirmationWindow)為2016,等于難度改變周期除以平均出塊時(shí)間。

接下來(lái)設(shè)置區(qū)塊鏈相關(guān)的部署狀態(tài),包括:測(cè)試相關(guān)的(DEPLOYMENT_TESTDUMMY)、CSV軟分叉相關(guān)的(涉及到BIP68、BIP112、BIP113)和隔離見(jiàn)證相關(guān)的(涉及到BIP141、BIP143、BIP147)。

最佳區(qū)塊鏈的最小工作量。

設(shè)置默認(rèn)端口(nDefaultPort)為8333。

達(dá)到多少個(gè)區(qū)塊之后進(jìn)行區(qū)塊修剪(nPruneAfterHeight),當(dāng)前值為100000。

接下來(lái),調(diào)用CreateGenesisBlock方法,生成創(chuàng)世區(qū)塊。這個(gè)方法的參數(shù)是固定的,指定了創(chuàng)世區(qū)塊的時(shí)間、隨機(jī)數(shù)、難度值、版本號(hào)、獎(jiǎng)勵(lì)等。在方法內(nèi)部,生成創(chuàng)世區(qū)塊的輸出腳本和輸入腳本,中本聰那句著名的評(píng)論就出現(xiàn)在創(chuàng)世區(qū)塊的第一個(gè)交易的簽名中,他寫(xiě)道:TheTimes03/Jan/2009Chancelloronbrinkofsecondbailoutforbanks。

設(shè)置創(chuàng)世區(qū)塊的哈希為剛生成的創(chuàng)業(yè)區(qū)塊的哈希。

設(shè)置DNS種子節(jié)點(diǎn)vSeeds集合包含的DNS種子有:seed.bitcoin.sipa.be,dnsseed.bluematt.me,dnsseed.bitcoin.dashjr.org,seed.bitcoinstats.com,seed.bitcoin.jonasschnelli.ch,seed.btc.petertodd.org,seed.bitcoin.sprovoost.nl等,通過(guò)解析DNS種子節(jié)點(diǎn),比特幣節(jié)點(diǎn)啟動(dòng)時(shí)可以找到更多的對(duì)等節(jié)點(diǎn)來(lái)進(jìn)行連接。

接下來(lái),設(shè)置相關(guān)的檢查點(diǎn)數(shù)據(jù)。

如果是測(cè)試網(wǎng)絡(luò),則生成CTestNetParams對(duì)象進(jìn)行初始化。(供開(kāi)發(fā)完成后測(cè)試使用。)

如果是回歸測(cè)試網(wǎng)絡(luò),則生成CRegTestParams對(duì)象進(jìn)行初始化。(供開(kāi)發(fā)時(shí)連接使用。)

對(duì)于這兩種測(cè)試網(wǎng)絡(luò),處理基本和主網(wǎng)絡(luò)相同,只是某些參數(shù)不一樣。

上面提到的3個(gè)對(duì)象CMainParamsCTestNetParamsCRegTestParams的定義都在chainparams.cpp文件中。感興趣同學(xué)的可以對(duì)照源代碼進(jìn)一步探究。

接下來(lái),設(shè)置系統(tǒng)可接收的所有參數(shù)。部分參數(shù)解釋如下:

-version,打印版本信息,并退出系統(tǒng)。

-assumevalid=hex,如果指定的區(qū)塊存在區(qū)塊鏈中,假定它及其祖先有效并可能跳過(guò)其腳本驗(yàn)證。

-blocksdir=dir,指定區(qū)塊鏈存放的目錄。

-blocknotify=cmd,指定當(dāng)主鏈上的區(qū)塊改變時(shí)執(zhí)行的命令。

-conf=file,指定配置文件的目錄,相對(duì)于下面指定的數(shù)據(jù)目錄。

-datadir=dir,指定數(shù)據(jù)目錄。

-dbcache=n,設(shè)置數(shù)據(jù)庫(kù)緩存大小。

-debuglogfile=file,設(shè)置調(diào)試文件的位置。

-feefilter,告訴其他節(jié)點(diǎn)通過(guò)最小交易費(fèi)用過(guò)濾發(fā)送給我們的庫(kù)存消息。

-loadblock=file,在啟動(dòng)時(shí),從外部blk000??.dat文件導(dǎo)入?yún)^(qū)塊。

-maxmempool=n,指定交易池的最大內(nèi)存數(shù),單位為兆字節(jié)。

-maxorphantx=n,指定內(nèi)存中最大的孤兒交易數(shù)量。

-mempoolexpiry=n,指定交易池中不跟蹤超過(guò)指定時(shí)間(小時(shí))的交易。

-par=n,指定腳本簽名的線程數(shù)量。

-persistmempool,指定是否持久化交易池中的交易,啟動(dòng)時(shí)恢復(fù)加載。

-pid=file,指定進(jìn)程文件。

-prune=n,通過(guò)啟用舊區(qū)塊的修剪(刪除)來(lái)降低存儲(chǔ)要求。這允許調(diào)用pruneblockchainRPC來(lái)刪除特定塊,并且如果提供目標(biāo)大小,則啟用對(duì)舊塊的自動(dòng)修剪。此模式與-txindex和-rescan不兼容。

-reindex,根據(jù)硬盤(pán)上的blk*.dat文件重建區(qū)塊鏈狀態(tài)和區(qū)塊的索引。

-reindex-chainstate,根據(jù)當(dāng)前區(qū)塊的索引重建區(qū)塊鏈的狀態(tài)。

-txindex,維護(hù)所有交易的索引,被getrawtransactionRPC命令調(diào)用。

-addnode=ip,添加一個(gè)節(jié)點(diǎn),并連接它,并保持連接。

-banscore=n,斷開(kāi)行為不端的同伴的門檻。

-bantime=n,不誠(chéng)實(shí)節(jié)點(diǎn)重新連接需要的秒數(shù)。

-bind=addr,綁定到指定的IP,并總是連接到這個(gè)地址。

-connect=ip,僅僅只連接到指定的節(jié)點(diǎn),如果不是ip而是0,則表示禁止自動(dòng)連接。

-discover,是否發(fā)現(xiàn)自己的IP地址。

-dns,對(duì)于-addnode、-seednode、-connect總是使用DNS查找。

-dnsseed,指定如果已有地址比較少,則進(jìn)行DNS查找來(lái)獲取對(duì)等節(jié)點(diǎn)。

-enablebip61,允許發(fā)送BIP61定義的拒絕消息。

-externalip=ip,指定自身的外部IP地址。

-forcednsseed,總是通過(guò)DNS查找來(lái)獲取對(duì)等節(jié)點(diǎn)的地址。

-listen,接收外部對(duì)等節(jié)點(diǎn)的連接。

-listenonion,自動(dòng)創(chuàng)建Tor隱藏服務(wù)。

-maxconnections=n,維護(hù)到別的節(jié)點(diǎn)的最大連接數(shù)。

-maxreceivebuffer=n,每個(gè)對(duì)等節(jié)點(diǎn)的最大接收緩存。

-maxsendbuffer=n,每個(gè)對(duì)等節(jié)點(diǎn)的最大發(fā)送緩存。

-onion=ip:port,設(shè)置SOCKS5代理。

-peerbloomfilters,支持布隆過(guò)濾器過(guò)濾區(qū)塊和交易。

-permitbaremultisig,中繼非P2SH多重簽名。

-port=port,指定默認(rèn)的監(jiān)聽(tīng)端口。

-proxy=ip:port,通過(guò)SOCKS5代理進(jìn)行連接。

-proxyrandomize,隨機(jī)化每個(gè)代理連接的憑據(jù)。從而使Tor流進(jìn)行隔離。

-seednode=ip,指定一個(gè)節(jié)點(diǎn)來(lái)檢索其他的節(jié)點(diǎn),隨后就從這個(gè)接點(diǎn)進(jìn)行斷開(kāi)。

-torcontrol=ip:port,在onion啟用的情況下,指定Tor控制器使用的端口。

-torpassword=pass,Tor控制器的密碼。

-checkblocks=n,在啟動(dòng)時(shí)要檢查多少個(gè)區(qū)塊。

-checklevel=n,checkblocks驗(yàn)證區(qū)塊的程度。

-checkblockindex,進(jìn)行完整的一致性檢查,包括:mapBlockIndex、setBlockIndexCandidates、chainActive、mapBlocksUnlinked等。

-checkmempool=n,每多少個(gè)交易進(jìn)行檢驗(yàn)。

-checkpoints,提供檢查點(diǎn),對(duì)已知鏈的歷史不進(jìn)行檢驗(yàn)。

-deprecatedrpc=method,不贊成使用的RPC方法。

-limitancestorcount=n,如果交易池中的祖先交易達(dá)到或超過(guò)指定的值時(shí),不再接收交易。

-limitancestorsize=n,如果交易池中的祖先交易大小達(dá)到或超過(guò)指定的值時(shí),不再接收交易。

-limitdescendantcount=n,如果交易池中祖先交易的后代已經(jīng)達(dá)到或超過(guò)指定的值時(shí),不再接收交易。

-blockmaxweight=n,設(shè)置BIP141區(qū)塊的最大weight。

-blockmintxfee=amt,設(shè)置包含在創(chuàng)建區(qū)塊的交易最小費(fèi)用。

-rpcuser=user,進(jìn)行RPC調(diào)用的用戶名。

-rpcpassword=pw,進(jìn)行RPC調(diào)用的用戶密碼。

-rpcport=port,進(jìn)行RPC調(diào)用的端口

上面是一些常用的參數(shù),通過(guò)這些參數(shù)可以影響比特幣核心的命令。應(yīng)用開(kāi)發(fā)者比較關(guān)注的是RPC相關(guān)的設(shè)置,通過(guò)RPC接口,我們調(diào)用比特幣核心提供的多種服務(wù)。這些命令通常會(huì)在配置文件中進(jìn)行設(shè)置,不用在命令行指定。

接下來(lái),檢查用戶指定命令參數(shù)是否正確。

 if (!gArgs.ParseParameters(argc, argv, error)) {
     fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
     return false;
 }

如果傳遞的是幫助和版本參數(shù),則顯示幫助或版本信息,然后退出。

檢查數(shù)據(jù)目錄(可指定或默認(rèn))是否是存在。如果不存在,則打印錯(cuò)誤信息,然后退出。

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方法中,根據(jù)用戶是否在命令行提供datadir參數(shù)來(lái)確定使用默認(rèn)的數(shù)據(jù)目錄還是用戶指定的數(shù)據(jù)目錄。

讀取并解析配置文件,同時(shí)檢查指定數(shù)據(jù)目錄是否存在。如果任何一個(gè)步驟出錯(cuò),都打印錯(cuò)誤信息,然后退出。

if (!gArgs.ReadConfigFiles(error, true)) {
     fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
     return false;
 }

其中ReadConfigFiles方法具體處理如下:

首先,調(diào)用GetArg方法,獲取配置文件名稱,默認(rèn)為bitcoin.conf。

然后,通過(guò)GetConfigFile方法獲取配置文件的絕對(duì)路徑(方法內(nèi)部會(huì)委托AbsPathForConfigVal方法進(jìn)行處理,后者決定根據(jù)用戶指定的路徑或使用默認(rèn)路徑來(lái)生成配置文件的絕對(duì)路徑)。在得到配置文件的絕對(duì)路徑之后,構(gòu)造文件輸入流,從而讀取配置文件fs::ifstreamstream(GetConfigFile(confPath))。

在成功構(gòu)造輸入流之后,調(diào)用ReadConfigStream方法開(kāi)始讀取配置文件的內(nèi)容。方法內(nèi)部按行讀取配置文件,并以鍵值對(duì)的形式保存在m_config_args集合中。

調(diào)用SelectParams(gArgs.GetChainName())函數(shù),生成全局的區(qū)塊鏈參數(shù),并設(shè)置系統(tǒng)的網(wǎng)絡(luò)類型。如果有錯(cuò)誤,則打印錯(cuò)誤,然后退出。gArgs.GetChainName()方法會(huì)返回當(dāng)前使用的網(wǎng)絡(luò)。針對(duì)主網(wǎng)絡(luò),返回字符串main;測(cè)試網(wǎng)絡(luò),返回字符串test;回歸測(cè)試網(wǎng)絡(luò),返回字符串regtest。SelectParams方法的實(shí)現(xiàn)如下所示:

void SelectParams(const std::string& network)
{
   SelectBaseParams(network);
   globalChainParams = CreateChainParams(network);
}

SelectBaseParams方法會(huì)根據(jù)指定的網(wǎng)絡(luò)參數(shù)生成CBaseChainParams對(duì)象,并保存在globalChainBaseParams變量中,并在指定gArgs對(duì)象中保存網(wǎng)絡(luò)類型(m_network屬性)。CBaseChainParams對(duì)象中僅保存系統(tǒng)的數(shù)據(jù)目錄和運(yùn)行的端口,所以稱之為基本區(qū)塊鏈參數(shù)對(duì)象。

CreateChainParams方法會(huì)根據(jù)不同的網(wǎng)絡(luò)參數(shù)生成CChainParams類的子對(duì)象,可能為以下三種:CMainParams、CTestNetParams、CRegTestParams。CChainParams對(duì)象包含了區(qū)塊鏈對(duì)象的所有重要信息,比如:共識(shí)規(guī)則、部署狀態(tài)、檢查點(diǎn)、創(chuàng)世區(qū)塊等。

檢查所有命令行參數(shù),如果有錯(cuò)誤,則打印錯(cuò)誤,并退出。

設(shè)置參數(shù)-server默認(rèn)為真。bitcoind守護(hù)進(jìn)程默認(rèn)server為真。

調(diào)用InitLogging函數(shù),初始化系統(tǒng)所用日志,并打印系統(tǒng)的版本信息。具體代碼如下,根據(jù)是否指定debuglogfile、printtoconsole等確定日志打印到文件或是控制臺(tái)。

void InitLogging()
{
   g_logger->m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
   g_logger->m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
   LogPrintf("\n\n\n\n\n");

   g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
   g_logger->m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
   g_logger->m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);

   fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);

   std::string version_string = FormatFullVersion();

   LogPrintf(PACKAGE_NAME " version %s\n", version_string);
}

調(diào)用InitParameterInteraction函數(shù),根據(jù)參數(shù)間的關(guān)系,檢查所有的交互參數(shù)。

調(diào)用AppInitBasicSetup函數(shù),進(jìn)行基本的設(shè)置。如果有錯(cuò)誤,則打印錯(cuò)誤,然后退出。經(jīng)過(guò)前面漫長(zhǎng)的檢查與設(shè)置,終于開(kāi)始了應(yīng)用基本的設(shè)置。具體解讀見(jiàn)第二部分。

調(diào)用AppInitSanityChecks函數(shù),處理底層加密函數(shù)相關(guān)內(nèi)容。具體解讀見(jiàn)第二部分。

調(diào)用AppInitLockDataDirectory函數(shù),檢查并鎖定數(shù)據(jù)目錄。具體解讀見(jiàn)第二部分。

調(diào)用AppInitMain函數(shù),比特幣主要的啟動(dòng)過(guò)程。具體解讀見(jiàn)第二部分。

如果應(yīng)用初始化主函數(shù)出錯(cuò),則調(diào)用Interrupt函數(shù)進(jìn)行中止,否則調(diào)用WaitForShutdown函數(shù)等待系統(tǒng)結(jié)束。WaitForShutdown函數(shù)是一個(gè)無(wú)限循環(huán)函數(shù)。


【關(guān)注微信公眾號(hào)獲取更多學(xué)習(xí)資料】

 

查看更多關(guān)于區(qū)塊鏈培訓(xùn)技術(shù)資訊的相關(guān)文章>>

標(biāo)簽: 區(qū)塊鏈培訓(xùn) 區(qū)塊鏈技術(shù) 區(qū)塊鏈開(kāi)發(fā) 區(qū)塊鏈視頻教程 比特幣 以太坊

熱門專區(qū)

暫無(wú)熱門資訊

課程推薦

微信
微博
15311698296

全國(guó)免費(fèi)咨詢熱線

郵箱:codingke@1000phone.com

官方群:148715490

北京千鋒互聯(lián)科技有限公司版權(quán)所有   北京市海淀區(qū)寶盛北里西區(qū)28號(hào)中關(guān)村智誠(chéng)科創(chuàng)大廈4層
京ICP備2021002079號(hào)-2   Copyright ? 2017 - 2022
返回頂部 返回頂部